plan9fox/sys/src/cmd/spin/pangen6.h
cinap_lenrek 28e9566dc5 spin: Update to most recent version. (thanks Ori_B)
from Ori_B:

There were a small number of changes needed from the tarball
on spinroot.org:

  - The mkfile needed to be updated
  - Memory.h needed to not be included
  - It needed to invoke /bin/cpp instead of gcc -E
  - It depended on `yychar`, which our yacc doesn't
    provide.

I'm still figuring out how to use spin, but it seems to do
the right thing when testing a few of the examples:

	% cd $home/src/Spin/Examples/
	% spin -a peterson.pml
	% pcc pan.c -D_POSIX_SOURCE
	% ./6.out

	(Spin Version 6.4.7 -- 19 August 2017)
		+ Partial Order Reduction

	Full statespace search for:
		never claim         	- (none specified)
		assertion violations	+
		acceptance   cycles 	- (not selected)
		invalid end states	+

	State-vector 32 byte, depth reached 24, errors: 0
	40 states, stored
	27 states, matched
	67 transitions (= stored+matched)
		0 atomic steps
	hash conflicts:         0 (resolved)

	Stats on memory usage (in Megabytes):
	0.002	equivalent memory usage for states (stored*(State-vector + overhead))
	0.292	actual memory usage for states
	128.000	memory used for hash table (-w24)
	0.534	memory used for DFS stack (-m10000)
	128.730	total actual memory usage


	unreached in proctype user
		/tmp/Spin/Examples/peterson.pml:20, state 10, "-end-"
		(1 of 10 states)

	pan: elapsed time 1.25 seconds
	pan: rate        32 states/second
2017-11-22 21:09:31 +01:00

2879 lines
90 KiB
C

