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