doc: Add serial to list of ci file reserved words
[charm.git] / src / conv-core / threads.c
1 /**************************************************************************
2  *
3  * typedef CthThread
4  *
5  *   - a first-class thread object.
6  *
7  * CthThread CthSelf()
8  *
9  *   - returns the current thread.
10  *
11  * void CthResume(CthThread t)
12  *
13  *   - Immediately transfers control to thread t.  Note: normally, the user
14  *     of a thread package wouldn't explicitly choose which thread to transfer
15  *     to.  Instead, the user would rely upon a "scheduler" to choose the
16  *     next thread.  Therefore, this routine is primarily intended for people
17  *     who are implementing schedulers, not for end-users.  End-users should
18  *     probably call CthSuspend or CthAwaken (see below).
19  *
20  * CthThread CthCreate(CthVoidFn fn, void *arg, int size)
21  *
22  *   - Creates a new thread object.  The thread is not given control yet.
23  *     The thread is not passed to the scheduler.  When (and if) the thread
24  *     eventually receives control, it will begin executing the specified 
25  *     function 'fn' with the specified argument.  The 'size' parameter
26  *     specifies the stack size, 0 means use the default size.
27  *
28  * void CthFree(CthThread t)
29  *
30  *   - Frees thread t.  You may free the currently-executing thread, although
31  *     the free will actually be postponed until the thread suspends.
32  *
33  *
34  * In addition to the routines above, the threads package assumes that there
35  * will be a "scheduler" of some sort, whose job is to select which threads
36  * to execute.  The threads package does not provide a scheduler (although
37  * converse may provide one or more schedulers separately).  However, for
38  * standardization reasons, it does define an interface to which all schedulers
39  * can comply.  A scheduler consists of a pair of functions:
40  *
41  *   - An awaken-function.  The awaken-function is called to
42  *     notify the scheduler that a particular thread needs the CPU.  The
43  *     scheduler is expected to respond to this by inserting the thread
44  *     into a ready-pool of some sort.
45  *
46  *   - A choose-next function.  The choose-next function is called to
47  *     to ask the scheduler which thread to execute next.
48  *
49  * The interface to the scheduler is formalized in the following functions:
50  *
51  * void CthSchedInit()
52  *
53  *   - you must call this before any of the following functions will work.
54  *
55  * void CthSuspend()
56  *
57  *   - The thread calls this function, which in turn calls the scheduler's
58  *     choose-next function.  It then resumes whatever thread is returned
59  *     by the choose-next function.
60  *
61  * void CthAwaken(CthThread t)
62  *
63  *   - The thread-package user calls this function, which in turn calls the
64  *     scheduler's awaken-function to awaken thread t.  This probably causes
65  *     the thread t to be inserted in the ready-pool.
66  *
67  * void CthSetStrategy(CthThread t, CthAwkFn awakenfn, CthThFn choosefn)
68  *
69  *     This specifies the scheduling functions to be used for thread 't'.
70  *     The scheduling functions must have the following prototypes:
71  *
72 *          void awakenfn(CthThread t);
73 *          CthThread choosefn();
74 *
75 *     These functions must be provided on a per-thread basis.  (Eg, if you
76     *     CthAwaken a thread X, then X's awakefn will be called.  If a thread Y
77     *     calls CthSuspend, then Y's choosefn will be called to pick the next
78     *     thread.)  Of course, you may use the same functions for all threads
79 *     (the common case), but the specification on a per-thread basis gives
80 *     you maximum flexibility in controlling scheduling.
81 *
82 *     See also: common code, CthSetStrategyDefault.
83   *
84 * void CthYield()
85   *
86   *   - simply executes { CthAwaken(CthSelf()); CthSuspend(); }.  This
87   *     combination gives up control temporarily, but ensures that control
88   *     will eventually return.
89   *
90   *
91   * Note: there are several possible ways to implement threads.   
92   *****************************************************************************/
93
94 #include <stdio.h>
95 #include <stdlib.h>
96 #include <string.h>
97 #if CMK_MEMORY_PROTECTABLE
98 #if CMK_HAS_MALLOC_H
99 #include <malloc.h> /*<- for memalign*/
100 #endif
101 #endif
102 #if CMK_BLUEGENEL
103 #include "rts.h"        /*<- for rts_memory_alias */
104 #endif
105
106 #include "converse.h"
107 #include "qt.h"
108
109 #include "conv-trace.h"
110 #include <sys/types.h>
111
112 #ifndef CMK_STACKSIZE_DEFAULT
113 #define CMK_STACKSIZE_DEFAULT 32768
114 #endif
115
116 #if ! CMK_THREADS_BUILD_DEFAULT
117 #undef CMK_THREADS_USE_JCONTEXT
118 #undef CMK_THREADS_USE_CONTEXT
119 #undef CMK_THREADS_ARE_WIN32_FIBERS
120 #undef CMK_THREADS_USE_PTHREADS
121
122 #if CMK_THREADS_BUILD_CONTEXT
123 #define CMK_THREADS_USE_CONTEXT       1
124 #elif CMK_THREADS_BUILD_JCONTEXT
125 #define CMK_THREADS_USE_JCONTEXT       1
126 #elif  CMK_THREADS_BUILD_FIBERS
127 #define CMK_THREADS_ARE_WIN32_FIBERS  1
128 #elif  CMK_THREADS_BUILD_PTHREADS
129 #define CMK_THREADS_USE_PTHREADS      1
130 #elif  CMK_THREADS_BUILD_STACKCOPY
131 #define CMK_THREADS_USE_STACKCOPY      1
132 #endif
133
134 #endif
135
136 #if CMK_THREADS_BUILD_TLS
137 #include "cmitls.h"
138 #endif
139
140   /**************************** Shared Base Thread Class ***********************/
141   /*
142      FAULT_EVAC
143      Moved the cmicore converse header from CthThreadBase to CthThreadToken.
144      The CthThreadToken gets enqueued in the converse queue instead of the
145      CthThread. This allows the thread to be moved out of a processor even
146      if there is an awaken call for it enqueued in the scheduler
147
148 */
149
150 #define THD_MAGIC_NUM 0x12345678
151
152   typedef struct CthThreadBase
153 {
154   CthThreadToken *token; /* token that shall be enqueued into the ready queue*/
155   int scheduled;         /* has this thread been added to the ready queue ? */
156
157   CmiObjId   tid;        /* globally unique tid */
158   CthAwkFn   awakenfn;   /* Insert this thread into the ready queue */
159   CthThFn    choosefn;   /* Return the next ready thread */
160   CthThread  next; /* Next active thread */
161   int        suspendable; /* Can this thread be blocked */
162   int        exiting;    /* Is this thread finished */
163
164   char      *data;       /* thread private data */
165   int        datasize;   /* size of thread-private data, in bytes */
166
167   int isMigratable; /* thread is migratable (isomalloc or aliased stack) */
168   int aliasStackHandle; /* handle for aliased stack */
169   void      *stack; /*Pointer to thread stack*/
170   int        stacksize; /*Size of thread stack (bytes)*/
171   struct CthThreadListener *listener; /* pointer to the first of the listeners */
172
173 #if CMK_THREADS_BUILD_TLS
174   tlsseg_t tlsseg;
175 #endif
176
177   int magic; /* magic number for checking corruption */
178
179 } CthThreadBase;
180
181 /* By default, there are no flags */
182 static int CmiThreadIs_flag=0;
183
184 int CmiThreadIs(int flag)
185 {
186   return (CmiThreadIs_flag&flag)==flag;
187 }
188
189 /*Macros to convert between base and specific thread types*/
190 #define B(t) ((CthThreadBase *)(t))
191 #define S(t) ((CthThread)(t))
192
193
194 CthThreadToken *CthGetToken(CthThread t){
195   return B(t)->token;
196 }
197
198 CpvStaticDeclare(int, Cth_serialNo);
199
200 /*********************** Stack Aliasing *********************
201   Stack aliasing: instead of consuming virtual address space
202   with isomalloc, map all stacks to the same virtual addresses
203   (like stack copying), but use the VM hardware to make thread
204   swaps fast.  This implementation uses *files* to store the stacks,
205   and mmap to drop the stack data into the right address.  Despite
206   the presence of files, at least under Linux with local disks context
207   switches are still fast; the mmap overhead is less than 5us per
208   switch, even for multi-megabyte stacks.
209
210 WARNING: Does NOT work in SMP mode, because all the processors
211 on a node will try to map their stacks to the same place.
212 WARNING: Does NOT work if switching directly from one migrateable
213 thread to another, because it blows away the stack you're currently
214 running on.  The usual Charm approach of switching to the 
215 (non-migratable) scheduler thread on context switch works fine.
216 */
217
218 #ifndef CMK_THREADS_ALIAS_STACK
219 #define CMK_THREADS_ALIAS_STACK 0
220 #endif
221
222 /** Address to map all migratable thread stacks to. */
223 #if CMK_OSF1
224 #define CMK_THREADS_ALIAS_LOCATION   ((void *)0xe00000000)
225 #elif CMK_IA64
226 #define CMK_THREADS_ALIAS_LOCATION   ((void *)0x6000000000000000)
227 #else
228 #define CMK_THREADS_ALIAS_LOCATION   ((void *)0xb0000000)
229 #endif
230
231 #if CMK_THREADS_ALIAS_STACK
232 #include <stdlib.h> /* for mkstemp */
233 #include <sys/mman.h> /* for mmap */
234 #include <errno.h> /* for perror */
235 #include <unistd.h> /* for unlink, lseek, close */
236
237 /** Create an aliasable area of this size.  Returns alias handle. */
238 int CthAliasCreate(int stackSize)
239 {
240   /* Make a file to contain thread stack */
241   char tmpName[128];
242   char lastByte=0;
243   int fd;
244   sprintf(tmpName,"/tmp/charmThreadStackXXXXXX");
245   fd=mkstemp(tmpName);
246   if (fd==-1) CmiAbort("threads.c> Cannot create /tmp file to contain thread stack");
247   unlink(tmpName); /* delete file when it gets closed */
248
249   /* Make file big enough for stack, by writing one byte at end */
250   lseek(fd,stackSize-sizeof(lastByte),SEEK_SET);
251   write(fd,&lastByte,sizeof(lastByte));
252
253   return fd;
254 }
255
256 void CthAliasFree(int fd) {
257   close(fd);
258 }
259
260 #endif
261
262 /**
263   CthAliasEnable brings this thread's stack into memory.
264   You must call it before accessing the thread stack, 
265   for example, before running, packing, or unpacking the stack data.
266   */
267 #if CMK_THREADS_ALIAS_STACK
268 CthThreadBase *_curMappedStack=0;
269 void CthAliasEnable(CthThreadBase *t) {
270   void *s;
271   int flags=MAP_FIXED|MAP_SHARED; /* Posix flags */
272   if (!t->isMigratable) return;
273   if (t==_curMappedStack) return; /* don't re-map */
274   _curMappedStack=t;
275   if (0) printf("Mmapping in thread %p from runtime stack %p\n",t,&s);
276
277 #if CMK_BLUEGENEL
278   /* Blue Gene/L does not have mmap */
279   /* So this depends on a hack in CNK for syscall rts_memory_alias to
280      map stack pointer to a fix address */
281   {
282     register char *dest=(char *)0x70000000; /* point stack at high memory, not user memory */
283     int alias_slot;
284     rts_memory_alias(t->stack,dest,t->stacksize,&alias_slot);
285   }
286 #else
287   /* Linux mmap flag MAP_POPULATE, to pre-fault in all the pages,
288      only seems to slow down overall performance. */
289   /* Linux mmap flag MAP_GROWSDOWN is rejected at runtime under 2.4.25 */
290 #if CMK_AIX
291   if (_curMappedStack) munmap(_curMappedStack->stack,_curMappedStack->stacksize);
292 #endif
293   s=mmap(t->stack,t->stacksize,
294       PROT_READ|PROT_WRITE|PROT_EXEC, /* exec for gcc nested function thunks */
295       flags, t->aliasStackHandle,0);
296   if (s!=t->stack) {
297     perror("threads.c CthAliasEnable mmap");
298     CmiAbort("threads.c CthAliasEnable mmap failed");
299   }
300 #endif
301 }
302 #else
303 #define CthAliasEnable(t) /* empty */
304 #endif
305
306
307
308
309
310 /*********** Thread-local storage *********/
311
312 CthCpvStatic(CthThread,  CthCurrent); /*Current thread*/
313 CthCpvDeclare(char *,    CthData); /*Current thread's private data (externally visible)*/
314 CthCpvStatic(int,        CthDatasize);
315
316 void CthSetThreadID(CthThread th, int a, int b, int c)
317 {
318   B(th)->tid.id[0] = a;
319   B(th)->tid.id[1] = b;
320   B(th)->tid.id[2] = c;
321 }
322
323 /* possible hack? CW */
324 CmiObjId *CthGetThreadID(CthThread th)
325 {
326   return &(B(th)->tid);
327 }
328
329 char *CthGetData(CthThread t) { return B(t)->data; }
330
331 /* Ensure this thread has at least enough 
332    room for all the thread-local variables 
333    initialized so far on this processor.
334    */
335 #if CMK_C_INLINE
336 inline
337 #endif
338 static void CthFixData(CthThread t)
339 {
340   int newsize = CthCpvAccess(CthDatasize);
341   int oldsize = B(t)->datasize;
342   if (oldsize < newsize) {
343     newsize = 2*newsize;
344     B(t)->datasize = newsize;
345     /* Note: realloc(NULL,size) is equivalent to malloc(size) */
346     B(t)->data = (char *)realloc(B(t)->data, newsize);
347     memset(B(t)->data+oldsize, 0, newsize-oldsize);
348   }
349 }
350
351 /**
352   Allocate another size bytes of thread-local storage,
353   and return the offset into the thread storage buffer.
354   */
355 int CthRegister(int size)
356 {
357   int datasize=CthCpvAccess(CthDatasize);
358   CthThreadBase *th=(CthThreadBase *)CthCpvAccess(CthCurrent);
359   int result, align = 1;
360   while (size>align) align<<=1;
361   datasize = (datasize+align-1) & ~(align-1);
362   result = datasize;
363   datasize += size;
364   CthCpvAccess(CthDatasize) = datasize;
365   CthFixData(S(th)); /*Make the current thread have this much storage*/
366   CthCpvAccess(CthData) = th->data;
367   return result;
368 }
369
370 /**
371   Make sure we have room to store up to at least maxOffset
372   bytes of thread-local storage.
373   */
374 void CthRegistered(int maxOffset) {
375   if (CthCpvAccess(CthDatasize)<maxOffset) {
376     CthThreadBase *th=(CthThreadBase *)CthCpvAccess(CthCurrent);
377     CthCpvAccess(CthDatasize) = maxOffset;
378     CthFixData(S(th)); /*Make the current thread have this much storage*/
379     CthCpvAccess(CthData) = th->data;
380   }
381 }
382
383 /*********** Creation and Deletion **********/
384 CthCpvStatic(int, _defaultStackSize);
385
386 void CthSetSerialNo(CthThread t, int no)
387 {
388   B(t)->token->serialNo = no;
389 }
390
391 static void CthThreadBaseInit(CthThreadBase *th)
392 {
393   static int serialno = 1;
394   th->token = (CthThreadToken *)malloc(sizeof(CthThreadToken));
395   th->token->thread = S(th);
396 #if CMK_BIGSIM_CHARM
397   th->token->serialNo = -1;
398 #else
399   th->token->serialNo = CpvAccess(Cth_serialNo)++;
400 #endif
401   th->scheduled = 0;
402
403   th->awakenfn = 0;
404   th->choosefn = 0;
405   th->next=0;
406   th->suspendable = 1;
407   th->exiting = 0;
408
409   th->data=0;
410   th->datasize=0;
411   CthFixData(S(th));
412
413   CthSetStrategyDefault(S(th));
414
415   th->isMigratable=0;
416   th->aliasStackHandle=0;
417   th->stack=NULL;
418   th->stacksize=0;
419
420   th->tid.id[0] = CmiMyPe();
421   th->tid.id[1] = serialno++;
422   th->tid.id[2] = 0;
423
424   th->listener = NULL;
425
426
427   th->magic = THD_MAGIC_NUM;
428 }
429
430 static void *CthAllocateStack(CthThreadBase *th,int *stackSize,int useMigratable)
431 {
432   void *ret=NULL;
433   if (*stackSize==0) *stackSize=CthCpvAccess(_defaultStackSize);
434   th->stacksize=*stackSize;
435   if (!useMigratable) {
436     ret=malloc(*stackSize); 
437   } else {
438     th->isMigratable=1;
439 #if CMK_THREADS_ALIAS_STACK
440     th->aliasStackHandle=CthAliasCreate(*stackSize);
441     ret=CMK_THREADS_ALIAS_LOCATION;
442 #else /* isomalloc */
443 #if defined(__APPLE__) && CMK_64BIT
444       /* MAC OS needs 16-byte aligned stack */
445     ret=CmiIsomallocAlign(16, *stackSize, (CthThread)th);
446 #else
447     ret=CmiIsomalloc(*stackSize, (CthThread)th);
448 #endif
449 #endif
450   }
451   _MEMCHECK(ret);
452   th->stack=ret;
453   return ret;
454 }
455 static void CthThreadBaseFree(CthThreadBase *th)
456 {
457   struct CthThreadListener *l,*lnext;
458   /*
459    * remove the token if it is not queued in the converse scheduler             
460    */
461   if(th->scheduled == 0){
462     free(th->token);
463   }else{
464     th->token->thread = NULL;
465   }
466   /* Call the free function pointer on all the listeners on
467      this thread and also delete the thread listener objects
468      */
469   for(l=th->listener;l!=NULL;l=lnext){
470     lnext=l->next;
471     l->next=0;
472     if (l->free) l->free(l);
473   }
474   free(th->data);
475   if (th->isMigratable) {
476 #if CMK_THREADS_ALIAS_STACK
477     CthAliasFree(th->aliasStackHandle);
478 #else /* isomalloc */
479 #if !CMK_USE_MEMPOOL_ISOMALLOC
480     CmiIsomallocFree(th->stack);
481 #endif
482 #endif
483   } 
484   else if (th->stack!=NULL) {
485     free(th->stack);
486   }
487   th->stack=NULL;
488 }
489
490 CpvDeclare(int, _numSwitches); /*Context switch count*/
491
492 static void CthBaseInit(char **argv)
493 {
494   CpvInitialize(int, _numSwitches);
495   CpvAccess(_numSwitches) = 0;
496
497   CthCpvInitialize(int,  _defaultStackSize);
498   CthCpvAccess(_defaultStackSize)=CMK_STACKSIZE_DEFAULT;
499   CmiGetArgIntDesc(argv,"+stacksize",&CthCpvAccess(_defaultStackSize),
500       "Default user-level thread stack size");  
501
502   CthCpvInitialize(CthThread,  CthCurrent);
503   CthCpvInitialize(char *, CthData);
504   CthCpvInitialize(int,        CthDatasize);
505
506   CthCpvAccess(CthData)=0;
507   CthCpvAccess(CthDatasize)=0;
508
509   CpvInitialize(int, Cth_serialNo);
510   CpvAccess(Cth_serialNo) = 1;
511
512 #if CMK_THREADS_BUILD_TLS
513   CmiThreadIs_flag |= CMI_THREAD_IS_TLS;
514 #endif
515 }
516
517 int CthImplemented() { return 1; } 
518
519 CthThread CthSelf()
520 {
521   return CthCpvAccess(CthCurrent);
522 }
523
524 void CthPupBase(pup_er p,CthThreadBase *t,int useMigratable)
525 {
526 #if CMK_ERROR_CHECKING
527   if ((CthThread)t==CthCpvAccess(CthCurrent))
528     CmiAbort("CthPupBase: Cannot pack running thread!");
529 #endif
530   /*
531    * Token will never be freed, so its pointer should be pupped.
532    * When packing, set the thread pointer in this token to be NULL.
533    * When unpacking, reset the thread pointer in token to this thread.
534    */
535
536   if(_BgOutOfCoreFlag!=0){
537     pup_bytes(p, &t->token, sizeof(void *));
538     if(!pup_isUnpacking(p)){
539       t->token->thread = NULL;
540     }
541     pup_int(p, &t->scheduled);
542   }
543   if(pup_isUnpacking(p)){
544     if(_BgOutOfCoreFlag==0){
545       t->token = (CthThreadToken *)malloc(sizeof(CthThreadToken));
546       t->token->thread = S(t);
547       t->token->serialNo = CpvAccess(Cth_serialNo)++;
548       /*For normal runs where this pup is needed,
549         set scheduled to 0 in the unpacking period since the thread has
550         not been scheduled */
551       t->scheduled = 0;
552     }else{
553       /* During out-of-core emulation */
554       /* 
555        * When t->scheduled is set, the thread is in the queue so the token
556        * should be kept. Otherwise, allocate a new space for the token
557        */
558       if(t->scheduled==0){
559         /*CmiPrintf("Creating a new token for %p!\n", t->token);*/
560         t->token = (CthThreadToken *)malloc(sizeof(CthThreadToken));
561       }
562       t->token->thread = S(t);
563       t->token->serialNo = CpvAccess(Cth_serialNo)++;
564     }
565   }
566
567   /*BIGSIM_OOC DEBUGGING */
568   /*if(_BgOutOfCoreFlag!=0){
569     if(pup_isUnpacking(p)){
570     CmiPrintf("Unpacking: ");
571     }else{
572     CmiPrintf("Packing: ");
573     }   
574     CmiPrintf("thd=%p, its token=%p, token's thd=%p\n", t, t->token, t->token->thread); 
575     } */
576
577   /*Really need a pup_functionPtr here:*/
578   pup_bytes(p,&t->awakenfn,sizeof(t->awakenfn));
579   pup_bytes(p,&t->choosefn,sizeof(t->choosefn));
580   pup_bytes(p,&t->next,sizeof(t->next));
581   pup_int(p,&t->suspendable);
582   pup_int(p,&t->datasize);
583   if (pup_isUnpacking(p)) { 
584     t->data = (char *) malloc(t->datasize);_MEMCHECK(t->data);
585   }
586   pup_bytes(p,(void *)t->data,t->datasize);
587   pup_int(p,&t->isMigratable);
588   pup_int(p,&t->stacksize);
589   if (t->isMigratable) {
590 #if CMK_THREADS_ALIAS_STACK
591     if (pup_isUnpacking(p)) { 
592       CthAllocateStack(t,&t->stacksize,1);
593     }
594     CthAliasEnable(t);
595     pup_bytes(p,t->stack,t->stacksize);
596 #elif CMK_THREADS_USE_STACKCOPY
597     /* do nothing */
598 #else /* isomalloc */
599 #if CMK_USE_MEMPOOL_ISOMALLOC
600     pup_bytes(p,&t->stack,sizeof(char*));
601 #else
602     CmiIsomallocPup(p,&t->stack);
603 #endif
604 #endif
605   } 
606   else {
607     if (useMigratable)
608       CmiAbort("You must use CthCreateMigratable to use CthPup!\n");
609     /*Pup the stack pointer as raw bytes*/
610     pup_bytes(p,&t->stack,sizeof(t->stack));
611   }
612   if (pup_isUnpacking(p)) { 
613     /* FIXME:  restore thread listener */
614     t->listener = NULL;
615   }
616
617   pup_int(p, &t->magic);
618
619 #if CMK_THREADS_BUILD_TLS
620   void* aux;
621   pup_bytes(p, &t->tlsseg, sizeof(tlsseg_t));
622   aux = ((void*)(t->tlsseg.memseg)) - t->tlsseg.size;
623   /* fixme: tls global variables handling needs isomalloc */
624 #if CMK_USE_MEMPOOL_ISOMALLOC
625   pup_bytes(p,&aux,sizeof(char*));
626 #else
627   CmiIsomallocPup(p, &aux);
628 #endif
629   /* printf("[%d] %s %p\n", CmiMyPe(), pup_typeString(p), t->tlsseg.memseg); */
630 #endif
631 }
632
633 static void CthThreadFinished(CthThread t)
634 {
635   B(t)->exiting=1;
636   CthSuspend();
637 }
638
639
640 /************ Scheduler Interface **********/
641
642 void CthSetSuspendable(CthThread t, int val) { B(t)->suspendable = val; }
643 int CthIsSuspendable(CthThread t) { return B(t)->suspendable; }
644
645 void CthSetNext(CthThread t, CthThread v) { B(t)->next = v; }
646 CthThread CthGetNext(CthThread t) { return B(t)->next; }
647
648 static void CthNoStrategy(void)
649 {
650   CmiAbort("Called CthAwaken or CthSuspend before calling CthSetStrategy.\n");
651 }
652
653 void CthSetStrategy(CthThread t, CthAwkFn awkfn, CthThFn chsfn)
654 {
655   B(t)->awakenfn = awkfn;
656   B(t)->choosefn = chsfn;
657 }
658
659 #if CMK_C_INLINE
660 inline
661 #endif
662 static void CthBaseResume(CthThread t)
663 {
664   struct CthThreadListener *l;
665   for(l=B(t)->listener;l!=NULL;l=l->next){
666     if (l->resume) l->resume(l);
667   }
668   CpvAccess(_numSwitches)++;
669   CthFixData(t); /*Thread-local storage may have changed in other thread.*/
670   CthCpvAccess(CthCurrent) = t;
671   CthCpvAccess(CthData) = B(t)->data;
672   CthAliasEnable(B(t));
673 }
674
675 /**
676   switch the thread to t
677   */
678 void CthSwitchThread(CthThread t)
679 {
680   CthBaseResume(t);
681 }
682
683 /*
684 Suspend: finds the next thread to execute, and resumes it
685 */
686 void CthSuspend(void)
687 {
688   CthThread next;
689   struct CthThreadListener *l;
690   CthThreadBase *cur=B(CthCpvAccess(CthCurrent));
691
692   if (cur->suspendable == 0)
693     CmiAbort("Fatal Error> trying to suspend a non-suspendable thread!\n");
694
695   /*
696      Call the suspend function on listeners
697      */
698   for(l=cur->listener;l!=NULL;l=l->next){
699     if (l->suspend) l->suspend(l);
700   }
701   if (cur->choosefn == 0) CthNoStrategy();
702   next = cur->choosefn();
703   /*cur->scheduled=0;*/
704   /*changed due to out-of-core emulation in BigSim*/
705   /** Sometimes, a CthThread is running without ever being awakened
706    * In this case, the scheduled is the initialized value "0"
707    */
708   if(cur->scheduled > 0)
709     cur->scheduled--;
710
711 #if CMK_ERROR_CHECKING
712   if(cur->scheduled<0)
713     CmiAbort("A thread's scheduler should not be less than 0!\n");
714 #endif    
715
716 #if CMK_TRACE_ENABLED
717 #if !CMK_TRACE_IN_CHARM
718   if(CpvAccess(traceOn))
719     traceSuspend();
720 #endif
721 #endif
722   CthResume(next);
723 }
724
725 void CthAwaken(CthThread th)
726 {
727   if (B(th)->awakenfn == 0) CthNoStrategy();
728
729   /*BIGSIM_OOC DEBUGGING
730     if(B(th)->scheduled==1){
731     CmiPrintf("====Thread %p is already scheduled!!!!\n", th);
732     return;
733     } */
734
735 #if CMK_TRACE_ENABLED
736 #if ! CMK_TRACE_IN_CHARM
737   if(CpvAccess(traceOn))
738     traceAwaken(th);
739 #endif
740 #endif
741   B(th)->awakenfn(B(th)->token, CQS_QUEUEING_FIFO, 0, 0);
742   /*B(th)->scheduled = 1; */
743   /*changed due to out-of-core emulation in BigSim */
744   B(th)->scheduled++;
745 }
746
747 void CthYield()
748 {
749   CthAwaken(CthCpvAccess(CthCurrent));
750   CthSuspend();
751 }
752
753 void CthAwakenPrio(CthThread th, int s, int pb, unsigned int *prio)
754 {
755   if (B(th)->awakenfn == 0) CthNoStrategy();
756 #if CMK_TRACE_ENABLED
757 #if ! CMK_TRACE_IN_CHARM
758   if(CpvAccess(traceOn))
759     traceAwaken(th);
760 #endif
761 #endif
762   B(th)->awakenfn(B(th)->token, s, pb, prio);
763   /*B(th)->scheduled = 1; */
764   /*changed due to out-of-core emulation in BigSim */
765   B(th)->scheduled++;
766 }
767
768 void CthYieldPrio(int s, int pb, unsigned int *prio)
769 {
770   CthAwakenPrio(CthCpvAccess(CthCurrent), s, pb, prio);
771   CthSuspend();
772 }
773
774 /*
775    Add a new thread listener to a thread 
776    */
777 void CthAddListener(CthThread t,struct CthThreadListener *l){
778   struct CthThreadListener *p=B(t)->listener;
779   if(p== NULL){ /* first listener */
780     B(t)->listener=l;
781     l->thread = t;
782     l->next=NULL;
783     return;     
784   }
785   /* Add l at end of current chain of listeners: */
786   while(p->next != NULL){
787     p = p->next;
788   }
789   p->next = l;
790   l->next = NULL;
791   l->thread = t;
792 }
793
794 /*************************** Stack-Copying Threads (obsolete) *******************
795   Basic idea: switch from thread A (currently running) to thread B by copying
796   A's stack from the system stack area into A's buffer in the heap, then
797   copy B's stack from its heap buffer onto the system stack.
798
799   This allows thread migration, because the system stack is in the same
800   location on every processor; but the context-switching overhead (especially
801   for threads with deep stacks) is extremely high.
802
803   Written by Josh Yelon around May 1999
804
805   stack grows down like:
806   lo   <- savedptr    <- savedstack
807
808   ...
809
810   high <- stackbase
811
812 NOTE: this only works when system stack base is same on all processors.
813 Which is not the case on my FC4 laptop ?!
814
815 extended it to work for tcharm and registered user data migration
816 tested platforms: opteron, Cygwin.
817
818 For Fedora and Ubuntu, run the following command as root
819 echo 0 > /proc/sys/kernel/randomize_va_space
820 will disable the randomization of the stack pointer
821
822 Gengbin Zheng March, 2006
823 */
824
825 #if CMK_THREADS_USE_STACKCOPY
826
827 #define SWITCHBUF_SIZE 32768
828
829 typedef struct CthProcInfo *CthProcInfo;
830
831 typedef struct CthThreadStruct
832 {
833   CthThreadBase base;
834   CthVoidFn  startfn;    /* function that thread will execute */
835   void      *startarg;   /* argument that start function will be passed */
836   qt_t      *savedstack; /* pointer to saved stack */
837   int        savedsize;  /* length of saved stack (zero when running) */        
838   int        stacklen;   /* length of the allocated savedstack >= savedsize */
839   qt_t      *savedptr;   /* stack pointer */    
840 } CthThreadStruct;
841
842 int CthMigratable()
843 {
844   return 1;
845 }
846
847 CthThread CthPup(pup_er p, CthThread t)
848 {
849   if (pup_isUnpacking(p))
850   { t = (CthThread) malloc(sizeof(CthThreadStruct));_MEMCHECK(t);}
851   pup_bytes(p, (void*) t, sizeof(CthThreadStruct)); 
852   CthPupBase(p,&t->base,0);
853   pup_int(p,&t->savedsize);
854   if (pup_isUnpacking(p)) {
855     t->savedstack = (qt_t*) malloc(t->savedsize);_MEMCHECK(t->savedstack);
856     t->stacklen = t->savedsize;       /* reflect actual size */
857   }
858   pup_bytes(p, (void*) t->savedstack, t->savedsize);
859
860   /* assume system stacks are same on all processors !! */
861   pup_bytes(p,&t->savedptr,sizeof(t->savedptr));  
862
863   if (pup_isDeleting(p))
864   {CthFree(t);t=0;}
865   return t;
866 }
867
868
869
870 struct CthProcInfo
871 {
872   qt_t      *stackbase;
873   qt_t      *switchbuf_sp;
874   qt_t      *switchbuf;
875 };
876
877 CthCpvDeclare(CthProcInfo, CthProc);
878
879 static void CthThreadInit(CthThread t, CthVoidFn fn, void *arg)
880 {
881   CthThreadBaseInit(&t->base);
882   t->startfn = fn;
883   t->startarg = arg;
884   t->savedstack = 0;
885   t->savedsize = 0;
886   t->stacklen = 0;
887   t->savedptr = 0;
888 }
889
890 static void CthThreadFree(CthThread t)
891 {
892   CthThreadBaseFree(&t->base);
893   if (t->savedstack) free(t->savedstack);
894   free(t);
895 }
896
897 void CthFree(t)
898   CthThread t;
899 {
900   if (t==NULL) return;
901   CthProcInfo proc = CthCpvAccess(CthProc);     
902
903   if (t != CthSelf()) {
904     CthThreadFree(t);
905   } else
906     t->base.exiting = 1;
907 }
908
909 void CthDummy() { }
910
911 void CthInit(char **argv)
912 {
913   CthThread t; CthProcInfo p; qt_t *switchbuf, *sp;
914
915   CthCpvInitialize(CthProcInfo, CthProc);
916
917   CthBaseInit(argv);
918   t = (CthThread)malloc(sizeof(struct CthThreadStruct));
919   _MEMCHECK(t);
920   CthCpvAccess(CthCurrent)=t;
921   CthThreadInit(t,0,0);
922
923   p = (CthProcInfo)malloc(sizeof(struct CthProcInfo));
924   _MEMCHECK(p);
925   CthCpvAccess(CthProc)=p;
926
927   /* leave some space for current stack frame < 256 bytes */
928   /* sp must be same on all processors for migration to work ! */
929   sp = (qt_t*)(((size_t)&t) & ~((size_t)0xFF));
930   /*printf("[%d] System stack base: %p\n", CmiMyPe(), sp);*/
931   p->stackbase = QT_SP(sp, 0x100);
932
933   /* printf("sp: %p\n", sp); */
934
935   switchbuf = (qt_t*)malloc(QT_STKALIGN + SWITCHBUF_SIZE);
936   _MEMCHECK(switchbuf);
937   switchbuf = (qt_t*)((((size_t)switchbuf)+QT_STKALIGN) & ~(QT_STKALIGN-1));
938   p->switchbuf = switchbuf;
939   sp = QT_SP(switchbuf, SWITCHBUF_SIZE);
940   sp = QT_ARGS(sp,0,0,0,(qt_only_t*)CthDummy);
941   p->switchbuf_sp = sp;
942
943   CmiThreadIs_flag |= CMI_THREAD_IS_STACKCOPY;
944 }
945
946 static void CthOnly(CthThread t, void *dum1, void *dum2)
947 {
948   t->startfn(t->startarg);
949   CthThreadFinished(t);
950 }
951
952 #define USE_SPECIAL_STACKPOINTER    1
953
954 /* p is a pointer on stack */
955 size_t CthStackOffset(CthThread t, char *p)
956 {
957   CthProcInfo proc = CthCpvAccess(CthProc);
958   return p - (char *)proc->stackbase;
959 }
960
961 char * CthPointer(CthThread t, size_t pos)
962 {
963   char *stackbase;
964   CmiAssert(t);
965   CthProcInfo proc = CthCpvAccess(CthProc);
966   if (CthCpvAccess(CthCurrent) == t)    /* current thread uses current stack */
967     stackbase = (char *)proc->stackbase;
968   else                                  /* sleep thread uses its saved stack */
969     stackbase = (char *)t->savedstack;
970 #ifdef QT_GROW_DOWN
971   char *p = stackbase + t->savedsize + pos;
972 #else
973   char *p = stackbase + pos;
974 #endif
975   return p;
976 }
977
978 static void CthResume1(qt_t *sp, CthProcInfo proc, CthThread t)
979 {
980   int bytes; qt_t *lo, *hi;
981   CthThread old = CthCpvAccess(CthCurrent);
982   CthBaseResume(t);
983   if (old->base.exiting) {
984     CthThreadFree(old);
985   } else {
986 #ifdef QT_GROW_DOWN
987     lo = sp; hi = proc->stackbase;
988 #else
989     hi = sp; lo = proc->stackbase;
990 #endif
991     bytes = ((size_t)hi)-((size_t)lo);
992     if(bytes > old->stacklen) {
993       if(old->savedstack) free((void *)old->savedstack);
994       old->savedstack = (qt_t*)malloc(bytes);
995       _MEMCHECK(old->savedstack);
996       old->stacklen = bytes;
997     }
998     old->savedsize = bytes;
999     old->savedptr = sp;
1000     memcpy(old->savedstack, lo, bytes);
1001   }
1002   if (t->savedstack) {
1003 #ifdef QT_GROW_DOWN
1004     lo = t->savedptr;
1005 #else
1006     lo = proc->stackbase;
1007 #endif
1008     memcpy(lo, t->savedstack, t->savedsize);
1009     t->savedsize=0;
1010     sp = t->savedptr;
1011   } else {
1012     sp = proc->stackbase;
1013     sp = QT_ARGS(sp,t,0,0,(qt_only_t*)CthOnly);
1014   }
1015   QT_ABORT((qt_helper_t*)CthDummy,0,0,sp);
1016 }
1017
1018 void CthResume(t)
1019   CthThread t;
1020 {
1021   CthProcInfo proc = CthCpvAccess(CthProc);
1022   QT_BLOCK((qt_helper_t*)CthResume1, proc, t, proc->switchbuf_sp);
1023 }
1024
1025 CthThread CthCreate(CthVoidFn fn,void *arg,int size)
1026 {
1027   CthThread result = (CthThread)malloc(sizeof(struct CthThreadStruct));
1028   _MEMCHECK(result);
1029   CthThreadInit(result, fn, arg);
1030   return result;
1031 }
1032 CthThread CthCreateMigratable(CthVoidFn fn,void *arg,int size)
1033 {
1034   /*All threads are migratable under stack copying*/
1035   return CthCreate(fn,arg,size);
1036 }
1037
1038 /**************************************************************************
1039   QuickThreads does not work on Win32-- our stack-shifting large allocas
1040   fail a stack depth check.  Windows NT and 98 provide a user-level thread 
1041   interface called "Fibers", used here.
1042
1043   Written by Sameer Paranjpye around October 2000
1044   */
1045 #elif  CMK_THREADS_ARE_WIN32_FIBERS
1046 #include <windows.h>
1047 #include <winbase.h>
1048
1049 #ifndef _WIN32_WINNT
1050 #define _WIN32_WINNT  0x0400
1051 #endif
1052
1053 #if(_WIN32_WINNT >= 0x0400)
1054 typedef VOID (WINAPI *PFIBER_START_ROUTINE)(
1055     LPVOID lpFiberParameter
1056     );
1057 typedef PFIBER_START_ROUTINE LPFIBER_START_ROUTINE;
1058 #endif
1059
1060 #if(_WIN32_WINNT >= 0x0400)
1061 WINBASEAPI
1062 LPVOID
1063 WINAPI
1064 CreateFiber(
1065     DWORD dwStackSize,
1066     LPFIBER_START_ROUTINE lpStartAddress,
1067     LPVOID lpParameter
1068     );
1069
1070 WINBASEAPI
1071 LPVOID 
1072 WINAPI 
1073 CreateFiberEx(
1074     SIZE_T dwStackCommitSize,
1075     SIZE_T dwStackReserveSize,
1076     DWORD dwFlags,
1077     LPFIBER_START_ROUTINE lpStartAddress,
1078     LPVOID lpParameter
1079     );
1080
1081
1082 WINBASEAPI
1083 VOID
1084 WINAPI
1085 DeleteFiber(
1086     LPVOID lpFiber
1087     );
1088
1089 WINBASEAPI
1090 LPVOID
1091 WINAPI
1092 ConvertThreadToFiber(
1093     LPVOID lpParameter
1094     );
1095
1096 WINBASEAPI
1097 VOID
1098 WINAPI
1099 SwitchToFiber(
1100     LPVOID lpFiber
1101     );
1102
1103 WINBASEAPI
1104 BOOL
1105 WINAPI
1106 SwitchToThread(
1107     VOID
1108     );
1109 #endif /* _WIN32_WINNT >= 0x0400 */
1110
1111
1112 struct CthThreadStruct
1113 {
1114   CthThreadBase base;
1115   LPVOID     fiber;
1116 };
1117
1118 CthCpvStatic(CthThread,  CthPrevious);
1119
1120 typedef CthThread *threadTable;
1121 CthCpvStatic(int,     tablesize);
1122 CthCpvStatic(threadTable, exitThreads);
1123 CthCpvStatic(int,     nExit);
1124
1125 static void CthThreadInit(CthThread t)
1126 {
1127   CthThreadBaseInit(&t->base);
1128 }
1129
1130 void CthInit(char **argv)
1131 {
1132   CthThread t;
1133   int i;
1134
1135   CthCpvInitialize(CthThread,  CthPrevious);
1136   CthCpvInitialize(int,        nExit);
1137   CthCpvInitialize(threadTable,        exitThreads);
1138   CthCpvInitialize(int, tablesize);
1139
1140 #define INITIALSIZE 128
1141   CthCpvAccess(tablesize) = INITIALSIZE;   /* initial size */
1142   CthCpvAccess(exitThreads) = (threadTable)malloc(sizeof(CthThread)*INITIALSIZE);
1143   for (i=0; i<INITIALSIZE; i++) CthCpvAccess(exitThreads)[i] = NULL;
1144
1145   CthCpvAccess(CthPrevious)=0;
1146   CthCpvAccess(nExit)=0;
1147
1148   CthBaseInit(argv);  
1149   t = (CthThread)malloc(sizeof(struct CthThreadStruct));
1150   _MEMCHECK(t);
1151   CthCpvAccess(CthCurrent)=t;
1152   CthThreadInit(t);
1153   t->fiber = ConvertThreadToFiber(t);
1154   _MEMCHECK(t->fiber);
1155
1156   CmiThreadIs_flag |= CMI_THREAD_IS_FIBERS;
1157 }
1158
1159 void CthThreadFree(CthThread old)
1160 {
1161   CthThreadBaseFree(&old->base);
1162   if (old->fiber) DeleteFiber((PVOID)old->fiber);
1163   free(old);
1164 }
1165
1166 static void CthClearThreads()
1167 {
1168   int i,p,m;
1169   int n = CthCpvAccess(nExit);
1170   CthThread tc = CthCpvAccess(CthCurrent);
1171   CthThread tp = CthCpvAccess(CthPrevious);
1172   m = n;
1173   p=0;
1174   for (i=0; i<m; i++) {
1175     CthThread t = CthCpvAccess(exitThreads)[i];
1176     if (t && t != tc && t != tp) {
1177       CthThreadFree(t);
1178       CthCpvAccess(nExit) --;
1179     }
1180     else {
1181       if (p != i) CthCpvAccess(exitThreads)[p] = t;
1182       p++;
1183     }
1184   }
1185   if (m!=p)
1186     for (i=m; i<n; i++,p++) {
1187       CthCpvAccess(exitThreads)[p] = CthCpvAccess(exitThreads)[i];
1188     }
1189 }
1190
1191 void CthFree(CthThread t)
1192 {
1193   int i;
1194   if (t==NULL) return;
1195
1196   if(CthCpvAccess(nExit) >= CthCpvAccess(tablesize)) {   /* expand */
1197     threadTable newtable;
1198     int oldsize = CthCpvAccess(tablesize);
1199     CthCpvAccess(tablesize) *= 2;
1200     newtable = (threadTable)malloc(sizeof(CthThread)*CthCpvAccess(tablesize));
1201     for (i=0; i<CthCpvAccess(tablesize); i++) newtable[i] = NULL;
1202     for (i=0; i<oldsize; i++) newtable[i] = CthCpvAccess(exitThreads)[i];
1203     free(CthCpvAccess(exitThreads));
1204     CthCpvAccess(exitThreads) = newtable;
1205   }
1206
1207   /* store into exiting threads table to avoid delete thread itself */
1208   CthCpvAccess(exitThreads)[CthCpvAccess(nExit)++] = t;
1209   if (t==CthCpvAccess(CthCurrent)) 
1210   {
1211     t->base.exiting = 1;
1212   } 
1213   else 
1214   {
1215     CthClearThreads();
1216     /*  was
1217         if (t->data) free(t->data);
1218         DeleteFiber(t->fiber);
1219         free(t);
1220         */
1221   }
1222 }
1223
1224 #if 0
1225 void CthFiberBlock(CthThread t)
1226 {
1227   CthThread tp;
1228
1229   SwitchToFiber(t->fiber);
1230   tp = CthCpvAccess(CthPrevious);
1231   if (tp != 0 && tp->killed == 1)
1232     CthThreadFree(tp);
1233 }
1234 #endif
1235
1236 void CthResume(CthThread t)
1237 {
1238   CthThread tc;
1239
1240   tc = CthCpvAccess(CthCurrent);
1241   if (t == tc) return;
1242   CthBaseResume(t);
1243   CthCpvAccess(CthPrevious)=tc;
1244 #if 0
1245   if (tc->base.exiting) 
1246   {
1247     SwitchToFiber(t->fiber);
1248   } 
1249   else 
1250     CthFiberBlock(t);
1251 #endif
1252   SwitchToFiber(t->fiber);
1253 }
1254
1255 VOID CALLBACK FiberSetUp(PVOID fiberData)
1256 {
1257   void **ptr = (void **) fiberData;
1258   qt_userf_t* fn = (qt_userf_t *)ptr[0];
1259   void *arg = ptr[1];
1260   CthThread  t = CthSelf();
1261
1262   CthClearThreads();
1263
1264   fn(arg);
1265
1266   CthCpvAccess(exitThreads)[CthCpvAccess(nExit)++] = t;
1267   CthThreadFinished(t);
1268 }
1269
1270 CthThread CthCreate(CthVoidFn fn, void *arg, int size)
1271 {
1272   CthThread result; 
1273   void**    fiberData;
1274   fiberData = (void**)malloc(2*sizeof(void *));
1275   fiberData[0] = (void *)fn;
1276   fiberData[1] = arg;
1277
1278   result = (CthThread)malloc(sizeof(struct CthThreadStruct));
1279   _MEMCHECK(result);
1280   CthThreadInit(result);
1281   /* result->fiber = CreateFiber(size, FiberSetUp, (PVOID) fiberData); */
1282   result->fiber = CreateFiberEx(size, size, 0, FiberSetUp, (PVOID) fiberData);
1283   if (!result->fiber)
1284     CmiAbort("CthCreate failed to create fiber!\n");
1285
1286   return result;
1287 }
1288
1289 int CthMigratable()
1290 {
1291   return 0;
1292 }
1293 CthThread CthPup(pup_er p, CthThread t)
1294 {
1295   CmiAbort("CthPup not implemented.\n");
1296   return 0;
1297 }
1298 CthThread CthCreateMigratable(CthVoidFn fn,void *arg,int size)
1299 {
1300   /*Fibers are never migratable, unless we can figure out how to set their stacks*/
1301   return CthCreate(fn,arg,size);
1302 }
1303
1304 /***************************************************
1305   Use Posix Threads to simulate cooperative user-level
1306   threads.  This version is very portable but inefficient.
1307
1308   Written by Milind Bhandarkar around November 2000
1309
1310 IMPORTANT:  for SUN, must link with -mt compiler flag
1311 Rewritten by Gengbin Zheng
1312 */
1313 #elif CMK_THREADS_USE_PTHREADS
1314
1315 #include <pthread.h>
1316 #include <errno.h> /* for perror */
1317
1318 struct CthThreadStruct
1319 {
1320   CthThreadBase base;
1321   pthread_t  self;
1322   pthread_cond_t cond;
1323   pthread_cond_t *creator;
1324   CthVoidFn  fn;
1325   void      *arg;
1326   char       inited;
1327 };
1328
1329 /**
1330   The sched_mutex is the current token of execution.
1331   Only the running thread holds this lock; all other threads
1332   have released the lock and are waiting on their condition variable.
1333   */
1334 CthCpvStatic(pthread_mutex_t, sched_mutex);
1335
1336 static void CthThreadInit(t)
1337   CthThread t;
1338 {
1339   CthThreadBaseInit(&t->base);
1340   t->inited = 0;
1341   pthread_cond_init(&(t->cond) , (pthread_condattr_t *) 0);
1342 }
1343
1344 void CthInit(char **argv)
1345 {
1346   CthThread t;
1347
1348   CthCpvInitialize(pthread_mutex_t, sched_mutex);
1349
1350   pthread_mutex_init(&CthCpvAccess(sched_mutex), (pthread_mutexattr_t *) 0);
1351   pthread_mutex_lock(&CthCpvAccess(sched_mutex));
1352   CthBaseInit(argv); 
1353   t = (CthThread)malloc(sizeof(struct CthThreadStruct));
1354   _MEMCHECK(t);
1355   CthCpvAccess(CthCurrent)=t;
1356   CthThreadInit(t);
1357   t->self = pthread_self();
1358
1359   CmiThreadIs_flag |= CMI_THREAD_IS_PTHREADS;
1360 }
1361
1362 void CthFree(t)
1363   CthThread t;
1364 {
1365   if (t==NULL) return;
1366   if (t==CthCpvAccess(CthCurrent)) {
1367     t->base.exiting = 1;
1368   } else {
1369     CthThreadBaseFree(&t->base);
1370     free(t);
1371   }
1372 }
1373
1374 void CthResume(CthThread t)
1375 {
1376   CthThread tc = CthCpvAccess(CthCurrent);
1377   if (t == tc) return;
1378   CthBaseResume(t);
1379   pthread_cond_signal(&(t->cond)); /* wake up the next thread */
1380   if (tc->base.exiting) {
1381     pthread_mutex_unlock(&CthCpvAccess(sched_mutex));
1382     pthread_exit(0);
1383   } else {
1384     /* pthread_cond_wait might (with low probability) return when the 
1385        condition variable has not been signaled, guarded with 
1386        predicate checks */
1387     do {
1388       pthread_cond_wait(&(tc->cond), &CthCpvAccess(sched_mutex));
1389     } while (tc!=CthCpvAccess(CthCurrent)) ;
1390   }
1391 }
1392
1393 static void *CthOnly(void * arg)
1394 {
1395   CthThread th = (CthThread)arg;
1396   th->inited = 1;
1397   pthread_detach(pthread_self());
1398   pthread_mutex_lock(&CthCpvAccess(sched_mutex));
1399   pthread_cond_signal(th->creator);
1400   do {
1401     pthread_cond_wait(&(th->cond), &CthCpvAccess(sched_mutex));
1402   } while (arg!=CthCpvAccess(CthCurrent)) ;
1403   th->fn(th->arg);
1404   CthThreadFinished(th);
1405   return 0;
1406 }
1407
1408 CthThread CthCreate(CthVoidFn fn, void *arg, int size)
1409 {
1410   static int reported = 0;
1411   pthread_attr_t attr;
1412   int r;
1413   CthThread result;
1414   CthThread self = CthSelf();
1415   /* size is ignored in this version */
1416   result = (CthThread)malloc(sizeof(struct CthThreadStruct));
1417   _MEMCHECK(result);
1418   CthThreadInit(result);
1419   result->fn = fn;
1420   result->arg = arg;
1421   result->creator = &(self->cond);
1422
1423   /* try set pthread stack, not necessarily supported on all platforms */
1424   pthread_attr_init(&attr);
1425   /* pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); */
1426   if (size<1024) size = CthCpvAccess(_defaultStackSize);
1427   if (0!=(r=pthread_attr_setstacksize(&attr,size))) {
1428     if (!reported) {
1429       CmiPrintf("Warning: pthread_attr_setstacksize failed\n");
1430       errno = r;
1431       perror("pthread_attr_setstacksize");
1432       reported = 1;
1433     }
1434   }
1435
1436   /* **CWL** Am assuming Gengbin left this unchanged because the macro
1437      re-definition of pthread_create would not happen before this part of
1438      the code. If the assumption is not true, then we can simply replace
1439      this hash-if with the else portion.
1440      */
1441 #if CMK_WITH_TAU
1442   r = tau_pthread_create(&(result->self), &attr, CthOnly, (void*) result);
1443 #else
1444   r = pthread_create(&(result->self), &attr, CthOnly, (void*) result);
1445 #endif
1446   if (0 != r) {
1447     CmiPrintf("pthread_create failed with %d\n", r);
1448     CmiAbort("CthCreate failed to created a new pthread\n");
1449   }
1450   do {
1451     pthread_cond_wait(&(self->cond), &CthCpvAccess(sched_mutex));
1452   } while (result->inited==0);
1453   return result;
1454 }
1455
1456 int CthMigratable()
1457 {
1458   return 0;
1459 }
1460 CthThread CthPup(pup_er p, CthThread t)
1461 {
1462   CmiAbort("CthPup not implemented.\n");
1463   return 0;
1464 }
1465 CthThread CthCreateMigratable(CthVoidFn fn,void *arg,int size)
1466 {
1467   /*Pthreads are never migratable, unless we can figure out how to set their stacks*/
1468   return CthCreate(fn,arg,size);
1469 }
1470
1471 /***************************************************************
1472   Use SysV r3 setcontext/getcontext calls instead of
1473   quickthreads.  This works on lots of architectures (such as
1474   SUN, IBM SP, O2K, DEC Alpha, IA64, Cray X1, Linux with newer version of 
1475   glibc such as the one with RH9) 
1476   On some machine such as IA64 and Cray X1, the context version is the 
1477   only thread package that is working. 
1478
1479   Porting should be easy. To port context threads, one need to set the 
1480   direction of the thread stack properly in conv-mach.h.
1481
1482 Note: on some machine like Sun and IBM SP, one needs to link with memory gnuold
1483 to have this context thread working.
1484
1485 Written by Gengbin Zheng around April 2001
1486
1487 For thread checkpoint/restart, isomalloc requires that iso region from all
1488 machines are same.
1489
1490 For Fedora and Ubuntu, run the following command as root
1491 echo 0 > /proc/sys/kernel/randomize_va_space
1492 will disable the randomization of the stack pointer
1493
1494 Gengbin Zheng October, 2007
1495
1496 */
1497 #elif (CMK_THREADS_USE_CONTEXT || CMK_THREADS_USE_JCONTEXT)
1498
1499 #include <signal.h>
1500 #include <errno.h>
1501
1502 #if CMK_THREADS_USE_CONTEXT
1503 /* system builtin context routines: */
1504 #include <ucontext.h>
1505
1506 #define uJcontext_t ucontext_t
1507 #define setJcontext setcontext
1508 #define getJcontext getcontext
1509 #define swapJcontext swapcontext
1510 #define makeJcontext makecontext
1511 typedef void (*uJcontext_fn_t)(void);
1512
1513 #else /* CMK_THREADS_USE_JCONTEXT */
1514 /* Orion's setjmp-based context routines: */
1515 #include "uJcontext.h"
1516 #include "uJcontext.c"
1517
1518 #endif
1519
1520
1521 struct CthThreadStruct
1522 {
1523   CthThreadBase base;
1524   double * dummy;
1525   uJcontext_t context;
1526 };
1527
1528
1529 static void CthThreadInit(t)
1530   CthThread t;
1531 {
1532   CthThreadBaseInit(&t->base);
1533 }
1534
1535 /* Threads waiting to be destroyed */
1536 CpvStaticDeclare(CthThread , doomedThreadPool);
1537
1538 void CthInit(char **argv)
1539 {
1540   CthThread t;
1541
1542   CthBaseInit(argv);
1543   t = (CthThread)malloc(sizeof(struct CthThreadStruct));
1544   _MEMCHECK(t);
1545   CthCpvAccess(CthCurrent)=t;
1546   if (0 != getJcontext(&t->context))
1547     CmiAbort("CthInit: getcontext failed.\n");
1548   CthThreadInit(t);
1549   CpvInitialize(CthThread, doomedThreadPool);
1550   CpvAccess(doomedThreadPool) = (CthThread)NULL;
1551
1552   /* don't trust the _defaultStackSize */
1553 #ifdef MINSIGSTKSZ
1554   if (CthCpvAccess(_defaultStackSize) < MINSIGSTKSZ) 
1555     CthCpvAccess(_defaultStackSize) = MINSIGSTKSZ;
1556 #endif
1557 #if CMK_THREADS_USE_CONTEXT
1558   CmiThreadIs_flag |= CMI_THREAD_IS_CONTEXT;
1559 #else
1560   CmiThreadIs_flag |= CMI_THREAD_IS_UJCONTEXT;
1561 #endif
1562 #if CMK_THREADS_ALIAS_STACK
1563   CmiThreadIs_flag |= CMI_THREAD_IS_ALIAS;
1564 #endif
1565 }
1566
1567 static void CthThreadFree(CthThread t)
1568 {
1569   /* avoid freeing thread while it is being used, store in pool and 
1570      free it next time. Note the last thread in pool won't be free'd! */
1571   CthThread doomed=CpvAccess(doomedThreadPool);
1572   CpvAccess(doomedThreadPool) = t;
1573   if (doomed != NULL) {
1574     CthThreadBaseFree(&doomed->base);
1575     free(doomed);
1576   }
1577 }
1578
1579 void CthFree(CthThread t)
1580 {
1581   if (t==NULL) return;
1582   if (t==CthCpvAccess(CthCurrent)) {
1583     t->base.exiting = 1; /* thread is already running-- free on next swap out */
1584   } else {
1585     CthThreadFree(t);
1586   }
1587 }
1588
1589 #if CMK_THREADS_BUILD_TLS
1590 void CthResume(CthThread) __attribute__((optimize(0)));
1591 #endif
1592
1593 void CthResume(t)
1594   CthThread t;
1595 {
1596   CthThread tc;
1597   tc = CthCpvAccess(CthCurrent);
1598
1599 #if CMK_THREADS_BUILD_TLS
1600   switchTLS(&B(tc)->tlsseg, &B(t)->tlsseg);
1601 #endif
1602
1603   if (t != tc) { /* Actually switch threads */
1604     CthBaseResume(t);
1605     if (!tc->base.exiting) 
1606     {
1607       if (0 != swapJcontext(&tc->context, &t->context)) 
1608         CmiAbort("CthResume: swapcontext failed.\n");
1609     } 
1610     else /* tc->base.exiting, so jump directly to next context */ 
1611     {
1612       CthThreadFree(tc);
1613       setJcontext(&t->context);
1614     }
1615   }
1616   /*This check will mistakenly fail if the thread migrates (changing tc)
1617     if (tc!=CthCpvAccess(CthCurrent)) { CmiAbort("Stack corrupted?\n"); }
1618     */
1619 }
1620
1621 #if CMK_THREADS_USE_CONTEXT && CMK_64BIT /* makecontext only pass integer arguments */
1622 void CthStartThread(CmiUInt4 fn1, CmiUInt4 fn2, CmiUInt4 arg1, CmiUInt4 arg2)
1623 {
1624   CmiUInt8 fn0 =  (((CmiUInt8)fn1) << 32) | fn2;
1625   CmiUInt8 arg0 = (((CmiUInt8)arg1) << 32) | arg2;
1626   void *arg = (void *)arg0;
1627   qt_userf_t *fn = (qt_userf_t*)fn0;
1628   (*fn)(arg);
1629   CthThreadFinished(CthSelf());
1630 }
1631 #else
1632 void CthStartThread(qt_userf_t fn,void *arg)
1633 {
1634   fn(arg);
1635   CthThreadFinished(CthSelf());
1636 }
1637 #endif
1638
1639 #define STP_STKALIGN(sp, alignment) \
1640   ((void *)((((qt_word_t)(sp)) + (alignment) - 1) & ~((alignment)-1)))
1641
1642 int ptrDiffLen(const void *a,const void *b) {
1643   char *ac=(char *)a, *bc=(char *)b;
1644   int ret=ac-bc;
1645   if (ret<0) ret=-ret;
1646   return ret;
1647 }
1648
1649 static CthThread CthCreateInner(CthVoidFn fn,void *arg,int size,int migratable)
1650 {
1651   CthThread result;
1652   char *stack, *ss_sp, *ss_end;
1653
1654   result = (CthThread)malloc(sizeof(struct CthThreadStruct));
1655   _MEMCHECK(result);
1656   CthThreadInit(result);
1657 #ifdef MINSIGSTKSZ
1658   /* if (size<MINSIGSTKSZ) size = CthCpvAccess(_defaultStackSize); */
1659   if (size && size<MINSIGSTKSZ) size = MINSIGSTKSZ;
1660 #endif
1661   CthAllocateStack(&result->base,&size,migratable);
1662   stack = result->base.stack;
1663
1664   if (0 != getJcontext(&result->context))
1665     CmiAbort("CthCreateInner: getcontext failed.\n");
1666
1667   ss_end = stack + size;
1668
1669   /**
1670     Decide where to point the uc_stack.ss_sp field of our "context"
1671     structure.  The configuration values CMK_CONTEXT_STACKBEGIN, 
1672     CMK_CONTEXT_STACKEND, and CMK_CONTEXT_STACKMIDDLE determine where to
1673     point ss_sp: to the beginning, end, and middle of the stack buffer
1674     respectively.  The default, used by most machines, is CMK_CONTEXT_STACKBEGIN.
1675     */
1676 #if CMK_THREADS_USE_JCONTEXT /* Jcontext is always STACKBEGIN */
1677   ss_sp = stack;
1678 #elif CMK_CONTEXT_STACKEND /* ss_sp should point to *end* of buffer */
1679   ss_sp = stack+size-MINSIGSTKSZ; /* the MINSIGSTKSZ seems like a hack */
1680   ss_end = stack;
1681 #elif CMK_CONTEXT_STACKMIDDLE /* ss_sp should point to *middle* of buffer */
1682   ss_sp = stack+size/2;
1683 #else /* CMK_CONTEXT_STACKBEGIN, the usual case  */
1684   ss_sp = stack;
1685 #endif
1686
1687   result->context.uc_stack.ss_sp = STP_STKALIGN(ss_sp,sizeof(char *)*8);
1688   result->context.uc_stack.ss_size = ptrDiffLen(result->context.uc_stack.ss_sp,ss_end);
1689   result->context.uc_stack.ss_flags = 0;
1690   result->context.uc_link = 0;
1691
1692   CthAliasEnable(B(result)); /* Change to new thread's stack while building context */
1693   errno = 0;
1694 #if CMK_THREADS_USE_CONTEXT
1695   if (sizeof(void *) == 8) {
1696     CmiUInt4 fn1 = ((CmiUInt8)fn) >> 32;
1697     CmiUInt4 fn2 = (CmiUInt8)fn & 0xFFFFFFFF;
1698     CmiUInt4 arg1 = ((CmiUInt8)arg) >> 32;
1699     CmiUInt4 arg2 = (CmiUInt8)arg & 0xFFFFFFFF;
1700     makeJcontext(&result->context, (uJcontext_fn_t)CthStartThread, 4, fn1, fn2, arg1, arg2);
1701   }
1702   else
1703 #endif
1704     makeJcontext(&result->context, (uJcontext_fn_t)CthStartThread, 2, (void *)fn,(void *)arg);
1705   if(errno !=0) { 
1706     perror("makecontext"); 
1707     CmiAbort("CthCreateInner: makecontext failed.\n");
1708   }
1709   CthAliasEnable(B(CthCpvAccess(CthCurrent)));
1710
1711 #if CMK_THREADS_BUILD_TLS
1712   allocNewTLSSeg(&B(result)->tlsseg, result);
1713 #endif
1714
1715   return result;  
1716 }
1717
1718 CthThread CthCreate(CthVoidFn fn,void *arg,int size)
1719 {
1720   return CthCreateInner(fn,arg,size,0);
1721 }
1722 CthThread CthCreateMigratable(CthVoidFn fn,void *arg,int size)
1723 {
1724   return CthCreateInner(fn,arg,size,1);
1725 }
1726
1727 int CthMigratable()
1728 {
1729   return CmiIsomallocEnabled();
1730 }
1731
1732 CthThread CthPup(pup_er p, CthThread t)
1733 {
1734   int flag;
1735   if (pup_isUnpacking(p)) {
1736     t=(CthThread)malloc(sizeof(struct CthThreadStruct));
1737     _MEMCHECK(t);
1738     CthThreadInit(t);
1739   }
1740   CthPupBase(p,&t->base,1);
1741
1742   /*Pup the processor context as bytes-- this is not guarenteed to work!*/
1743   /* so far, context and context-memoryalias works for IA64, not ia32 */
1744   /* so far, uJcontext and context-memoryalias works for IA32, not ia64 */
1745   pup_bytes(p,&t->context,sizeof(t->context));
1746 #if !CMK_THREADS_USE_JCONTEXT && CMK_CONTEXT_FPU_POINTER
1747 #if ! CMK_CONTEXT_FPU_POINTER_UCREGS
1748   /* context is not portable for ia32 due to pointer in uc_mcontext.fpregs,
1749      pup it separately */
1750   if (!pup_isUnpacking(p)) flag = t->context.uc_mcontext.fpregs != NULL;
1751   pup_int(p,&flag);
1752   if (flag) {
1753     if (pup_isUnpacking(p)) {
1754       t->context.uc_mcontext.fpregs = malloc(sizeof(struct _libc_fpstate));
1755     }
1756     pup_bytes(p,t->context.uc_mcontext.fpregs,sizeof(struct _libc_fpstate));
1757   }
1758 #else             /* net-linux-ppc 32 bit */
1759   if (!pup_isUnpacking(p)) flag = t->context.uc_mcontext.uc_regs != NULL;
1760   pup_int(p,&flag);
1761   if (flag) {
1762     if (pup_isUnpacking(p)) {
1763       t->context.uc_mcontext.uc_regs = malloc(sizeof(mcontext_t));
1764     }
1765     pup_bytes(p,t->context.uc_mcontext.uc_regs,sizeof(mcontext_t));
1766   }
1767 #endif
1768 #endif
1769 #if !CMK_THREADS_USE_JCONTEXT && CMK_CONTEXT_V_REGS
1770   /* linux-ppc  64 bit */
1771   if (pup_isUnpacking(p)) {
1772     t->context.uc_mcontext.v_regs = malloc(sizeof(vrregset_t));
1773   }
1774   pup_bytes(p,t->context.uc_mcontext.v_regs,sizeof(vrregset_t));
1775 #endif
1776   if (pup_isUnpacking(p)) {
1777     t->context.uc_link = 0;
1778   }
1779   if (pup_isDeleting(p)) {
1780     CthFree(t);
1781     return 0;
1782   }
1783   return t;
1784 }
1785
1786 #else 
1787 /***************************************************************
1788   Basic qthreads implementation. 
1789
1790   These threads can also add a "protection block" of
1791   inaccessible memory to detect stack overflows, which
1792   would otherwise just trash the heap.
1793
1794   (7/13/2001 creation times on 300MHz AMD K6-3 x86, Linux 2.2.18:
1795   Qt setjmp, without stackprotect: 18.5 us
1796   Qt i386, without stackprotect: 17.9 us
1797   Qt setjmp, with stackprotect: 68.6 us
1798   )
1799
1800   Written by Josh Yelon around 1995
1801   */
1802
1803 #if !CMK_ERROR_CHECKING || (!CMK_MEMORY_PROTECTABLE)
1804 #  define CMK_STACKPROTECT 0
1805
1806 #  define CthMemAlign(x,n) 0
1807 #  define CthMemoryProtect(m,p,l) CmiAbort("Shouldn't call CthMemoryProtect!\n")
1808 #  define CthMemoryUnprotect(m,p,l) CmiAbort("Shouldn't call CthMemoryUnprotect!\n")
1809 #else
1810 #  define CMK_STACKPROTECT 1
1811
1812 extern void setProtection(char*, char*, int, int);
1813 #  include "sys/mman.h"
1814 #  define CthMemAlign(x,n) memalign((x),(n))
1815 #  define CthMemoryProtect(m,p,l) mprotect(p,l,PROT_NONE);setProtection((char*)m,p,l,1);
1816 #  define CthMemoryUnprotect(m,p,l) mprotect(p,l,PROT_READ | PROT_WRITE);setProtection((char*)m,p,l,0);
1817 #endif
1818
1819 struct CthThreadStruct
1820 {
1821   CthThreadBase base;
1822
1823   char      *protect;
1824   int        protlen;
1825
1826   qt_t      *stack;
1827   qt_t      *stackp;
1828 };
1829
1830 static CthThread CthThreadInit(void)
1831 {
1832   CthThread ret=(CthThread)malloc(sizeof(struct CthThreadStruct));
1833   _MEMCHECK(ret);
1834   CthThreadBaseInit(&ret->base);
1835   ret->protect = 0;
1836   ret->protlen = 0;
1837
1838   return ret;
1839 }
1840
1841 static void CthThreadFree(CthThread t)
1842 {
1843   if (t->protlen!=0) {
1844     CthMemoryUnprotect(t->stack, t->protect, t->protlen);
1845   }
1846   CthThreadBaseFree(&t->base);
1847   free(t);
1848 }
1849
1850 void CthInit(char **argv)
1851 {
1852   CthThread mainThread;
1853
1854   CthBaseInit(argv);  
1855   mainThread=CthThreadInit();
1856   CthCpvAccess(CthCurrent)=mainThread;
1857   /* mainThread->base.suspendable=0;*/ /*Can't suspend main thread (trashes Quickthreads jump buffer)*/
1858
1859   CmiThreadIs_flag |= CMI_THREAD_IS_QT;
1860 #if CMK_THREADS_ALIAS_STACK
1861   CmiThreadIs_flag |= CMI_THREAD_IS_ALIAS;
1862 #endif
1863 }
1864
1865 void CthFree(CthThread t)
1866 {
1867   if (t==NULL) return;
1868   if (t==CthCpvAccess(CthCurrent)) {
1869     t->base.exiting = 1;
1870   } else {
1871     CthThreadFree(t);
1872   }
1873 }
1874
1875 static void *CthAbortHelp(qt_t *sp, CthThread old, void *null)
1876 {
1877   CthThreadFree(old);
1878   return (void *) 0;
1879 }
1880
1881 static void *CthBlockHelp(qt_t *sp, CthThread old, void *null)
1882 {
1883   old->stackp = sp;
1884   return (void *) 0;
1885 }
1886
1887 #if CMK_THREADS_BUILD_TLS
1888 void CthResume(CthThread) __attribute__((optimize(0)));
1889 #endif
1890
1891 void CthResume(t)
1892   CthThread t;
1893 {
1894   CthThread tc = CthCpvAccess(CthCurrent);
1895   if (t == tc) return;
1896
1897 #if CMK_THREADS_BUILD_TLS
1898   switchTLS(&B(tc)->tlsseg, &B(t)->tlsseg);
1899 #endif
1900
1901   CthBaseResume(t);
1902   if (tc->base.exiting) {
1903     QT_ABORT((qt_helper_t*)CthAbortHelp, tc, 0, t->stackp);
1904   } else {
1905     QT_BLOCK((qt_helper_t*)CthBlockHelp, tc, 0, t->stackp);
1906   }
1907   /*This check will mistakenly fail if the thread migrates (changing tc)
1908     if (tc!=CthCpvAccess(CthCurrent)) { CmiAbort("Stack corrupted?\n"); }
1909     */
1910 }
1911
1912 static void CthOnly(void *arg, void *vt, qt_userf_t fn)
1913 {
1914   fn(arg);
1915   CthThreadFinished(CthSelf());
1916 }
1917
1918 static CthThread CthCreateInner(CthVoidFn fn, void *arg, int size,int Migratable)
1919 {
1920   CthThread result; qt_t *stack, *stackbase, *stackp;
1921   int doProtect=(!Migratable) && CMK_STACKPROTECT;
1922   result=CthThreadInit();
1923   if (doProtect) 
1924   { /*Can only protect on a page boundary-- allocate an extra page and align stack*/
1925     if (size==0) size=CthCpvAccess(_defaultStackSize);
1926     size = (size+(CMK_MEMORY_PAGESIZE*2)-1) & ~(CMK_MEMORY_PAGESIZE-1);
1927     stack = (qt_t*)CthMemAlign(CMK_MEMORY_PAGESIZE, size);
1928     B(result)->stack = stack;
1929   } else
1930     stack=CthAllocateStack(&result->base,&size,Migratable);
1931   CthAliasEnable(B(result)); /* Change to new thread's stack while setting args */
1932   stackbase = QT_SP(stack, size);
1933   stackp = QT_ARGS(stackbase, arg, result, (qt_userf_t *)fn, CthOnly);
1934   CthAliasEnable(B(CthCpvAccess(CthCurrent)));
1935   result->stack = stack;
1936   result->stackp = stackp;
1937   if (doProtect) {
1938 #ifdef QT_GROW_UP
1939     /*Stack grows up-- protect highest page of stack*/
1940     result->protect = ((char*)stack) + size - CMK_MEMORY_PAGESIZE;
1941 #else
1942     /*Stack grows down-- protect lowest page in stack*/
1943     result->protect = ((char*)stack);
1944 #endif
1945     result->protlen = CMK_MEMORY_PAGESIZE;
1946     CthMemoryProtect(stack, result->protect, result->protlen);
1947   }
1948
1949 #if CMK_THREADS_BUILD_TLS
1950   allocNewTLSSeg(&B(result)->tlsseg, result);
1951 #endif
1952
1953   return result;
1954 }
1955
1956 CthThread CthCreate(CthVoidFn fn, void *arg, int size)
1957 { return CthCreateInner(fn,arg,size,0);}
1958
1959 CthThread CthCreateMigratable(CthVoidFn fn, void *arg, int size)
1960 { return CthCreateInner(fn,arg,size,1);}
1961
1962 int CthMigratable()
1963 {
1964 #if CMK_THREADS_ALIAS_STACK
1965   return 1;
1966 #else
1967   return CmiIsomallocEnabled();
1968 #endif
1969 }
1970
1971 CthThread CthPup(pup_er p, CthThread t)
1972 {
1973   if (pup_isUnpacking(p)) {
1974     t=CthThreadInit();
1975   }
1976 #if CMK_THREADS_ALIAS_STACK
1977   CthPupBase(p,&t->base,0);
1978 #else
1979   CthPupBase(p,&t->base,1);
1980 #endif
1981
1982   /*Pup the stack pointer as bytes-- this works because stack is migratable*/
1983   pup_bytes(p,&t->stackp,sizeof(t->stackp));
1984
1985   /*Don't worry about stack protection on migration*/  
1986
1987   if (pup_isDeleting(p)) {
1988     CthFree(t);
1989     return 0;
1990   }
1991   return t;
1992 }
1993
1994 /* Functions that help debugging of out-of-core emulation in BigSim */
1995 void CthPrintThdStack(CthThread t){
1996   CmiPrintf("thread=%p, base stack=%p, stack pointer=%p\n", t, t->base.stack, t->stackp);
1997 }
1998 #endif
1999
2000 #if ! USE_SPECIAL_STACKPOINTER
2001 size_t CthStackOffset(CthThread t, char *p)
2002 {
2003   size_t s;
2004   CmiAssert(t);
2005   if (B(t)->stack == NULL)      /* fiber, pthread */
2006     s = p - (char *)t;
2007   else
2008     s = p - (char *)B(t)->stack;
2009   /* size_t s = (size_t)p; */
2010   return s;
2011 }
2012
2013 char * CthPointer(CthThread t, size_t pos)
2014 {
2015   char *p;
2016   CmiAssert(t);
2017   if (B(t)->stack == NULL)      /* fiber, pthread */
2018     p = (char*)t + pos;
2019   else
2020     p = (char *)B(t)->stack + pos;
2021   /* char *p = (char *)size; */
2022   return p;
2023 }
2024 #endif
2025
2026
2027 void CthTraceResume(CthThread t)
2028 {
2029   traceResume(&t->base.tid);
2030 }
2031
2032 /* Functions that help debugging of out-of-core emulation in BigSim */
2033 void CthPrintThdMagic(CthThread t){
2034   CmiPrintf("CthThread[%p]'s magic: %x\n", t, t->base.magic);
2035 }
2036