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