xref: /plan9-contrib/sys/src/cmd/spin/pangen6.h (revision de2caf28f9ba1a56e70be94a699435d36eb50311)
1 /***** spin: pangen6.h *****/
2 
3 /*
4  * This file is part of the public release of Spin. It is subject to the
5  * terms in the LICENSE file that is included in this source directory.
6  * Tool documentation is available at http://spinroot.com
7  */
8 
9 static const char *Code2e[] = {
10 	"#if (NCORE>1 || defined(BFS_PAR)) && !defined(WIN32) && !defined(WIN64)",
11 	"	/* Test and Set assembly code */",
12 	"	#if defined(i386) || defined(__i386__) || defined(__x86_64__)",
13 	"		int",
14 	"		tas(volatile int *s)	/* tested */",
15 	"		{	int r;",
16 	"			__asm__ __volatile__(",
17 	"				\"xchgl %%0, %%1 \\n\\t\"",
18 	"		       		: \"=r\"(r), \"=m\"(*s)",
19 	"				: \"0\"(1), \"m\"(*s)",
20 	"				: \"memory\");",
21 	"		",
22 	"			return r;",
23 	"		}",
24 	"	#elif defined(__arm__)",
25 	"		int",
26 	"		tas(volatile int *s)	/* not tested */",
27 	"		{	int r = 1;",
28 	"			__asm__ __volatile__(",
29 	"				\"swpb %%0, %%0, [%%3] \\n\"",
30 	"				: \"=r\"(r), \"=m\"(*s)",
31 	"				: \"0\"(r), \"r\"(s));",
32 	"",
33 	"			return r;",
34 	"		}",
35 	"	#elif defined(sparc) || defined(__sparc__)",
36 	"		int",
37 	"		tas(volatile int *s)	/* not tested */",
38 	"		{	int r = 1;",
39 	"			__asm__ __volatile__(",
40 	"				\" ldstub [%%2], %%0 \\n\"",
41 	"				: \"=r\"(r), \"=m\"(*s)",
42 	"				: \"r\"(s));",
43 	"",
44 	"			return r;",
45 	"		}",
46 	"	#elif defined(ia64) || defined(__ia64__)",
47 	"		/* Intel Itanium */",
48 	"		int",
49 	"		tas(volatile int *s)	/* tested */",
50 	"		{	long int r;",
51 	"			__asm__ __volatile__(",
52 	"				\"	xchg4 	%%0=%%1,%%2	\\n\"",
53 	"		:		\"=r\"(r), \"+m\"(*s)",
54 	"		:		\"r\"(1)",
55 	"		:		\"memory\");",
56 	"			return (int) r;",
57 	"		}",
58 	"	#elif defined(__powerpc64__)",
59 	"		int",
60 	"		tas(volatile int *s)	/* courtesy srirajpaul */",
61 	"		{	int r;",
62 	" #if 1",
63 	"			r = __sync_lock_test_and_set();",
64 	" #else",
65 	"			/* xlc compiler only */",
66 	"			r = __fetch_and_or(s, 1);",
67 	"			__isync();",
68 	" #endif",
69 	"			return r;",
70 	"		}",
71 	"	#else",
72 	"		#error missing definition of test and set operation for this platform",
73 	"	#endif",
74 	"",
75 	"	#ifndef NO_CAS", /* linux, windows */
76 	"		#define cas(a,b,c) __sync_bool_compare_and_swap(a,b,c)",
77 	"	#else",
78 	"	int", /* workaround if the above is not available */
79 	"	cas(volatile uint32_t *a, uint32_t b, uint32_t c)",
80 	"	{	static volatile int cas_lock;",
81 	"		while (tas(&cas_lock) != 0) { ; }",
82 	"		if (*a == b)",
83 	"		{	*a = c;",
84 	"			cas_lock = 0;",
85 	"			return 1;",
86 	"		}",
87 	"		cas_lock = 0;",
88 	"		return 0;",
89 	"	}",
90 	"	#endif",
91 	"#endif",
92 	0,
93 };
94 
95 static const char *Code2c[] = { /* multi-core option - Spin 5.0 and later */
96 	"#if NCORE>1",
97 	"#if defined(WIN32) || defined(WIN64)",
98 	"	#ifndef _CONSOLE",
99 	"		#define _CONSOLE",
100 	"	#endif",
101 	"	#ifdef WIN64",
102 	"		#undef long",
103 	"	#endif",
104 	"	#include <windows.h>",
105 	"/*",
106 	"	#ifdef WIN64",
107 	"		#define long	long long",
108 	"	#endif",
109 	"*/",
110 	"#else",
111 	"	#include <sys/ipc.h>",
112 	"	#include <sys/sem.h>",
113 	"	#include <sys/shm.h>",
114 	"#endif",
115 	"",
116 	"/* code common to cygwin/linux and win32/win64: */",
117 	"",
118 	"#ifdef VERBOSE",
119 	"	#define VVERBOSE	(1)",
120 	"#else",
121 	"	#define VVERBOSE	(0)",
122 	"#endif",
123 	"",
124 	"/* the following values must be larger than 256 and must fit in an int */",
125 	"#define QUIT		1024	/* terminate now command */",
126 	"#define QUERY		 512	/* termination status query message */",
127 	"#define QUERY_F	 513	/* query failed, cannot quit */",
128 	"",
129 	"#define GN_FRAMES	(int) (GWQ_SIZE / (double) sizeof(SM_frame))",
130 	"#define LN_FRAMES	(int) (LWQ_SIZE / (double) sizeof(SM_frame))",
131 	"",
132 	"#ifndef VMAX",
133 	"	#define VMAX	VECTORSZ",
134 	"#endif",
135 	"#ifndef PMAX",
136 	"	#define PMAX	64",
137 	"#endif",
138 	"#ifndef QMAX",
139 	"	#define QMAX	64",
140 	"#endif",
141 	"",
142 	"#if VECTORSZ>32000",
143 	"	#define OFFT	int",
144 	"#else",
145 	"	#define OFFT	short",
146 	"#endif",
147 	"",
148 	"#ifdef SET_SEG_SIZE",
149 	"	/* no longer useful -- being recomputed for local heap size anyway */",
150 	"	double SEG_SIZE = (((double) SET_SEG_SIZE) * 1048576.);",
151 	"#else",
152 	"	double SEG_SIZE = (1048576.*1024.);	/* 1GB default shared memory pool segments */",
153 	"#endif",
154 	"",
155 	"double LWQ_SIZE = 0.; /* initialized in main */",
156 	"",
157 	"#ifdef SET_WQ_SIZE",
158 	"	#ifdef NGQ",
159 	"	#warning SET_WQ_SIZE applies to global queue -- ignored",
160 	"	double GWQ_SIZE = 0.;",
161 	"	#else",
162 	"	double GWQ_SIZE = (((double) SET_WQ_SIZE) * 1048576.);",
163 	"	/* must match the value in pan_proxy.c, if used */",
164 	"	#endif",
165 	"#else",
166 	"	#ifdef NGQ",
167 	"	double GWQ_SIZE = 0.;",
168 	"	#else",
169 	"	double GWQ_SIZE = (128.*1048576.);	/* 128 MB default queue sizes */",
170 	"	#endif",
171 	"#endif",
172 	"",
173 	"/* Crash Detection Parameters */",
174 	"#ifndef ONESECOND",
175 	"	#define ONESECOND	(1<<25)", /* name is somewhat of a misnomer */
176 	"#endif",
177 	"#ifndef SHORT_T",
178 	"	#define SHORT_T	(0.1)",
179 	"#endif",
180 	"#ifndef LONG_T",
181 	"	#define LONG_T	(600)",
182 	"#endif",
183 	"",
184 	"double OneSecond   = (double) (ONESECOND); /* waiting for a free slot -- checks crash */",
185 	"double TenSeconds  = 10. * (ONESECOND);    /* waiting for a lock -- check for a crash */",
186 	"",
187 	"/* Termination Detection Params -- waiting for new state input in Get_Full_Frame */",
188 	"double Delay       = ((double) SHORT_T) * (ONESECOND);	/* termination detection trigger */",
189 	"double OneHour     = ((double) LONG_T) * (ONESECOND);	/* timeout termination detection */",
190 	"",
191 	"typedef struct SM_frame     SM_frame;",
192 	"typedef struct SM_results   SM_results;",
193 	"typedef struct sh_Allocater sh_Allocater;",
194 	"",
195 	"struct SM_frame {			/* about 6K per slot */",
196 	"	volatile int	m_vsize;	/* 0 means free slot */",
197 	"	volatile int	m_boq;		/* >500 is a control message */",
198 	"#ifdef FULL_TRAIL",
199 	"	volatile struct Stack_Tree *m_stack;	/* ptr to previous state */",
200 	"#endif",
201 	"	volatile uchar	m_tau;",
202 	"	volatile uchar	m_o_pm;",
203 	"	volatile int	nr_handoffs;	/* to compute real_depth */",
204 	"	volatile char	m_now     [VMAX];",
205 	"#if !defined(NOCOMP) && !defined(HC)",
206 	"	volatile char	m_mask    [(VMAX + 7)/8];",
207 	"#endif",
208 	"	volatile OFFT	m_p_offset[PMAX];",
209 	"	volatile OFFT	m_q_offset[QMAX];",
210 	"	volatile uchar	m_p_skip  [PMAX];",
211 	"	volatile uchar	m_q_skip  [QMAX];",
212 	"#if defined(C_States) && (HAS_TRACK==1) && (HAS_STACK==1)",
213 	"	volatile uchar	m_c_stack [StackSize];",
214 		 /* captures contents of c_stack[] for unmatched objects */
215 	"#endif",
216 	"};",
217 	"",
218 	"int	proxy_pid;		/* id of proxy if nonzero -- receive half */",
219 	"int	store_proxy_pid;",
220 	"short	remote_party;",
221 	"int	proxy_pid_snd;		/* id of proxy if nonzero -- send half */",
222 	"",
223 	"int	iamin[CS_NR+NCORE];		/* non-shared */",
224 	"",
225 "#if defined(WIN32) || defined(WIN64)",
226 	"int tas(volatile LONG *);",
227 	"",
228 	"HANDLE		proxy_handle_snd;	/* for Windows Create and Terminate */",
229 	"",
230 	"struct sh_Allocater {			/* shared memory for states */",
231 	"	volatile char	*dc_arena;	/* to allocate states from */",
232 	"	volatile long	 pattern;	/* to detect overruns */",
233 	"	volatile long	 dc_size;	/* nr of bytes left */",
234 	"	volatile void	*dc_start;	/* where memory segment starts */",
235 	"	volatile void	*dc_id;		/* to attach, detach, remove shared memory segments */",
236 	"	volatile sh_Allocater *nxt;	/* linked list of pools */",
237 	"};",
238 	"DWORD		worker_pids[NCORE];	/* root mem of pids of all workers created */",
239 	"HANDLE		worker_handles[NCORE];	/* for windows Create and Terminate */",
240 	"void *		shmid      [NR_QS];	/* return value from CreateFileMapping */",
241 	"void *		shmid_M;		/* shared mem for state allocation in hashtable */",
242 	"",
243 	"#ifdef SEP_STATE",
244 	"	void *shmid_X;",
245 	"#else",
246 	"	void *shmid_S;			/* shared bitstate arena or hashtable */",
247 	"#endif",
248 "#else",
249 	"int tas(volatile int *);",
250 	"",
251 	"struct sh_Allocater {			/* shared memory for states */",
252 	"	volatile char	*dc_arena;	/* to allocate states from */",
253 	"	volatile long	 pattern;	/* to detect overruns */",
254 	"	volatile long	 dc_size;	/* nr of bytes left */",
255 	"	volatile char	*dc_start;	/* where memory segment starts */",
256 	"	volatile int	dc_id;		/* to attach, detach, remove shared memory segments */",
257 	"	volatile sh_Allocater *nxt;	/* linked list of pools */",
258 	"};",
259 	"",
260 	"int	worker_pids[NCORE];	/* root mem of pids of all workers created */",
261 	"int	shmid      [NR_QS];	/* return value from shmget */",
262 	"int	nibis = 0;		/* set after shared mem has been released */",
263 	"int	shmid_M;		/* shared mem for state allocation in hashtable */",
264 	"#ifdef SEP_STATE",
265 	"	long	shmid_X;",
266 	"#else",
267 	"	int	shmid_S;	/* shared bitstate arena or hashtable */",
268 	"	volatile sh_Allocater	*first_pool;	/* of shared state memory */",
269 	"	volatile sh_Allocater	*last_pool;",
270 	"#endif", /* SEP_STATE */
271 "#endif", /* WIN32 || WIN64 */
272 	"",
273 	"struct SM_results {			/* for shuttling back final stats */",
274 	"	volatile int	m_vsize;	/* avoid conflicts with frames */",
275 	"	volatile int	m_boq;		/* these 2 fields are not written in record_info */",
276 	"	/* probably not all fields really need to be volatile */",
277 	"	volatile double	m_memcnt;",
278 	"	volatile double	m_nstates;",
279 	"	volatile double	m_truncs;",
280 	"	volatile double	m_truncs2;",
281 	"	volatile double	m_nShadow;",
282 	"	volatile double	m_nlinks;",
283 	"	volatile double	m_ngrabs;",
284 	"	volatile double	m_nlost;",
285 	"	volatile double	m_hcmp;",
286 	"	volatile double	m_frame_wait;",
287 	"	volatile int	m_hmax;",
288 	"	volatile int	m_svmax;",
289 	"	volatile int	m_smax;",
290 	"	volatile int	m_mreached;",
291 	"	volatile int	m_errors;",
292 	"	volatile int	m_VMAX;",
293 	"	volatile short	m_PMAX;",
294 	"	volatile short	m_QMAX;",
295 	"	volatile uchar	m_R;		/* reached info for all proctypes */",
296 	"};",
297 	"",
298 	"int		core_id = 0;		/* internal process nr, to know which q to use */",
299 	"unsigned long	nstates_put = 0;	/* statistics */",
300 	"unsigned long	nstates_get = 0;",
301 	"int		query_in_progress = 0;	/* termination detection */",
302 	"",
303 	"double		free_wait  = 0.;	/* waiting for a free frame */",
304 	"double		frame_wait = 0.;	/* waiting for a full frame */",
305 	"double		lock_wait  = 0.;	/* waiting for access to cs */",
306 	"double		glock_wait[3];	/* waiting for access to global lock */",
307 	"",
308 	"char		*sprefix = \"rst\";",
309 	"uchar		was_interrupted, issued_kill, writing_trail;",
310 	"",
311 	"static SM_frame cur_Root;		/* current root, to be safe with error trails */",
312 	"",
313 	"SM_frame	*m_workq   [NR_QS];	/* per cpu work queues + global q */",
314 	"char		*shared_mem[NR_QS];	/* return value from shmat */",
315 	"#ifdef SEP_HEAP",
316 	"char		*my_heap;",
317 	"long		 my_size;",
318 	"#endif",
319 	"volatile sh_Allocater	*dc_shared;	/* assigned at initialization */",
320 	"",
321 	"static int	vmax_seen, pmax_seen, qmax_seen;",
322 	"static double	gq_tries, gq_hasroom, gq_hasnoroom;",
323 	"",
324 	"volatile int *prfree;",	/* [NCORE] */
325 	"volatile int *prfull;",	/* [NCORE] */
326 	"volatile int *prcnt;",		/* [NCORE] */
327 	"volatile int *prmax;",		/* [NCORE] */
328 	"",
329 	"volatile int	*sh_lock;	/* mutual exclusion locks - in shared memory */",
330 	"volatile double *is_alive;	/* to detect when processes crash */",
331 	"volatile int    *grfree, *grfull, *grcnt, *grmax;	/* access to shared global q */",
332 	"volatile double *gr_readmiss, *gr_writemiss;",
333 	"static   int	lrfree;		/* used for temporary recording of slot */",
334 	"static   int dfs_phase2;",
335 	"",
336 	"void mem_put(int);		/* handoff state to other cpu */",
337 	"void mem_put_acc(void);	/* liveness mode */",
338 	"void mem_get(void);		/* get state from work queue  */",
339 	"void sudden_stop(char *);",
340 	"",
341 	"void",
342 	"record_info(SM_results *r)",
343 	"{	int i;",
344 	"	uchar *ptr;",
345 	"",
346 	"#ifdef SEP_STATE",
347 	"	if (0)",
348 	"	{	cpu_printf(\"nstates %%g nshadow %%g -- memory %%-6.3f Mb\\n\",",
349 	"			nstates, nShadow, memcnt/(1048576.));",
350 	"	}",
351 	"	r->m_memcnt = 0;",
352 	"#else",
353 	"	#ifdef BITSTATE",
354 		"	r->m_memcnt = 0; /* it's shared */",
355 	"	#endif",
356 	"	r->m_memcnt = memcnt;",
357 	"#endif",
358 	"	if (a_cycles && core_id == 1)",
359 	"	{	r->m_nstates  = nstates;",
360 	"		r->m_nShadow  = nstates;",
361 	"	} else",
362 	"	{	r->m_nstates  = nstates;",
363 	"		r->m_nShadow  = nShadow;",
364 	"	}",
365 	"	r->m_truncs   = truncs;",
366 	"	r->m_truncs2  = truncs2;",
367 	"	r->m_nlinks   = nlinks;",
368 	"	r->m_ngrabs   = ngrabs;",
369 	"	r->m_nlost    = nlost;",
370 	"	r->m_hcmp     = hcmp;",
371 	"	r->m_frame_wait = frame_wait;",
372 	"	r->m_hmax     = hmax;",
373 	"	r->m_svmax    = svmax;",
374 	"	r->m_smax     = smax;",
375 	"	r->m_mreached = mreached;",
376 	"	r->m_errors   = (int) errors;",
377 	"	r->m_VMAX     = vmax_seen;",
378 	"	r->m_PMAX     = (short) pmax_seen;",
379 	"	r->m_QMAX     = (short) qmax_seen;",
380 	"	ptr = (uchar *) &(r->m_R);",
381 	"	for (i = 0; i <= _NP_; i++)	/* all proctypes */",
382 	"	{	memcpy(ptr, reached[i], NrStates[i]*sizeof(uchar));",
383 	"		ptr += NrStates[i]*sizeof(uchar);",
384 	"	}",
385 	"	if (verbose>1)",
386 	"	{	cpu_printf(\"Put Results nstates %%g (sz %%d)\\n\", nstates, ptr - &(r->m_R));",
387 	"	}",
388 	"}",
389 	"",
390 	"void snapshot(void);",
391 	"",
392 	"void",
393 	"retrieve_info(SM_results *r)",
394 	"{	int i, j;",
395 	"	volatile uchar *ptr;",
396 	"",
397 	"	snapshot();	/* for a final report */",
398 	"",
399 	"	enter_critical(GLOBAL_LOCK);",
400 	"#ifdef SEP_HEAP",
401 	"	if (verbose)",
402 	"	{	printf(\"cpu%%d: local heap-left %%ld KB (%%d MB)\\n\",",
403 	"			core_id, (long) (my_size/1024), (int) (my_size/1048576));",
404 	"	}",
405 	"#endif",
406 	"	if (verbose && core_id == 0)",
407 	"	{	printf(\"qmax: \");",
408 	"		for (i = 0; i < NCORE; i++)",
409 	"		{	printf(\"%%d \", prmax[i]);",
410 	"		}",
411 	"#ifndef NGQ",
412 	"		printf(\"G: %%d\", *grmax);",
413 	"#endif",
414 	"		printf(\"\\n\");",
415 	"	}",
416 	"	leave_critical(GLOBAL_LOCK);",
417 	"",
418 	"	memcnt  += r->m_memcnt;",
419 	"	nstates += r->m_nstates;",
420 	"	nShadow += r->m_nShadow;",
421 	"	truncs  += r->m_truncs;",
422 	"	truncs2 += r->m_truncs2;",
423 	"	nlinks  += r->m_nlinks;",
424 	"	ngrabs  += r->m_ngrabs;",
425 	"	nlost   += r->m_nlost;",
426 	"	hcmp    += r->m_hcmp;",
427 	"	/* frame_wait += r->m_frame_wait; */",
428 	"	errors  += (unsigned long int) r->m_errors;",
429 	"",
430 	"	if (hmax  < r->m_hmax)  hmax  = r->m_hmax;",
431 	"	if (svmax < r->m_svmax) svmax = r->m_svmax;",
432 	"	if (smax  < r->m_smax)  smax  = r->m_smax;",
433 	"	if (mreached < r->m_mreached) mreached = r->m_mreached;",
434 	"",
435 	"	if (vmax_seen < r->m_VMAX) vmax_seen = r->m_VMAX;",
436 	"	if (pmax_seen < (int) r->m_PMAX) pmax_seen = (int) r->m_PMAX;",
437 	"	if (qmax_seen < (int) r->m_QMAX) qmax_seen = (int) r->m_QMAX;",
438 	"",
439 	"	ptr = &(r->m_R);",
440 	"	for (i = 0; i <= _NP_; i++)	/* all proctypes */",
441 	"	{	for (j = 0; j < NrStates[i]; j++)",
442 	"		{	if (*(ptr + j) != 0)",
443 	"			{	reached[i][j] = 1;",
444 	"		}	}",
445 	"		ptr += NrStates[i]*sizeof(uchar);",
446 	"	}",
447 	"	if (verbose>1)",
448 	"	{	cpu_printf(\"Got Results (%%d)\\n\", (int) (ptr - &(r->m_R)));",
449 	"		snapshot();",
450 	"	}",
451 	"}",
452 	"",
453 	"#if !defined(WIN32) && !defined(WIN64)",
454 	"static void",
455 	"rm_shared_segments(void)",
456 	"{	int m;",
457 	"	volatile sh_Allocater *nxt_pool;",
458 	"	/*",
459 	"	 * mark all shared memory segments for removal ",
460 	"	 * the actual removes won't happen intil last process dies or detaches",
461 	"	 * the shmctl calls can return -1 if not all procs have detached yet",
462 	"	 */",
463 	"	for (m = 0; m < NR_QS; m++)	/* +1 for global q */",
464 	"	{	if (shmid[m] != -1)",
465 	"		{	(void) shmctl(shmid[m], IPC_RMID, NULL);",
466 	"	}	}",
467 	"#ifdef SEP_STATE",
468 	"	if (shmid_M != -1)",
469 	"	{	(void) shmctl(shmid_M, IPC_RMID, NULL);",
470 	"	}",
471 	"#else",
472 	"	if (shmid_S != -1)",
473 	"	{	(void) shmctl(shmid_S, IPC_RMID, NULL);",
474 	"	}",
475 	"	for (last_pool = first_pool; last_pool != NULL; last_pool = nxt_pool)",
476 	"	{	shmid_M = (int) (last_pool->dc_id);",
477 	"		nxt_pool = last_pool->nxt;	/* as a pre-caution only */",
478 	"		if (shmid_M != -1)",
479 	"		{	(void) shmctl(shmid_M, IPC_RMID, NULL);",
480 	"	}	}",
481 	"#endif",
482 	"}",
483 	"#endif",
484 	"",
485 	"void",
486 	"sudden_stop(char *s)",
487 	"{	char b[64];",
488 	"	int i;",
489 	"",
490 	"	printf(\"cpu%%d: stop - %%s\\n\", core_id, s);",
491 	"#if !defined(WIN32) && !defined(WIN64)",
492 	"	if (proxy_pid != 0)",
493 	"	{	rm_shared_segments();",
494 	"	}",
495 	"#endif",
496 	"	if (search_terminated != NULL)",
497 	"	{	if (*search_terminated != 0)",
498 	"		{	if (verbose)",
499 	"			{	printf(\"cpu%%d: termination initiated (%%d)\\n\",",
500 	"					core_id, (int) *search_terminated);",
501 	"			}",
502 	"		} else",
503 	"		{	if (verbose)",
504 	"			{	printf(\"cpu%%d: initiated termination\\n\", core_id);",
505 	"			}",
506 	"			*search_terminated |= 8;	/* sudden_stop */",
507 	"		}",
508 	"		if (core_id == 0)",
509 	"		{	if (((*search_terminated) & 4)	/* uerror in one of the cpus */",
510 	"			&& !((*search_terminated) & (8|32|128|256))) /* abnormal stop */",
511 	"			{	if (errors == 0) errors++; /* we know there is at least 1 */",
512 	"			}",
513 	"			wrapup(); /* incomplete stats, but at least something */",
514 	"		}",
515 	"		return;",
516 	"	} /* else: should rarely happen, take more drastic measures */",
517 	"",
518 	"	if (core_id == 0)	/* local root process */",
519 	"	{	for (i = 1; i < NCORE; i++)	/* not for 0 of course */",
520 	"		{	int ignore;",
521 	"#if defined(WIN32) || defined(WIN64)",
522 	"				DWORD dwExitCode = 0;",
523 	"				GetExitCodeProcess(worker_handles[i], &dwExitCode);",
524 	"				if (dwExitCode == STILL_ACTIVE)",
525 	"				{	TerminateProcess(worker_handles[i], 0);",
526 	"				}",
527 	"				printf(\"cpu0: terminate %%d %%d\\n\",",
528 	"					(int) worker_pids[i], (dwExitCode == STILL_ACTIVE));",
529 	"#else",
530 	"				sprintf(b, \"kill -%%d %%d\", (int) SIGKILL, (int) worker_pids[i]);",
531 	"				ignore = system(b);	/* if this is a proxy: receive half */",
532 	"				printf(\"cpu0: %%s\\n\", b);",
533 	"#endif",
534 	"		}",
535 	"		issued_kill++;",
536 	"	} else",
537 	"	{	/* on WIN32/WIN64 -- these merely kills the root process... */",
538 	"		if (was_interrupted == 0)",	/* 2=SIGINT to root to trigger stop */
539 	"		{	int ignore;",
540 	"			sprintf(b, \"kill -%%d %%d\", (int) SIGINT, (int) worker_pids[0]);",
541 	"			ignore = system(b);	/* warn the root process */",
542 	"			printf(\"cpu%%d: %%s\\n\", core_id, b);",
543 	"			issued_kill++;",
544 	"	}	}",
545 	"}",
546 	"",
547 	"#define iam_alive()	is_alive[core_id]++",	/* for crash detection */
548 	"",
549 	"extern int crash_test(double);",
550 	"extern void crash_reset(void);",
551 	"",
552 	"int",
553 	"someone_crashed(int wait_type)",
554 	"{	static double last_value = 0.0;",
555 	"	static int count = 0;",
556 	"",
557 	"	if (search_terminated == NULL",
558 	"	|| *search_terminated != 0)",
559 	"	{",
560 	"		if (!(*search_terminated & (8|32|128|256)))",
561 	"		{	if (count++ < 100*NCORE)",
562 	"			{	return 0;",
563 	"		}	}",
564 	"		return 1;",
565 	"	}",
566 	"	/* check left neighbor only */",
567 	"	if (last_value == is_alive[(core_id + NCORE - 1) %% NCORE])",
568 	"	{	if (count++ >= 100)	/* to avoid unnecessary checks */",
569 	"		{	return 1;",
570 	"		}",
571 	"		return 0;",
572 	"	}",
573 	"	last_value = is_alive[(core_id + NCORE - 1) %% NCORE];",
574 	"	count = 0;",
575 	"	crash_reset();",
576 	"	return 0;",
577 	"}",
578 	"",
579 	"void",
580 	"sleep_report(void)",
581 	"{",
582 	"	enter_critical(GLOBAL_LOCK);",
583 	"	if (verbose)",
584 	"	{",
585 	"#ifdef NGQ",
586 	"		printf(\"cpu%%d: locks: global %%g\\tother %%g\\t\",",
587 	"			core_id, glock_wait[0], lock_wait - glock_wait[0]);",
588 	"#else",
589 	"		printf(\"cpu%%d: locks: GL %%g, RQ %%g, WQ %%g, HT %%g\\t\",",
590 	"			core_id, glock_wait[0], glock_wait[1], glock_wait[2],",
591 	"			lock_wait - glock_wait[0] - glock_wait[1] - glock_wait[2]);",
592 	"#endif",
593 	"		printf(\"waits: states %%g slots %%g\\n\", frame_wait, free_wait);",
594 	"#ifndef NGQ",
595 	"		printf(\"cpu%%d: gq [tries %%g, room %%g, noroom %%g]\\n\", core_id, gq_tries, gq_hasroom, gq_hasnoroom);",
596 	"		if (core_id == 0 && (*gr_readmiss >= 1.0 || *gr_readmiss >= 1.0 || *grcnt != 0))",
597 	"		printf(\"cpu0: gq [readmiss: %%g, writemiss: %%g cnt %%d]\\n\", *gr_readmiss, *gr_writemiss, *grcnt);",
598 	"#endif",
599 	"	}",
600 	"	if (free_wait > 1000000.)",
601 	"	#ifndef NGQ",
602 	"	if (!a_cycles)",
603 	"	{	printf(\"hint: this search may be faster with a larger work-queue\\n\");",
604 	"		printf(\"	(-DSET_WQ_SIZE=N with N>%%g), and/or with -DUSE_DISK\\n\",",
605 	"			GWQ_SIZE/sizeof(SM_frame));",
606 	"		printf(\"      or with a larger value for -zN (N>%%ld)\\n\", z_handoff);",
607 	"	#else",
608 	"	{	printf(\"hint: this search may be faster if compiled without -DNGQ, with -DUSE_DISK, \");",
609 	"		printf(\"or with a larger -zN (N>%%d)\\n\", z_handoff);",
610 	"	#endif",
611 	"	}",
612 	"	leave_critical(GLOBAL_LOCK);",
613 	"}",
614 	"",
615 	"#ifndef MAX_DSK_FILE",
616 	"	#define MAX_DSK_FILE	1000000	/* default is max 1M states per file */",
617 	"#endif",
618 	"",
619 	"void",
620 	"multi_usage(FILE *fd)",
621 	"{	static int warned = 0;",
622 	"	if (warned > 0) { return; } else { warned++; }",
623 	"	fprintf(fd, \"\\n\");",
624 	"	fprintf(fd, \"Defining multi-core mode:\\n\\n\");",
625 	"	fprintf(fd, \"        -DDUAL_CORE --> same as -DNCORE=2\\n\");",
626 	"	fprintf(fd, \"        -DQUAD_CORE --> same as -DNCORE=4\\n\");",
627 	"	fprintf(fd, \"        -DNCORE=N   --> enables multi_core verification if N>1\\n\");",
628 	"	fprintf(fd, \"\\n\");",
629 	"	fprintf(fd, \"Additional directives supported in multi-core mode:\\n\\n\");",
630 	"	fprintf(fd, \"        -DSEP_STATE --> forces separate statespaces instead of a single shared state space\\n\");",
631 	"	fprintf(fd, \"        -DNUSE_DISK --> use disk for storing states when a work queue overflows\\n\");",
632 	"	fprintf(fd, \"        -DMAX_DSK_FILE --> max nr of states per diskfile (%%d)\\n\", MAX_DSK_FILE);",
633 	"	fprintf(fd, \"        -DFULL_TRAIL --> support full error trails (increases memory use)\\n\");",
634 	"	fprintf(fd, \"\\n\");",
635 	"	fprintf(fd, \"More advanced use (should rarely need changing):\\n\\n\");",
636 	"	fprintf(fd, \"     To change the nr of states that can be stored in the global queue\\n\");",
637 	"	fprintf(fd, \"     (lower numbers allow for more states to be stored, prefer multiples of 8):\\n\");",
638 	"	fprintf(fd, \"        -DVMAX=N    --> upperbound on statevector for handoffs (N=%%d)\\n\", VMAX);",
639 	"	fprintf(fd, \"        -DPMAX=N    --> upperbound on nr of procs (default: N=%%d)\\n\", PMAX);",
640 	"	fprintf(fd, \"        -DQMAX=N    --> upperbound on nr of channels (default: N=%%d)\\n\", QMAX);",
641 	"	fprintf(fd, \"\\n\");",
642 #if 0
643 	"#if !defined(WIN32) && !defined(WIN64)",
644 	"	fprintf(fd, \"     To change the size of spin's individual shared memory segments for cygwin/linux:\\n\");",
645 	"	fprintf(fd, \"        -DSET_SEG_SIZE=N --> default %%g (Mbytes)\\n\", SEG_SIZE/(1048576.));",
646 	"	fprintf(fd, \"\\n\");",
647 	"#endif",
648 #endif
649 	"	fprintf(fd, \"     To set the total amount of memory reserved for the global workqueue:\\n\");",
650 	"	fprintf(fd, \"        -DSET_WQ_SIZE=N --> default: N=128 (defined in MBytes)\\n\\n\");",
651 #if 0
652 	"	fprintf(fd, \"     To omit the global workqueue completely (bad idea):\\n\");",
653 	"	fprintf(fd, \"        -DNGQ\\n\\n\");",
654 #endif
655 	"	fprintf(fd, \"     To force the use of a single global heap, instead of separate heaps:\\n\");",
656 	"	fprintf(fd, \"        -DGLOB_HEAP\\n\");",
657 	"	fprintf(fd, \"\\n\");",
658 	"	fprintf(fd, \"     To define a fct to initialize data before spawning processes (use quotes):\\n\");",
659 	"	fprintf(fd, \"        \\\"-DC_INIT=fct()\\\"\\n\");",
660 	"	fprintf(fd, \"\\n\");",
661 	"	fprintf(fd, \"     Timer settings for termination and crash detection:\\n\");",
662 	"	fprintf(fd, \"        -DSHORT_T=N --> timeout for termination detection trigger (N=%%g)\\n\", (double) SHORT_T);",
663 	"	fprintf(fd, \"        -DLONG_T=N  --> timeout for giving up on termination detection (N=%%g)\\n\", (double) LONG_T);",
664 	"	fprintf(fd, \"        -DONESECOND --> (1<<29) --> timeout waiting for a free slot -- to check for crash\\n\");",
665 	"	fprintf(fd, \"        -DT_ALERT   --> collect stats on crash alert timeouts\\n\\n\");",
666 	"	fprintf(fd, \"Help with Linux/Windows/Cygwin configuration for multi-core:\\n\");",
667 	"	fprintf(fd, \"	http://spinroot.com/spin/multicore/V5_Readme.html\\n\");",
668 	"	fprintf(fd, \"\\n\");",
669 	"}",
670 	"#if NCORE>1 && defined(FULL_TRAIL)",
671 	"typedef struct Stack_Tree {",
672 	"	uchar	      pr;	/* process that made transition */",
673 	"	T_ID	    t_id;	/* id of transition */",
674 	"	volatile struct Stack_Tree *prv; /* backward link towards root */",
675 	"} Stack_Tree;",
676 	"",
677 	"H_el *grab_shared(int);",
678 	"volatile Stack_Tree **stack_last; /* in shared memory */",
679 	"char *stack_cache = NULL;	/* local */",
680 	"int  nr_cached = 0;		/* local */",
681 	"",
682 	"#ifndef CACHE_NR",
683 	"	#define CACHE_NR	1024",
684 	"#endif",
685 	"",
686 	"volatile Stack_Tree *",
687 	"stack_prefetch(void)",
688 	"{	volatile Stack_Tree *st;",
689 	"",
690 	"	if (nr_cached == 0)",
691 	"	{	stack_cache = (char *) grab_shared(CACHE_NR * sizeof(Stack_Tree));",
692 	"		nr_cached = CACHE_NR;",
693 	"	}",
694 	"	st = (volatile Stack_Tree *) stack_cache;",
695 	"	stack_cache += sizeof(Stack_Tree);",
696 	"	nr_cached--;",
697 	"	return st;",
698 	"}",
699 	"",
700 	"void",
701 	"Push_Stack_Tree(short II, T_ID t_id)",
702 	"{	volatile Stack_Tree *st;",
703 	"",
704 	"	st = (volatile Stack_Tree *) stack_prefetch();",
705 	"	st->pr = II;",
706 	"	st->t_id = t_id;",
707 	"	st->prv = (Stack_Tree *) stack_last[core_id];",
708 	"	stack_last[core_id] = st;",
709 	"}",
710 	"",
711 	"void",
712 	"Pop_Stack_Tree(void)",
713 	"{	volatile Stack_Tree *cf = stack_last[core_id];",
714 	"",
715 	"	if (cf)",
716 	"	{	stack_last[core_id] = cf->prv;",
717 	"	} else if (nr_handoffs * z_handoff + depth > 0)",
718 	"	{	printf(\"cpu%%d: error pop_stack_tree (depth %%ld)\\n\",",
719 	"			core_id, depth);",
720 	"	}",
721 	"}",
722 	"#endif", /* NCORE>1 && FULL_TRAIL */
723 	"",
724 	"void",
725 	"e_critical(int which)",
726 	"{	double cnt_start;",
727 	"",
728 	"	if (readtrail || iamin[which] > 0)",
729 	"	{	if (!readtrail && verbose)",
730 	"		{	printf(\"cpu%%d: Double Lock on %%d (now %%d)\\n\",",
731 	"				core_id, which, iamin[which]+1);",
732 	"			fflush(stdout);",
733 	"		}",
734 	"		iamin[which]++;	/* local variable */",
735 	"		return;",
736 	"	}",
737 	"",
738 	"	cnt_start = lock_wait;",
739 	"",
740 	"	while (sh_lock != NULL)	/* as long as we have shared memory */",
741 	"	{	int r = tas(&sh_lock[which]);",
742 	"		if (r == 0)",
743 	"		{	iamin[which] = 1;",
744 	"			return;		/* locked */",
745 	"		}",
746 	"",
747 	"		lock_wait++;",
748 	"#ifndef NGQ",
749 	"		if (which < 3) { glock_wait[which]++; }",
750 	"#else",
751 	"		if (which == 0) { glock_wait[which]++; }",
752 	"#endif",
753 	"		iam_alive();",
754 	"",
755 	"		if (lock_wait - cnt_start > TenSeconds)",
756 	"		{	printf(\"cpu%%d: lock timeout on %%d\\n\", core_id, which);",
757 	"			cnt_start = lock_wait;",
758 	"			if (someone_crashed(1))",
759 	"			{	sudden_stop(\"lock timeout\");",
760 	"				pan_exit(1);",
761 	"	}	}	}",
762 	"}",
763 	"",
764 	"void",
765 	"x_critical(int which)",
766 	"{",
767 	"	if (iamin[which] != 1)",
768 	"	{	if (iamin[which] > 1)",
769 	"		{	iamin[which]--;	/* this is thread-local - no races on this one */",
770 	"			if (!readtrail && verbose)",
771 	"			{	printf(\"cpu%%d: Partial Unlock on %%d (%%d more needed)\\n\",",
772 	"					core_id, which, iamin[which]);",
773 	"				fflush(stdout);",
774 	"			}",
775 	"			return;",
776 	"		} else /* iamin[which] <= 0 */",
777 	"		{	if (!readtrail)",
778 	"			{	printf(\"cpu%%d: Invalid Unlock iamin[%%d] = %%d\\n\",",
779 	"					core_id, which, iamin[which]);",
780 	"				fflush(stdout);",
781 	"			}",
782 	"			return;",
783 	"	}	}",
784 	"",
785 	"	if (sh_lock != NULL)",
786 	"	{	iamin[which]   = 0;",
787 	"#if defined(__powerpc64__)",
788 	"	#if 1",
789 	"		__sync_synchronize();	/* srirajpaul */",
790 	"	#else",
791 	"		__lwsync();		/* xlc compiler only */",
792 	"	#endif",
793 	"#endif",
794 	"		sh_lock[which] = 0;	/* unlock */",
795 	"	}",
796 	"}",
797 	"",
798 	"void",
799 	"#if defined(WIN32) || defined(WIN64)",
800 	"start_proxy(char *s, DWORD r_pid)",
801 	"#else",
802 	"start_proxy(char *s, int r_pid)",
803 	"#endif",
804 	"{	char  Q_arg[16], Z_arg[16], Y_arg[16];",
805 	"	char *args[32], *ptr;",
806 	"	int   argcnt = 0;",
807 	"",
808 	"	sprintf(Q_arg, \"-Q%%d\", getpid());",
809 	"	sprintf(Y_arg, \"-Y%%d\", r_pid);",
810 	"	sprintf(Z_arg, \"-Z%%d\", proxy_pid /* core_id */);",
811 	"",
812 	"	args[argcnt++] = \"proxy\";",
813 	"	args[argcnt++] = s; /* -r or -s */",
814 	"	args[argcnt++] = Q_arg;",
815 	"	args[argcnt++] = Z_arg;",
816 	"	args[argcnt++] = Y_arg;",
817 	"",
818 	"	if (strlen(o_cmdline) > 0)",
819 	"	{	ptr = o_cmdline; /* assume args separated by spaces */",
820 	"		do {	args[argcnt++] = ptr++;",
821 	"			if ((ptr = strchr(ptr, ' ')) != NULL)",
822 	"			{	while (*ptr == ' ')",
823 	"				{	*ptr++ = '\\0';",
824 	"				}",
825 	"			} else",
826 	"			{	break;",
827 	"			}",
828 	"		} while (argcnt < 31);",
829 	"	}",
830 	"	args[argcnt] = NULL;",
831 	"#if defined(WIN32) || defined(WIN64)",
832 	"	execvp(\"pan_proxy\", args); /* no return */",
833 	"#else",
834 	"	execvp(\"./pan_proxy\", args); /* no return */",
835 	"#endif",
836 	"	Uerror(\"pan_proxy exec failed\");",
837 	"}",
838 	"/*** end of common code fragment ***/",
839 	"",
840 	"#if !defined(WIN32) && !defined(WIN64)",
841 	"void",
842 	"init_shm(void)		/* initialize shared work-queues - linux/cygwin */",
843 	"{	key_t	key[NR_QS];",
844 	"	int	n, m;",
845 	"	int	must_exit = 0;",
846 	"",
847 	"	if (core_id == 0 && verbose)",
848 	"	{	printf(\"cpu0: step 3: allocate shared workqueues %%g MB\\n\",",
849 	"			((double) NCORE * LWQ_SIZE + GWQ_SIZE) / (1048576.) );",
850 	"	}",
851 	"	for (m = 0; m < NR_QS; m++)		/* last q is the global q */",
852 	"	{	double qsize = (m == NCORE) ? GWQ_SIZE : LWQ_SIZE;",
853 	"		key[m] = ftok(PanSource, m+1);", /* m must be nonzero, 1..NCORE */
854 	"		if (key[m] == -1)",
855 	"		{	perror(\"ftok shared queues\"); must_exit = 1; break;",
856 	"		}",
857 	"",
858 	"		if (core_id == 0)	/* root creates */",
859 	"		{	/* check for stale copy */",
860 	"			shmid[m] = shmget(key[m], (size_t) qsize, 0600);",
861 	"			if (shmid[m] != -1)	/* yes there is one; remove it */",
862 	"			{	printf(\"cpu0: removing stale q%%d, status: %%d\\n\",",
863 	"					m, shmctl(shmid[m], IPC_RMID, NULL));",
864 	"			}",
865 	"			shmid[m] = shmget(key[m], (size_t) qsize, 0600|IPC_CREAT|IPC_EXCL);",
866 	"			memcnt += qsize;",
867 	"		} else			/* workers attach */",
868 	"		{	shmid[m] = shmget(key[m], (size_t) qsize, 0600);",
869 	"			/* never called, since we create shm *before* we fork */",
870 	"		}",
871 	"		if (shmid[m] == -1)",
872 	"		{	perror(\"shmget shared queues\"); must_exit = 1; break;",
873 	"		}",
874 	"",
875 	"		shared_mem[m] = (char *) shmat(shmid[m], (void *) 0, 0);	/* attach */",
876 	"		if (shared_mem[m] == (char *) -1)",
877 	"		{ fprintf(stderr, \"error: cannot attach shared wq %%d (%%d Mb)\\n\",",
878 	"				m+1, (int) (qsize/(1048576.)));",
879 	"		  perror(\"shmat shared queues\"); must_exit = 1; break;",
880 	"		}",
881 	"",
882 	"		m_workq[m] = (SM_frame *) shared_mem[m];",
883 	"		if (core_id == 0)",
884 	"		{	int nframes = (m == NCORE) ? GN_FRAMES : LN_FRAMES;",
885 	"			for (n = 0; n < nframes; n++)",
886 	"			{	m_workq[m][n].m_vsize = 0;",
887 	"				m_workq[m][n].m_boq = 0;",
888 	"	}	}	}",
889 	"",
890 	"	if (must_exit)",
891 	"	{	rm_shared_segments();",
892 	"		fprintf(stderr, \"pan: check './pan --' for usage details\\n\");",
893 	"		pan_exit(1);	/* calls cleanup_shm */",
894 	"	}",
895 	"}",
896 	"",
897 	"static uchar *",
898 	"prep_shmid_S(size_t n)		/* either sets SS or H_tab, linux/cygwin */",
899 	"{	char	*rval;",
900 	"#ifndef SEP_STATE",
901 	"	key_t	key;",
902 	"",
903 	"	if (verbose && core_id == 0)",
904 	"	{",
905 	"	#ifdef BITSTATE",
906 	"		printf(\"cpu0: step 1: allocate shared bitstate %%g Mb\\n\",",
907 	"			(double) n / (1048576.));",
908 	"	#else",
909 	"		printf(\"cpu0: step 1: allocate shared hastable %%g Mb\\n\",",
910 	"			(double) n / (1048576.));",
911 	"	#endif",
912 	"	}",
913 	"	#ifdef MEMLIM", /* memlim has a value */
914 	"	if (memcnt + (double) n > memlim)",
915 	"	{	printf(\"cpu0: S %%8g + %%d Kb exceeds memory limit of %%8g Mb\\n\",",
916 	"			memcnt/1024., (int) (n/1024), memlim/(1048576.));",
917 	"		printf(\"cpu0: insufficient memory -- aborting\\n\");",
918 	"		exit(1);",
919 	"	}",
920 	"	#endif",
921 	"",
922 	"	key = ftok(PanSource, NCORE+2);	/* different from queues */",
923 	"	if (key == -1)",
924 	"	{	perror(\"ftok shared bitstate or hashtable\");",
925 	"		fprintf(stderr, \"pan: check './pan --' for usage details\\n\");",
926 	"		pan_exit(1);",
927 	"	}",
928 	"",
929 	"	if (core_id == 0)	/* root */",
930 	"	{	shmid_S = shmget(key, n, 0600);",
931 	"		if (shmid_S != -1)",
932 	"		{	printf(\"cpu0: removing stale segment, status: %%d\\n\",",
933 	"				(int) shmctl(shmid_S, IPC_RMID, NULL));",
934 	"		}",
935 	"		shmid_S = shmget(key, n, 0600 | IPC_CREAT | IPC_EXCL);",
936 	"		memcnt += (double) n;",
937 	"	} else			/* worker */",
938 	"	{	shmid_S = shmget(key, n, 0600);",
939 	"	}",
940 	"	if (shmid_S == -1)",
941 	"	{	perror(\"shmget shared bitstate or hashtable too large?\");",
942 	"		fprintf(stderr, \"pan: check './pan --' for usage details\\n\");",
943 	"		pan_exit(1);",
944 	"	}",
945 	"",
946 	"	rval = (char *) shmat(shmid_S, (void *) 0, 0);	/* attach */",
947 	"	if ((char *) rval == (char *) -1)",
948 	"	{	perror(\"shmat shared bitstate or hashtable\");",
949 	"		fprintf(stderr, \"pan: check './pan --' for usage details\\n\");",
950 	"		pan_exit(1);",
951 	"	}",
952 	"#else",
953 	"	rval = (char *) emalloc(n);",
954 	"#endif",
955 	"	return (uchar *) rval;",
956 	"}",
957 	"",
958 	"#define TRY_AGAIN	1",
959 	"#define NOT_AGAIN	0",
960 	"",
961 	"static char shm_prep_result;",
962 	"",
963 	"static uchar *",
964 	"prep_state_mem(size_t n)		/* sets memory arena for states linux/cygwin */",
965 	"{	char	*rval;",
966 	"	key_t	key;",
967 	"	static int cnt = 3;		/* start larger than earlier ftok calls */",
968 	"",
969 	"	shm_prep_result = NOT_AGAIN;	/* default */",
970 	"	if (verbose && core_id == 0)",
971 	"	{	printf(\"cpu0: step 2+: pre-allocate memory arena %%d of %%6.2g Mb\\n\",",
972 	"			cnt-3, (double) n / (1048576.));",
973 	"	}",
974 	"	#ifdef MEMLIM",
975 	"	if (memcnt + (double) n > memlim)",
976 	"	{	printf(\"cpu0: error: M %%.0f + %%.0f Kb exceeds memory limit of %%.0f Mb\\n\",",
977 	"			memcnt/1024.0, (double) n/1024.0, memlim/(1048576.));",
978 	"		return NULL;",
979 	"	}",
980 	"	#endif",
981 	"",
982 	"	key = ftok(PanSource, NCORE+cnt); cnt++;", /* starts at NCORE+3 */
983 	"	if (key == -1)",
984 	"	{	perror(\"ftok T\");",
985 	"		printf(\"pan: check './pan --' for usage details\\n\");",
986 	"		pan_exit(1);",
987 	"	}",
988 	"",
989 	"	if (core_id == 0)",
990 	"	{	shmid_M = shmget(key, n, 0600);",
991 	"		if (shmid_M != -1)",
992 	"		{	printf(\"cpu0: removing stale memory segment %%d, status: %%d\\n\",",
993 	"				cnt-3, shmctl(shmid_M, IPC_RMID, NULL));",
994 	"		}",
995 	"		shmid_M = shmget(key, n, 0600 | IPC_CREAT | IPC_EXCL);",
996 	"		/* memcnt += (double) n; -- only amount actually used is counted */",
997 	"	} else",
998 	"	{	shmid_M = shmget(key, n, 0600);",
999 	"	",
1000 	"	}",
1001 	"	if (shmid_M == -1)",
1002 	"	{	if (verbose)",
1003 	"		{	printf(\"error: failed to get pool of shared memory %%d of %%.0f Mb\\n\",",
1004 	"				cnt-3, ((double)n)/(1048576.));",
1005 	"			perror(\"state mem\");",
1006 	"			printf(\"pan: check './pan --' for usage details\\n\");",
1007 	"		}",
1008 	"		shm_prep_result = TRY_AGAIN;",
1009 	"		return NULL;",
1010 	"	}",
1011 	"	rval = (char *) shmat(shmid_M, (void *) 0, 0);	/* attach */",
1012 	"",
1013 	"	if ((char *) rval == (char *) -1)",
1014 	"	{	printf(\"cpu%%d error: failed to attach pool of shared memory %%d of %%.0f Mb\\n\",",
1015 	"			 core_id, cnt-3, ((double)n)/(1048576.));",
1016 	"		perror(\"state mem\");",
1017 	"		return NULL;",
1018 	"	}",
1019 	"	return (uchar *) rval;",
1020 	"}",
1021 	"",
1022 	"void",
1023 	"init_HT(unsigned long n)	/* cygwin/linux version */",
1024 	"{	volatile char	*x;",
1025 	"	double  get_mem;",
1026 	"#ifndef SEP_STATE",
1027 	"	volatile char	*dc_mem_start;",
1028 	"	double  need_mem, got_mem = 0.;",
1029 	"#endif",
1030 	"",
1031 "#ifdef SEP_STATE",
1032 	" #ifndef MEMLIM",
1033 	"	if (verbose)",
1034 	"	{	printf(\"cpu0: steps 0,1: no -DMEMLIM set\\n\");", /* cannot happen */
1035 	"	}",
1036 	" #else",
1037 	"	if (verbose)",
1038 	"	{	printf(\"cpu0: steps 0,1: -DMEMLIM=%%d Mb - (hashtable %%g Mb + workqueues %%g Mb)\\n\",",
1039 	"		MEMLIM, ((double)n/(1048576.)), (((double) NCORE * LWQ_SIZE) + GWQ_SIZE) /(1048576.) );",
1040 	"	}",
1041 	" #endif",
1042 	"	get_mem = NCORE * sizeof(double) + (1 + CS_NR) * sizeof(void *) + 4*sizeof(void *) + 2*sizeof(double);",
1043 	"	/* NCORE * is_alive + search_terminated + CS_NR * sh_lock + 6 gr vars */",
1044 	"	get_mem += 4 * NCORE * sizeof(void *); /* prfree, prfull, prcnt, prmax */",
1045 	" #ifdef FULL_TRAIL",
1046 	"	get_mem += (NCORE) * sizeof(Stack_Tree *); /* NCORE * stack_last */",
1047 	" #endif",
1048 	"	x = (volatile char *) prep_state_mem((size_t) get_mem); /* work queues and basic structs */",
1049 	"	shmid_X = (long) x;",
1050 	"	if (x == NULL)", /* do not repeat for smaller sizes */
1051 	"	{	printf(\"cpu0: could not allocate shared memory, see ./pan --\\n\");",
1052 	"		exit(1);",
1053 	"	}",
1054 	"	search_terminated = (volatile unsigned int *) x; /* comes first */",
1055 	"	x += sizeof(void *); /* maintain alignment */",
1056 	"",
1057 	"	is_alive   = (volatile double *) x;",
1058 	"	x += NCORE * sizeof(double);",
1059 	"",
1060 	"	sh_lock   = (volatile int *) x;",
1061 	"	x += CS_NR * sizeof(void *);", /* allow 1 word per entry */
1062 	"",
1063 	"	grfree    = (volatile int *) x;",
1064 	"	x += sizeof(void *);",
1065 	"	grfull    = (volatile int *) x;",
1066 	"	x += sizeof(void *);",
1067 	"	grcnt    = (volatile int *) x;",
1068 	"	x += sizeof(void *);",
1069 	"	grmax    = (volatile int *) x;",
1070 	"	x += sizeof(void *);",
1071 	"	prfree = (volatile int *) x;",
1072 	"	x += NCORE * sizeof(void *);",
1073 	"	prfull = (volatile int *) x;",
1074 	"	x += NCORE * sizeof(void *);",
1075 	"	prcnt = (volatile int *) x;",
1076 	"	x += NCORE * sizeof(void *);",
1077 	"	prmax = (volatile int *) x;",
1078 	"	x += NCORE * sizeof(void *);",
1079 	"	gr_readmiss    = (volatile double *) x;",
1080 	"	x += sizeof(double);",
1081 	"	gr_writemiss    = (volatile double *) x;",
1082 	"	x += sizeof(double);",
1083 	"",
1084 	"	#ifdef FULL_TRAIL",
1085 	"		stack_last = (volatile Stack_Tree **) x;",
1086 	"		x += NCORE * sizeof(Stack_Tree *);",
1087 	"	#endif",
1088 	"",
1089 	"	#ifndef BITSTATE",
1090 	"		H_tab = (H_el **) emalloc(n);",
1091 	"	#endif",
1092 "#else",
1093 	"	#ifndef MEMLIM",
1094 	"		#warning MEMLIM not set", /* cannot happen */
1095 	"		#define MEMLIM	(2048)",
1096 	"	#endif",
1097 	"",
1098 	"	if (core_id == 0 && verbose)",
1099 	"	{	printf(\"cpu0: step 0: -DMEMLIM=%%d Mb minus hashtable+workqs (%%g + %%g Mb) leaves %%g Mb\\n\",",
1100 	"			MEMLIM, ((double)n/(1048576.)), (NCORE * LWQ_SIZE + GWQ_SIZE)/(1048576.),",
1101 	"			(memlim - memcnt - (double) n - (NCORE * LWQ_SIZE + GWQ_SIZE))/(1048576.));",
1102 	"	}",
1103 	"	#ifndef BITSTATE",
1104 	"		H_tab = (H_el **) prep_shmid_S((size_t) n);	/* hash_table */",
1105 	"	#endif",
1106 	"	need_mem = memlim - memcnt - ((double) NCORE * LWQ_SIZE) - GWQ_SIZE;",
1107 	"	if (need_mem <= 0.)",
1108 	"	{	Uerror(\"internal error -- shared state memory\");",
1109 	"	}",
1110 	"",
1111 	"	if (core_id == 0 && verbose)",
1112 	"	{	printf(\"cpu0: step 2: pre-allocate shared state memory %%g Mb\\n\",",
1113 	"			need_mem/(1048576.));",
1114 	"	}",
1115 	"#ifdef SEP_HEAP",
1116 	"	SEG_SIZE = need_mem / NCORE;",
1117 	"	if (verbose && core_id == 0)",
1118 	"	{	printf(\"cpu0: setting segsize to %%6g MB\\n\",",
1119 	"			SEG_SIZE/(1048576.));",
1120 	"	}",
1121 	"	#if defined(CYGWIN) || defined(__CYGWIN__)",
1122 	"	if (SEG_SIZE > 512.*1024.*1024.)",
1123 	"	{	printf(\"warning: reducing SEG_SIZE of %%g MB to 512MB (exceeds max for Cygwin)\\n\",",
1124 	"			SEG_SIZE/(1024.*1024.));",
1125 	"		SEG_SIZE = 512.*1024.*1024.;",
1126 	"	}",
1127 	"	#endif",
1128 	"#endif",
1129 	"	mem_reserved = need_mem;",
1130 	"	while (need_mem > 1024.)",
1131 	"	{	get_mem = need_mem;",
1132 	"shm_more:",
1133 	"		if (get_mem > (double) SEG_SIZE)",
1134 	"		{	get_mem = (double) SEG_SIZE;",
1135 	"		}",
1136 	"		if (get_mem <= 0.0) break;",
1137 	"",
1138 	"		/* for allocating states: */",
1139 	"		x = dc_mem_start = (volatile char *) prep_state_mem((size_t) get_mem);",
1140 	"		if (x == NULL)",
1141 	"		{	if (shm_prep_result == NOT_AGAIN",
1142 	"			||  first_pool != NULL",
1143 	"			||  SEG_SIZE < (16. * 1048576.))",
1144 	"			{	break;",
1145 	"			}",
1146 	"			SEG_SIZE /= 2.;",
1147 	"			if (verbose)",
1148 	"			{	printf(\"pan: lowered segsize to %%f\\n\", SEG_SIZE);",
1149 	"			}",
1150 	"			if (SEG_SIZE >= 1024.)",
1151 	"			{	goto shm_more;", /* always terminates */
1152 	"			}",
1153 	"			break;",
1154 	"		}",
1155 	"",
1156 	"		need_mem -= get_mem;",
1157 	"		got_mem  += get_mem;",
1158 	"		if (first_pool == NULL)",
1159 	"		{	search_terminated = (volatile unsigned int *) x; /* comes first */",
1160 	"			x += sizeof(void *); /* maintain alignment */",
1161 	"",
1162 	"			is_alive   = (volatile double *) x;",
1163 	"			x += NCORE * sizeof(double);",
1164 	"",
1165 	"			sh_lock   = (volatile int *) x;",
1166 	"			x += CS_NR * sizeof(void *);", /* allow 1 word per entry */
1167 	"",
1168 	"			grfree    = (volatile int *) x;",
1169 	"			x += sizeof(void *);",
1170 	"			grfull    = (volatile int *) x;",
1171 	"			x += sizeof(void *);",
1172 	"			grcnt    = (volatile int *) x;",
1173 	"			x += sizeof(void *);",
1174 	"			grmax    = (volatile int *) x;",
1175 	"			x += sizeof(void *);",
1176 	"			prfree = (volatile int *) x;",
1177 	"			x += NCORE * sizeof(void *);",
1178 	"			prfull = (volatile int *) x;",
1179 	"			x += NCORE * sizeof(void *);",
1180 	"			prcnt = (volatile int *) x;",
1181 	"			x += NCORE * sizeof(void *);",
1182 	"			prmax = (volatile int *) x;",
1183 	"			x += NCORE * sizeof(void *);",
1184 	"			gr_readmiss  = (volatile double *) x;",
1185 	"			x += sizeof(double);",
1186 	"			gr_writemiss = (volatile double *) x;",
1187 	"			x += sizeof(double);",
1188 	" #ifdef FULL_TRAIL",
1189 	"			stack_last = (volatile Stack_Tree **) x;",
1190 	"			x += NCORE * sizeof(Stack_Tree *);",
1191 	" #endif",
1192 	"			if (((long)x)&(sizeof(void *)-1)) /* 64-bit word alignment */",
1193 	"			{	x += sizeof(void *)-(((long)x)&(sizeof(void *)-1));",
1194 	"			}",
1195 	"",
1196 	"			#ifdef COLLAPSE",
1197 	"			ncomps = (unsigned long *) x;",
1198 	"			x += (256+2) * sizeof(unsigned long);",
1199 	"			#endif",
1200 	"		}",
1201 	"",
1202 	"		dc_shared = (sh_Allocater *) x; /* must be in shared memory */",
1203 	"		x += sizeof(sh_Allocater);",
1204 	"",
1205 	"		if (core_id == 0)	/* root only */",
1206 	"		{	dc_shared->dc_id     = shmid_M;",
1207 	"			dc_shared->dc_start  = dc_mem_start;",
1208 	"			dc_shared->dc_arena  = x;",
1209 	"			dc_shared->pattern   = 1234567; /* protection */",
1210 	"			dc_shared->dc_size   = (long) get_mem - (long) (x - dc_mem_start);",
1211 	"			dc_shared->nxt       = (long) 0;",
1212 	"",
1213 	"			if (last_pool == NULL)",
1214 	"			{	first_pool = last_pool = dc_shared;",
1215 	"			} else",
1216 	"			{	last_pool->nxt = dc_shared;",
1217 	"				last_pool = dc_shared;",
1218 	"			}",
1219 	"		} else if (first_pool == NULL)",
1220 	"		{	first_pool = dc_shared;",
1221 	"	}	}",
1222 	"",
1223 	"	if (need_mem > 1024.)",
1224 	"	{	printf(\"cpu0: could allocate only %%g Mb of shared memory (wanted %%g more)\\n\",",
1225 	"			got_mem/(1048576.), need_mem/(1048576.));",
1226 	"	}",
1227 	"",
1228 	"	if (!first_pool)",
1229 	"	{	printf(\"cpu0: insufficient memory -- aborting.\\n\");",
1230 	"		exit(1);",
1231 	"	}",
1232 	"	/* we are still single-threaded at this point, with core_id 0 */",
1233 	"	dc_shared = first_pool;",
1234 	"",
1235 "#endif", /* !SEP_STATE */
1236 	"}",
1237 	"",
1238 	"void",
1239 	"cleanup_shm(int val)",
1240 	"{	volatile sh_Allocater *nxt_pool;",
1241 	"	unsigned long cnt = 0;",
1242 	"	int m;",
1243 	"",
1244 	"	if (nibis != 0)",
1245 	"	{	printf(\"cpu%%d: Redundant call to cleanup_shm(%%d)\\n\", core_id, val);",
1246 	"		return;",
1247 	"	} else",
1248 	"	{	nibis = 1;",
1249 	"	}",
1250 	"	if (search_terminated != NULL)",
1251 	"	{	*search_terminated |= 16; /* cleanup_shm */",
1252 	"	}",
1253 	"",
1254 	"	for (m = 0; m < NR_QS; m++)",
1255 	"	{	if (shmdt((void *) shared_mem[m]) > 0)",
1256 	"		{	perror(\"shmdt detaching from shared queues\");",
1257 	"	}	}",
1258 	"",
1259 	"#ifdef SEP_STATE",
1260 	"	if (shmdt((void *) shmid_X) != 0)",
1261 	"	{	perror(\"shmdt detaching from shared state memory\");",
1262 	"	}",
1263 	"#else",
1264 	"	#ifdef BITSTATE",
1265 	"		if (SS > 0 && shmdt((void *) SS) != 0)",
1266 	"		{	if (verbose)",
1267 	"			{	perror(\"shmdt detaching from shared bitstate arena\");",
1268 	"		}	}",
1269 	"	#else",
1270 	"		if (core_id == 0)",
1271 	"		{	/* before detaching: */",
1272 	"			for (nxt_pool = dc_shared; nxt_pool != NULL; nxt_pool = nxt_pool->nxt)",
1273 	"			{	cnt += nxt_pool->dc_size;",
1274 	"			}",
1275 	"			if (verbose)",
1276 	"			{	printf(\"cpu0: done, %%ld Mb of shared state memory left\\n\",",
1277 	"					cnt / (long)(1048576));",
1278 	"		}	}",
1279 	"",
1280 	"		if (shmdt((void *) H_tab) != 0)",
1281 	"		{	perror(\"shmdt detaching from shared hashtable\");",
1282 	"		}",
1283 	"",
1284 	"		for (last_pool = first_pool; last_pool != NULL; last_pool = nxt_pool)",
1285 	"		{	nxt_pool = last_pool->nxt;",
1286 	"			if (shmdt((void *) last_pool->dc_start) != 0)",
1287 	"			{	perror(\"shmdt detaching from shared state memory\");",
1288 	"		}	}",
1289 	"		first_pool = last_pool = NULL;	/* precaution */",
1290 	"	#endif",
1291 	"#endif",
1292 	"	/* detached from shared memory - so cannot use cpu_printf */",
1293 	"	if (verbose)",
1294 	"	{	printf(\"cpu%%d: done -- got %%ld states from queue\\n\",",
1295 	"			core_id, nstates_get);",
1296 	"	}",
1297 	"}",
1298 	"",
1299 	"extern void give_up(int);",
1300 	"extern void Read_Queue(int);",
1301 	"",
1302 	"void",
1303 	"mem_get(void)",
1304 	"{	SM_frame   *f;",
1305 	"	int is_parent;",
1306 	"",
1307 	"#if defined(MA) && !defined(SEP_STATE)",
1308 	"	#error MA without SEP_STATE is not supported with multi-core",
1309 	"#endif",
1310 	"#ifdef BFS",
1311 	"	#error instead of -DNCORE -DBFS use -DBFS_PAR",
1312 	"#endif",
1313 	"#ifdef SC",
1314 	"	#error SC is not supported with multi-core",
1315 	"#endif",
1316 	"	init_shm();	/* we are single threaded when this starts */",
1317 	"",
1318 	"	if (core_id == 0 && verbose)",
1319 	"	{	printf(\"cpu0: step 4: calling fork()\\n\");",
1320 	"	}",
1321 	"	fflush(stdout);",
1322 	"",
1323 	"/*	if NCORE > 1 the child or the parent should fork N-1 more times",
1324 	" *	the parent is the only process with core_id == 0 and is_parent > 0",
1325 	" *	the workers have is_parent = 0 and core_id = 1..NCORE-1",
1326 	" */",
1327 	"	if (core_id == 0)",
1328 	"	{	worker_pids[0] = getpid();	/* for completeness */",
1329 	"		while (++core_id < NCORE)	/* first worker sees core_id = 1 */",
1330 	"		{	is_parent = fork();",
1331 	"			if (is_parent == -1)",
1332 	"			{	Uerror(\"fork failed\");",
1333 	"			}",
1334 	"			if (is_parent == 0)	/* this is a worker process */",
1335 	"			{	if (proxy_pid == core_id)	/* always non-zero */",
1336 	"				{	start_proxy(\"-r\", 0);	/* no return */",
1337 	"				}",
1338 	"				goto adapt;	/* root process continues spawning */",
1339 	"			}",
1340 	"			worker_pids[core_id] = is_parent;",
1341 	"		}",
1342 	"		/* note that core_id is now NCORE */",
1343 	"		if (proxy_pid > 0 && proxy_pid < NCORE)", /* add send-half of proxy */
1344 	"		{	proxy_pid_snd = fork();",
1345 	"			if (proxy_pid_snd == -1)",
1346 	"			{	Uerror(\"proxy fork failed\");",
1347 	"			}",
1348 	"			if (proxy_pid_snd == 0)",
1349 	"			{	start_proxy(\"-s\", worker_pids[proxy_pid]); /* no return */",
1350 	"		}	} /* else continue */",
1351 
1352 	"		if (is_parent > 0)",
1353 	"		{	core_id = 0;	/* reset core_id for root process */",
1354 	"		}",
1355 	"	} else	/* worker */",
1356 	"	{	static char db0[16];	/* good for up to 10^6 cores */",
1357 	"		static char db1[16];",
1358 	"adapt:		tprefix = db0; sprefix = db1;",
1359 	"		sprintf(tprefix, \"cpu%%d_trail\", core_id);",
1360 	"		sprintf(sprefix, \"cpu%%d_rst\", core_id);",
1361 	"		memcnt = 0;	/* count only additionally allocated memory */",
1362 	"	}",
1363 	"	signal(SIGINT, give_up);",
1364 	"",
1365 	"	if (proxy_pid == 0)		/* not in a cluster setup, pan_proxy must attach */",
1366 	"	{	rm_shared_segments();	/* mark all shared segments for removal on exit */",
1367 	"	}", /* doing it early means less chance of being unable to do this */
1368 	"	if (verbose)",
1369 	"	{	cpu_printf(\"starting core_id %%d -- pid %%d\\n\", core_id, getpid());",
1370 	"	}",
1371 
1372 	"#if defined(SEP_HEAP) && !defined(SEP_STATE)",	/* set my_heap and adjust dc_shared */
1373 	"	{	int i;",
1374 	"		volatile sh_Allocater *ptr;",
1375 	"		ptr = first_pool;",
1376 	"		for (i = 0; i < NCORE  && ptr != NULL; i++)",
1377 	"		{	if (i == core_id)",
1378 	"			{	my_heap = (char *) ptr->dc_arena;",
1379 	"				my_size = (long) ptr->dc_size;",
1380 	"				if (verbose)",
1381 	"				cpu_printf(\"local heap %%ld MB\\n\", my_size/(1048576));",
1382 	"				break;",
1383 	"			}",
1384 	"			ptr = ptr->nxt; /* local */",
1385 	"		}",
1386 	"		if (my_heap == NULL)",
1387 	"		{	printf(\"cpu%%d: no local heap\\n\", core_id);",
1388 	"			pan_exit(1);",
1389 	"		} /* else */",
1390 	"	#if defined(CYGWIN) || defined(__CYGWIN__)",
1391 	"		ptr = first_pool;",
1392 	"		for (i = 0; i < NCORE  && ptr != NULL; i++)",
1393 	"		{	ptr = ptr->nxt; /* local */",
1394 	"		}",
1395 	"		dc_shared = ptr; /* any remainder */",
1396 	"	#else",
1397 	"		dc_shared = NULL; /* used all mem for local heaps */",
1398 	"	#endif",
1399 	"	}",
1400 	"#endif",
1401 
1402 	"	if (core_id == 0 && !remote_party)",
1403 	"	{	new_state();		/* cpu0 explores root */",
1404 	"		if (verbose)",
1405 	"		cpu_printf(\"done with 1st dfs, nstates %%g (put %%d states), read q\\n\",",
1406 	"			nstates, nstates_put);",
1407 	"		dfs_phase2 = 1;",
1408 	"	}",
1409 	"	Read_Queue(core_id);	/* all cores */",
1410 	"",
1411 	"	if (verbose)",
1412 	"	{	cpu_printf(\"put %%6d states into queue -- got %%6d\\n\",",
1413 	"			nstates_put, nstates_get);",
1414 	"	}",
1415 	"	if (proxy_pid != 0)",
1416 	"	{	rm_shared_segments();",
1417 	"	}",
1418 	"	done = 1;",
1419 	"	wrapup();",
1420 	"	exit(0);",
1421 	"}",
1422 	"",
1423 	"#else",
1424 	"int unpack_state(SM_frame *, int);",
1425 	"#endif",
1426 	"",
1427 	"H_el *",
1428 	"grab_shared(int n)",
1429 	"{",
1430 	"#ifndef SEP_STATE",
1431 	"	char *rval = (char *) 0;",
1432 	"",
1433 	"	if (n == 0)",
1434 	"	{	printf(\"cpu%%d: grab shared zero\\n\", core_id); fflush(stdout);",
1435 	"		return (H_el *) rval;",
1436 	"	} else if (n&(sizeof(void *)-1))",
1437 	"	{	n += sizeof(void *)-(n&(sizeof(void *)-1)); /* alignment */",
1438 	"	}",
1439 	"",
1440 	"#ifdef SEP_HEAP",
1441 	"	/* no locking */",
1442 	"	if (my_heap != NULL && my_size > n)",
1443 	"	{	rval = my_heap;",
1444 	"		my_heap += n;",
1445 	"		my_size -= n;",
1446 	"		goto done;",
1447 	"	}",
1448 	"#endif",
1449 	"",
1450 	"	if (!dc_shared)",
1451 	"	{	sudden_stop(\"pan: out of memory\");",
1452 	"	}",
1453 	"",
1454 	"	/* another lock is always already in effect when this is called */",
1455 	"	/* but not always the same lock -- i.e., on different parts of the hashtable */",
1456 	"	enter_critical(GLOBAL_LOCK);	/* this must be independently mutex */",
1457 	"#if defined(SEP_HEAP) && !defined(WIN32) && !defined(WIN64)",
1458 	"	{	static int noted = 0;",
1459 	"		if (!noted)",
1460 	"		{	noted = 1;",
1461 	"			printf(\"cpu%%d: global heap has %%ld bytes left, needed %%d\\n\",",
1462 	"				core_id, dc_shared?dc_shared->dc_size:0, n);",
1463 	"	}	}",
1464 	"#endif",
1465 	"#if 0",	/* for debugging */
1466 	"		if (dc_shared->pattern != 1234567)",
1467 	"		{	leave_critical(GLOBAL_LOCK);",
1468 	"			Uerror(\"overrun -- memory corruption\");",
1469 	"		}",
1470 	"#endif",
1471 	"		if (dc_shared->dc_size < n)",
1472 	"		{	if (verbose)",
1473 	"			{ printf(\"Next Pool %%g Mb + %%d\\n\", memcnt/(1048576.), n);",
1474 	"			}",
1475 	"			if (dc_shared->nxt == NULL",
1476 	"			||  dc_shared->nxt->dc_arena == NULL",
1477 	"			||  dc_shared->nxt->dc_size < n)",
1478 	"			{	printf(\"cpu%%d: memcnt %%g Mb + wanted %%d bytes more\\n\",",
1479 	"					core_id, memcnt / (1048576.), n);",
1480 	"				leave_critical(GLOBAL_LOCK);",
1481 	"				sudden_stop(\"out of memory -- aborting\");",
1482 	"				wrapup();	/* exits */",
1483 	"			} else",
1484 	"			{	dc_shared = (sh_Allocater *) dc_shared->nxt;",
1485 	"		}	}",
1486 	"",
1487 	"		rval = (char *) dc_shared->dc_arena;",
1488 	"		dc_shared->dc_arena += n;",
1489 	"		dc_shared->dc_size  -= (long) n;",
1490 	"#if 0",
1491 	"		if (VVERBOSE)",
1492 	"		printf(\"cpu%%d grab shared (%%d bytes) -- %%ld left\\n\",",
1493 	"			core_id, n, dc_shared->dc_size);",
1494 	"#endif",
1495 	"	leave_critical(GLOBAL_LOCK);",
1496 	"done:",
1497 	"	memset(rval, 0, n);",
1498 	"	memcnt += (double) n;",
1499 	"",
1500 	"	return (H_el *) rval;",
1501 	"#else",
1502 	"	return (H_el *) emalloc(n);",
1503 	"#endif",
1504 	"}",
1505 	"",
1506 	"SM_frame *",
1507 	"Get_Full_Frame(int n)",
1508 	"{	SM_frame *f;",
1509 	"	double cnt_start = frame_wait;",
1510 	"",
1511 	"	f = &m_workq[n][prfull[n]];",
1512 	"	while (f->m_vsize == 0)	/* await full slot LOCK : full frame */",
1513 	"	{	iam_alive();",
1514 	"#ifndef NGQ",
1515 	"	#ifndef SAFETY",
1516 	"		if (!a_cycles || core_id != 0)",
1517 	"	#endif",
1518 	"		if (*grcnt > 0)	/* accessed outside lock, but safe even if wrong */",
1519 	"		{	enter_critical(GQ_RD);	/* gq - read access */",
1520 	"			if (*grcnt > 0)		/* could have changed */",
1521 	"			{	f = &m_workq[NCORE][*grfull];	/* global q */",
1522 	"				if (f->m_vsize == 0)",
1523 	"				{	/* writer is still filling the slot */",
1524 	"					*gr_writemiss++;",
1525 	"					f = &m_workq[n][prfull[n]]; /* reset */",
1526 	"				} else",
1527 	"				{	*grfull = (*grfull+1) %% (GN_FRAMES);",
1528 	"						enter_critical(GQ_WR);",
1529 	"						*grcnt = *grcnt - 1;",
1530 	"						leave_critical(GQ_WR);",
1531 	"					leave_critical(GQ_RD);",
1532 	"					return f;",
1533 	"			}	}",
1534 	"			leave_critical(GQ_RD);",
1535 	"		}",
1536 	"#endif",
1537 	"		if (frame_wait++ - cnt_start > Delay)",
1538 	"		{	if (0)", /* too frequent to enable this one */
1539 	"			{	cpu_printf(\"timeout on q%%d -- %%u -- query %%d\\n\",",
1540 	"					n, f, query_in_progress);",
1541 	"			}",
1542 	"			return (SM_frame *) 0;	/* timeout */",
1543 	"	}	}",
1544 	"	iam_alive();",
1545 	"	if (VVERBOSE) cpu_printf(\"got frame from q%%d\\n\", n);",
1546 	"	prfull[n] = (prfull[n] + 1) %% (LN_FRAMES);",
1547 	"	enter_critical(QLOCK(n));",
1548 	"		prcnt[n]--; /* lock out increments */",
1549 	"	leave_critical(QLOCK(n));",
1550 	"	return f;",
1551 	"}",
1552 	"",
1553 	"SM_frame *",
1554 	"Get_Free_Frame(int n)",
1555 	"{	SM_frame *f;",
1556 	"	double cnt_start = free_wait;",
1557 	"",
1558 	"	if (VVERBOSE) { cpu_printf(\"get free frame from q%%d\\n\", n); }",
1559 	"",
1560 	"	if (n == NCORE)	/* global q */",
1561 	"	{	f = &(m_workq[n][lrfree]);",
1562 	"	} else",
1563 	"	{	f = &(m_workq[n][prfree[n]]);",
1564 	"	}",
1565 	"	while (f->m_vsize != 0)	/* await free slot LOCK : free slot */",
1566 	"	{	iam_alive();",
1567 	"		if (free_wait++ - cnt_start > OneSecond)",
1568 	"		{	if (verbose)",
1569 	"			{	cpu_printf(\"timeout waiting for free slot q%%d\\n\", n);",
1570 	"			}",
1571 	"			cnt_start = free_wait;",
1572 	"			if (someone_crashed(1))",
1573 	"			{	printf(\"cpu%%d: search terminated\\n\", core_id);",
1574 	"				sudden_stop(\"get free frame\");",
1575 	"				pan_exit(1);",
1576 	"	}	}	}",
1577 	"	if (n != NCORE)",
1578 	"	{	prfree[n] = (prfree[n] + 1) %% (LN_FRAMES);",
1579 	"		enter_critical(QLOCK(n));",
1580 	"			prcnt[n]++; /* lock out decrements */",
1581 	"			if (prmax[n] < prcnt[n])",
1582 	"			{	prmax[n] = prcnt[n];",
1583 	"			}",
1584 	"		leave_critical(QLOCK(n));",
1585 	"	}",
1586 	"	return f;",
1587 	"}",
1588 	"",
1589 	"#ifndef NGQ",
1590 	"int",
1591 	"GlobalQ_HasRoom(void)",
1592 	"{	int rval = 0;",
1593 	"",
1594 	"	gq_tries++;",
1595 	"	if (*grcnt < GN_FRAMES) /* there seems to be room */",
1596 	"	{	enter_critical(GQ_WR);	/* gq write access */",
1597 	"		if (*grcnt < GN_FRAMES)",
1598 	"		{	if (m_workq[NCORE][*grfree].m_vsize != 0)",
1599 	"			{	/* can happen if reader is slow emptying slot */",
1600 	"				*gr_readmiss++;",
1601 	"				goto out; /* don't wait: release lock and return */",
1602 	"			}",
1603 	"			lrfree = *grfree;	/* Get_Free_Frame use lrfree in this mode */",
1604 	"			*grfree = (*grfree + 1) %% GN_FRAMES;",	/* next process looks at next slot */
1605 	"			*grcnt = *grcnt + 1;	/* count nr of slots filled -- no additional lock needed */",
1606 	"			if (*grmax < *grcnt) *grmax = *grcnt;",
1607 	"			leave_critical(GQ_WR);	/* for short lock duration */",
1608 	"			gq_hasroom++;",
1609 	"			mem_put(NCORE);		/* copy state into reserved slot */",
1610 	"			rval = 1;		/* successful handoff */",
1611 	"		} else",
1612 	"		{	gq_hasnoroom++;",
1613 	"out:			leave_critical(GQ_WR);",	/* should be rare */
1614 	"	}	}",
1615 	"	return rval;",
1616 	"}",
1617 	"#endif",
1618 	"",
1619 	"int",
1620 	"unpack_state(SM_frame *f, int from_q)",
1621 	"{	int i, j;",
1622 	"	static H_el D_State;",
1623 	"",
1624 	"	if (f->m_vsize > 0)",
1625 	"	{	boq   = f->m_boq;",
1626 	"		if (boq > 256)",
1627 	"		{	cpu_printf(\"saw control %%d, expected state\\n\", boq);",
1628 	"			return 0;",
1629 	"		}",
1630 	"		vsize = f->m_vsize;",
1631 	"correct:",
1632 	"		memcpy((uchar *) &now, (uchar *) f->m_now, vsize);",
1633 	"	#if !defined(NOCOMP) && !defined(HC)",
1634 	"		for (i = j = 0; i < VMAX; i++, j = (j+1)%%8)",
1635 	"		{	Mask[i] = (f->m_mask[i/8] & (1<<j)) ? 1 : 0;",
1636 	"		}",
1637 	"	#endif",
1638 	"		if (now._nr_pr > 0)",
1639 	"		{	memcpy((uchar *) proc_offset, (uchar *) f->m_p_offset, now._nr_pr * sizeof(OFFT));",
1640 	"			memcpy((uchar *) proc_skip,   (uchar *) f->m_p_skip,   now._nr_pr * sizeof(uchar));",
1641 	"		}",
1642 	"		if (now._nr_qs > 0)",
1643 	"		{	memcpy((uchar *) q_offset,    (uchar *) f->m_q_offset, now._nr_qs * sizeof(OFFT));",
1644 	"			memcpy((uchar *) q_skip,      (uchar *) f->m_q_skip,   now._nr_qs * sizeof(uchar));",
1645 	"		}",
1646 	"#ifndef NOVSZ",
1647 	"		if (vsize != now._vsz)",
1648 	"		{	cpu_printf(\"vsize %%d != now._vsz %%d (type %%d) %%d\\n\",",
1649 	"				vsize, now._vsz, f->m_boq, f->m_vsize);",
1650 	"			vsize = now._vsz;",
1651 	"			goto correct;	/* rare event: a race */",
1652 	"		}",
1653 	"#endif",
1654 	"		hmax = max(hmax, vsize);",
1655 	"",
1656 	"		if (f != &cur_Root)",
1657 	"		{	memcpy((uchar *) &cur_Root, (uchar *) f, sizeof(SM_frame));",
1658 	"		}",
1659 	"",
1660 	"		if (((now._a_t) & 1) == 1)	/* i.e., when starting nested DFS */",
1661 	"		{	A_depth = depthfound = 0;",
1662 	"			memcpy((uchar *)&A_Root, (uchar *)&now, vsize);",
1663 	"		}",
1664 	"		nr_handoffs = f->nr_handoffs;",
1665 	"	} else",
1666 	"	{	cpu_printf(\"pan: state empty\\n\");",
1667 	"	}",
1668 	"",
1669 	"	depth = 0;",
1670 	"	trpt = &trail[1];",
1671 	"	trpt->tau    = f->m_tau;",
1672 	"	trpt->o_pm   = f->m_o_pm;",
1673 	"",
1674 	"	(trpt-1)->ostate = &D_State; /* stub */",
1675 	"	trpt->ostate = &D_State;",
1676 	"",
1677 	"#ifdef FULL_TRAIL",
1678 	"	if (upto > 0)",
1679 	"	{	stack_last[core_id] = (Stack_Tree *) f->m_stack;",
1680 	"	}",
1681 	"	#if defined(VERBOSE)",
1682 	"	if (stack_last[core_id])",
1683 	"	{	cpu_printf(\"%%d: UNPACK -- SET m_stack %%u (%%d,%%d)\\n\",",
1684 	"			depth, stack_last[core_id], stack_last[core_id]->pr,",
1685 	"			stack_last[core_id]->t_id);",
1686 	"	}",
1687 	"	#endif",
1688 	"#endif",
1689 	"",
1690 	"	if (!trpt->o_t)",
1691 	"	{	static Trans D_Trans;",
1692 	"		trpt->o_t = &D_Trans;",
1693 	"	}",
1694 	"",
1695 	"	#ifdef VERI",
1696 	"	if ((trpt->tau & 4) != 4)",
1697 	"	{	trpt->tau |= 4;	/* the claim moves first */",
1698 	"		cpu_printf(\"warning: trpt was not up to date\\n\");",
1699 	"	}",
1700 	"	#endif",
1701 	"",
1702 	"	for (i = 0; i < (int) now._nr_pr; i++)",
1703 	"	{	P0 *ptr = (P0 *) pptr(i);",
1704 	"	#ifndef NP",
1705 	"		if (accpstate[ptr->_t][ptr->_p])",
1706 	"		{	trpt->o_pm |= 2;",
1707 	"		}",
1708 	"	#else",
1709 	"		if (progstate[ptr->_t][ptr->_p])",
1710 	"		{	trpt->o_pm |= 4;",
1711 	"		}",
1712 	"	#endif",
1713 	"	}",
1714 	"",
1715 	"	#ifdef EVENT_TRACE",
1716 	"		#ifndef NP",
1717 	"			if (accpstate[EVENT_TRACE][now._event])",
1718 	"			{	trpt->o_pm |= 2;",
1719 	"			}",
1720 	"		#else",
1721 	"			if (progstate[EVENT_TRACE][now._event])",
1722 	"			{	trpt->o_pm |= 4;",
1723 	"			}",
1724 	"		#endif",
1725 	"	#endif",
1726 	"",
1727 	"	#if defined(C_States) && (HAS_TRACK==1)",
1728 	"		/* restore state of tracked C objects */",
1729 	"		c_revert((uchar *) &(now.c_state[0]));",
1730 	"		#if (HAS_STACK==1)",
1731 	"		c_unstack((uchar *) f->m_c_stack); /* unmatched tracked data */",
1732 	"		#endif",
1733 	"	#endif",
1734 	"	return 1;",
1735 	"}",
1736 	"",
1737 	"void",
1738 	"write_root(void)	/* for trail file */",
1739 	"{	int fd;",
1740 	"",
1741 	"	if (iterative == 0 && Nr_Trails > 1)",
1742 	"		sprintf(fnm, \"%%s%%d.%%s\", TrailFile, Nr_Trails-1, sprefix);",
1743 	"	else",
1744 	"		sprintf(fnm, \"%%s.%%s\", TrailFile, sprefix);",
1745 	"",
1746 	"	if (cur_Root.m_vsize == 0)",
1747 	"	{	(void) unlink(fnm); /* remove possible old copy */",
1748 	"		return;	/* its the default initial state */",
1749 	"	}",
1750 	"",
1751 	"	if ((fd = creat(fnm, TMODE)) < 0)",
1752 	"	{	char *q;",
1753 	"		if ((q = strchr(TrailFile, \'.\')))",
1754 	"		{	*q = \'\\0\';		/* strip .pml */",
1755 	"			if (iterative == 0 && Nr_Trails-1 > 0)",
1756 	"				sprintf(fnm, \"%%s%%d.%%s\", TrailFile, Nr_Trails-1, sprefix);",
1757 	"			else",
1758 	"				sprintf(fnm, \"%%s.%%s\", TrailFile, sprefix);",
1759 	"			*q = \'.\';",
1760 	"			fd = creat(fnm, TMODE);",
1761 	"		}",
1762 	"		if (fd < 0)",
1763 	"		{	cpu_printf(\"pan: cannot create %%s\\n\", fnm);",
1764 	"			perror(\"cause\");",
1765 	"			return;",
1766 	"	}	}",
1767 	"",
1768 	"	if (write(fd, &cur_Root, sizeof(SM_frame)) != sizeof(SM_frame))",
1769 	"	{	cpu_printf(\"pan: error writing %%s\\n\", fnm);",
1770 	"	} else",
1771 	"	{	cpu_printf(\"pan: wrote %%s\\n\", fnm);",
1772 	"	}",
1773 	"	close(fd);",
1774 	"}",
1775 	"",
1776 	"void",
1777 	"set_root(void)",
1778 	"{	int fd;",
1779 	"	char *q;",
1780 	"	char MyFile[512];",	/* enough to hold a reasonable pathname */
1781 	"	char MySuffix[16];",
1782 	"	char *ssuffix = \"rst\";",
1783 	"	int  try_core = 1;",
1784 	"",
1785 	"	strcpy(MyFile, TrailFile);",
1786 	"try_again:",
1787 	"	if (whichtrail > 0)",
1788 	"	{	sprintf(fnm, \"%%s%%d.%%s\", MyFile, whichtrail, ssuffix);",
1789 	"		fd = open(fnm, O_RDONLY, 0);",
1790 	"		if (fd < 0 && (q = strchr(MyFile, \'.\')))",
1791 	"		{	*q = \'\\0\';	/* strip .pml */",
1792 	"			sprintf(fnm, \"%%s%%d.%%s\", MyFile, whichtrail, ssuffix);",
1793 	"			*q = \'.\';",
1794 	"			fd = open(fnm, O_RDONLY, 0);",
1795 	"		}",
1796 	"	} else",
1797 	"	{	sprintf(fnm, \"%%s.%%s\", MyFile, ssuffix);",
1798 	"		fd = open(fnm, O_RDONLY, 0);",
1799 	"		if (fd < 0 && (q = strchr(MyFile, \'.\')))",
1800 	"		{	*q = \'\\0\';	/* strip .pml */",
1801 	"			sprintf(fnm, \"%%s.%%s\", MyFile, ssuffix);",
1802 	"			*q = \'.\';",
1803 	"			fd = open(fnm, O_RDONLY, 0);",
1804 	"	}	}",
1805 	"",
1806 	"	if (fd < 0)",
1807 	"	{	if (try_core < NCORE)",
1808 	"		{	ssuffix = MySuffix;",
1809 	"			sprintf(ssuffix, \"cpu%%d_rst\", try_core++);",
1810 	"			goto try_again;",
1811 	"		}",
1812 	"		cpu_printf(\"no file '%%s.rst' or '%%s' (not an error)\\n\", MyFile, fnm);",
1813 	"	} else",
1814 	"	{	if (read(fd, &cur_Root, sizeof(SM_frame)) != sizeof(SM_frame))",
1815 	"		{	cpu_printf(\"read error %%s\\n\", fnm);",
1816 	"			close(fd);",
1817 	"			pan_exit(1);",
1818 	"		}",
1819 	"		close(fd);",
1820 	"		(void) unpack_state(&cur_Root, -2);",
1821 	"#ifdef SEP_STATE",
1822 	"		cpu_printf(\"partial trail -- last few steps only\\n\");",
1823 	"#endif",
1824 	"		cpu_printf(\"restored root from '%%s'\\n\", fnm);",
1825 	"		printf(\"=====State:=====\\n\");",
1826 	"		{	int i, j; P0 *z;",
1827 	"			for (i = 0; i < now._nr_pr; i++)",
1828 	"			{	z = (P0 *)pptr(i);",
1829 	"				printf(\"proc %%2d (%%s) \", i, procname[z->_t]);",
1830 
1831 	"				for (j = 0; src_all[j].src; j++)",
1832 	"				if (src_all[j].tp == (int) z->_t)",
1833 	"				{	printf(\" %%s:%%d \",",
1834 	"						PanSource, src_all[j].src[z->_p]);",
1835 	"					break;",
1836 	"				}",
1837 	"				printf(\"(state %%d)\\n\", z->_p);",
1838 	"				c_locals(i, z->_t);",
1839 	"			}",
1840 	"			c_globals();",
1841 	"		}",
1842 	"		printf(\"================\\n\");",
1843 	"	}",
1844 	"}",
1845 	"",
1846 	"#ifdef USE_DISK",
1847 	"unsigned long dsk_written, dsk_drained;",
1848 	"void mem_drain(void);",
1849 	"#endif",
1850 	"",
1851 	"void",
1852 	"m_clear_frame(SM_frame *f)", /* clear room for stats */
1853 	"{	int i, clr_sz = sizeof(SM_results);",
1854 	"",
1855 	"	for (i = 0; i <= _NP_; i++)	/* all proctypes */",
1856 	"	{	clr_sz += NrStates[i]*sizeof(uchar);",
1857 	"	}",
1858 	"	memset(f, 0, clr_sz);",
1859 	"	/* caution if sizeof(SM_results) > sizeof(SM_frame) */",
1860 	"}",
1861 	"",
1862 	"#define TargetQ_Full(n)	(m_workq[n][prfree[n]].m_vsize != 0)", /* no free slot */
1863 	"#define TargetQ_NotFull(n)	(m_workq[n][prfree[n]].m_vsize == 0)", /* avoiding prcnt */
1864 	"",
1865 	"int",
1866 	"AllQueuesEmpty(void)",
1867 	"{	int q;",
1868 	"#ifndef NGQ",
1869 	"	if (*grcnt != 0)",
1870 	"	{	return 0;",
1871 	"	}",
1872 	"#endif",
1873 	"	for (q = 0; q < NCORE; q++)",
1874 	"	{	if (prcnt[q] != 0)", /* not locked, ok if race */
1875 	"		{	return 0;",
1876 	"	}	}",
1877 	"	return 1;",
1878 	"}",
1879 	"",
1880 	"void",
1881 	"Read_Queue(int q)",
1882 	"{	SM_frame   *f, *of;",
1883 	"	int	remember, target_q;",
1884 	"	SM_results *r;",
1885 	"	double patience = 0.0;",
1886 	"",
1887 	"	target_q = (q + 1) %% NCORE;",
1888 	"",
1889 	"	for (;;)",
1890 	"	{	f = Get_Full_Frame(q);",
1891 	"		if (!f)	/* 1 second timeout -- and trigger for Query */",
1892 	"		{	if (someone_crashed(2))",
1893 	"			{	printf(\"cpu%%d: search terminated [code %%d]\\n\",",
1894 	"					core_id, search_terminated?*search_terminated:-1);",
1895 	"				sudden_stop(\"\");",
1896 	"				pan_exit(1);",
1897 	"			}",
1898 	"#ifdef TESTING",
1899 	"	/* to profile with cc -pg and gprof pan.exe -- set handoff depth beyond maxdepth */",
1900 	"			exit(0);",
1901 	"#endif",
1902 	"			remember = *grfree;",
1903 	"			if (core_id == 0		/* root can initiate termination */",
1904 	"			&& remote_party == 0		/* and only the original root */",
1905 	"			&& query_in_progress == 0	/* unless its already in progress */",
1906 	"			&& AllQueuesEmpty())",
1907 	"			{	f = Get_Free_Frame(target_q);",
1908 	"				query_in_progress = 1;	/* only root process can do this */",
1909 	"				if (!f) { Uerror(\"Fatal1: no free slot\"); }",
1910 	"				f->m_boq = QUERY;	/* initiate Query */",
1911 	"				if (verbose)",
1912 	"				{  cpu_printf(\"snd QUERY to q%%d (%%d) into slot %%d\\n\",",
1913 	"					target_q, nstates_get + 1, prfree[target_q]-1);",
1914 	"				}",
1915 	"				f->m_vsize = remember + 1;",
1916 	"				/* number will not change unless we receive more states */",
1917 	"			} else if (patience++ > OneHour) /* one hour watchdog timer */",
1918 	"			{	cpu_printf(\"timeout -- giving up\\n\");",
1919 	"				sudden_stop(\"queue timeout\");",
1920 	"				pan_exit(1);",
1921 	"			}",
1922 	"			if (0) cpu_printf(\"timed out -- try again\\n\");",
1923 	"			continue;	",
1924 	"		}",
1925 	"		patience = 0.0; /* reset watchdog */",
1926 	"",
1927 	"		if (f->m_boq == QUERY)",
1928 	"		{	if (verbose)",
1929 	"			{	cpu_printf(\"got QUERY on q%%d (%%d <> %%d) from slot %%d\\n\",",
1930 	"					q, f->m_vsize, nstates_put + 1, prfull[q]-1);",
1931 	"				snapshot();",
1932 	"			}",
1933 	"			remember = f->m_vsize;",
1934 	"			f->m_vsize = 0;	/* release slot */",
1935 	"",
1936 	"			if (core_id == 0 && remote_party == 0)	/* original root cpu0 */",
1937 	"			{	if (query_in_progress == 1	/* didn't send more states in the interim */",
1938 	"				&&  *grfree + 1 == remember)	/* no action on global queue meanwhile */",
1939 	"				{	if (verbose) cpu_printf(\"Termination detected\\n\");",
1940 	"					if (TargetQ_Full(target_q))",
1941 	"					{	if (verbose)",
1942 	"						cpu_printf(\"warning: target q is full\\n\");",
1943 	"					}",
1944 	"					f = Get_Free_Frame(target_q);",
1945 	"					if (!f) { Uerror(\"Fatal2: no free slot\"); }",
1946 	"					m_clear_frame(f);",
1947 	"					f->m_boq = QUIT; /* send final Quit, collect stats */",
1948 	"					f->m_vsize = 111; /* anything non-zero will do */",
1949 	"					if (verbose)",
1950 	"					cpu_printf(\"put QUIT on q%%d\\n\", target_q);",
1951 	"				} else",
1952 	"				{	if (verbose) cpu_printf(\"Stale Query\\n\");",
1953 	"#ifdef USE_DISK",
1954 	"					mem_drain();",
1955 	"#endif",
1956 	"				}",
1957 	"				query_in_progress = 0;",
1958 	"			} else",
1959 	"			{	if (TargetQ_Full(target_q))",
1960 	"				{	if (verbose)",
1961 	"					cpu_printf(\"warning: forward query - target q full\\n\");",
1962 	"				}",
1963 	"				f = Get_Free_Frame(target_q);",
1964 	"				if (verbose)",
1965 	"				cpu_printf(\"snd QUERY response to q%%d (%%d <> %%d) in slot %%d\\n\",",
1966 	"					target_q, remember, *grfree + 1, prfree[target_q]-1);",
1967 	"				if (!f) { Uerror(\"Fatal4: no free slot\"); }",
1968 	"",
1969 	"				if (*grfree + 1 == remember)	/* no action on global queue */",
1970 	"				{	f->m_boq = QUERY;	/* forward query, to root */",
1971 	"					f->m_vsize = remember;",
1972 	"				} else",
1973 	"				{	f->m_boq = QUERY_F;	/* no match -- busy */",
1974 	"					f->m_vsize = 112;	/* anything non-zero */",
1975 	"#ifdef USE_DISK",
1976 	"					if (dsk_written != dsk_drained)",
1977 	"					{	mem_drain();",
1978 	"					}",
1979 	"#endif",
1980 	"			}	}",
1981 	"			continue;",
1982 	"		}",
1983 	"",
1984 	"		if (f->m_boq == QUERY_F)",
1985 	"		{	if (verbose)",
1986 	"			{	cpu_printf(\"got QUERY_F on q%%d from slot %%d\\n\", q, prfull[q]-1);",
1987 	"			}",
1988 	"			f->m_vsize = 0;	/* release slot */",
1989 	"",
1990 	"			if (core_id == 0 && remote_party == 0)		/* original root cpu0 */",
1991 	"			{	if (verbose) cpu_printf(\"No Match on Query\\n\");",
1992 	"				query_in_progress = 0;",
1993 	"			} else",
1994 	"			{	if (TargetQ_Full(target_q))",
1995 	"				{	if (verbose) cpu_printf(\"warning: forwarding query_f, target queue full\\n\");",
1996 	"				}",
1997 	"				f = Get_Free_Frame(target_q);",
1998 	"				if (verbose) cpu_printf(\"forward QUERY_F to q%%d into slot %%d\\n\",",
1999 	"						target_q, prfree[target_q]-1);",
2000 	"				if (!f) { Uerror(\"Fatal5: no free slot\"); }",
2001 	"				f->m_boq = QUERY_F;		/* cannot terminate yet */",
2002 	"				f->m_vsize = 113;		/* anything non-zero */",
2003 	"			}",
2004 	"#ifdef USE_DISK",
2005 	"			if (dsk_written != dsk_drained)",
2006 	"			{	mem_drain();",
2007 	"			}",
2008 	"#endif",
2009 	"			continue;",
2010 	"		}",
2011 	"",
2012 	"		if (f->m_boq == QUIT)",
2013 	"		{	if (0) cpu_printf(\"done -- local memcnt %%g Mb\\n\", memcnt/(1048576.));",
2014 	"			retrieve_info((SM_results *) f); /* collect and combine stats */",
2015 	"			if (verbose)",
2016 	"			{	cpu_printf(\"received Quit\\n\");",
2017 	"				snapshot();",
2018 	"			}",
2019 	"			f->m_vsize = 0;	/* release incoming slot */",
2020 	"			if (core_id != 0)",
2021 	"			{	f = Get_Free_Frame(target_q); /* new outgoing slot */",
2022 	"				if (!f) { Uerror(\"Fatal6: no free slot\"); }",
2023 	"				m_clear_frame(f);	/* start with zeroed stats */",
2024 	"				record_info((SM_results *) f);",
2025 	"				f->m_boq = QUIT;	/* forward combined results */",
2026 	"				f->m_vsize = 114;	/* anything non-zero */",
2027 	"				if (verbose>1)",
2028 	"				cpu_printf(\"fwd Results to q%%d\\n\", target_q);",
2029 	"			}",
2030 	"			break;			/* successful termination */",
2031 	"		}",
2032 	"",
2033 	"		/* else: 0<= boq <= 255, means STATE transfer */",
2034 	"		if (unpack_state(f, q) != 0)",
2035 	"		{	nstates_get++;",
2036 	"			f->m_vsize = 0;	/* release slot */",
2037 	"			if (VVERBOSE) cpu_printf(\"Got state\\n\");",
2038 	"",
2039 	"			if (search_terminated != NULL",
2040 	"			&&  *search_terminated == 0)",
2041 	"			{	new_state();	/* explore successors */",
2042 	"				memset((uchar *) &cur_Root, 0, sizeof(SM_frame));	/* avoid confusion */",
2043 	"			} else",
2044 	"			{	pan_exit(0);",
2045 	"			}",
2046 	"		} else",
2047 	"		{	pan_exit(0);",
2048 	"	}	}",
2049 	"	if (verbose) cpu_printf(\"done got %%d put %%d\\n\", nstates_get, nstates_put);",
2050 	"	sleep_report();",
2051 	"}",
2052 	"",
2053 	"void",
2054 	"give_up(int unused_x)",
2055 	"{",
2056 	"	if (search_terminated != NULL)",
2057 	"	{	*search_terminated |= 32;	/* give_up */",
2058 	"	}",
2059 	"	if (!writing_trail)",
2060 	"	{	was_interrupted = 1;",
2061 	"		snapshot();",
2062 	"		cpu_printf(\"Give Up\\n\");",
2063 	"		sleep_report();",
2064 	"		pan_exit(1);",
2065 	"	} else /* we are already terminating */",
2066 	"	{	cpu_printf(\"SIGINT\\n\");",
2067 	"	}",
2068 	"}",
2069 	"",
2070 	"void",
2071 	"check_overkill(void)",
2072 	"{",
2073 	"	vmax_seen = (vmax_seen + 7)/ 8;",
2074 	"	vmax_seen *= 8;	/* round up to a multiple of 8 */",
2075 	"",
2076 	"	if (core_id == 0",
2077 	"	&&  !remote_party",
2078 	"	&&  nstates_put > 0",
2079 	"	&&  VMAX - vmax_seen > 8)",
2080 	"	{",
2081 	"#ifdef BITSTATE",
2082 	"		printf(\"cpu0: max VMAX value seen in this run: \");",
2083 	"#else",
2084 	"		printf(\"cpu0: recommend recompiling with \");",
2085 	"#endif",
2086 	"		printf(\"-DVMAX=%%d\\n\", vmax_seen);",
2087 	"	}",
2088 	"}",
2089 	"",
2090 	"void",
2091 	"mem_put(int q)	/* handoff state to other cpu, workq q */",
2092 	"{	SM_frame *f;",
2093 	"	int i, j;",
2094 	"",
2095 	"	if (vsize > VMAX)",
2096 	"	{	vsize = (vsize + 7)/8; vsize *= 8; /* round up */",
2097 	"		printf(\"pan: recompile with -DVMAX=N with N >= %%d\\n\", (int) vsize);",
2098 	"		Uerror(\"aborting\");",
2099 	"	}",
2100 	"	if (now._nr_pr > PMAX)",
2101 	"	{	printf(\"pan: recompile with -DPMAX=N with N >= %%d\\n\", now._nr_pr);",
2102 	"		Uerror(\"aborting\");",
2103 	"	}",
2104 	"	if (now._nr_qs > QMAX)",
2105 	"	{	printf(\"pan: recompile with -DQMAX=N with N >= %%d\\n\", now._nr_qs);",
2106 	"		Uerror(\"aborting\");",
2107 	"	}",
2108 	"	if (vsize > vmax_seen) vmax_seen = vsize;",
2109 	"	if (now._nr_pr > pmax_seen) pmax_seen = now._nr_pr;",
2110 	"	if (now._nr_qs > qmax_seen) qmax_seen = now._nr_qs;",
2111 	"",
2112 	"	f = Get_Free_Frame(q);	/* not called in likely deadlock states */",
2113 	"	if (!f) { Uerror(\"Fatal3: no free slot\"); }",
2114 	"",
2115 	"	if (VVERBOSE) cpu_printf(\"putting state into q%%d\\n\", q);",
2116 	"",
2117 	"	memcpy((uchar *) f->m_now,  (uchar *) &now, vsize);",
2118 	"#if !defined(NOCOMP) && !defined(HC)",
2119 	"	memset((uchar *) f->m_mask, 0, (VMAX+7)/8 * sizeof(char));",
2120 	"	for (i = j = 0; i < VMAX; i++, j = (j+1)%%8)",
2121 	"	{	if (Mask[i])",
2122 	"		{	f->m_mask[i/8] |= (1<<j);",
2123 	"	}	}",
2124 	"#endif",
2125 	"	if (now._nr_pr > 0)",
2126 	"	{ memcpy((uchar *) f->m_p_offset, (uchar *) proc_offset, now._nr_pr * sizeof(OFFT));",
2127 	"	  memcpy((uchar *) f->m_p_skip,   (uchar *) proc_skip,   now._nr_pr * sizeof(uchar));",
2128 	"	}",
2129 	"	if (now._nr_qs > 0)",
2130 	"	{ memcpy((uchar *) f->m_q_offset, (uchar *) q_offset, now._nr_qs * sizeof(OFFT));",
2131 	"	  memcpy((uchar *) f->m_q_skip,   (uchar *) q_skip,   now._nr_qs * sizeof(uchar));",
2132 	"	}",
2133 	"#if defined(C_States) && (HAS_TRACK==1) && (HAS_STACK==1)",
2134 	"	c_stack((uchar *) f->m_c_stack); /* save unmatched tracked data */",
2135 	"#endif",
2136 	"#ifdef FULL_TRAIL",
2137 	"	f->m_stack = stack_last[core_id];",
2138 	"#endif",
2139 	"	f->nr_handoffs = nr_handoffs+1;",
2140 	"	f->m_tau    = trpt->tau;",
2141 	"	f->m_o_pm   = trpt->o_pm;",
2142 	"	f->m_boq    = boq;",
2143 	"	f->m_vsize  = vsize;	/* must come last - now the other cpu can see it */",
2144 	"",
2145 	"	if (query_in_progress == 1)",
2146 	"		query_in_progress = 2;	/* make sure we know, if a query makes the rounds */",
2147 	"	nstates_put++;",
2148 	"}",
2149 	"",
2150 	"#ifdef USE_DISK",
2151 	"int Dsk_W_Nr, Dsk_R_Nr;",
2152 	"int dsk_file = -1, dsk_read = -1;",
2153 	"unsigned long dsk_written, dsk_drained;",
2154 	"char dsk_name[512];",
2155 	"",
2156 	"#ifndef BFS_DISK",
2157 	"#if defined(WIN32) || defined(WIN64)",
2158 	"	#define RFLAGS	(O_RDONLY|O_BINARY)",
2159 	"	#define WFLAGS	(O_CREAT|O_WRONLY|O_TRUNC|O_BINARY)",
2160 	"#else",
2161 	"	#define RFLAGS	(O_RDONLY)",
2162 	"	#define WFLAGS	(O_CREAT|O_WRONLY|O_TRUNC)",
2163 	"#endif",
2164 	"#endif",
2165 	"",
2166 	"void",
2167 	"dsk_stats(void)",
2168 	"{	int i;",
2169 	"",
2170 	"	if (dsk_written > 0)",
2171 	"	{	cpu_printf(\"dsk_written %%d states in %%d files\\ncpu%%d: dsk_drained %%6d states\\n\",",
2172 	"			dsk_written, Dsk_W_Nr, core_id, dsk_drained);",
2173 	"		close(dsk_read);",
2174 	"		close(dsk_file);",
2175 	"		for (i = 0; i < Dsk_W_Nr; i++)",
2176 	"		{	sprintf(dsk_name, \"Q%%.3d_%%.3d.tmp\", i, core_id);",
2177 	"			unlink(dsk_name);",
2178 	"	}	}",
2179 	"}",
2180 	"",
2181 	"void",
2182 	"mem_drain(void)",
2183 	"{	SM_frame *f, g;",
2184 	"	int q = (core_id + 1) %% NCORE;	/* target q */",
2185 	"	int sz;",
2186 	"",
2187 	"	if (dsk_read < 0",
2188 	"	||  dsk_written <= dsk_drained)",
2189 	"	{	return;",
2190 	"	}",
2191 	"",
2192 	"	while (dsk_written > dsk_drained",
2193 	"	&& TargetQ_NotFull(q))",
2194 	"	{	f = Get_Free_Frame(q);",
2195 	"		if (!f) { Uerror(\"Fatal: unhandled condition\"); }",
2196 	"",
2197 	"		if ((dsk_drained+1)%%MAX_DSK_FILE == 0)	/* 100K states max per file */",
2198 	"		{	(void) close(dsk_read); 	/* close current read handle */",
2199 	"			sprintf(dsk_name, \"Q%%.3d_%%.3d.tmp\", Dsk_R_Nr++, core_id);",
2200 	"			(void) unlink(dsk_name);	/* remove current file */",
2201 	"			sprintf(dsk_name, \"Q%%.3d_%%.3d.tmp\", Dsk_R_Nr, core_id);",
2202 	"			cpu_printf(\"reading %%s\\n\", dsk_name);",
2203 	"			dsk_read = open(dsk_name, RFLAGS); /* open next file */",
2204 	"			if (dsk_read < 0)",
2205 	"			{	Uerror(\"could not open dsk file\");",
2206 	"		}	}",
2207 	"		if (read(dsk_read, &g, sizeof(SM_frame)) != sizeof(SM_frame))",
2208 	"		{	Uerror(\"bad dsk file read\");",
2209 	"		}",
2210 	"		sz = g.m_vsize;",
2211 	"		g.m_vsize = 0;",
2212 	"		memcpy(f, &g, sizeof(SM_frame));",
2213 	"		f->m_vsize = sz;	/* last */",
2214 	"",
2215 	"		dsk_drained++;",
2216 	"	}",
2217 	"}",
2218 	"",
2219 	"void",
2220 	"mem_file(void)",
2221 	"{	SM_frame f;",
2222 	"	int i, j, q = (core_id + 1) %% NCORE;	/* target q */",
2223 	"",
2224 	"	if (vsize > VMAX)",
2225 	"	{	printf(\"pan: recompile with -DVMAX=N with N >= %%d\\n\", vsize);",
2226 	"		Uerror(\"aborting\");",
2227 	"	}",
2228 	"	if (now._nr_pr > PMAX)",
2229 	"	{	printf(\"pan: recompile with -DPMAX=N with N >= %%d\\n\", now._nr_pr);",
2230 	"		Uerror(\"aborting\");",
2231 	"	}",
2232 	"	if (now._nr_qs > QMAX)",
2233 	"	{	printf(\"pan: recompile with -DQMAX=N with N >= %%d\\n\", now._nr_qs);",
2234 	"		Uerror(\"aborting\");",
2235 	"	}",
2236 	"",
2237 	"	if (VVERBOSE) cpu_printf(\"filing state for q%%d\\n\", q);",
2238 	"",
2239 	"	memcpy((uchar *) f.m_now,  (uchar *) &now, vsize);",
2240 	"#if !defined(NOCOMP) && !defined(HC)",
2241 	"	memset((uchar *) f.m_mask, 0, (VMAX+7)/8 * sizeof(char));",
2242 	"	for (i = j = 0; i < VMAX; i++, j = (j+1)%%8)",
2243 	"	{	if (Mask[i])",
2244 	"		{	f.m_mask[i/8] |= (1<<j);",
2245 	"	}	}",
2246 	"#endif",
2247 	"	if (now._nr_pr > 0)",
2248 	"	{	memcpy((uchar *)f.m_p_offset, (uchar *)proc_offset, now._nr_pr*sizeof(OFFT));",
2249 	"		memcpy((uchar *)f.m_p_skip,   (uchar *)proc_skip,   now._nr_pr*sizeof(uchar));",
2250 	"	}",
2251 	"	if (now._nr_qs > 0)",
2252 	"	{	memcpy((uchar *) f.m_q_offset, (uchar *) q_offset, now._nr_qs*sizeof(OFFT));",
2253 	"		memcpy((uchar *) f.m_q_skip,   (uchar *) q_skip,   now._nr_qs*sizeof(uchar));",
2254 	"	}",
2255 	"#if defined(C_States) && (HAS_TRACK==1) && (HAS_STACK==1)",
2256 	"	c_stack((uchar *) f.m_c_stack); /* save unmatched tracked data */",
2257 	"#endif",
2258 	"#ifdef FULL_TRAIL",
2259 	"	f.m_stack  = stack_last[core_id];",
2260 	"#endif",
2261 	"	f.nr_handoffs = nr_handoffs+1;",
2262 	"	f.m_tau    = trpt->tau;",
2263 	"	f.m_o_pm   = trpt->o_pm;",
2264 	"	f.m_boq    = boq;",
2265 	"	f.m_vsize  = vsize;",
2266 	"",
2267 	"	if (query_in_progress == 1)",
2268 	"	{	query_in_progress = 2;",
2269 	"	}",
2270 	"	if (dsk_file < 0)",
2271 	"	{	sprintf(dsk_name, \"Q%%.3d_%%.3d.tmp\", Dsk_W_Nr, core_id);",
2272 	"		dsk_file = open(dsk_name, WFLAGS, 0644);",
2273 	"		dsk_read = open(dsk_name, RFLAGS);",
2274 	"		if (dsk_file < 0 || dsk_read < 0)",
2275 	"		{	cpu_printf(\"File: <%%s>\\n\", dsk_name);",
2276 	"			Uerror(\"cannot open diskfile\");",
2277 	"		}",
2278 	"		Dsk_W_Nr++; /* nr of next file to open */",
2279 	"		cpu_printf(\"created temporary diskfile %%s\\n\", dsk_name);",
2280 	"	} else if ((dsk_written+1)%%MAX_DSK_FILE == 0)",
2281 	"	{	close(dsk_file); /* close write handle */",
2282 	"		sprintf(dsk_name, \"Q%%.3d_%%.3d.tmp\", Dsk_W_Nr++, core_id);",
2283 	"		dsk_file = open(dsk_name, WFLAGS, 0644);",
2284 	"		if (dsk_file < 0)",
2285 	"		{	cpu_printf(\"File: <%%s>\\n\", dsk_name);",
2286 	"			Uerror(\"aborting: cannot open new diskfile\");",
2287 	"		}",
2288 	"		cpu_printf(\"created temporary diskfile %%s\\n\", dsk_name);",
2289 	"	}",
2290 	"	if (write(dsk_file, &f, sizeof(SM_frame)) != sizeof(SM_frame))",
2291 	"	{	Uerror(\"aborting -- disk write failed (disk full?)\");",
2292 	"	}",
2293 	"	nstates_put++;",
2294 	"	dsk_written++;",
2295 	"}",
2296 	"#endif",
2297 	"",
2298 	"int",
2299 	"mem_hand_off(void)",
2300 	"{",
2301 	"	if (search_terminated == NULL",
2302 	"	||  *search_terminated != 0)	/* not a full crash check */",
2303 	"	{	pan_exit(0);",
2304 	"	}",
2305 	"	iam_alive();		/* on every transition of Down */",
2306 	"#ifdef USE_DISK",
2307 	"	mem_drain();		/* maybe call this also on every Up */",
2308 	"#endif",
2309 	"	if (depth > z_handoff	/* above handoff limit */",
2310 	"#ifndef SAFETY",
2311 	"	&&  !a_cycles		/* not in liveness mode */",
2312 	"#endif",
2313 	"#if SYNC",
2314 	"	&&  boq == -1		/* not mid-rv */",
2315 	"#endif",
2316 	"#ifdef VERI",
2317 	"	&&  (trpt->tau&4)	 /* claim moves first  */",
2318 	"	&&  !((trpt-1)->tau&128) /* not a stutter move */",
2319 	"#endif",
2320 	"	&&  !(trpt->tau&8))	/* not an atomic move */",
2321 	"	{	int q = (core_id + 1) %% NCORE;	/* circular handoff */",
2322 	"	#ifdef GENEROUS",
2323 	"		if (prcnt[q] < LN_FRAMES)", /* not the best strategy */
2324 	"	#else",
2325 	"		if (TargetQ_NotFull(q)",
2326 	"		&& (dfs_phase2 == 0 || prcnt[core_id] > 0))", /* not locked, ok if race */
2327 	"	#endif",
2328 	"		{	mem_put(q);",	/* only 1 writer: lock-free */
2329 	"			return 1;",
2330 	"		}",
2331 	"		{	int rval;",
2332 	"	#ifndef NGQ",
2333 	"			rval = GlobalQ_HasRoom();",
2334 	"	#else",
2335 	"			rval = 0;",
2336 	"	#endif",
2337 	"	#ifdef USE_DISK",
2338 	"			if (rval == 0)",
2339 	"			{	void mem_file(void);",
2340 	"				mem_file();",
2341 	"				rval = 1;",
2342 	"			}",
2343 	"	#endif",
2344 	"			return rval;",
2345 	"		}",
2346 	"	}",
2347 	"	return 0; /* i.e., no handoff */",
2348 	"}",
2349 	"",
2350 	"void",
2351 	"mem_put_acc(void)	/* liveness mode */",
2352 	"{	int q = (core_id + 1) %% NCORE;",
2353 	"",
2354 	"	if (search_terminated == NULL",
2355 	"	||  *search_terminated != 0)",
2356 	"	{	pan_exit(0);",
2357 	"	}",
2358 	"#ifdef USE_DISK",
2359 	"	mem_drain();",
2360 	"#endif",
2361 	"	/* some tortured use of preprocessing: */",
2362 	"#if !defined(NGQ) || defined(USE_DISK)",
2363 	"	if (TargetQ_Full(q))",
2364 	"	{",
2365 	"#endif",
2366 	"#ifndef NGQ",
2367 	"		if (GlobalQ_HasRoom())",
2368 	"		{	return;",
2369 	"		}",
2370 	"#endif",
2371 	"#ifdef USE_DISK",
2372 	"		mem_file();",
2373 	"	} else",
2374 	"#else",
2375 	"	#if !defined(NGQ) || defined(USE_DISK)",
2376 	"	}",
2377 	"	#endif",
2378 	"#endif",
2379 	"	{	mem_put(q);",
2380 	"	}",
2381 	"}",
2382 	"",
2383 	"#if defined(WIN32) || defined(WIN64)", /* visual studio */
2384 	"void",
2385 	"init_shm(void)		/* initialize shared work-queues */",
2386 	"{	char	key[512];",
2387 	"	int	n, m;",
2388 	"	int	must_exit = 0;",
2389 	"",
2390 	"	if (core_id == 0 && verbose)",
2391 	"	{	printf(\"cpu0: step 3: allocate shared work-queues %%g Mb\\n\",",
2392 	"			((double) NCORE * LWQ_SIZE + GWQ_SIZE) / (1048576.));",
2393 	"	}",
2394 	"	for (m = 0; m < NR_QS; m++)	/* last q is global 1 */",
2395 	"	{	double qsize = (m == NCORE) ? GWQ_SIZE : LWQ_SIZE;",
2396 	"		sprintf(key, \"Global\\\\pan_%%s_%%.3d\", PanSource, m);",
2397 	"		if (core_id == 0)",	/* root process creates shared memory segments */
2398 	"		{	shmid[m] = CreateFileMapping(",
2399 	"				INVALID_HANDLE_VALUE,	/* use paging file */",
2400 	"				NULL,			/* default security */",
2401 	"				PAGE_READWRITE,		/* access permissions */",
2402 	"				0,			/* high-order 4 bytes */",
2403 	"				qsize,			/* low-order bytes, size in bytes */",
2404 	"				key);			/* name */",
2405 	"		} else			/* worker nodes just open these segments */",
2406 	"		{	shmid[m] = OpenFileMapping(",
2407 	"				FILE_MAP_ALL_ACCESS,	/* read/write access */",
2408 	"				FALSE,			/* children do not inherit handle */",
2409 	"				key);",
2410 	"		}",
2411 	"		if (shmid[m] == NULL)",
2412 	"		{	fprintf(stderr, \"cpu%%d: could not create or open shared queues\\n\",",
2413 	"				core_id);",
2414 	"			must_exit = 1;",
2415 	"			break;",
2416 	"		}",
2417 	"		/* attach: */",
2418 	"		shared_mem[m] = (char *) MapViewOfFile(shmid[m], FILE_MAP_ALL_ACCESS, 0, 0, 0);",
2419 	"		if (shared_mem[m] == NULL)",
2420 	"		{ fprintf(stderr, \"cpu%%d: cannot attach shared q%%d (%%d Mb)\\n\",",
2421 	"			core_id, m+1, (int) (qsize/(1048576.)));",
2422 	"		  must_exit = 1;",
2423 	"		  break;",
2424 	"		}",
2425 	"",
2426 	"		memcnt += qsize;",
2427 	"",
2428 	"		m_workq[m] = (SM_frame *) shared_mem[m];",
2429 	"		if (core_id == 0)",
2430 	"		{	int nframes = (m == NCORE) ? GN_FRAMES : LN_FRAMES;",
2431 	"			for (n = 0; n < nframes; n++)",
2432 	"			{	m_workq[m][n].m_vsize = 0;",
2433 	"				m_workq[m][n].m_boq = 0;",
2434 	"	}	}	}",
2435 	"",
2436 	"	if (must_exit)",
2437 	"	{	fprintf(stderr, \"pan: check './pan --' for usage details\\n\");",
2438 	"		pan_exit(1);	/* calls cleanup_shm */",
2439 	"	}",
2440 	"}",
2441 	"",
2442 	"static uchar *",
2443 	"prep_shmid_S(size_t n)		/* either sets SS or H_tab, WIN32/WIN64 */",
2444 	"{	char	*rval;",
2445 	"#ifndef SEP_STATE",
2446 	"	char	key[512];",
2447 	"",
2448 	"	if (verbose && core_id == 0)",
2449 	"	{",
2450 	"	#ifdef BITSTATE",
2451 	"		printf(\"cpu0: step 1: allocate shared bitstate %%g Mb\\n\",",
2452 	"			(double) n / (1048576.));",
2453 	"	#else",
2454 	"		printf(\"cpu0: step 1: allocate shared hastable %%g Mb\\n\",",
2455 	"			(double) n / (1048576.));",
2456 	"	#endif",
2457 	"	}",
2458 	"	#ifdef MEMLIM",
2459 	"	if (memcnt + (double) n > memlim)",
2460 	"	{	printf(\"cpu%%d: S %%8g + %%d Kb exceeds memory limit of %%8g Mb\\n\",",
2461 	"			core_id, memcnt/1024., n/1024, memlim/(1048576.));",
2462 	"		printf(\"cpu%%d: insufficient memory -- aborting\\n\", core_id);",
2463 	"		exit(1);",
2464 	"	}",
2465 	"	#endif",
2466 	"",
2467 	"	/* make key different from queues: */",
2468 	"	sprintf(key, \"Global\\\\pan_%%s_%%.3d\", PanSource, NCORE+2); /* different from qs */",
2469 	"",
2470 	"	if (core_id == 0)	/* root */",
2471 	"	{	shmid_S = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,",
2472 	"#ifdef WIN64",
2473 	"			PAGE_READWRITE, (n>>32), (n & 0xffffffff), key);",
2474 	"#else",
2475 	"			PAGE_READWRITE, 0, n, key);",
2476 	"#endif",
2477 	"		memcnt += (double) n;",
2478 	"	} else			/* worker */",
2479 	"	{	shmid_S = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, key);",
2480 	"	}",
2481 
2482 	"	if (shmid_S == NULL)",
2483 	"	{",
2484 	"	#ifdef BITSTATE",
2485 	"		fprintf(stderr, \"cpu%%d: cannot %%s shared bitstate\",",
2486 	"			core_id, core_id?\"open\":\"create\");",
2487 	"	#else",
2488 	"		fprintf(stderr, \"cpu%%d: cannot %%s shared hashtable\",",
2489 	"			core_id, core_id?\"open\":\"create\");",
2490 	"	#endif",
2491 	"		fprintf(stderr, \"pan: check './pan --' for usage details\\n\");",
2492 	"		pan_exit(1);",
2493 	"	}",
2494 	"",
2495 	"	rval = (char *) MapViewOfFile(shmid_S, FILE_MAP_ALL_ACCESS, 0, 0, 0);	/* attach */",
2496 	"	if ((char *) rval == NULL)",
2497 	"	{ fprintf(stderr, \"cpu%%d: cannot attach shared bitstate or hashtable\\n\", core_id);",
2498 	"	  fprintf(stderr, \"pan: check './pan --' for usage details\\n\");",
2499 	"	  pan_exit(1);",
2500 	"	}",
2501 	"#else",
2502 	"	rval = (char *) emalloc(n);",
2503 	"#endif",
2504 	"	return (uchar *) rval;",
2505 	"}",
2506 	"",
2507 	"static uchar *",
2508 	"prep_state_mem(size_t n)		/* WIN32/WIN64 sets memory arena for states */",
2509 	"{	char	*rval;",
2510 	"	char	key[512];",
2511 	"	static int cnt = 3;		/* start larger than earlier ftok calls */",
2512 	"",
2513 	"	if (verbose && core_id == 0)",
2514 	"	{	printf(\"cpu0: step 2+: pre-allocate memory arena %%d of %%g Mb\\n\",",
2515 	"			cnt-3, (double) n / (1048576.));",
2516 	"	}",
2517 	"	#ifdef MEMLIM",
2518 	"	if (memcnt + (double) n > memlim)",
2519 	"	{	printf(\"cpu%%d: error: M %%.0f + %%.0f exceeds memory limit of %%.0f Kb\\n\",",
2520 	"			core_id, memcnt/1024.0, (double) n/1024.0, memlim/1024.0);",
2521 	"		return NULL;",
2522 	"	}",
2523 	"	#endif",
2524 	"",
2525 	"	sprintf(key, \"Global\\\\pan_%%s_%%.3d\", PanSource, NCORE+cnt); cnt++;",
2526 	"",
2527 	"	if (core_id == 0)",
2528 	"	{	shmid_M = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,",
2529 	"#ifdef WIN64",
2530 	"			PAGE_READWRITE, (n>>32), (n & 0xffffffff), key);",
2531 	"#else",
2532 	"			PAGE_READWRITE, 0, n, key);",
2533 	"#endif",
2534 	"	} else",
2535 	"	{	shmid_M = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, key);",
2536 	"	}",
2537 	"	if (shmid_M == NULL)",
2538 	"	{	printf(\"cpu%%d: failed to get pool of shared memory nr %%d of size %%d\\n\",",
2539 	"			core_id, cnt-3, n);",
2540 	"		printf(\"pan: check './pan --' for usage details\\n\");",
2541 	"		return NULL;",
2542 	"	}",
2543 	"	rval = (char *) MapViewOfFile(shmid_M, FILE_MAP_ALL_ACCESS, 0, 0, 0);	/* attach */",
2544 	"",
2545 	"	if (rval == NULL)",
2546 	"	{ printf(\"cpu%%d: failed to attach pool of shared memory nr %%d of size %%d\\n\",",
2547 	"		core_id, cnt-3, n);",
2548 	"	  return NULL;",
2549 	"	}",
2550 	"	return (uchar *) rval;",
2551 	"}",
2552 	"",
2553 	"void",
2554 	"init_HT(unsigned long n)	/* WIN32/WIN64 version */",
2555 	"{	volatile char	*x;",
2556 	"	double  get_mem;",
2557 	"#ifndef SEP_STATE",
2558 	"	char	*dc_mem_start;",
2559 	"#endif",
2560 	"	if (verbose) printf(\"cpu%%d: initialization for Windows\\n\", core_id);",
2561 	"",
2562 "#ifdef SEP_STATE",
2563 	" #ifndef MEMLIM",
2564 	"	if (verbose)",
2565 	"	{	printf(\"cpu0: steps 0,1: no -DMEMLIM set\\n\");",
2566 	"	}",
2567 	" #else",
2568 	"	if (verbose)",
2569 	"	printf(\"cpu0: steps 0,1: -DMEMLIM=%%d Mb - (hashtable %%g Mb + workqueues %%g Mb)\\n\",",
2570 	"		MEMLIM, ((double)n/(1048576.)), ((double) NCORE * LWQ_SIZE + GWQ_SIZE)/(1048576.));",
2571 	"#endif",
2572 	"	get_mem = NCORE * sizeof(double) + (1 + CS_NR) * sizeof(void *)+ 4*sizeof(void *) + 2*sizeof(double);",
2573 	"	/* NCORE * is_alive + search_terminated + CS_NR * sh_lock + 6 gr vars */",
2574 	"	get_mem += 4 * NCORE * sizeof(void *);", /* prfree, prfull, prcnt, prmax */
2575 	" #ifdef FULL_TRAIL",
2576 	"	get_mem += (NCORE) * sizeof(Stack_Tree *);",
2577 	"	/* NCORE * stack_last */",
2578 	" #endif",
2579 	"	x = (volatile char *) prep_state_mem((size_t) get_mem);",
2580 	"	shmid_X = (void *) x;",
2581 	"	if (x == NULL)",
2582 	"	{	printf(\"cpu0: could not allocate shared memory, see ./pan --\\n\");",
2583 	"		exit(1);",
2584 	"	}",
2585 	"	search_terminated = (volatile unsigned int *) x; /* comes first */",
2586 	"	x += sizeof(void *); /* maintain alignment */",
2587 	"",
2588 	"	is_alive   = (volatile double *) x;",
2589 	"	x += NCORE * sizeof(double);",
2590 	"",
2591 	"	sh_lock   = (volatile int *) x;",
2592 	"	x += CS_NR * sizeof(void *); /* allow 1 word per entry */",
2593 	"",
2594 	"	grfree    = (volatile int *) x;",
2595 	"	x += sizeof(void *);",
2596 	"	grfull    = (volatile int *) x;",
2597 	"	x += sizeof(void *);",
2598 	"	grcnt    = (volatile int *) x;",
2599 	"	x += sizeof(void *);",
2600 	"	grmax    = (volatile int *) x;",
2601 	"	x += sizeof(void *);",
2602 	"	prfree = (volatile int *) x;",
2603 	"	x += NCORE * sizeof(void *);",
2604 	"	prfull = (volatile int *) x;",
2605 	"	x += NCORE * sizeof(void *);",
2606 	"	prcnt = (volatile int *) x;",
2607 	"	x += NCORE * sizeof(void *);",
2608 	"	prmax = (volatile int *) x;",
2609 	"	x += NCORE * sizeof(void *);",
2610 	"	gr_readmiss    = (volatile double *) x;",
2611 	"	x += sizeof(double);",
2612 	"	gr_writemiss    = (volatile double *) x;",
2613 	"	x += sizeof(double);",
2614 	"",
2615 	"	#ifdef FULL_TRAIL",
2616 	"		stack_last = (volatile Stack_Tree **) x;",
2617 	"		x += NCORE * sizeof(Stack_Tree *);",
2618 	"	#endif",
2619 	"",
2620 	"	#ifndef BITSTATE",
2621 	"		H_tab = (H_el **) emalloc(n);",
2622 	"	#endif",
2623 "#else",
2624 	"	#ifndef MEMLIM",
2625 	"		#warning MEMLIM not set",	/* cannot happen */
2626 	"		#define MEMLIM	(2048)",
2627 	"	#endif",
2628 	"",
2629 	"	if (core_id == 0 && verbose)",
2630 	"		printf(\"cpu0: step 0: -DMEMLIM=%%d Mb - (hashtable %%g Mb + workqueues %%g Mb) = %%g Mb for state storage\\n\",",
2631 	"		MEMLIM, ((double)n/(1048576.)), ((double) NCORE * LWQ_SIZE + GWQ_SIZE)/(1048576.),",
2632 	"		(memlim - memcnt - (double) n - ((double) NCORE * LWQ_SIZE + GWQ_SIZE))/(1048576.));",
2633 	"	#ifndef BITSTATE",
2634 	"		H_tab = (H_el **) prep_shmid_S((size_t) n);	/* hash_table */",
2635 	"	#endif",
2636 	"	get_mem = memlim - memcnt - ((double) NCORE) * LWQ_SIZE - GWQ_SIZE;",
2637 	"	if (get_mem <= 0)",
2638 	"	{	Uerror(\"internal error -- shared state memory\");",
2639 	"	}",
2640 	"",
2641 	"	if (core_id == 0 && verbose)",
2642 	"	{	printf(\"cpu0: step 2: shared state memory %%g Mb\\n\",",
2643 	"			get_mem/(1048576.));",
2644 	"	}",
2645 	"	x = dc_mem_start = (char *) prep_state_mem((size_t) get_mem);	/* for states */",
2646 	"	if (x == NULL)",
2647 	"	{	printf(\"cpu%%d: insufficient memory -- aborting\\n\", core_id);",
2648 	"		exit(1);",
2649 	"	}",
2650 	"",
2651 	"	search_terminated = (volatile unsigned int *) x; /* comes first */",
2652 	"	x += sizeof(void *); /* maintain alignment */",
2653 	"",
2654 	"	is_alive   = (volatile double *) x;",
2655 	"	x += NCORE * sizeof(double);",
2656 	"",
2657 	"	sh_lock   = (volatile int *) x;",
2658 	"	x += CS_NR * sizeof(int);",
2659 	"",
2660 	"	grfree    = (volatile int *) x;",
2661 	"	x += sizeof(void *);",
2662 	"	grfull    = (volatile int *) x;",
2663 	"	x += sizeof(void *);",
2664 	"	grcnt    = (volatile int *) x;",
2665 	"	x += sizeof(void *);",
2666 	"	grmax    = (volatile int *) x;",
2667 	"	x += sizeof(void *);",
2668 	"	prfree = (volatile int *) x;",
2669 	"	x += NCORE * sizeof(void *);",
2670 	"	prfull = (volatile int *) x;",
2671 	"	x += NCORE * sizeof(void *);",
2672 	"	prcnt = (volatile int *) x;",
2673 	"	x += NCORE * sizeof(void *);",
2674 	"	prmax = (volatile int *) x;",
2675 	"	x += NCORE * sizeof(void *);",
2676 	"	gr_readmiss = (volatile double *) x;",
2677 	"	x += sizeof(double);",
2678 	"	gr_writemiss = (volatile double *) x;",
2679 	"	x += sizeof(double);",
2680 	"",
2681 	" #ifdef FULL_TRAIL",
2682 	"	stack_last = (volatile Stack_Tree **) x;",
2683 	"	x += NCORE * sizeof(Stack_Tree *);",
2684 	" #endif",
2685 	"	if (((long)x)&(sizeof(void *)-1))	/* word alignment */",
2686 	"	{	x += sizeof(void *)-(((long)x)&(sizeof(void *)-1)); /* 64-bit align */",
2687 	"	}",
2688 	"",
2689 	"	#ifdef COLLAPSE",
2690 	"	ncomps = (unsigned long *) x;",
2691 	"	x += (256+2) * sizeof(unsigned long);",
2692 	"	#endif",
2693 	"",
2694 	"	dc_shared = (sh_Allocater *) x; /* in shared memory */",
2695 	"	x += sizeof(sh_Allocater);",
2696 	"",
2697 	"	if (core_id == 0)	/* root only */",
2698 	"	{	dc_shared->dc_id     = shmid_M;",
2699 	"		dc_shared->dc_start  = (void *) dc_mem_start;",
2700 	"		dc_shared->dc_arena  = x;",
2701 	"		dc_shared->pattern   = 1234567;",
2702 	"		dc_shared->dc_size   = (long) get_mem - (long) (x - dc_mem_start);",
2703 	"		dc_shared->nxt       = NULL;",
2704 	"	}",
2705 "#endif",
2706 	"}",
2707 	"",
2708 	"#if defined(WIN32) || defined(WIN64) || defined(__i386__) || defined(__x86_64__)",
2709 	"extern BOOLEAN InterlockedBitTestAndSet(LONG volatile* Base, LONG Bit);",
2710 	"int",
2711 	"tas(volatile LONG *s)", /* atomic test and set */
2712 	"{	return InterlockedBitTestAndSet(s, 1);",
2713 	"}",
2714 	"#else",
2715 	"	#error missing definition of test and set operation for this platform",
2716 	"#endif",
2717 	"",
2718 	"void",
2719 	"cleanup_shm(int val)",
2720 	"{	int m;",
2721 	"	static int nibis = 0;",
2722 	"",
2723 	"	if (nibis != 0)",
2724 	"	{	printf(\"cpu%%d: Redundant call to cleanup_shm(%%d)\\n\", core_id, val);",
2725 	"		return;",
2726 	"	} else",
2727 	"	{	nibis = 1;",
2728 	"	}",
2729 	"	if (search_terminated != NULL)",
2730 	"	{	*search_terminated |= 16; /* cleanup_shm */",
2731 	"	}",
2732 	"",
2733 	"	for (m = 0; m < NR_QS; m++)",
2734 	"	{	if (shmid[m] != NULL)",
2735 	"		{	UnmapViewOfFile((char *) shared_mem[m]);",
2736 	"			CloseHandle(shmid[m]);",
2737 	"	}	}",
2738 	"#ifdef SEP_STATE",
2739 	"	UnmapViewOfFile((void *) shmid_X);",
2740 	"	CloseHandle((void *) shmid_M);",
2741 	"#else",
2742 	"	#ifdef BITSTATE",
2743 	"		if (shmid_S != NULL)",
2744 	"		{	UnmapViewOfFile(SS);",
2745 	"			CloseHandle(shmid_S);",
2746 	"		}",
2747 	"	#else",
2748 	"		if (core_id == 0 && verbose)",
2749 	"		{	printf(\"cpu0: done, %%ld Mb of shared state memory left\\n\",",
2750 	"				dc_shared->dc_size / (long)(1048576));",
2751 	"		}",
2752 	"		if (shmid_S != NULL)",
2753 	"		{	UnmapViewOfFile(H_tab);",
2754 	"			CloseHandle(shmid_S);",
2755 	"		}",
2756 	"		shmid_M = (void *) (dc_shared->dc_id);",
2757 	"		UnmapViewOfFile((char *) dc_shared->dc_start);",
2758 	"		CloseHandle(shmid_M);",
2759 	"	#endif",
2760 	"#endif",
2761 	"	/* detached from shared memory - so cannot use cpu_printf */",
2762 	"	if (verbose)",
2763 	"	{	printf(\"cpu%%d: done -- got %%d states from queue\\n\",",
2764 	"			core_id, nstates_get);",
2765 	"	}",
2766 	"}",
2767 	"",
2768 	"void",
2769 	"mem_get(void)",
2770 	"{	SM_frame   *f;",
2771 	"	int is_parent;",
2772 	"",
2773 	"#if defined(MA) && !defined(SEP_STATE)",
2774 	"	#error MA requires SEP_STATE in multi-core mode",
2775 	"#endif",
2776 	"#ifdef BFS",
2777 	"	#error instead of -DNCORE -DBFS use -DBFS_PAR",
2778 	"#endif",
2779 	"#ifdef SC",
2780 	"	#error SC is not supported in multi-core mode",
2781 	"#endif",
2782 	"	init_shm();	/* we are single threaded when this starts */",
2783 	"	signal(SIGINT, give_up);	/* windows control-c interrupt */",
2784 	"",
2785 	"	if (core_id == 0 && verbose)",
2786 	"	{	printf(\"cpu0: step 4: creating additional workers (proxy %%d)\\n\",",
2787 	"			proxy_pid);",
2788 	"	}",
2789 	"#if 0",
2790 	"	if NCORE > 1 the child or the parent should fork N-1 more times",
2791 	"	the parent is the only process with core_id == 0 and is_parent > 0",
2792 	"	the others (workers) have is_parent = 0 and core_id = 1..NCORE-1",
2793 	"#endif",
2794 	"	if (core_id == 0)			/* root starts up the workers */",
2795 	"	{	worker_pids[0] = (DWORD) getpid();	/* for completeness */",
2796 	"		while (++core_id < NCORE)	/* first worker sees core_id = 1 */",
2797 	"		{	char cmdline[64];",
2798 	"			STARTUPINFO si = { sizeof(si) };",
2799 	"			PROCESS_INFORMATION pi;",
2800 	"",
2801 	"			if (proxy_pid == core_id)	/* always non-zero */",
2802 	"			{	sprintf(cmdline, \"pan_proxy.exe -r %%s-Q%%d -Z%%d\",",
2803 	"					o_cmdline, getpid(), core_id);",
2804 	"			} else",
2805 	"			{	sprintf(cmdline, \"pan.exe %%s-Q%%d -Z%%d\",",
2806 	"					o_cmdline, getpid(), core_id);",
2807 	"			}",
2808 	"			if (verbose) printf(\"cpu%%d: spawn %%s\\n\", core_id, cmdline);",
2809 	"",
2810 	"			is_parent = CreateProcess(0, cmdline, 0, 0, FALSE, 0, 0, 0, &si, &pi);",
2811 	"			if (is_parent == 0)",
2812 	"			{	Uerror(\"fork failed\");",
2813 	"			}",
2814 	"			worker_pids[core_id] = pi.dwProcessId;",
2815 	"			worker_handles[core_id] = pi.hProcess;",
2816 	"			if (verbose)",
2817 	"			{	cpu_printf(\"created core %%d, pid %%d\\n\",",
2818 	"					core_id, pi.dwProcessId);",
2819 	"			}",
2820 	"			if (proxy_pid == core_id)	/* we just created the receive half */",
2821 	"			{	/* add proxy send, store pid in proxy_pid_snd */",
2822 	"				sprintf(cmdline, \"pan_proxy.exe -s %%s-Q%%d -Z%%d -Y%%d\",",
2823 	"					o_cmdline, getpid(), core_id, worker_pids[proxy_pid]);",
2824 	"				if (verbose) printf(\"cpu%%d: spawn %%s\\n\", core_id, cmdline);",
2825 	"				is_parent = CreateProcess(0, cmdline, 0,0, FALSE, 0,0,0, &si, &pi);",
2826 	"				if (is_parent == 0)",
2827 	"				{	Uerror(\"fork failed\");",
2828 	"				}",
2829 	"				proxy_pid_snd = pi.dwProcessId;",
2830 	"				proxy_handle_snd = pi.hProcess;",
2831 	"				if (verbose)",
2832 	"				{	cpu_printf(\"created core %%d, pid %%d (send proxy)\\n\",",
2833 	"						core_id, pi.dwProcessId);",
2834 	"		}	}	}",
2835 	"		core_id = 0;		/* reset core_id for root process */",
2836 	"	} else	/* worker */",
2837 	"	{	static char db0[16];	/* good for up to 10^6 cores */",
2838 	"		static char db1[16];",
2839 	"		tprefix = db0; sprefix = db1;",
2840 	"		sprintf(tprefix, \"cpu%%d_trail\", core_id);	/* avoid conflicts on file access */",
2841 	"		sprintf(sprefix, \"cpu%%d_rst\", core_id);",
2842 	"		memcnt = 0;	/* count only additionally allocated memory */",
2843 	"	}",
2844 	"	if (verbose)",
2845 	"	{	cpu_printf(\"starting core_id %%d -- pid %%d\\n\", core_id, getpid());",
2846 	"	}",
2847 	"	if (core_id == 0 && !remote_party)",
2848 	"	{	new_state();	/* root starts the search */",
2849 	"		if (verbose)",
2850 	"		cpu_printf(\"done with 1st dfs, nstates %%g (put %%d states), start reading q\\n\",",
2851 	"			nstates, nstates_put);",
2852 	"		dfs_phase2 = 1;",
2853 	"	}",
2854 	"	Read_Queue(core_id);	/* all cores */",
2855 	"",
2856 	"	if (verbose)",
2857 	"	{	cpu_printf(\"put %%6d states into queue -- got %%6d\\n\",",
2858 	"			nstates_put, nstates_get);",
2859 	"	}",
2860 	"	done = 1;",
2861 	"	wrapup();",
2862 	"	exit(0);",
2863 	"}",
2864 	"#endif", /* WIN32 || WIN64 */
2865 	"",
2866 	"#ifdef BITSTATE",
2867 	"void",
2868 	"init_SS(unsigned long n)",
2869 	"{",
2870 	"	SS = (uchar *) prep_shmid_S((size_t) n);",
2871 	"	init_HT(0L);", /* locks and shared memory for Stack_Tree allocations */
2872 	"}",
2873 	"#endif", /* BITSTATE */
2874 	"",
2875 	"#endif", /* NCORE>1 */
2876 	0,
2877 };
2878