/***** spin: pangen6.h *****/
/*
* This file is part of the public release of Spin. It is subject to the
* terms in the LICENSE file that is included in this source directory.
* Tool documentation is available at http://spinroot.com
*/
static const char *Code2e[] = {
"#if (NCORE>1 || defined(BFS_PAR)) && !defined(WIN32) && !defined(WIN64)",
" /* Test and Set assembly code */",
" #if defined(i386) || defined(__i386__) || defined(__x86_64__)",
" int",
" tas(volatile int *s) /* tested */",
" { int r;",
" __asm__ __volatile__(",
" \"xchgl %%0, %%1 \\n\\t\"",
" : \"=r\"(r), \"=m\"(*s)",
" : \"0\"(1), \"m\"(*s)",
" : \"memory\");",
" ",
" return r;",
" }",
" #elif defined(__arm__)",
" int",
" tas(volatile int *s) /* not tested */",
" { int r = 1;",
" __asm__ __volatile__(",
" \"swpb %%0, %%0, [%%3] \\n\"",
" : \"=r\"(r), \"=m\"(*s)",
" : \"0\"(r), \"r\"(s));",
"",
" return r;",
" }",
" #elif defined(sparc) || defined(__sparc__)",
" int",
" tas(volatile int *s) /* not tested */",
" { int r = 1;",
" __asm__ __volatile__(",
" \" ldstub [%%2], %%0 \\n\"",
" : \"=r\"(r), \"=m\"(*s)",
" : \"r\"(s));",
"",
" return r;",
" }",
" #elif defined(ia64) || defined(__ia64__)",
" /* Intel Itanium */",
" int",
" tas(volatile int *s) /* tested */",
" { long int r;",
" __asm__ __volatile__(",
" \" xchg4 %%0=%%1,%%2 \\n\"",
" : \"=r\"(r), \"+m\"(*s)",
" : \"r\"(1)",
" : \"memory\");",
" return (int) r;",
" }",
" #elif defined(__powerpc64__)",
" int",
" tas(volatile int *s) /* courtesy srirajpaul */",
" { int r;",
" #if 1",
" r = __sync_lock_test_and_set();",
" #else",
" /* xlc compiler only */",
" r = __fetch_and_or(s, 1);",
" __isync();",
" #endif",
" return r;",
" }",
" #else",
" #error missing definition of test and set operation for this platform",
" #endif",
"",
" #ifndef NO_CAS", /* linux, windows */
" #define cas(a,b,c) __sync_bool_compare_and_swap(a,b,c)",
" #else",
" int", /* workaround if the above is not available */
" cas(volatile uint32_t *a, uint32_t b, uint32_t c)",
" { static volatile int cas_lock;",
" while (tas(&cas_lock) != 0) { ; }",
" if (*a == b)",
" { *a = c;",
" cas_lock = 0;",
" return 1;",
" }",
" cas_lock = 0;",
" return 0;",
" }",
" #endif",
"#endif",
0,
};
static const char *Code2c[] = { /* multi-core option - Spin 5.0 and later */
"#if NCORE>1",
"#if defined(WIN32) || defined(WIN64)",
" #ifndef _CONSOLE",
" #define _CONSOLE",
" #endif",
" #ifdef WIN64",
" #undef long",
" #endif",
" #include <windows.h>",
"/*",
" #ifdef WIN64",
" #define long long long",
" #endif",
"*/",
"#else",
" #include <sys/ipc.h>",
" #include <sys/sem.h>",
" #include <sys/shm.h>",
"#endif",
"",
"/* code common to cygwin/linux and win32/win64: */",
"",
"#ifdef VERBOSE",
" #define VVERBOSE (1)",
"#else",
" #define VVERBOSE (0)",
"#endif",
"",
"/* the following values must be larger than 256 and must fit in an int */",
"#define QUIT 1024 /* terminate now command */",
"#define QUERY 512 /* termination status query message */",
"#define QUERY_F 513 /* query failed, cannot quit */",
"",
"#define GN_FRAMES (int) (GWQ_SIZE / (double) sizeof(SM_frame))",
"#define LN_FRAMES (int) (LWQ_SIZE / (double) sizeof(SM_frame))",
"",
"#ifndef VMAX",
" #define VMAX VECTORSZ",
"#endif",
"#ifndef PMAX",
" #define PMAX 64",
"#endif",
"#ifndef QMAX",
" #define QMAX 64",
"#endif",
"",
"#if VECTORSZ>32000",
" #define OFFT int",
"#else",
" #define OFFT short",
"#endif",
"",
"#ifdef SET_SEG_SIZE",
" /* no longer useful -- being recomputed for local heap size anyway */",
" double SEG_SIZE = (((double) SET_SEG_SIZE) * 1048576.);",
"#else",
" double SEG_SIZE = (1048576.*1024.); /* 1GB default shared memory pool segments */",
"#endif",
"",
"double LWQ_SIZE = 0.; /* initialized in main */",
"",
"#ifdef SET_WQ_SIZE",
" #ifdef NGQ",
" #warning SET_WQ_SIZE applies to global queue -- ignored",
" double GWQ_SIZE = 0.;",
" #else",
" double GWQ_SIZE = (((double) SET_WQ_SIZE) * 1048576.);",
" /* must match the value in pan_proxy.c, if used */",
" #endif",
"#else",
" #ifdef NGQ",
" double GWQ_SIZE = 0.;",
" #else",
" double GWQ_SIZE = (128.*1048576.); /* 128 MB default queue sizes */",
" #endif",
"#endif",
"",
"/* Crash Detection Parameters */",
"#ifndef ONESECOND",
" #define ONESECOND (1<<25)", /* name is somewhat of a misnomer */
"#endif",
"#ifndef SHORT_T",
" #define SHORT_T (0.1)",
"#endif",
"#ifndef LONG_T",
" #define LONG_T (600)",
"#endif",
"",
"double OneSecond = (double) (ONESECOND); /* waiting for a free slot -- checks crash */",
"double TenSeconds = 10. * (ONESECOND); /* waiting for a lock -- check for a crash */",
"",
"/* Termination Detection Params -- waiting for new state input in Get_Full_Frame */",
"double Delay = ((double) SHORT_T) * (ONESECOND); /* termination detection trigger */",
"double OneHour = ((double) LONG_T) * (ONESECOND); /* timeout termination detection */",
"",
"typedef struct SM_frame SM_frame;",
"typedef struct SM_results SM_results;",
"typedef struct sh_Allocater sh_Allocater;",
"",
"struct SM_frame { /* about 6K per slot */",
" volatile int m_vsize; /* 0 means free slot */",
" volatile int m_boq; /* >500 is a control message */",
"#ifdef FULL_TRAIL",
" volatile struct Stack_Tree *m_stack; /* ptr to previous state */",
"#endif",
" volatile uchar m_tau;",
" volatile uchar m_o_pm;",
" volatile int nr_handoffs; /* to compute real_depth */",
" volatile char m_now [VMAX];",
"#if !defined(NOCOMP) && !defined(HC)",
" volatile char m_mask [(VMAX + 7)/8];",
"#endif",
" volatile OFFT m_p_offset[PMAX];",
" volatile OFFT m_q_offset[QMAX];",
" volatile uchar m_p_skip [PMAX];",
" volatile uchar m_q_skip [QMAX];",
"#if defined(C_States) && (HAS_TRACK==1) && (HAS_STACK==1)",
" volatile uchar m_c_stack [StackSize];",
/* captures contents of c_stack[] for unmatched objects */
"#endif",
"};",
"",
"int proxy_pid; /* id of proxy if nonzero -- receive half */",
"int store_proxy_pid;",
"short remote_party;",
"int proxy_pid_snd; /* id of proxy if nonzero -- send half */",
"char o_cmdline[512]; /* to pass options to children */",
"",
"int iamin[CS_NR+NCORE]; /* non-shared */",
"",
"#if defined(WIN32) || defined(WIN64)",
"int tas(volatile LONG *);",
"",
"HANDLE proxy_handle_snd; /* for Windows Create and Terminate */",
"",
"struct sh_Allocater { /* shared memory for states */",
" volatile char *dc_arena; /* to allocate states from */",
" volatile long pattern; /* to detect overruns */",
" volatile long dc_size; /* nr of bytes left */",
" volatile void *dc_start; /* where memory segment starts */",
" volatile void *dc_id; /* to attach, detach, remove shared memory segments */",
" volatile sh_Allocater *nxt; /* linked list of pools */",
"};",
"DWORD worker_pids[NCORE]; /* root mem of pids of all workers created */",
"HANDLE worker_handles[NCORE]; /* for windows Create and Terminate */",
"void * shmid [NR_QS]; /* return value from CreateFileMapping */",
"void * shmid_M; /* shared mem for state allocation in hashtable */",
"",
"#ifdef SEP_STATE",
" void *shmid_X;",
"#else",
" void *shmid_S; /* shared bitstate arena or hashtable */",
"#endif",
"#else",
"int tas(volatile int *);",
"",
"struct sh_Allocater { /* shared memory for states */",
" volatile char *dc_arena; /* to allocate states from */",
" volatile long pattern; /* to detect overruns */",
" volatile long dc_size; /* nr of bytes left */",
" volatile char *dc_start; /* where memory segment starts */",
" volatile int dc_id; /* to attach, detach, remove shared memory segments */",
" volatile sh_Allocater *nxt; /* linked list of pools */",
"};",
"",
"int worker_pids[NCORE]; /* root mem of pids of all workers created */",
"int shmid [NR_QS]; /* return value from shmget */",
"int nibis = 0; /* set after shared mem has been released */",
"int shmid_M; /* shared mem for state allocation in hashtable */",
"#ifdef SEP_STATE",
" long shmid_X;",
"#else",
" int shmid_S; /* shared bitstate arena or hashtable */",
" volatile sh_Allocater *first_pool; /* of shared state memory */",
" volatile sh_Allocater *last_pool;",
"#endif", /* SEP_STATE */
"#endif", /* WIN32 || WIN64 */
"",
"struct SM_results { /* for shuttling back final stats */",
" volatile int m_vsize; /* avoid conflicts with frames */",
" volatile int m_boq; /* these 2 fields are not written in record_info */",
" /* probably not all fields really need to be volatile */",
" volatile double m_memcnt;",
" volatile double m_nstates;",
" volatile double m_truncs;",
" volatile double m_truncs2;",
" volatile double m_nShadow;",
" volatile double m_nlinks;",
" volatile double m_ngrabs;",
" volatile double m_nlost;",
" volatile double m_hcmp;",
" volatile double m_frame_wait;",
" volatile int m_hmax;",
" volatile int m_svmax;",
" volatile int m_smax;",
" volatile int m_mreached;",
" volatile int m_errors;",
" volatile int m_VMAX;",
" volatile short m_PMAX;",
" volatile short m_QMAX;",
" volatile uchar m_R; /* reached info for all proctypes */",
"};",
"",
"int core_id = 0; /* internal process nr, to know which q to use */",
"unsigned long nstates_put = 0; /* statistics */",
"unsigned long nstates_get = 0;",
"int query_in_progress = 0; /* termination detection */",
"",
"double free_wait = 0.; /* waiting for a free frame */",
"double frame_wait = 0.; /* waiting for a full frame */",
"double lock_wait = 0.; /* waiting for access to cs */",
"double glock_wait[3]; /* waiting for access to global lock */",
"",
"char *sprefix = \"rst\";",
"uchar was_interrupted, issued_kill, writing_trail;",
"",
"static SM_frame cur_Root; /* current root, to be safe with error trails */",
"",
"SM_frame *m_workq [NR_QS]; /* per cpu work queues + global q */",
"char *shared_mem[NR_QS]; /* return value from shmat */",
"#ifdef SEP_HEAP",
"char *my_heap;",
"long my_size;",
"#endif",
"volatile sh_Allocater *dc_shared; /* assigned at initialization */",
"",
"static int vmax_seen, pmax_seen, qmax_seen;",
"static double gq_tries, gq_hasroom, gq_hasnoroom;",
"",
"volatile int *prfree;", /* [NCORE] */
"volatile int *prfull;", /* [NCORE] */
"volatile int *prcnt;", /* [NCORE] */
"volatile int *prmax;", /* [NCORE] */
"",
"volatile int *sh_lock; /* mutual exclusion locks - in shared memory */",
"volatile double *is_alive; /* to detect when processes crash */",
"volatile int *grfree, *grfull, *grcnt, *grmax; /* access to shared global q */",
"volatile double *gr_readmiss, *gr_writemiss;",
"static int lrfree; /* used for temporary recording of slot */",
"static int dfs_phase2;",
"",
"void mem_put(int); /* handoff state to other cpu */",
"void mem_put_acc(void); /* liveness mode */",
"void mem_get(void); /* get state from work queue */",
"void sudden_stop(char *);",
"",
"void",
"record_info(SM_results *r)",
"{ int i;",
" uchar *ptr;",
"",
"#ifdef SEP_STATE",
" if (0)",
" { cpu_printf(\"nstates %%g nshadow %%g -- memory %%-6.3f Mb\\n\",",
" nstates, nShadow, memcnt/(1048576.));",
" }",
" r->m_memcnt = 0;",
"#else",
" #ifdef BITSTATE",
" r->m_memcnt = 0; /* it's shared */",
" #endif",
" r->m_memcnt = memcnt;",
"#endif",
" if (a_cycles && core_id == 1)",
" { r->m_nstates = nstates;",
" r->m_nShadow = nstates;",
" } else",
" { r->m_nstates = nstates;",
" r->m_nShadow = nShadow;",
" }",
" r->m_truncs = truncs;",
" r->m_truncs2 = truncs2;",
" r->m_nlinks = nlinks;",
" r->m_ngrabs = ngrabs;",
" r->m_nlost = nlost;",
" r->m_hcmp = hcmp;",
" r->m_frame_wait = frame_wait;",
" r->m_hmax = hmax;",
" r->m_svmax = svmax;",
" r->m_smax = smax;",
" r->m_mreached = mreached;",
" r->m_errors = errors;",
" r->m_VMAX = vmax_seen;",
" r->m_PMAX = (short) pmax_seen;",
" r->m_QMAX = (short) qmax_seen;",
" ptr = (uchar *) &(r->m_R);",
" for (i = 0; i <= _NP_; i++) /* all proctypes */",
" { memcpy(ptr, reached[i], NrStates[i]*sizeof(uchar));",
" ptr += NrStates[i]*sizeof(uchar);",
" }",
" if (verbose>1)",
" { cpu_printf(\"Put Results nstates %%g (sz %%d)\\n\", nstates, ptr - &(r->m_R));",
" }",
"}",
"",
"void snapshot(void);",
"",
"void",
"retrieve_info(SM_results *r)",
"{ int i, j;",
" volatile uchar *ptr;",
"",
" snapshot(); /* for a final report */",
"",
" enter_critical(GLOBAL_LOCK);",
"#ifdef SEP_HEAP",
" if (verbose)",
" { printf(\"cpu%%d: local heap-left %%ld KB (%%d MB)\\n\",",
" core_id, (long) (my_size/1024), (int) (my_size/1048576));",
" }",
"#endif",
" if (verbose && core_id == 0)",
" { printf(\"qmax: \");",
" for (i = 0; i < NCORE; i++)",
" { printf(\"%%d \", prmax[i]);",
" }",
"#ifndef NGQ",
" printf(\"G: %%d\", *grmax);",
"#endif",
" printf(\"\\n\");",
" }",
" leave_critical(GLOBAL_LOCK);",
"",
" memcnt += r->m_memcnt;",
" nstates += r->m_nstates;",
" nShadow += r->m_nShadow;",
" truncs += r->m_truncs;",
" truncs2 += r->m_truncs2;",
" nlinks += r->m_nlinks;",
" ngrabs += r->m_ngrabs;",
" nlost += r->m_nlost;",
" hcmp += r->m_hcmp;",
" /* frame_wait += r->m_frame_wait; */",
" errors += r->m_errors;",
"",
" if (hmax < r->m_hmax) hmax = r->m_hmax;",
" if (svmax < r->m_svmax) svmax = r->m_svmax;",
" if (smax < r->m_smax) smax = r->m_smax;",
" if (mreached < r->m_mreached) mreached = r->m_mreached;",
"",
" if (vmax_seen < r->m_VMAX) vmax_seen = r->m_VMAX;",
" if (pmax_seen < (int) r->m_PMAX) pmax_seen = (int) r->m_PMAX;",
" if (qmax_seen < (int) r->m_QMAX) qmax_seen = (int) r->m_QMAX;",
"",
" ptr = &(r->m_R);",
" for (i = 0; i <= _NP_; i++) /* all proctypes */",
" { for (j = 0; j < NrStates[i]; j++)",
" { if (*(ptr + j) != 0)",
" { reached[i][j] = 1;",
" } }",
" ptr += NrStates[i]*sizeof(uchar);",
" }",
" if (verbose>1)",
" { cpu_printf(\"Got Results (%%d)\\n\", (int) (ptr - &(r->m_R)));",
" snapshot();",
" }",
"}",
"",
"#if !defined(WIN32) && !defined(WIN64)",
"static void",
"rm_shared_segments(void)",
"{ int m;",
" volatile sh_Allocater *nxt_pool;",
" /*",
" * mark all shared memory segments for removal ",
" * the actual removes wont happen intil last process dies or detaches",
" * the shmctl calls can return -1 if not all procs have detached yet",
" */",
" for (m = 0; m < NR_QS; m++) /* +1 for global q */",
" { if (shmid[m] != -1)",
" { (void) shmctl(shmid[m], IPC_RMID, NULL);",
" } }",
"#ifdef SEP_STATE",
" if (shmid_M != -1)",
" { (void) shmctl(shmid_M, IPC_RMID, NULL);",
" }",
"#else",
" if (shmid_S != -1)",
" { (void) shmctl(shmid_S, IPC_RMID, NULL);",
" }",
" for (last_pool = first_pool; last_pool != NULL; last_pool = nxt_pool)",
" { shmid_M = (int) (last_pool->dc_id);",
" nxt_pool = last_pool->nxt; /* as a pre-caution only */",
" if (shmid_M != -1)",
" { (void) shmctl(shmid_M, IPC_RMID, NULL);",
" } }",
"#endif",
"}",
"#endif",
"",
"void",
"sudden_stop(char *s)",
"{ char b[64];",
" int i;",
"",
" printf(\"cpu%%d: stop - %%s\\n\", core_id, s);",
"#if !defined(WIN32) && !defined(WIN64)",
" if (proxy_pid != 0)",
" { rm_shared_segments();",
" }",
"#endif",
" if (search_terminated != NULL)",
" { if (*search_terminated != 0)",
" { if (verbose)",
" { printf(\"cpu%%d: termination initiated (%%d)\\n\",",
" core_id, (int) *search_terminated);",
" }",
" } else",
" { if (verbose)",
" { printf(\"cpu%%d: initiated termination\\n\", core_id);",
" }",
" *search_terminated |= 8; /* sudden_stop */",
" }",
" if (core_id == 0)",
" { if (((*search_terminated) & 4) /* uerror in one of the cpus */",
" && !((*search_terminated) & (8|32|128|256))) /* abnormal stop */",
" { if (errors == 0) errors++; /* we know there is at least 1 */",
" }",
" wrapup(); /* incomplete stats, but at least something */",
" }",
" return;",
" } /* else: should rarely happen, take more drastic measures */",
"",
" if (core_id == 0) /* local root process */",
" { for (i = 1; i < NCORE; i++) /* not for 0 of course */",
" { int ignore;",
"#if defined(WIN32) || defined(WIN64)",
" DWORD dwExitCode = 0;",
" GetExitCodeProcess(worker_handles[i], &dwExitCode);",
" if (dwExitCode == STILL_ACTIVE)",
" { TerminateProcess(worker_handles[i], 0);",
" }",
" printf(\"cpu0: terminate %%d %%d\\n\",",
" (int) worker_pids[i], (dwExitCode == STILL_ACTIVE));",
"#else",
" sprintf(b, \"kill -%%d %%d\", (int) SIGKILL, (int) worker_pids[i]);",
" ignore = system(b); /* if this is a proxy: receive half */",
" printf(\"cpu0: %%s\\n\", b);",
"#endif",
" }",
" issued_kill++;",
" } else",
" { /* on WIN32/WIN64 -- these merely kills the root process... */",
" if (was_interrupted == 0)", /* 2=SIGINT to root to trigger stop */
" { int ignore;",
" sprintf(b, \"kill -%%d %%d\", (int) SIGINT, (int) worker_pids[0]);",
" ignore = system(b); /* warn the root process */",
" printf(\"cpu%%d: %%s\\n\", core_id, b);",
" issued_kill++;",
" } }",
"}",
"",
"#define iam_alive() is_alive[core_id]++", /* for crash detection */
"",
"extern int crash_test(double);",
"extern void crash_reset(void);",
"",
"int",
"someone_crashed(int wait_type)",
"{ static double last_value = 0.0;",
" static int count = 0;",
"",
" if (search_terminated == NULL",
" || *search_terminated != 0)",
" {",
" if (!(*search_terminated & (8|32|128|256)))",
" { if (count++ < 100*NCORE)",
" { return 0;",
" } }",
" return 1;",
" }",
" /* check left neighbor only */",
" if (last_value == is_alive[(core_id + NCORE - 1) %% NCORE])",
" { if (count++ >= 100) /* to avoid unnecessary checks */",
" { return 1;",
" }",
" return 0;",
" }",
" last_value = is_alive[(core_id + NCORE - 1) %% NCORE];",
" count = 0;",
" crash_reset();",
" return 0;",
"}",
"",
"void",
"sleep_report(void)",
"{",
" enter_critical(GLOBAL_LOCK);",
" if (verbose)",
" {",
"#ifdef NGQ",
" printf(\"cpu%%d: locks: global %%g\\tother %%g\\t\",",
" core_id, glock_wait[0], lock_wait - glock_wait[0]);",
"#else",
" printf(\"cpu%%d: locks: GL %%g, RQ %%g, WQ %%g, HT %%g\\t\",",
" core_id, glock_wait[0], glock_wait[1], glock_wait[2],",
" lock_wait - glock_wait[0] - glock_wait[1] - glock_wait[2]);",
"#endif",
" printf(\"waits: states %%g slots %%g\\n\", frame_wait, free_wait);",
"#ifndef NGQ",
" printf(\"cpu%%d: gq [tries %%g, room %%g, noroom %%g]\\n\", core_id, gq_tries, gq_hasroom, gq_hasnoroom);",
" if (core_id == 0 && (*gr_readmiss >= 1.0 || *gr_readmiss >= 1.0 || *grcnt != 0))",
" printf(\"cpu0: gq [readmiss: %%g, writemiss: %%g cnt %%d]\\n\", *gr_readmiss, *gr_writemiss, *grcnt);",
"#endif",
" }",
" if (free_wait > 1000000.)",
" #ifndef NGQ",
" if (!a_cycles)",
" { printf(\"hint: this search may be faster with a larger work-queue\\n\");",
" printf(\" (-DSET_WQ_SIZE=N with N>%%g), and/or with -DUSE_DISK\\n\",",
" GWQ_SIZE/sizeof(SM_frame));",
" printf(\" or with a larger value for -zN (N>%%ld)\\n\", z_handoff);",
" #else",
" { printf(\"hint: this search may be faster if compiled without -DNGQ, with -DUSE_DISK, \");",
" printf(\"or with a larger -zN (N>%%d)\\n\", z_handoff);",
" #endif",
" }",
" leave_critical(GLOBAL_LOCK);",
"}",
"",
"#ifndef MAX_DSK_FILE",
" #define MAX_DSK_FILE 1000000 /* default is max 1M states per file */",
"#endif",
"",
"void",
"multi_usage(FILE *fd)",
"{ static int warned = 0;",
" if (warned > 0) { return; } else { warned++; }",
" fprintf(fd, \"\\n\");",
" fprintf(fd, \"Defining multi-core mode:\\n\\n\");",
" fprintf(fd, \" -DDUAL_CORE --> same as -DNCORE=2\\n\");",
" fprintf(fd, \" -DQUAD_CORE --> same as -DNCORE=4\\n\");",
" fprintf(fd, \" -DNCORE=N --> enables multi_core verification if N>1\\n\");",
" fprintf(fd, \"\\n\");",
" fprintf(fd, \"Additional directives supported in multi-core mode:\\n\\n\");",
" fprintf(fd, \" -DSEP_STATE --> forces separate statespaces instead of a single shared state space\\n\");",
" fprintf(fd, \" -DNUSE_DISK --> use disk for storing states when a work queue overflows\\n\");",
" fprintf(fd, \" -DMAX_DSK_FILE --> max nr of states per diskfile (%%d)\\n\", MAX_DSK_FILE);",
" fprintf(fd, \" -DFULL_TRAIL --> support full error trails (increases memory use)\\n\");",
" fprintf(fd, \"\\n\");",
" fprintf(fd, \"More advanced use (should rarely need changing):\\n\\n\");",
" fprintf(fd, \" To change the nr of states that can be stored in the global queue\\n\");",
" fprintf(fd, \" (lower numbers allow for more states to be stored, prefer multiples of 8):\\n\");",
" fprintf(fd, \" -DVMAX=N --> upperbound on statevector for handoffs (N=%%d)\\n\", VMAX);",
" fprintf(fd, \" -DPMAX=N --> upperbound on nr of procs (default: N=%%d)\\n\", PMAX);",
" fprintf(fd, \" -DQMAX=N --> upperbound on nr of channels (default: N=%%d)\\n\", QMAX);",
" fprintf(fd, \"\\n\");",
#if 0
"#if !defined(WIN32) && !defined(WIN64)",
" fprintf(fd, \" To change the size of spin's individual shared memory segments for cygwin/linux:\\n\");",
" fprintf(fd, \" -DSET_SEG_SIZE=N --> default %%g (Mbytes)\\n\", SEG_SIZE/(1048576.));",
" fprintf(fd, \"\\n\");",
"#endif",
#endif
" fprintf(fd, \" To set the total amount of memory reserved for the global workqueue:\\n\");",
" fprintf(fd, \" -DSET_WQ_SIZE=N --> default: N=128 (defined in MBytes)\\n\\n\");",
#if 0
" fprintf(fd, \" To omit the global workqueue completely (bad idea):\\n\");",
" fprintf(fd, \" -DNGQ\\n\\n\");",
#endif
" fprintf(fd, \" To force the use of a single global heap, instead of separate heaps:\\n\");",
" fprintf(fd, \" -DGLOB_HEAP\\n\");",
" fprintf(fd, \"\\n\");",
" fprintf(fd, \" To define a fct to initialize data before spawning processes (use quotes):\\n\");",
" fprintf(fd, \" \\\"-DC_INIT=fct()\\\"\\n\");",
" fprintf(fd, \"\\n\");",
" fprintf(fd, \" Timer settings for termination and crash detection:\\n\");",
" fprintf(fd, \" -DSHORT_T=N --> timeout for termination detection trigger (N=%%g)\\n\", (double) SHORT_T);",
" fprintf(fd, \" -DLONG_T=N --> timeout for giving up on termination detection (N=%%g)\\n\", (double) LONG_T);",
" fprintf(fd, \" -DONESECOND --> (1<<29) --> timeout waiting for a free slot -- to check for crash\\n\");",
" fprintf(fd, \" -DT_ALERT --> collect stats on crash alert timeouts\\n\\n\");",
" fprintf(fd, \"Help with Linux/Windows/Cygwin configuration for multi-core:\\n\");",
" fprintf(fd, \" http://spinroot.com/spin/multicore/V5_Readme.html\\n\");",
" fprintf(fd, \"\\n\");",
"}",
"#if NCORE>1 && defined(FULL_TRAIL)",
"typedef struct Stack_Tree {",
" uchar pr; /* process that made transition */",
" T_ID t_id; /* id of transition */",
" volatile struct Stack_Tree *prv; /* backward link towards root */",
"} Stack_Tree;",
"",
"H_el *grab_shared(int);",
"volatile Stack_Tree **stack_last; /* in shared memory */",
"char *stack_cache = NULL; /* local */",
"int nr_cached = 0; /* local */",
"",
"#ifndef CACHE_NR",
" #define CACHE_NR 1024",
"#endif",
"",
"volatile Stack_Tree *",
"stack_prefetch(void)",
"{ volatile Stack_Tree *st;",
"",
" if (nr_cached == 0)",
" { stack_cache = (char *) grab_shared(CACHE_NR * sizeof(Stack_Tree));",
" nr_cached = CACHE_NR;",
" }",
" st = (volatile Stack_Tree *) stack_cache;",
" stack_cache += sizeof(Stack_Tree);",
" nr_cached--;",
" return st;",
"}",
"",
"void",
"Push_Stack_Tree(short II, T_ID t_id)",
"{ volatile Stack_Tree *st;",
"",
" st = (volatile Stack_Tree *) stack_prefetch();",
" st->pr = II;",
" st->t_id = t_id;",
" st->prv = (Stack_Tree *) stack_last[core_id];",
" stack_last[core_id] = st;",
"}",
"",
"void",
"Pop_Stack_Tree(void)",
"{ volatile Stack_Tree *cf = stack_last[core_id];",
"",
" if (cf)",
" { stack_last[core_id] = cf->prv;",
" } else if (nr_handoffs * z_handoff + depth > 0)",
" { printf(\"cpu%%d: error pop_stack_tree (depth %%ld)\\n\",",
" core_id, depth);",
" }",
"}",
"#endif", /* NCORE>1 && FULL_TRAIL */
"",
"void",
"e_critical(int which)",
"{ double cnt_start;",
"",
" if (readtrail || iamin[which] > 0)",
" { if (!readtrail && verbose)",
" { printf(\"cpu%%d: Double Lock on %%d (now %%d)\\n\",",
" core_id, which, iamin[which]+1);",
" fflush(stdout);",
" }",
" iamin[which]++; /* local variable */",
" return;",
" }",
"",
" cnt_start = lock_wait;",
"",
" while (sh_lock != NULL) /* as long as we have shared memory */",
" { int r = tas(&sh_lock[which]);",
" if (r == 0)",
" { iamin[which] = 1;",
" return; /* locked */",
" }",
"",
" lock_wait++;",
"#ifndef NGQ",
" if (which < 3) { glock_wait[which]++; }",
"#else",
" if (which == 0) { glock_wait[which]++; }",
"#endif",
" iam_alive();",
"",
" if (lock_wait - cnt_start > TenSeconds)",
" { printf(\"cpu%%d: lock timeout on %%d\\n\", core_id, which);",
" cnt_start = lock_wait;",
" if (someone_crashed(1))",
" { sudden_stop(\"lock timeout\");",
" pan_exit(1);",
" } } }",
"}",
"",
"void",
"x_critical(int which)",
"{",
" if (iamin[which] != 1)",
" { if (iamin[which] > 1)",
" { iamin[which]--; /* this is thread-local - no races on this one */",
" if (!readtrail && verbose)",
" { printf(\"cpu%%d: Partial Unlock on %%d (%%d more needed)\\n\",",
" core_id, which, iamin[which]);",
" fflush(stdout);",
" }",
" return;",
" } else /* iamin[which] <= 0 */",
" { if (!readtrail)",
" { printf(\"cpu%%d: Invalid Unlock iamin[%%d] = %%d\\n\",",
" core_id, which, iamin[which]);",
" fflush(stdout);",
" }",
" return;",
" } }",
"",
" if (sh_lock != NULL)",
" { iamin[which] = 0;",
"#if defined(__powerpc64__)",
" #if 1",
" __sync_synchronize(); /* srirajpaul */",
" #else",
" __lwsync(); /* xlc compiler only */",
" #endif",
"#endif",
" sh_lock[which] = 0; /* unlock */",
" }",
"}",
"",
"void",
"#if defined(WIN32) || defined(WIN64)",
"start_proxy(char *s, DWORD r_pid)",
"#else",
"start_proxy(char *s, int r_pid)",
"#endif",
"{ char Q_arg[16], Z_arg[16], Y_arg[16];",
" char *args[32], *ptr;",
" int argcnt = 0;",
"",
" sprintf(Q_arg, \"-Q%%d\", getpid());",
" sprintf(Y_arg, \"-Y%%d\", r_pid);",
" sprintf(Z_arg, \"-Z%%d\", proxy_pid /* core_id */);",
"",
" args[argcnt++] = \"proxy\";",
" args[argcnt++] = s; /* -r or -s */",
" args[argcnt++] = Q_arg;",
" args[argcnt++] = Z_arg;",
" args[argcnt++] = Y_arg;",
"",
" if (strlen(o_cmdline) > 0)",
" { ptr = o_cmdline; /* assume args separated by spaces */",
" do { args[argcnt++] = ptr++;",
" if ((ptr = strchr(ptr, ' ')) != NULL)",
" { while (*ptr == ' ')",
" { *ptr++ = '\\0';",
" }",
" } else",
" { break;",
" }",
" } while (argcnt < 31);",
" }",
" args[argcnt] = NULL;",
"#if defined(WIN32) || defined(WIN64)",
" execvp(\"pan_proxy\", args); /* no return */",
"#else",
" execvp(\"./pan_proxy\", args); /* no return */",
"#endif",
" Uerror(\"pan_proxy exec failed\");",
"}",
"/*** end of common code fragment ***/",
"",
"#if !defined(WIN32) && !defined(WIN64)",
"void",
"init_shm(void) /* initialize shared work-queues - linux/cygwin */",
"{ key_t key[NR_QS];",
" int n, m;",
" int must_exit = 0;",
"",
" if (core_id == 0 && verbose)",
" { printf(\"cpu0: step 3: allocate shared workqueues %%g MB\\n\",",
" ((double) NCORE * LWQ_SIZE + GWQ_SIZE) / (1048576.) );",
" }",
" for (m = 0; m < NR_QS; m++) /* last q is the global q */",
" { double qsize = (m == NCORE) ? GWQ_SIZE : LWQ_SIZE;",
" key[m] = ftok(PanSource, m+1);", /* m must be nonzero, 1..NCORE */
" if (key[m] == -1)",
" { perror(\"ftok shared queues\"); must_exit = 1; break;",
" }",
"",
" if (core_id == 0) /* root creates */",
" { /* check for stale copy */",
" shmid[m] = shmget(key[m], (size_t) qsize, 0600);",
" if (shmid[m] != -1) /* yes there is one; remove it */",
" { printf(\"cpu0: removing stale q%%d, status: %%d\\n\",",
" m, shmctl(shmid[m], IPC_RMID, NULL));",
" }",
" shmid[m] = shmget(key[m], (size_t) qsize, 0600|IPC_CREAT|IPC_EXCL);",
" memcnt += qsize;",
" } else /* workers attach */",
" { shmid[m] = shmget(key[m], (size_t) qsize, 0600);",
" /* never called, since we create shm *before* we fork */",
" }",
" if (shmid[m] == -1)",
" { perror(\"shmget shared queues\"); must_exit = 1; break;",
" }",
"",
" shared_mem[m] = (char *) shmat(shmid[m], (void *) 0, 0); /* attach */",
" if (shared_mem[m] == (char *) -1)",
" { fprintf(stderr, \"error: cannot attach shared wq %%d (%%d Mb)\\n\",",
" m+1, (int) (qsize/(1048576.)));",
" perror(\"shmat shared queues\"); must_exit = 1; break;",
" }",
"",
" m_workq[m] = (SM_frame *) shared_mem[m];",
" if (core_id == 0)",
" { int nframes = (m == NCORE) ? GN_FRAMES : LN_FRAMES;",
" for (n = 0; n < nframes; n++)",
" { m_workq[m][n].m_vsize = 0;",
" m_workq[m][n].m_boq = 0;",
" } } }",
"",
" if (must_exit)",
" { rm_shared_segments();",
" fprintf(stderr, \"pan: check './pan --' for usage details\\n\");",
" pan_exit(1); /* calls cleanup_shm */",
" }",
"}",
"",
"static uchar *",
"prep_shmid_S(size_t n) /* either sets SS or H_tab, linux/cygwin */",
"{ char *rval;",
"#ifndef SEP_STATE",
" key_t key;",
"",
" if (verbose && core_id == 0)",
" {",
" #ifdef BITSTATE",
" printf(\"cpu0: step 1: allocate shared bitstate %%g Mb\\n\",",
" (double) n / (1048576.));",
" #else",
" printf(\"cpu0: step 1: allocate shared hastable %%g Mb\\n\",",
" (double) n / (1048576.));",
" #endif",
" }",
" #ifdef MEMLIM", /* memlim has a value */
" if (memcnt + (double) n > memlim)",
" { printf(\"cpu0: S %%8g + %%d Kb exceeds memory limit of %%8g Mb\\n\",",
" memcnt/1024., (int) (n/1024), memlim/(1048576.));",
" printf(\"cpu0: insufficient memory -- aborting\\n\");",
" exit(1);",
" }",
" #endif",
"",
" key = ftok(PanSource, NCORE+2); /* different from queues */",
" if (key == -1)",
" { perror(\"ftok shared bitstate or hashtable\");",
" fprintf(stderr, \"pan: check './pan --' for usage details\\n\");",
" pan_exit(1);",
" }",
"",
" if (core_id == 0) /* root */",
" { shmid_S = shmget(key, n, 0600);",
" if (shmid_S != -1)",
" { printf(\"cpu0: removing stale segment, status: %%d\\n\",",
" (int) shmctl(shmid_S, IPC_RMID, NULL));",
" }",
" shmid_S = shmget(key, n, 0600 | IPC_CREAT | IPC_EXCL);",
" memcnt += (double) n;",
" } else /* worker */",
" { shmid_S = shmget(key, n, 0600);",
" }",
" if (shmid_S == -1)",
" { perror(\"shmget shared bitstate or hashtable too large?\");",
" fprintf(stderr, \"pan: check './pan --' for usage details\\n\");",
" pan_exit(1);",
" }",
"",
" rval = (char *) shmat(shmid_S, (void *) 0, 0); /* attach */",
" if ((char *) rval == (char *) -1)",
" { perror(\"shmat shared bitstate or hashtable\");",
" fprintf(stderr, \"pan: check './pan --' for usage details\\n\");",
" pan_exit(1);",
" }",
"#else",
" rval = (char *) emalloc(n);",
"#endif",
" return (uchar *) rval;",
"}",
"",
"#define TRY_AGAIN 1",
"#define NOT_AGAIN 0",
"",
"static char shm_prep_result;",
"",
"static uchar *",
"prep_state_mem(size_t n) /* sets memory arena for states linux/cygwin */",
"{ char *rval;",
" key_t key;",
" static int cnt = 3; /* start larger than earlier ftok calls */",
"",
" shm_prep_result = NOT_AGAIN; /* default */",
" if (verbose && core_id == 0)",
" { printf(\"cpu0: step 2+: pre-allocate memory arena %%d of %%6.2g Mb\\n\",",
" cnt-3, (double) n / (1048576.));",
" }",
" #ifdef MEMLIM",
" if (memcnt + (double) n > memlim)",
" { printf(\"cpu0: error: M %%.0f + %%.0f Kb exceeds memory limit of %%.0f Mb\\n\",",
" memcnt/1024.0, (double) n/1024.0, memlim/(1048576.));",
" return NULL;",
" }",
" #endif",
"",
" key = ftok(PanSource, NCORE+cnt); cnt++;", /* starts at NCORE+3 */
" if (key == -1)",
" { perror(\"ftok T\");",
" printf(\"pan: check './pan --' for usage details\\n\");",
" pan_exit(1);",
" }",
"",
" if (core_id == 0)",
" { shmid_M = shmget(key, n, 0600);",
" if (shmid_M != -1)",
" { printf(\"cpu0: removing stale memory segment %%d, status: %%d\\n\",",
" cnt-3, shmctl(shmid_M, IPC_RMID, NULL));",
" }",
" shmid_M = shmget(key, n, 0600 | IPC_CREAT | IPC_EXCL);",
" /* memcnt += (double) n; -- only amount actually used is counted */",
" } else",
" { shmid_M = shmget(key, n, 0600);",
" ",
" }",
" if (shmid_M == -1)",
" { if (verbose)",
" { printf(\"error: failed to get pool of shared memory %%d of %%.0f Mb\\n\",",
" cnt-3, ((double)n)/(1048576.));",
" perror(\"state mem\");",
" printf(\"pan: check './pan --' for usage details\\n\");",
" }",
" shm_prep_result = TRY_AGAIN;",
" return NULL;",
" }",
" rval = (char *) shmat(shmid_M, (void *) 0, 0); /* attach */",
"",
" if ((char *) rval == (char *) -1)",
" { printf(\"cpu%%d error: failed to attach pool of shared memory %%d of %%.0f Mb\\n\",",
" core_id, cnt-3, ((double)n)/(1048576.));",
" perror(\"state mem\");",
" return NULL;",
" }",
" return (uchar *) rval;",
"}",
"",
"void",
"init_HT(unsigned long n) /* cygwin/linux version */",
"{ volatile char *x;",
" double get_mem;",
"#ifndef SEP_STATE",
" volatile char *dc_mem_start;",
" double need_mem, got_mem = 0.;",
"#endif",
"",
"#ifdef SEP_STATE",
" #ifndef MEMLIM",
" if (verbose)",
" { printf(\"cpu0: steps 0,1: no -DMEMLIM set\\n\");", /* cannot happen */
" }",
" #else",
" if (verbose)",
" { printf(\"cpu0: steps 0,1: -DMEMLIM=%%d Mb - (hashtable %%g Mb + workqueues %%g Mb)\\n\",",
" MEMLIM, ((double)n/(1048576.)), (((double) NCORE * LWQ_SIZE) + GWQ_SIZE) /(1048576.) );",
" }",
" #endif",
" get_mem = NCORE * sizeof(double) + (1 + CS_NR) * sizeof(void *) + 4*sizeof(void *) + 2*sizeof(double);",
" /* NCORE * is_alive + search_terminated + CS_NR * sh_lock + 6 gr vars */",
" get_mem += 4 * NCORE * sizeof(void *); /* prfree, prfull, prcnt, prmax */",
" #ifdef FULL_TRAIL",
" get_mem += (NCORE) * sizeof(Stack_Tree *); /* NCORE * stack_last */",
" #endif",
" x = (volatile char *) prep_state_mem((size_t) get_mem); /* work queues and basic structs */",
" shmid_X = (long) x;",
" if (x == NULL)", /* do not repeat for smaller sizes */
" { printf(\"cpu0: could not allocate shared memory, see ./pan --\\n\");",
" exit(1);",
" }",
" search_terminated = (volatile unsigned int *) x; /* comes first */",
" x += sizeof(void *); /* maintain alignment */",
"",
" is_alive = (volatile double *) x;",
" x += NCORE * sizeof(double);",
"",
" sh_lock = (volatile int *) x;",
" x += CS_NR * sizeof(void *);", /* allow 1 word per entry */
"",
" grfree = (volatile int *) x;",
" x += sizeof(void *);",
" grfull = (volatile int *) x;",
" x += sizeof(void *);",
" grcnt = (volatile int *) x;",
" x += sizeof(void *);",
" grmax = (volatile int *) x;",
" x += sizeof(void *);",
" prfree = (volatile int *) x;",
" x += NCORE * sizeof(void *);",
" prfull = (volatile int *) x;",
" x += NCORE * sizeof(void *);",
" prcnt = (volatile int *) x;",
" x += NCORE * sizeof(void *);",
" prmax = (volatile int *) x;",
" x += NCORE * sizeof(void *);",
" gr_readmiss = (volatile double *) x;",
" x += sizeof(double);",
" gr_writemiss = (volatile double *) x;",
" x += sizeof(double);",
"",
" #ifdef FULL_TRAIL",
" stack_last = (volatile Stack_Tree **) x;",
" x += NCORE * sizeof(Stack_Tree *);",
" #endif",
"",
" #ifndef BITSTATE",
" H_tab = (H_el **) emalloc(n);",
" #endif",
"#else",
" #ifndef MEMLIM",
" #warning MEMLIM not set", /* cannot happen */
" #define MEMLIM (2048)",
" #endif",
"",
" if (core_id == 0 && verbose)",
" { printf(\"cpu0: step 0: -DMEMLIM=%%d Mb minus hashtable+workqs (%%g + %%g Mb) leaves %%g Mb\\n\",",
" MEMLIM, ((double)n/(1048576.)), (NCORE * LWQ_SIZE + GWQ_SIZE)/(1048576.),",
" (memlim - memcnt - (double) n - (NCORE * LWQ_SIZE + GWQ_SIZE))/(1048576.));",
" }",
" #ifndef BITSTATE",
" H_tab = (H_el **) prep_shmid_S((size_t) n); /* hash_table */",
" #endif",
" need_mem = memlim - memcnt - ((double) NCORE * LWQ_SIZE) - GWQ_SIZE;",
" if (need_mem <= 0.)",
" { Uerror(\"internal error -- shared state memory\");",
" }",
"",
" if (core_id == 0 && verbose)",
" { printf(\"cpu0: step 2: pre-allocate shared state memory %%g Mb\\n\",",
" need_mem/(1048576.));",
" }",
"#ifdef SEP_HEAP",
" SEG_SIZE = need_mem / NCORE;",
" if (verbose && core_id == 0)",
" { printf(\"cpu0: setting segsize to %%6g MB\\n\",",
" SEG_SIZE/(1048576.));",
" }",
" #if defined(CYGWIN) || defined(__CYGWIN__)",
" if (SEG_SIZE > 512.*1024.*1024.)",
" { printf(\"warning: reducing SEG_SIZE of %%g MB to 512MB (exceeds max for Cygwin)\\n\",",
" SEG_SIZE/(1024.*1024.));",
" SEG_SIZE = 512.*1024.*1024.;",
" }",
" #endif",
"#endif",
" mem_reserved = need_mem;",
" while (need_mem > 1024.)",
" { get_mem = need_mem;",
"shm_more:",
" if (get_mem > (double) SEG_SIZE)",
" { get_mem = (double) SEG_SIZE;",
" }",
" if (get_mem <= 0.0) break;",
"",
" /* for allocating states: */",
" x = dc_mem_start = (volatile char *) prep_state_mem((size_t) get_mem);",
" if (x == NULL)",
" { if (shm_prep_result == NOT_AGAIN",
" || first_pool != NULL",
" || SEG_SIZE < (16. * 1048576.))",
" { break;",
" }",
" SEG_SIZE /= 2.;",
" if (verbose)",
" { printf(\"pan: lowered segsize to %%f\\n\", SEG_SIZE);",
" }",
" if (SEG_SIZE >= 1024.)",
" { goto shm_more;", /* always terminates */
" }",
" break;",
" }",
"",
" need_mem -= get_mem;",
" got_mem += get_mem;",
" if (first_pool == NULL)",
" { search_terminated = (volatile unsigned int *) x; /* comes first */",
" x += sizeof(void *); /* maintain alignment */",
"",
" is_alive = (volatile double *) x;",
" x += NCORE * sizeof(double);",
"",
" sh_lock = (volatile int *) x;",
" x += CS_NR * sizeof(void *);", /* allow 1 word per entry */
"",
" grfree = (volatile int *) x;",
" x += sizeof(void *);",
" grfull = (volatile int *) x;",
" x += sizeof(void *);",
" grcnt = (volatile int *) x;",
" x += sizeof(void *);",
" grmax = (volatile int *) x;",
" x += sizeof(void *);",
" prfree = (volatile int *) x;",
" x += NCORE * sizeof(void *);",
" prfull = (volatile int *) x;",
" x += NCORE * sizeof(void *);",
" prcnt = (volatile int *) x;",
" x += NCORE * sizeof(void *);",
" prmax = (volatile int *) x;",
" x += NCORE * sizeof(void *);",
" gr_readmiss = (volatile double *) x;",
" x += sizeof(double);",
" gr_writemiss = (volatile double *) x;",
" x += sizeof(double);",
" #ifdef FULL_TRAIL",
" stack_last = (volatile Stack_Tree **) x;",
" x += NCORE * sizeof(Stack_Tree *);",
" #endif",
" if (((long)x)&(sizeof(void *)-1)) /* 64-bit word alignment */",
" { x += sizeof(void *)-(((long)x)&(sizeof(void *)-1));",
" }",
"",
" #ifdef COLLAPSE",
" ncomps = (unsigned long *) x;",
" x += (256+2) * sizeof(unsigned long);",
" #endif",
" }",
"",
" dc_shared = (sh_Allocater *) x; /* must be in shared memory */",
" x += sizeof(sh_Allocater);",
"",
" if (core_id == 0) /* root only */",
" { dc_shared->dc_id = shmid_M;",
" dc_shared->dc_start = dc_mem_start;",
" dc_shared->dc_arena = x;",
" dc_shared->pattern = 1234567; /* protection */",
" dc_shared->dc_size = (long) get_mem - (long) (x - dc_mem_start);",
" dc_shared->nxt = (long) 0;",
"",
" if (last_pool == NULL)",
" { first_pool = last_pool = dc_shared;",
" } else",
" { last_pool->nxt = dc_shared;",
" last_pool = dc_shared;",
" }",
" } else if (first_pool == NULL)",
" { first_pool = dc_shared;",
" } }",
"",
" if (need_mem > 1024.)",
" { printf(\"cpu0: could allocate only %%g Mb of shared memory (wanted %%g more)\\n\",",
" got_mem/(1048576.), need_mem/(1048576.));",
" }",
"",
" if (!first_pool)",
" { printf(\"cpu0: insufficient memory -- aborting.\\n\");",
" exit(1);",
" }",
" /* we are still single-threaded at this point, with core_id 0 */",
" dc_shared = first_pool;",
"",
"#endif", /* !SEP_STATE */
"}",
"",
"void",
"cleanup_shm(int val)",
"{ volatile sh_Allocater *nxt_pool;",
" unsigned long cnt = 0;",
" int m;",
"",
" if (nibis != 0)",
" { printf(\"cpu%%d: Redundant call to cleanup_shm(%%d)\\n\", core_id, val);",
" return;",
" } else",
" { nibis = 1;",
" }",
" if (search_terminated != NULL)",
" { *search_terminated |= 16; /* cleanup_shm */",
" }",
"",
" for (m = 0; m < NR_QS; m++)",
" { if (shmdt((void *) shared_mem[m]) > 0)",
" { perror(\"shmdt detaching from shared queues\");",
" } }",
"",
"#ifdef SEP_STATE",
" if (shmdt((void *) shmid_X) != 0)",
" { perror(\"shmdt detaching from shared state memory\");",
" }",
"#else",
" #ifdef BITSTATE",
" if (SS > 0 && shmdt((void *) SS) != 0)",
" { if (verbose)",
" { perror(\"shmdt detaching from shared bitstate arena\");",
" } }",
" #else",
" if (core_id == 0)",
" { /* before detaching: */",
" for (nxt_pool = dc_shared; nxt_pool != NULL; nxt_pool = nxt_pool->nxt)",
" { cnt += nxt_pool->dc_size;",
" }",
" if (verbose)",
" { printf(\"cpu0: done, %%ld Mb of shared state memory left\\n\",",
" cnt / (long)(1048576));",
" } }",
"",
" if (shmdt((void *) H_tab) != 0)",
" { perror(\"shmdt detaching from shared hashtable\");",
" }",
"",
" for (last_pool = first_pool; last_pool != NULL; last_pool = nxt_pool)",
" { nxt_pool = last_pool->nxt;",
" if (shmdt((void *) last_pool->dc_start) != 0)",
" { perror(\"shmdt detaching from shared state memory\");",
" } }",
" first_pool = last_pool = NULL; /* precaution */",
" #endif",
"#endif",
" /* detached from shared memory - so cannot use cpu_printf */",
" if (verbose)",
" { printf(\"cpu%%d: done -- got %%ld states from queue\\n\",",
" core_id, nstates_get);",
" }",
"}",
"",
"extern void give_up(int);",
"extern void Read_Queue(int);",
"",
"void",
"mem_get(void)",
"{ SM_frame *f;",
" int is_parent;",
"",
"#if defined(MA) && !defined(SEP_STATE)",
" #error MA without SEP_STATE is not supported with multi-core",
"#endif",
"#ifdef BFS",
" #error instead of -DNCORE -DBFS use -DBFS_PAR",
"#endif",
"#ifdef SC",
" #error SC is not supported with multi-core",
"#endif",
" init_shm(); /* we are single threaded when this starts */",
"",
" if (core_id == 0 && verbose)",
" { printf(\"cpu0: step 4: calling fork()\\n\");",
" }",
" fflush(stdout);",
"",
"/* if NCORE > 1 the child or the parent should fork N-1 more times",
" * the parent is the only process with core_id == 0 and is_parent > 0",
" * the workers have is_parent = 0 and core_id = 1..NCORE-1",
" */",
" if (core_id == 0)",
" { worker_pids[0] = getpid(); /* for completeness */",
" while (++core_id < NCORE) /* first worker sees core_id = 1 */",
" { is_parent = fork();",
" if (is_parent == -1)",
" { Uerror(\"fork failed\");",
" }",
" if (is_parent == 0) /* this is a worker process */",
" { if (proxy_pid == core_id) /* always non-zero */",
" { start_proxy(\"-r\", 0); /* no return */",
" }",
" goto adapt; /* root process continues spawning */",
" }",
" worker_pids[core_id] = is_parent;",
" }",
" /* note that core_id is now NCORE */",
" if (proxy_pid > 0 && proxy_pid < NCORE)", /* add send-half of proxy */
" { proxy_pid_snd = fork();",
" if (proxy_pid_snd == -1)",
" { Uerror(\"proxy fork failed\");",
" }",
" if (proxy_pid_snd == 0)",
" { start_proxy(\"-s\", worker_pids[proxy_pid]); /* no return */",
" } } /* else continue */",
" if (is_parent > 0)",
" { core_id = 0; /* reset core_id for root process */",
" }",
" } else /* worker */",
" { static char db0[16]; /* good for up to 10^6 cores */",
" static char db1[16];",
"adapt: tprefix = db0; sprefix = db1;",
" sprintf(tprefix, \"cpu%%d_trail\", core_id);",
" sprintf(sprefix, \"cpu%%d_rst\", core_id);",
" memcnt = 0; /* count only additionally allocated memory */",
" }",
" signal(SIGINT, give_up);",
"",
" if (proxy_pid == 0) /* not in a cluster setup, pan_proxy must attach */",
" { rm_shared_segments(); /* mark all shared segments for removal on exit */",
" }", /* doing it early means less chance of being unable to do this */
" if (verbose)",
" { cpu_printf(\"starting core_id %%d -- pid %%d\\n\", core_id, getpid());",
" }",
"#if defined(SEP_HEAP) && !defined(SEP_STATE)", /* set my_heap and adjust dc_shared */
" { int i;",
" volatile sh_Allocater *ptr;",
" ptr = first_pool;",
" for (i = 0; i < NCORE && ptr != NULL; i++)",
" { if (i == core_id)",
" { my_heap = (char *) ptr->dc_arena;",
" my_size = (long) ptr->dc_size;",
" if (verbose)",
" cpu_printf(\"local heap %%ld MB\\n\", my_size/(1048576));",
" break;",
" }",
" ptr = ptr->nxt; /* local */",
" }",
" if (my_heap == NULL)",
" { printf(\"cpu%%d: no local heap\\n\", core_id);",
" pan_exit(1);",
" } /* else */",
" #if defined(CYGWIN) || defined(__CYGWIN__)",
" ptr = first_pool;",
" for (i = 0; i < NCORE && ptr != NULL; i++)",
" { ptr = ptr->nxt; /* local */",
" }",
" dc_shared = ptr; /* any remainder */",
" #else",
" dc_shared = NULL; /* used all mem for local heaps */",
" #endif",
" }",
"#endif",
" if (core_id == 0 && !remote_party)",
" { new_state(); /* cpu0 explores root */",
" if (verbose)",
" cpu_printf(\"done with 1st dfs, nstates %%g (put %%d states), read q\\n\",",
" nstates, nstates_put);",
" dfs_phase2 = 1;",
" }",
" Read_Queue(core_id); /* all cores */",
"",
" if (verbose)",
" { cpu_printf(\"put %%6d states into queue -- got %%6d\\n\",",
" nstates_put, nstates_get);",
" }",
" if (proxy_pid != 0)",
" { rm_shared_segments();",
" }",
" done = 1;",
" wrapup();",
" exit(0);",
"}",
"",
"#else",
"int unpack_state(SM_frame *, int);",
"#endif",
"",
"H_el *",
"grab_shared(int n)",
"{",
"#ifndef SEP_STATE",
" char *rval = (char *) 0;",
"",
" if (n == 0)",
" { printf(\"cpu%%d: grab shared zero\\n\", core_id); fflush(stdout);",
" return (H_el *) rval;",
" } else if (n&(sizeof(void *)-1))",
" { n += sizeof(void *)-(n&(sizeof(void *)-1)); /* alignment */",
" }",
"",
"#ifdef SEP_HEAP",
" /* no locking */",
" if (my_heap != NULL && my_size > n)",
" { rval = my_heap;",
" my_heap += n;",
" my_size -= n;",
" goto done;",
" }",
"#endif",
"",
" if (!dc_shared)",
" { sudden_stop(\"pan: out of memory\");",
" }",
"",
" /* another lock is always already in effect when this is called */",
" /* but not always the same lock -- i.e., on different parts of the hashtable */",
" enter_critical(GLOBAL_LOCK); /* this must be independently mutex */",
"#if defined(SEP_HEAP) && !defined(WIN32) && !defined(WIN64)",
" { static int noted = 0;",
" if (!noted)",
" { noted = 1;",
" printf(\"cpu%%d: global heap has %%ld bytes left, needed %%d\\n\",",
" core_id, dc_shared?dc_shared->dc_size:0, n);",
" } }",
"#endif",
"#if 0", /* for debugging */
" if (dc_shared->pattern != 1234567)",
" { leave_critical(GLOBAL_LOCK);",
" Uerror(\"overrun -- memory corruption\");",
" }",
"#endif",
" if (dc_shared->dc_size < n)",
" { if (verbose)",
" { printf(\"Next Pool %%g Mb + %%d\\n\", memcnt/(1048576.), n);",
" }",
" if (dc_shared->nxt == NULL",
" || dc_shared->nxt->dc_arena == NULL",
" || dc_shared->nxt->dc_size < n)",
" { printf(\"cpu%%d: memcnt %%g Mb + wanted %%d bytes more\\n\",",
" core_id, memcnt / (1048576.), n);",
" leave_critical(GLOBAL_LOCK);",
" sudden_stop(\"out of memory -- aborting\");",
" wrapup(); /* exits */",
" } else",
" { dc_shared = (sh_Allocater *) dc_shared->nxt;",
" } }",
"",
" rval = (char *) dc_shared->dc_arena;",
" dc_shared->dc_arena += n;",
" dc_shared->dc_size -= (long) n;",
"#if 0",
" if (VVERBOSE)",
" printf(\"cpu%%d grab shared (%%d bytes) -- %%ld left\\n\",",
" core_id, n, dc_shared->dc_size);",
"#endif",
" leave_critical(GLOBAL_LOCK);",
"done:",
" memset(rval, 0, n);",
" memcnt += (double) n;",
"",
" return (H_el *) rval;",
"#else",
" return (H_el *) emalloc(n);",
"#endif",
"}",
"",
"SM_frame *",
"Get_Full_Frame(int n)",
"{ SM_frame *f;",
" double cnt_start = frame_wait;",
"",
" f = &m_workq[n][prfull[n]];",
" while (f->m_vsize == 0) /* await full slot LOCK : full frame */",
" { iam_alive();",
"#ifndef NGQ",
" #ifndef SAFETY",
" if (!a_cycles || core_id != 0)",
" #endif",
" if (*grcnt > 0) /* accessed outside lock, but safe even if wrong */",
" { enter_critical(GQ_RD); /* gq - read access */",
" if (*grcnt > 0) /* could have changed */",
" { f = &m_workq[NCORE][*grfull]; /* global q */",
" if (f->m_vsize == 0)",
" { /* writer is still filling the slot */",
" *gr_writemiss++;",
" f = &m_workq[n][prfull[n]]; /* reset */",
" } else",
" { *grfull = (*grfull+1) %% (GN_FRAMES);",
" enter_critical(GQ_WR);",
" *grcnt = *grcnt - 1;",
" leave_critical(GQ_WR);",
" leave_critical(GQ_RD);",
" return f;",
" } }",
" leave_critical(GQ_RD);",
" }",
"#endif",
" if (frame_wait++ - cnt_start > Delay)",
" { if (0)", /* too frequent to enable this one */
" { cpu_printf(\"timeout on q%%d -- %%u -- query %%d\\n\",",
" n, f, query_in_progress);",
" }",
" return (SM_frame *) 0; /* timeout */",
" } }",
" iam_alive();",
" if (VVERBOSE) cpu_printf(\"got frame from q%%d\\n\", n);",
" prfull[n] = (prfull[n] + 1) %% (LN_FRAMES);",
" enter_critical(QLOCK(n));",
" prcnt[n]--; /* lock out increments */",
" leave_critical(QLOCK(n));",
" return f;",
"}",
"",
"SM_frame *",
"Get_Free_Frame(int n)",
"{ SM_frame *f;",
" double cnt_start = free_wait;",
"",
" if (VVERBOSE) { cpu_printf(\"get free frame from q%%d\\n\", n); }",
"",
" if (n == NCORE) /* global q */",
" { f = &(m_workq[n][lrfree]);",
" } else",
" { f = &(m_workq[n][prfree[n]]);",
" }",
" while (f->m_vsize != 0) /* await free slot LOCK : free slot */",
" { iam_alive();",
" if (free_wait++ - cnt_start > OneSecond)",
" { if (verbose)",
" { cpu_printf(\"timeout waiting for free slot q%%d\\n\", n);",
" }",
" cnt_start = free_wait;",
" if (someone_crashed(1))",
" { printf(\"cpu%%d: search terminated\\n\", core_id);",
" sudden_stop(\"get free frame\");",
" pan_exit(1);",
" } } }",
" if (n != NCORE)",
" { prfree[n] = (prfree[n] + 1) %% (LN_FRAMES);",
" enter_critical(QLOCK(n));",
" prcnt[n]++; /* lock out decrements */",
" if (prmax[n] < prcnt[n])",
" { prmax[n] = prcnt[n];",
" }",
" leave_critical(QLOCK(n));",
" }",
" return f;",
"}",
"",
"#ifndef NGQ",
"int",
"GlobalQ_HasRoom(void)",
"{ int rval = 0;",
"",
" gq_tries++;",
" if (*grcnt < GN_FRAMES) /* there seems to be room */",
" { enter_critical(GQ_WR); /* gq write access */",
" if (*grcnt < GN_FRAMES)",
" { if (m_workq[NCORE][*grfree].m_vsize != 0)",
" { /* can happen if reader is slow emptying slot */",
" *gr_readmiss++;",
" goto out; /* dont wait: release lock and return */",
" }",
" lrfree = *grfree; /* Get_Free_Frame use lrfree in this mode */",
" *grfree = (*grfree + 1) %% GN_FRAMES;", /* next process looks at next slot */
" *grcnt = *grcnt + 1; /* count nr of slots filled -- no additional lock needed */",
" if (*grmax < *grcnt) *grmax = *grcnt;",
" leave_critical(GQ_WR); /* for short lock duration */",
" gq_hasroom++;",
" mem_put(NCORE); /* copy state into reserved slot */",
" rval = 1; /* successfull handoff */",
" } else",
" { gq_hasnoroom++;",
"out: leave_critical(GQ_WR);", /* should be rare */
" } }",
" return rval;",
"}",
"#endif",
"",
"int",
"unpack_state(SM_frame *f, int from_q)",
"{ int i, j;",
" static H_el D_State;",
"",
" if (f->m_vsize > 0)",
" { boq = f->m_boq;",
" if (boq > 256)",
" { cpu_printf(\"saw control %%d, expected state\\n\", boq);",
" return 0;",
" }",
" vsize = f->m_vsize;",
"correct:",
" memcpy((uchar *) &now, (uchar *) f->m_now, vsize);",
" #if !defined(NOCOMP) && !defined(HC)",
" for (i = j = 0; i < VMAX; i++, j = (j+1)%%8)",
" { Mask[i] = (f->m_mask[i/8] & (1<<j)) ? 1 : 0;",
" }",
" #endif",
" if (now._nr_pr > 0)",
" { memcpy((uchar *) proc_offset, (uchar *) f->m_p_offset, now._nr_pr * sizeof(OFFT));",
" memcpy((uchar *) proc_skip, (uchar *) f->m_p_skip, now._nr_pr * sizeof(uchar));",
" }",
" if (now._nr_qs > 0)",
" { memcpy((uchar *) q_offset, (uchar *) f->m_q_offset, now._nr_qs * sizeof(OFFT));",
" memcpy((uchar *) q_skip, (uchar *) f->m_q_skip, now._nr_qs * sizeof(uchar));",
" }",
"#ifndef NOVSZ",
" if (vsize != now._vsz)",
" { cpu_printf(\"vsize %%d != now._vsz %%d (type %%d) %%d\\n\",",
" vsize, now._vsz, f->m_boq, f->m_vsize);",
" vsize = now._vsz;",
" goto correct; /* rare event: a race */",
" }",
"#endif",
" hmax = max(hmax, vsize);",
"",
" if (f != &cur_Root)",
" { memcpy((uchar *) &cur_Root, (uchar *) f, sizeof(SM_frame));",
" }",
"",
" if (((now._a_t) & 1) == 1) /* i.e., when starting nested DFS */",
" { A_depth = depthfound = 0;",
" memcpy((uchar *)&A_Root, (uchar *)&now, vsize);",
" }",
" nr_handoffs = f->nr_handoffs;",
" } else",
" { cpu_printf(\"pan: state empty\\n\");",
" }",
"",
" depth = 0;",
" trpt = &trail[1];",
" trpt->tau = f->m_tau;",
" trpt->o_pm = f->m_o_pm;",
"",
" (trpt-1)->ostate = &D_State; /* stub */",
" trpt->ostate = &D_State;",
"",
"#ifdef FULL_TRAIL",
" if (upto > 0)",
" { stack_last[core_id] = (Stack_Tree *) f->m_stack;",
" }",
" #if defined(VERBOSE)",
" if (stack_last[core_id])",
" { cpu_printf(\"%%d: UNPACK -- SET m_stack %%u (%%d,%%d)\\n\",",
" depth, stack_last[core_id], stack_last[core_id]->pr,",
" stack_last[core_id]->t_id);",
" }",
" #endif",
"#endif",
"",
" if (!trpt->o_t)",
" { static Trans D_Trans;",
" trpt->o_t = &D_Trans;",
" }",
"",
" #ifdef VERI",
" if ((trpt->tau & 4) != 4)",
" { trpt->tau |= 4; /* the claim moves first */",
" cpu_printf(\"warning: trpt was not up to date\\n\");",
" }",
" #endif",
"",
" for (i = 0; i < (int) now._nr_pr; i++)",
" { P0 *ptr = (P0 *) pptr(i);",
" #ifndef NP",
" if (accpstate[ptr->_t][ptr->_p])",
" { trpt->o_pm |= 2;",
" }",
" #else",
" if (progstate[ptr->_t][ptr->_p])",
" { trpt->o_pm |= 4;",
" }",
" #endif",
" }",
"",
" #ifdef EVENT_TRACE",
" #ifndef NP",
" if (accpstate[EVENT_TRACE][now._event])",
" { trpt->o_pm |= 2;",
" }",
" #else",
" if (progstate[EVENT_TRACE][now._event])",
" { trpt->o_pm |= 4;",
" }",
" #endif",
" #endif",
"",
" #if defined(C_States) && (HAS_TRACK==1)",
" /* restore state of tracked C objects */",
" c_revert((uchar *) &(now.c_state[0]));",
" #if (HAS_STACK==1)",
" c_unstack((uchar *) f->m_c_stack); /* unmatched tracked data */",
" #endif",
" #endif",
" return 1;",
"}",
"",
"void",
"write_root(void) /* for trail file */",
"{ int fd;",
"",
" if (iterative == 0 && Nr_Trails > 1)",
" sprintf(fnm, \"%%s%%d.%%s\", TrailFile, Nr_Trails-1, sprefix);",
" else",
" sprintf(fnm, \"%%s.%%s\", TrailFile, sprefix);",
"",
" if (cur_Root.m_vsize == 0)",
" { (void) unlink(fnm); /* remove possible old copy */",
" return; /* its the default initial state */",
" }",
"",
" if ((fd = creat(fnm, TMODE)) < 0)",
" { char *q;",
" if ((q = strchr(TrailFile, \'.\')))",
" { *q = \'\\0\'; /* strip .pml */",
" if (iterative == 0 && Nr_Trails-1 > 0)",
" sprintf(fnm, \"%%s%%d.%%s\", TrailFile, Nr_Trails-1, sprefix);",
" else",
" sprintf(fnm, \"%%s.%%s\", TrailFile, sprefix);",
" *q = \'.\';",
" fd = creat(fnm, TMODE);",
" }",
" if (fd < 0)",
" { cpu_printf(\"pan: cannot create %%s\\n\", fnm);",
" perror(\"cause\");",
" return;",
" } }",
"",
" if (write(fd, &cur_Root, sizeof(SM_frame)) != sizeof(SM_frame))",
" { cpu_printf(\"pan: error writing %%s\\n\", fnm);",
" } else",
" { cpu_printf(\"pan: wrote %%s\\n\", fnm);",
" }",
" close(fd);",
"}",
"",
"void",
"set_root(void)",
"{ int fd;",
" char *q;",
" char MyFile[512];", /* enough to hold a reasonable pathname */
" char MySuffix[16];",
" char *ssuffix = \"rst\";",
" int try_core = 1;",
"",
" strcpy(MyFile, TrailFile);",
"try_again:",
" if (whichtrail > 0)",
" { sprintf(fnm, \"%%s%%d.%%s\", MyFile, whichtrail, ssuffix);",
" fd = open(fnm, O_RDONLY, 0);",
" if (fd < 0 && (q = strchr(MyFile, \'.\')))",
" { *q = \'\\0\'; /* strip .pml */",
" sprintf(fnm, \"%%s%%d.%%s\", MyFile, whichtrail, ssuffix);",
" *q = \'.\';",
" fd = open(fnm, O_RDONLY, 0);",
" }",
" } else",
" { sprintf(fnm, \"%%s.%%s\", MyFile, ssuffix);",
" fd = open(fnm, O_RDONLY, 0);",
" if (fd < 0 && (q = strchr(MyFile, \'.\')))",
" { *q = \'\\0\'; /* strip .pml */",
" sprintf(fnm, \"%%s.%%s\", MyFile, ssuffix);",
" *q = \'.\';",
" fd = open(fnm, O_RDONLY, 0);",
" } }",
"",
" if (fd < 0)",
" { if (try_core < NCORE)",
" { ssuffix = MySuffix;",
" sprintf(ssuffix, \"cpu%%d_rst\", try_core++);",
" goto try_again;",
" }",
" cpu_printf(\"no file '%%s.rst' or '%%s' (not an error)\\n\", MyFile, fnm);",
" } else",
" { if (read(fd, &cur_Root, sizeof(SM_frame)) != sizeof(SM_frame))",
" { cpu_printf(\"read error %%s\\n\", fnm);",
" close(fd);",
" pan_exit(1);",
" }",
" close(fd);",
" (void) unpack_state(&cur_Root, -2);",
"#ifdef SEP_STATE",
" cpu_printf(\"partial trail -- last few steps only\\n\");",
"#endif",
" cpu_printf(\"restored root from '%%s'\\n\", fnm);",
" printf(\"=====State:=====\\n\");",
" { int i, j; P0 *z;",
" for (i = 0; i < now._nr_pr; i++)",
" { z = (P0 *)pptr(i);",
" printf(\"proc %%2d (%%s) \", i, procname[z->_t]);",
" for (j = 0; src_all[j].src; j++)",
" if (src_all[j].tp == (int) z->_t)",
" { printf(\" %%s:%%d \",",
" PanSource, src_all[j].src[z->_p]);",
" break;",
" }",
" printf(\"(state %%d)\\n\", z->_p);",
" c_locals(i, z->_t);",
" }",
" c_globals();",
" }",
" printf(\"================\\n\");",
" }",
"}",
"",
"#ifdef USE_DISK",
"unsigned long dsk_written, dsk_drained;",
"void mem_drain(void);",
"#endif",
"",
"void",
"m_clear_frame(SM_frame *f)", /* clear room for stats */
"{ int i, clr_sz = sizeof(SM_results);",
"",
" for (i = 0; i <= _NP_; i++) /* all proctypes */",
" { clr_sz += NrStates[i]*sizeof(uchar);",
" }",
" memset(f, 0, clr_sz);",
" /* caution if sizeof(SM_results) > sizeof(SM_frame) */",
"}",
"",
"#define TargetQ_Full(n) (m_workq[n][prfree[n]].m_vsize != 0)", /* no free slot */
"#define TargetQ_NotFull(n) (m_workq[n][prfree[n]].m_vsize == 0)", /* avoiding prcnt */
"",
"int",
"AllQueuesEmpty(void)",
"{ int q;",
"#ifndef NGQ",
" if (*grcnt != 0)",
" { return 0;",
" }",
"#endif",
" for (q = 0; q < NCORE; q++)",
" { if (prcnt[q] != 0)", /* not locked, ok if race */
" { return 0;",
" } }",
" return 1;",
"}",
"",
"void",
"Read_Queue(int q)",
"{ SM_frame *f, *of;",
" int remember, target_q;",
" SM_results *r;",
" double patience = 0.0;",
"",
" target_q = (q + 1) %% NCORE;",
"",
" for (;;)",
" { f = Get_Full_Frame(q);",
" if (!f) /* 1 second timeout -- and trigger for Query */",
" { if (someone_crashed(2))",
" { printf(\"cpu%%d: search terminated [code %%d]\\n\",",
" core_id, search_terminated?*search_terminated:-1);",
" sudden_stop(\"\");",
" pan_exit(1);",
" }",
"#ifdef TESTING",
" /* to profile with cc -pg and gprof pan.exe -- set handoff depth beyond maxdepth */",
" exit(0);",
"#endif",
" remember = *grfree;",
" if (core_id == 0 /* root can initiate termination */",
" && remote_party == 0 /* and only the original root */",
" && query_in_progress == 0 /* unless its already in progress */",
" && AllQueuesEmpty())",
" { f = Get_Free_Frame(target_q);",
" query_in_progress = 1; /* only root process can do this */",
" if (!f) { Uerror(\"Fatal1: no free slot\"); }",
" f->m_boq = QUERY; /* initiate Query */",
" if (verbose)",
" { cpu_printf(\"snd QUERY to q%%d (%%d) into slot %%d\\n\",",
" target_q, nstates_get + 1, prfree[target_q]-1);",
" }",
" f->m_vsize = remember + 1;",
" /* number will not change unless we receive more states */",
" } else if (patience++ > OneHour) /* one hour watchdog timer */",
" { cpu_printf(\"timeout -- giving up\\n\");",
" sudden_stop(\"queue timeout\");",
" pan_exit(1);",
" }",
" if (0) cpu_printf(\"timed out -- try again\\n\");",
" continue; ",
" }",
" patience = 0.0; /* reset watchdog */",
"",
" if (f->m_boq == QUERY)",
" { if (verbose)",
" { cpu_printf(\"got QUERY on q%%d (%%d <> %%d) from slot %%d\\n\",",
" q, f->m_vsize, nstates_put + 1, prfull[q]-1);",
" snapshot();",
" }",
" remember = f->m_vsize;",
" f->m_vsize = 0; /* release slot */",
"",
" if (core_id == 0 && remote_party == 0) /* original root cpu0 */",
" { if (query_in_progress == 1 /* didn't send more states in the interim */",
" && *grfree + 1 == remember) /* no action on global queue meanwhile */",
" { if (verbose) cpu_printf(\"Termination detected\\n\");",
" if (TargetQ_Full(target_q))",
" { if (verbose)",
" cpu_printf(\"warning: target q is full\\n\");",
" }",
" f = Get_Free_Frame(target_q);",
" if (!f) { Uerror(\"Fatal2: no free slot\"); }",
" m_clear_frame(f);",
" f->m_boq = QUIT; /* send final Quit, collect stats */",
" f->m_vsize = 111; /* anything non-zero will do */",
" if (verbose)",
" cpu_printf(\"put QUIT on q%%d\\n\", target_q);",
" } else",
" { if (verbose) cpu_printf(\"Stale Query\\n\");",
"#ifdef USE_DISK",
" mem_drain();",
"#endif",
" }",
" query_in_progress = 0;",
" } else",
" { if (TargetQ_Full(target_q))",
" { if (verbose)",
" cpu_printf(\"warning: forward query - target q full\\n\");",
" }",
" f = Get_Free_Frame(target_q);",
" if (verbose)",
" cpu_printf(\"snd QUERY response to q%%d (%%d <> %%d) in slot %%d\\n\",",
" target_q, remember, *grfree + 1, prfree[target_q]-1);",
" if (!f) { Uerror(\"Fatal4: no free slot\"); }",
"",
" if (*grfree + 1 == remember) /* no action on global queue */",
" { f->m_boq = QUERY; /* forward query, to root */",
" f->m_vsize = remember;",
" } else",
" { f->m_boq = QUERY_F; /* no match -- busy */",
" f->m_vsize = 112; /* anything non-zero */",
"#ifdef USE_DISK",
" if (dsk_written != dsk_drained)",
" { mem_drain();",
" }",
"#endif",
" } }",
" continue;",
" }",
"",
" if (f->m_boq == QUERY_F)",
" { if (verbose)",
" { cpu_printf(\"got QUERY_F on q%%d from slot %%d\\n\", q, prfull[q]-1);",
" }",
" f->m_vsize = 0; /* release slot */",
"",
" if (core_id == 0 && remote_party == 0) /* original root cpu0 */",
" { if (verbose) cpu_printf(\"No Match on Query\\n\");",
" query_in_progress = 0;",
" } else",
" { if (TargetQ_Full(target_q))",
" { if (verbose) cpu_printf(\"warning: forwarding query_f, target queue full\\n\");",
" }",
" f = Get_Free_Frame(target_q);",
" if (verbose) cpu_printf(\"forward QUERY_F to q%%d into slot %%d\\n\",",
" target_q, prfree[target_q]-1);",
" if (!f) { Uerror(\"Fatal5: no free slot\"); }",
" f->m_boq = QUERY_F; /* cannot terminate yet */",
" f->m_vsize = 113; /* anything non-zero */",
" }",
"#ifdef USE_DISK",
" if (dsk_written != dsk_drained)",
" { mem_drain();",
" }",
"#endif",
" continue;",
" }",
"",
" if (f->m_boq == QUIT)",
" { if (0) cpu_printf(\"done -- local memcnt %%g Mb\\n\", memcnt/(1048576.));",
" retrieve_info((SM_results *) f); /* collect and combine stats */",
" if (verbose)",
" { cpu_printf(\"received Quit\\n\");",
" snapshot();",
" }",
" f->m_vsize = 0; /* release incoming slot */",
" if (core_id != 0)",
" { f = Get_Free_Frame(target_q); /* new outgoing slot */",
" if (!f) { Uerror(\"Fatal6: no free slot\"); }",
" m_clear_frame(f); /* start with zeroed stats */",
" record_info((SM_results *) f);",
" f->m_boq = QUIT; /* forward combined results */",
" f->m_vsize = 114; /* anything non-zero */",
" if (verbose>1)",
" cpu_printf(\"fwd Results to q%%d\\n\", target_q);",
" }",
" break; /* successful termination */",
" }",
"",
" /* else: 0<= boq <= 255, means STATE transfer */",
" if (unpack_state(f, q) != 0)",
" { nstates_get++;",
" f->m_vsize = 0; /* release slot */",
" if (VVERBOSE) cpu_printf(\"Got state\\n\");",
"",
" if (search_terminated != NULL",
" && *search_terminated == 0)",
" { new_state(); /* explore successors */",
" memset((uchar *) &cur_Root, 0, sizeof(SM_frame)); /* avoid confusion */",
" } else",
" { pan_exit(0);",
" }",
" } else",
" { pan_exit(0);",
" } }",
" if (verbose) cpu_printf(\"done got %%d put %%d\\n\", nstates_get, nstates_put);",
" sleep_report();",
"}",
"",
"void",
"give_up(int unused_x)",
"{",
" if (search_terminated != NULL)",
" { *search_terminated |= 32; /* give_up */",
" }",
" if (!writing_trail)",
" { was_interrupted = 1;",
" snapshot();",
" cpu_printf(\"Give Up\\n\");",
" sleep_report();",
" pan_exit(1);",
" } else /* we are already terminating */",
" { cpu_printf(\"SIGINT\\n\");",
" }",
"}",
"",
"void",
"check_overkill(void)",
"{",
" vmax_seen = (vmax_seen + 7)/ 8;",
" vmax_seen *= 8; /* round up to a multiple of 8 */",
"",
" if (core_id == 0",
" && !remote_party",
" && nstates_put > 0",
" && VMAX - vmax_seen > 8)",
" {",
"#ifdef BITSTATE",
" printf(\"cpu0: max VMAX value seen in this run: \");",
"#else",
" printf(\"cpu0: recommend recompiling with \");",
"#endif",
" printf(\"-DVMAX=%%d\\n\", vmax_seen);",
" }",
"}",
"",
"void",
"mem_put(int q) /* handoff state to other cpu, workq q */",
"{ SM_frame *f;",
" int i, j;",
"",
" if (vsize > VMAX)",
" { vsize = (vsize + 7)/8; vsize *= 8; /* round up */",
" printf(\"pan: recompile with -DVMAX=N with N >= %%d\\n\", (int) vsize);",
" Uerror(\"aborting\");",
" }",
" if (now._nr_pr > PMAX)",
" { printf(\"pan: recompile with -DPMAX=N with N >= %%d\\n\", now._nr_pr);",
" Uerror(\"aborting\");",
" }",
" if (now._nr_qs > QMAX)",
" { printf(\"pan: recompile with -DQMAX=N with N >= %%d\\n\", now._nr_qs);",
" Uerror(\"aborting\");",
" }",
" if (vsize > vmax_seen) vmax_seen = vsize;",
" if (now._nr_pr > pmax_seen) pmax_seen = now._nr_pr;",
" if (now._nr_qs > qmax_seen) qmax_seen = now._nr_qs;",
"",
" f = Get_Free_Frame(q); /* not called in likely deadlock states */",
" if (!f) { Uerror(\"Fatal3: no free slot\"); }",
"",
" if (VVERBOSE) cpu_printf(\"putting state into q%%d\\n\", q);",
"",
" memcpy((uchar *) f->m_now, (uchar *) &now, vsize);",
"#if !defined(NOCOMP) && !defined(HC)",
" memset((uchar *) f->m_mask, 0, (VMAX+7)/8 * sizeof(char));",
" for (i = j = 0; i < VMAX; i++, j = (j+1)%%8)",
" { if (Mask[i])",
" { f->m_mask[i/8] |= (1<<j);",
" } }",
"#endif",
" if (now._nr_pr > 0)",
" { memcpy((uchar *) f->m_p_offset, (uchar *) proc_offset, now._nr_pr * sizeof(OFFT));",
" memcpy((uchar *) f->m_p_skip, (uchar *) proc_skip, now._nr_pr * sizeof(uchar));",
" }",
" if (now._nr_qs > 0)",
" { memcpy((uchar *) f->m_q_offset, (uchar *) q_offset, now._nr_qs * sizeof(OFFT));",
" memcpy((uchar *) f->m_q_skip, (uchar *) q_skip, now._nr_qs * sizeof(uchar));",
" }",
"#if defined(C_States) && (HAS_TRACK==1) && (HAS_STACK==1)",
" c_stack((uchar *) f->m_c_stack); /* save unmatched tracked data */",
"#endif",
"#ifdef FULL_TRAIL",
" f->m_stack = stack_last[core_id];",
"#endif",
" f->nr_handoffs = nr_handoffs+1;",
" f->m_tau = trpt->tau;",
" f->m_o_pm = trpt->o_pm;",
" f->m_boq = boq;",
" f->m_vsize = vsize; /* must come last - now the other cpu can see it */",
"",
" if (query_in_progress == 1)",
" query_in_progress = 2; /* make sure we know, if a query makes the rounds */",
" nstates_put++;",
"}",
"",
"#ifdef USE_DISK",
"int Dsk_W_Nr, Dsk_R_Nr;",
"int dsk_file = -1, dsk_read = -1;",
"unsigned long dsk_written, dsk_drained;",
"char dsk_name[512];",
"",
"#ifndef BFS_DISK",
"#if defined(WIN32) || defined(WIN64)",
" #define RFLAGS (O_RDONLY|O_BINARY)",
" #define WFLAGS (O_CREAT|O_WRONLY|O_TRUNC|O_BINARY)",
"#else",
" #define RFLAGS (O_RDONLY)",
" #define WFLAGS (O_CREAT|O_WRONLY|O_TRUNC)",
"#endif",
"#endif",
"",
"void",
"dsk_stats(void)",
"{ int i;",
"",
" if (dsk_written > 0)",
" { cpu_printf(\"dsk_written %%d states in %%d files\\ncpu%%d: dsk_drained %%6d states\\n\",",
" dsk_written, Dsk_W_Nr, core_id, dsk_drained);",
" close(dsk_read);",
" close(dsk_file);",
" for (i = 0; i < Dsk_W_Nr; i++)",
" { sprintf(dsk_name, \"Q%%.3d_%%.3d.tmp\", i, core_id);",
" unlink(dsk_name);",
" } }",
"}",
"",
"void",
"mem_drain(void)",
"{ SM_frame *f, g;",
" int q = (core_id + 1) %% NCORE; /* target q */",
" int sz;",
"",
" if (dsk_read < 0",
" || dsk_written <= dsk_drained)",
" { return;",
" }",
"",
" while (dsk_written > dsk_drained",
" && TargetQ_NotFull(q))",
" { f = Get_Free_Frame(q);",
" if (!f) { Uerror(\"Fatal: unhandled condition\"); }",
"",
" if ((dsk_drained+1)%%MAX_DSK_FILE == 0) /* 100K states max per file */",
" { (void) close(dsk_read); /* close current read handle */",
" sprintf(dsk_name, \"Q%%.3d_%%.3d.tmp\", Dsk_R_Nr++, core_id);",
" (void) unlink(dsk_name); /* remove current file */",
" sprintf(dsk_name, \"Q%%.3d_%%.3d.tmp\", Dsk_R_Nr, core_id);",
" cpu_printf(\"reading %%s\\n\", dsk_name);",
" dsk_read = open(dsk_name, RFLAGS); /* open next file */",
" if (dsk_read < 0)",
" { Uerror(\"could not open dsk file\");",
" } }",
" if (read(dsk_read, &g, sizeof(SM_frame)) != sizeof(SM_frame))",
" { Uerror(\"bad dsk file read\");",
" }",
" sz = g.m_vsize;",
" g.m_vsize = 0;",
" memcpy(f, &g, sizeof(SM_frame));",
" f->m_vsize = sz; /* last */",
"",
" dsk_drained++;",
" }",
"}",
"",
"void",
"mem_file(void)",
"{ SM_frame f;",
" int i, j, q = (core_id + 1) %% NCORE; /* target q */",
"",
" if (vsize > VMAX)",
" { printf(\"pan: recompile with -DVMAX=N with N >= %%d\\n\", vsize);",
" Uerror(\"aborting\");",
" }",
" if (now._nr_pr > PMAX)",
" { printf(\"pan: recompile with -DPMAX=N with N >= %%d\\n\", now._nr_pr);",
" Uerror(\"aborting\");",
" }",
" if (now._nr_qs > QMAX)",
" { printf(\"pan: recompile with -DQMAX=N with N >= %%d\\n\", now._nr_qs);",
" Uerror(\"aborting\");",
" }",
"",
" if (VVERBOSE) cpu_printf(\"filing state for q%%d\\n\", q);",
"",
" memcpy((uchar *) f.m_now, (uchar *) &now, vsize);",
"#if !defined(NOCOMP) && !defined(HC)",
" memset((uchar *) f.m_mask, 0, (VMAX+7)/8 * sizeof(char));",
" for (i = j = 0; i < VMAX; i++, j = (j+1)%%8)",
" { if (Mask[i])",
" { f.m_mask[i/8] |= (1<<j);",
" } }",
"#endif",
" if (now._nr_pr > 0)",
" { memcpy((uchar *)f.m_p_offset, (uchar *)proc_offset, now._nr_pr*sizeof(OFFT));",
" memcpy((uchar *)f.m_p_skip, (uchar *)proc_skip, now._nr_pr*sizeof(uchar));",
" }",
" if (now._nr_qs > 0)",
" { memcpy((uchar *) f.m_q_offset, (uchar *) q_offset, now._nr_qs*sizeof(OFFT));",
" memcpy((uchar *) f.m_q_skip, (uchar *) q_skip, now._nr_qs*sizeof(uchar));",
" }",
"#if defined(C_States) && (HAS_TRACK==1) && (HAS_STACK==1)",
" c_stack((uchar *) f.m_c_stack); /* save unmatched tracked data */",
"#endif",
"#ifdef FULL_TRAIL",
" f.m_stack = stack_last[core_id];",
"#endif",
" f.nr_handoffs = nr_handoffs+1;",
" f.m_tau = trpt->tau;",
" f.m_o_pm = trpt->o_pm;",
" f.m_boq = boq;",
" f.m_vsize = vsize;",
"",
" if (query_in_progress == 1)",
" { query_in_progress = 2;",
" }",
" if (dsk_file < 0)",
" { sprintf(dsk_name, \"Q%%.3d_%%.3d.tmp\", Dsk_W_Nr, core_id);",
" dsk_file = open(dsk_name, WFLAGS, 0644);",
" dsk_read = open(dsk_name, RFLAGS);",
" if (dsk_file < 0 || dsk_read < 0)",
" { cpu_printf(\"File: <%%s>\\n\", dsk_name);",
" Uerror(\"cannot open diskfile\");",
" }",
" Dsk_W_Nr++; /* nr of next file to open */",
" cpu_printf(\"created temporary diskfile %%s\\n\", dsk_name);",
" } else if ((dsk_written+1)%%MAX_DSK_FILE == 0)",
" { close(dsk_file); /* close write handle */",
" sprintf(dsk_name, \"Q%%.3d_%%.3d.tmp\", Dsk_W_Nr++, core_id);",
" dsk_file = open(dsk_name, WFLAGS, 0644);",
" if (dsk_file < 0)",
" { cpu_printf(\"File: <%%s>\\n\", dsk_name);",
" Uerror(\"aborting: cannot open new diskfile\");",
" }",
" cpu_printf(\"created temporary diskfile %%s\\n\", dsk_name);",
" }",
" if (write(dsk_file, &f, sizeof(SM_frame)) != sizeof(SM_frame))",
" { Uerror(\"aborting -- disk write failed (disk full?)\");",
" }",
" nstates_put++;",
" dsk_written++;",
"}",
"#endif",
"",
"int",
"mem_hand_off(void)",
"{",
" if (search_terminated == NULL",
" || *search_terminated != 0) /* not a full crash check */",
" { pan_exit(0);",
" }",
" iam_alive(); /* on every transition of Down */",
"#ifdef USE_DISK",
" mem_drain(); /* maybe call this also on every Up */",
"#endif",
" if (depth > z_handoff /* above handoff limit */",
"#ifndef SAFETY",
" && !a_cycles /* not in liveness mode */",
"#endif",
"#if SYNC",
" && boq == -1 /* not mid-rv */",
"#endif",
"#ifdef VERI",
" && (trpt->tau&4) /* claim moves first */",
" && !((trpt-1)->tau&128) /* not a stutter move */",
"#endif",
" && !(trpt->tau&8)) /* not an atomic move */",
" { int q = (core_id + 1) %% NCORE; /* circular handoff */",
" #ifdef GENEROUS",
" if (prcnt[q] < LN_FRAMES)", /* not the best strategy */
" #else",
" if (TargetQ_NotFull(q)",
" && (dfs_phase2 == 0 || prcnt[core_id] > 0))", /* not locked, ok if race */
" #endif",
" { mem_put(q);", /* only 1 writer: lock-free */
" return 1;",
" }",
" { int rval;",
" #ifndef NGQ",
" rval = GlobalQ_HasRoom();",
" #else",
" rval = 0;",
" #endif",
" #ifdef USE_DISK",
" if (rval == 0)",
" { void mem_file(void);",
" mem_file();",
" rval = 1;",
" }",
" #endif",
" return rval;",
" }",
" }",
" return 0; /* i.e., no handoff */",
"}",
"",
"void",
"mem_put_acc(void) /* liveness mode */",
"{ int q = (core_id + 1) %% NCORE;",
"",
" if (search_terminated == NULL",
" || *search_terminated != 0)",
" { pan_exit(0);",
" }",
"#ifdef USE_DISK",
" mem_drain();",
"#endif",
" /* some tortured use of preprocessing: */",
"#if !defined(NGQ) || defined(USE_DISK)",
" if (TargetQ_Full(q))",
" {",
"#endif",
"#ifndef NGQ",
" if (GlobalQ_HasRoom())",
" { return;",
" }",
"#endif",
"#ifdef USE_DISK",
" mem_file();",
" } else",
"#else",
" #if !defined(NGQ) || defined(USE_DISK)",
" }",
" #endif",
"#endif",
" { mem_put(q);",
" }",
"}",
"",
"#if defined(WIN32) || defined(WIN64)", /* visual studio */
"void",
"init_shm(void) /* initialize shared work-queues */",
"{ char key[512];",
" int n, m;",
" int must_exit = 0;",
"",
" if (core_id == 0 && verbose)",
" { printf(\"cpu0: step 3: allocate shared work-queues %%g Mb\\n\",",
" ((double) NCORE * LWQ_SIZE + GWQ_SIZE) / (1048576.));",
" }",
" for (m = 0; m < NR_QS; m++) /* last q is global 1 */",
" { double qsize = (m == NCORE) ? GWQ_SIZE : LWQ_SIZE;",
" sprintf(key, \"Global\\\\pan_%%s_%%.3d\", PanSource, m);",
" if (core_id == 0)", /* root process creates shared memory segments */
" { shmid[m] = CreateFileMapping(",
" INVALID_HANDLE_VALUE, /* use paging file */",
" NULL, /* default security */",
" PAGE_READWRITE, /* access permissions */",
" 0, /* high-order 4 bytes */",
" qsize, /* low-order bytes, size in bytes */",
" key); /* name */",
" } else /* worker nodes just open these segments */",
" { shmid[m] = OpenFileMapping(",
" FILE_MAP_ALL_ACCESS, /* read/write access */",
" FALSE, /* children do not inherit handle */",
" key);",
" }",
" if (shmid[m] == NULL)",
" { fprintf(stderr, \"cpu%%d: could not create or open shared queues\\n\",",
" core_id);",
" must_exit = 1;",
" break;",
" }",
" /* attach: */",
" shared_mem[m] = (char *) MapViewOfFile(shmid[m], FILE_MAP_ALL_ACCESS, 0, 0, 0);",
" if (shared_mem[m] == NULL)",
" { fprintf(stderr, \"cpu%%d: cannot attach shared q%%d (%%d Mb)\\n\",",
" core_id, m+1, (int) (qsize/(1048576.)));",
" must_exit = 1;",
" break;",
" }",
"",
" memcnt += qsize;",
"",
" m_workq[m] = (SM_frame *) shared_mem[m];",
" if (core_id == 0)",
" { int nframes = (m == NCORE) ? GN_FRAMES : LN_FRAMES;",
" for (n = 0; n < nframes; n++)",
" { m_workq[m][n].m_vsize = 0;",
" m_workq[m][n].m_boq = 0;",
" } } }",
"",
" if (must_exit)",
" { fprintf(stderr, \"pan: check './pan --' for usage details\\n\");",
" pan_exit(1); /* calls cleanup_shm */",
" }",
"}",
"",
"static uchar *",
"prep_shmid_S(size_t n) /* either sets SS or H_tab, WIN32/WIN64 */",
"{ char *rval;",
"#ifndef SEP_STATE",
" char key[512];",
"",
" if (verbose && core_id == 0)",
" {",
" #ifdef BITSTATE",
" printf(\"cpu0: step 1: allocate shared bitstate %%g Mb\\n\",",
" (double) n / (1048576.));",
" #else",
" printf(\"cpu0: step 1: allocate shared hastable %%g Mb\\n\",",
" (double) n / (1048576.));",
" #endif",
" }",
" #ifdef MEMLIM",
" if (memcnt + (double) n > memlim)",
" { printf(\"cpu%%d: S %%8g + %%d Kb exceeds memory limit of %%8g Mb\\n\",",
" core_id, memcnt/1024., n/1024, memlim/(1048576.));",
" printf(\"cpu%%d: insufficient memory -- aborting\\n\", core_id);",
" exit(1);",
" }",
" #endif",
"",
" /* make key different from queues: */",
" sprintf(key, \"Global\\\\pan_%%s_%%.3d\", PanSource, NCORE+2); /* different from qs */",
"",
" if (core_id == 0) /* root */",
" { shmid_S = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,",
"#ifdef WIN64",
" PAGE_READWRITE, (n>>32), (n & 0xffffffff), key);",
"#else",
" PAGE_READWRITE, 0, n, key);",
"#endif",
" memcnt += (double) n;",
" } else /* worker */",
" { shmid_S = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, key);",
" }",
" if (shmid_S == NULL)",
" {",
" #ifdef BITSTATE",
" fprintf(stderr, \"cpu%%d: cannot %%s shared bitstate\",",
" core_id, core_id?\"open\":\"create\");",
" #else",
" fprintf(stderr, \"cpu%%d: cannot %%s shared hashtable\",",
" core_id, core_id?\"open\":\"create\");",
" #endif",
" fprintf(stderr, \"pan: check './pan --' for usage details\\n\");",
" pan_exit(1);",
" }",
"",
" rval = (char *) MapViewOfFile(shmid_S, FILE_MAP_ALL_ACCESS, 0, 0, 0); /* attach */",
" if ((char *) rval == NULL)",
" { fprintf(stderr, \"cpu%%d: cannot attach shared bitstate or hashtable\\n\", core_id);",
" fprintf(stderr, \"pan: check './pan --' for usage details\\n\");",
" pan_exit(1);",
" }",
"#else",
" rval = (char *) emalloc(n);",
"#endif",
" return (uchar *) rval;",
"}",
"",
"static uchar *",
"prep_state_mem(size_t n) /* WIN32/WIN64 sets memory arena for states */",
"{ char *rval;",
" char key[512];",
" static int cnt = 3; /* start larger than earlier ftok calls */",
"",
" if (verbose && core_id == 0)",
" { printf(\"cpu0: step 2+: pre-allocate memory arena %%d of %%g Mb\\n\",",
" cnt-3, (double) n / (1048576.));",
" }",
" #ifdef MEMLIM",
" if (memcnt + (double) n > memlim)",
" { printf(\"cpu%%d: error: M %%.0f + %%.0f exceeds memory limit of %%.0f Kb\\n\",",
" core_id, memcnt/1024.0, (double) n/1024.0, memlim/1024.0);",
" return NULL;",
" }",
" #endif",
"",
" sprintf(key, \"Global\\\\pan_%%s_%%.3d\", PanSource, NCORE+cnt); cnt++;",
"",
" if (core_id == 0)",
" { shmid_M = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,",
"#ifdef WIN64",
" PAGE_READWRITE, (n>>32), (n & 0xffffffff), key);",
"#else",
" PAGE_READWRITE, 0, n, key);",
"#endif",
" } else",
" { shmid_M = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, key);",
" }",
" if (shmid_M == NULL)",
" { printf(\"cpu%%d: failed to get pool of shared memory nr %%d of size %%d\\n\",",
" core_id, cnt-3, n);",
" printf(\"pan: check './pan --' for usage details\\n\");",
" return NULL;",
" }",
" rval = (char *) MapViewOfFile(shmid_M, FILE_MAP_ALL_ACCESS, 0, 0, 0); /* attach */",
"",
" if (rval == NULL)",
" { printf(\"cpu%%d: failed to attach pool of shared memory nr %%d of size %%d\\n\",",
" core_id, cnt-3, n);",
" return NULL;",
" }",
" return (uchar *) rval;",
"}",
"",
"void",
"init_HT(unsigned long n) /* WIN32/WIN64 version */",
"{ volatile char *x;",
" double get_mem;",
"#ifndef SEP_STATE",
" char *dc_mem_start;",
"#endif",
" if (verbose) printf(\"cpu%%d: initialization for Windows\\n\", core_id);",
"",
"#ifdef SEP_STATE",
" #ifndef MEMLIM",
" if (verbose)",
" { printf(\"cpu0: steps 0,1: no -DMEMLIM set\\n\");",
" }",
" #else",
" if (verbose)",
" printf(\"cpu0: steps 0,1: -DMEMLIM=%%d Mb - (hashtable %%g Mb + workqueues %%g Mb)\\n\",",
" MEMLIM, ((double)n/(1048576.)), ((double) NCORE * LWQ_SIZE + GWQ_SIZE)/(1048576.));",
"#endif",
" get_mem = NCORE * sizeof(double) + (1 + CS_NR) * sizeof(void *)+ 4*sizeof(void *) + 2*sizeof(double);",
" /* NCORE * is_alive + search_terminated + CS_NR * sh_lock + 6 gr vars */",
" get_mem += 4 * NCORE * sizeof(void *);", /* prfree, prfull, prcnt, prmax */
" #ifdef FULL_TRAIL",
" get_mem += (NCORE) * sizeof(Stack_Tree *);",
" /* NCORE * stack_last */",
" #endif",
" x = (volatile char *) prep_state_mem((size_t) get_mem);",
" shmid_X = (void *) x;",
" if (x == NULL)",
" { printf(\"cpu0: could not allocate shared memory, see ./pan --\\n\");",
" exit(1);",
" }",
" search_terminated = (volatile unsigned int *) x; /* comes first */",
" x += sizeof(void *); /* maintain alignment */",
"",
" is_alive = (volatile double *) x;",
" x += NCORE * sizeof(double);",
"",
" sh_lock = (volatile int *) x;",
" x += CS_NR * sizeof(void *); /* allow 1 word per entry */",
"",
" grfree = (volatile int *) x;",
" x += sizeof(void *);",
" grfull = (volatile int *) x;",
" x += sizeof(void *);",
" grcnt = (volatile int *) x;",
" x += sizeof(void *);",
" grmax = (volatile int *) x;",
" x += sizeof(void *);",
" prfree = (volatile int *) x;",
" x += NCORE * sizeof(void *);",
" prfull = (volatile int *) x;",
" x += NCORE * sizeof(void *);",
" prcnt = (volatile int *) x;",
" x += NCORE * sizeof(void *);",
" prmax = (volatile int *) x;",
" x += NCORE * sizeof(void *);",
" gr_readmiss = (volatile double *) x;",
" x += sizeof(double);",
" gr_writemiss = (volatile double *) x;",
" x += sizeof(double);",
"",
" #ifdef FULL_TRAIL",
" stack_last = (volatile Stack_Tree **) x;",
" x += NCORE * sizeof(Stack_Tree *);",
" #endif",
"",
" #ifndef BITSTATE",
" H_tab = (H_el **) emalloc(n);",
" #endif",
"#else",
" #ifndef MEMLIM",
" #warning MEMLIM not set", /* cannot happen */
" #define MEMLIM (2048)",
" #endif",
"",
" if (core_id == 0 && verbose)",
" printf(\"cpu0: step 0: -DMEMLIM=%%d Mb - (hashtable %%g Mb + workqueues %%g Mb) = %%g Mb for state storage\\n\",",
" MEMLIM, ((double)n/(1048576.)), ((double) NCORE * LWQ_SIZE + GWQ_SIZE)/(1048576.),",
" (memlim - memcnt - (double) n - ((double) NCORE * LWQ_SIZE + GWQ_SIZE))/(1048576.));",
" #ifndef BITSTATE",
" H_tab = (H_el **) prep_shmid_S((size_t) n); /* hash_table */",
" #endif",
" get_mem = memlim - memcnt - ((double) NCORE) * LWQ_SIZE - GWQ_SIZE;",
" if (get_mem <= 0)",
" { Uerror(\"internal error -- shared state memory\");",
" }",
"",
" if (core_id == 0 && verbose)",
" { printf(\"cpu0: step 2: shared state memory %%g Mb\\n\",",
" get_mem/(1048576.));",
" }",
" x = dc_mem_start = (char *) prep_state_mem((size_t) get_mem); /* for states */",
" if (x == NULL)",
" { printf(\"cpu%%d: insufficient memory -- aborting\\n\", core_id);",
" exit(1);",
" }",
"",
" search_terminated = (volatile unsigned int *) x; /* comes first */",
" x += sizeof(void *); /* maintain alignment */",
"",
" is_alive = (volatile double *) x;",
" x += NCORE * sizeof(double);",
"",
" sh_lock = (volatile int *) x;",
" x += CS_NR * sizeof(int);",
"",
" grfree = (volatile int *) x;",
" x += sizeof(void *);",
" grfull = (volatile int *) x;",
" x += sizeof(void *);",
" grcnt = (volatile int *) x;",
" x += sizeof(void *);",
" grmax = (volatile int *) x;",
" x += sizeof(void *);",
" prfree = (volatile int *) x;",
" x += NCORE * sizeof(void *);",
" prfull = (volatile int *) x;",
" x += NCORE * sizeof(void *);",
" prcnt = (volatile int *) x;",
" x += NCORE * sizeof(void *);",
" prmax = (volatile int *) x;",
" x += NCORE * sizeof(void *);",
" gr_readmiss = (volatile double *) x;",
" x += sizeof(double);",
" gr_writemiss = (volatile double *) x;",
" x += sizeof(double);",
"",
" #ifdef FULL_TRAIL",
" stack_last = (volatile Stack_Tree **) x;",
" x += NCORE * sizeof(Stack_Tree *);",
" #endif",
" if (((long)x)&(sizeof(void *)-1)) /* word alignment */",
" { x += sizeof(void *)-(((long)x)&(sizeof(void *)-1)); /* 64-bit align */",
" }",
"",
" #ifdef COLLAPSE",
" ncomps = (unsigned long *) x;",
" x += (256+2) * sizeof(unsigned long);",
" #endif",
"",
" dc_shared = (sh_Allocater *) x; /* in shared memory */",
" x += sizeof(sh_Allocater);",
"",
" if (core_id == 0) /* root only */",
" { dc_shared->dc_id = shmid_M;",
" dc_shared->dc_start = (void *) dc_mem_start;",
" dc_shared->dc_arena = x;",
" dc_shared->pattern = 1234567;",
" dc_shared->dc_size = (long) get_mem - (long) (x - dc_mem_start);",
" dc_shared->nxt = NULL;",
" }",
"#endif",
"}",
"",
"#if defined(WIN32) || defined(WIN64) || defined(__i386__) || defined(__x86_64__)",
"extern BOOLEAN InterlockedBitTestAndSet(LONG volatile* Base, LONG Bit);",
"int",
"tas(volatile LONG *s)", /* atomic test and set */
"{ return InterlockedBitTestAndSet(s, 1);",
"}",
"#else",
" #error missing definition of test and set operation for this platform",
"#endif",
"",
"void",
"cleanup_shm(int val)",
"{ int m;",
" static int nibis = 0;",
"",
" if (nibis != 0)",
" { printf(\"cpu%%d: Redundant call to cleanup_shm(%%d)\\n\", core_id, val);",
" return;",
" } else",
" { nibis = 1;",
" }",
" if (search_terminated != NULL)",
" { *search_terminated |= 16; /* cleanup_shm */",
" }",
"",
" for (m = 0; m < NR_QS; m++)",
" { if (shmid[m] != NULL)",
" { UnmapViewOfFile((char *) shared_mem[m]);",
" CloseHandle(shmid[m]);",
" } }",
"#ifdef SEP_STATE",
" UnmapViewOfFile((void *) shmid_X);",
" CloseHandle((void *) shmid_M);",
"#else",
" #ifdef BITSTATE",
" if (shmid_S != NULL)",
" { UnmapViewOfFile(SS);",
" CloseHandle(shmid_S);",
" }",
" #else",
" if (core_id == 0 && verbose)",
" { printf(\"cpu0: done, %%ld Mb of shared state memory left\\n\",",
" dc_shared->dc_size / (long)(1048576));",
" }",
" if (shmid_S != NULL)",
" { UnmapViewOfFile(H_tab);",
" CloseHandle(shmid_S);",
" }",
" shmid_M = (void *) (dc_shared->dc_id);",
" UnmapViewOfFile((char *) dc_shared->dc_start);",
" CloseHandle(shmid_M);",
" #endif",
"#endif",
" /* detached from shared memory - so cannot use cpu_printf */",
" if (verbose)",
" { printf(\"cpu%%d: done -- got %%d states from queue\\n\",",
" core_id, nstates_get);",
" }",
"}",
"",
"void",
"mem_get(void)",
"{ SM_frame *f;",
" int is_parent;",
"",
"#if defined(MA) && !defined(SEP_STATE)",
" #error MA requires SEP_STATE in multi-core mode",
"#endif",
"#ifdef BFS",
" #error instead of -DNCORE -DBFS use -DBFS_PAR",
"#endif",
"#ifdef SC",
" #error SC is not supported in multi-core mode",
"#endif",
" init_shm(); /* we are single threaded when this starts */",
" signal(SIGINT, give_up); /* windows control-c interrupt */",
"",
" if (core_id == 0 && verbose)",
" { printf(\"cpu0: step 4: creating additional workers (proxy %%d)\\n\",",
" proxy_pid);",
" }",
"#if 0",
" if NCORE > 1 the child or the parent should fork N-1 more times",
" the parent is the only process with core_id == 0 and is_parent > 0",
" the others (workers) have is_parent = 0 and core_id = 1..NCORE-1",
"#endif",
" if (core_id == 0) /* root starts up the workers */",
" { worker_pids[0] = (DWORD) getpid(); /* for completeness */",
" while (++core_id < NCORE) /* first worker sees core_id = 1 */",
" { char cmdline[64];",
" STARTUPINFO si = { sizeof(si) };",
" PROCESS_INFORMATION pi;",
"",
" if (proxy_pid == core_id) /* always non-zero */",
" { sprintf(cmdline, \"pan_proxy.exe -r %%s-Q%%d -Z%%d\",",
" o_cmdline, getpid(), core_id);",
" } else",
" { sprintf(cmdline, \"pan.exe %%s-Q%%d -Z%%d\",",
" o_cmdline, getpid(), core_id);",
" }",
" if (verbose) printf(\"cpu%%d: spawn %%s\\n\", core_id, cmdline);",
"",
" is_parent = CreateProcess(0, cmdline, 0, 0, FALSE, 0, 0, 0, &si, &pi);",
" if (is_parent == 0)",
" { Uerror(\"fork failed\");",
" }",
" worker_pids[core_id] = pi.dwProcessId;",
" worker_handles[core_id] = pi.hProcess;",
" if (verbose)",
" { cpu_printf(\"created core %%d, pid %%d\\n\",",
" core_id, pi.dwProcessId);",
" }",
" if (proxy_pid == core_id) /* we just created the receive half */",
" { /* add proxy send, store pid in proxy_pid_snd */",
" sprintf(cmdline, \"pan_proxy.exe -s %%s-Q%%d -Z%%d -Y%%d\",",
" o_cmdline, getpid(), core_id, worker_pids[proxy_pid]);",
" if (verbose) printf(\"cpu%%d: spawn %%s\\n\", core_id, cmdline);",
" is_parent = CreateProcess(0, cmdline, 0,0, FALSE, 0,0,0, &si, &pi);",
" if (is_parent == 0)",
" { Uerror(\"fork failed\");",
" }",
" proxy_pid_snd = pi.dwProcessId;",
" proxy_handle_snd = pi.hProcess;",
" if (verbose)",
" { cpu_printf(\"created core %%d, pid %%d (send proxy)\\n\",",
" core_id, pi.dwProcessId);",
" } } }",
" core_id = 0; /* reset core_id for root process */",
" } else /* worker */",
" { static char db0[16]; /* good for up to 10^6 cores */",
" static char db1[16];",
" tprefix = db0; sprefix = db1;",
" sprintf(tprefix, \"cpu%%d_trail\", core_id); /* avoid conflicts on file access */",
" sprintf(sprefix, \"cpu%%d_rst\", core_id);",
" memcnt = 0; /* count only additionally allocated memory */",
" }",
" if (verbose)",
" { cpu_printf(\"starting core_id %%d -- pid %%d\\n\", core_id, getpid());",
" }",
" if (core_id == 0 && !remote_party)",
" { new_state(); /* root starts the search */",
" if (verbose)",
" cpu_printf(\"done with 1st dfs, nstates %%g (put %%d states), start reading q\\n\",",
" nstates, nstates_put);",
" dfs_phase2 = 1;",
" }",
" Read_Queue(core_id); /* all cores */",
"",
" if (verbose)",
" { cpu_printf(\"put %%6d states into queue -- got %%6d\\n\",",
" nstates_put, nstates_get);",
" }",
" done = 1;",
" wrapup();",
" exit(0);",
"}",
"#endif", /* WIN32 || WIN64 */
"",
"#ifdef BITSTATE",
"void",
"init_SS(unsigned long n)",
"{",
" SS = (uchar *) prep_shmid_S((size_t) n);",
" init_HT(0L);", /* locks and shared memory for Stack_Tree allocations */
"}",
"#endif", /* BITSTATE */
"",
"#endif", /* NCORE>1 */
0,
};