commit a lot of unwanted changes.
[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
609 /************ Scheduler Interface **********/
610
611 void CthSetSuspendable(CthThread t, int val) { B(t)->suspendable = val; }
612 int CthIsSuspendable(CthThread t) { return B(t)->suspendable; }
613
614 void CthSetNext(CthThread t, CthThread v) { B(t)->next = v; }
615 CthThread CthGetNext(CthThread t) { return B(t)->next; }
616
617 static void CthNoStrategy(void)
618 {
619   CmiAbort("Called CthAwaken or CthSuspend before calling CthSetStrategy.\n");
620 }
621
622 void CthSetStrategy(CthThread t, CthAwkFn awkfn, CthThFn chsfn)
623 {
624   B(t)->awakenfn = awkfn;
625   B(t)->choosefn = chsfn;
626 }
627
628 #if CMK_C_INLINE
629 inline
630 #endif
631 static void CthBaseResume(CthThread t)
632 {
633   struct CthThreadListener *l;
634   for(l=B(t)->listener;l!=NULL;l=l->next){
635         if (l->resume) l->resume(l);
636   }
637   CpvAccess(_numSwitches)++;
638   CthFixData(t); /*Thread-local storage may have changed in other thread.*/
639   CthCpvAccess(CthCurrent) = t;
640   CthCpvAccess(CthData) = B(t)->data;
641   CthAliasEnable(B(t));
642 }
643
644 /**
645   switch the thread to t
646 */
647 void CthSwitchThread(CthThread t)
648 {
649   CthBaseResume(t);
650 }
651
652 /*
653 Suspend: finds the next thread to execute, and resumes it
654 */
655 void CthSuspend(void)
656 {
657   CthThread next;
658   struct CthThreadListener *l;
659   CthThreadBase *cur=B(CthCpvAccess(CthCurrent));
660
661   if (cur->suspendable == 0)
662     CmiAbort("Fatal Error> trying to suspend a non-suspendable thread!\n");
663   
664   /*
665         Call the suspend function on listeners
666   */
667   for(l=cur->listener;l!=NULL;l=l->next){
668         if (l->suspend) l->suspend(l);
669   }
670   if (cur->choosefn == 0) CthNoStrategy();
671   next = cur->choosefn();
672   /*cur->scheduled=0;*/
673   /*changed due to out-of-core emulation in BigSim*/
674   /** Sometimes, a CthThread is running without ever being awakened
675     * In this case, the scheduled is the initialized value "0"
676     */
677   if(cur->scheduled > 0)
678     cur->scheduled--;
679
680 #ifndef CMK_OPTIMIZE
681   if(cur->scheduled<0)
682     CmiAbort("A thread's scheduler should not be less than 0!\n");
683 #endif    
684
685 #if CMK_TRACE_ENABLED
686 #if !CMK_TRACE_IN_CHARM
687   if(CpvAccess(traceOn))
688     traceSuspend();
689 #endif
690 #endif
691   CthResume(next);
692 }
693
694 void CthAwaken(CthThread th)
695 {
696   if (B(th)->awakenfn == 0) CthNoStrategy();
697
698   /*BIGSIM_OOC DEBUGGING
699   if(B(th)->scheduled==1){
700     CmiPrintf("====Thread %p is already scheduled!!!!\n", th);
701     return;
702   } */
703
704 #if CMK_TRACE_ENABLED
705 #if ! CMK_TRACE_IN_CHARM
706   if(CpvAccess(traceOn))
707     traceAwaken(th);
708 #endif
709 #endif
710   B(th)->awakenfn(B(th)->token, CQS_QUEUEING_FIFO, 0, 0);
711   /*B(th)->scheduled = 1; */
712   /*changed due to out-of-core emulation in BigSim */
713   B(th)->scheduled++;
714 }
715
716 void CthYield()
717 {
718   CthAwaken(CthCpvAccess(CthCurrent));
719   CthSuspend();
720 }
721
722 void CthAwakenPrio(CthThread th, int s, int pb, unsigned int *prio)
723 {
724   if (B(th)->awakenfn == 0) CthNoStrategy();
725 #if CMK_TRACE_ENABLED
726 #if ! CMK_TRACE_IN_CHARM
727   if(CpvAccess(traceOn))
728     traceAwaken(th);
729 #endif
730 #endif
731   B(th)->awakenfn(B(th)->token, s, pb, prio);
732   /*B(th)->scheduled = 1; */
733   /*changed due to out-of-core emulation in BigSim */
734   B(th)->scheduled++;
735 }
736
737 void CthYieldPrio(int s, int pb, unsigned int *prio)
738 {
739   CthAwakenPrio(CthCpvAccess(CthCurrent), s, pb, prio);
740   CthSuspend();
741 }
742
743 /*
744         Add a new thread listener to a thread 
745 */
746 void CthAddListener(CthThread t,struct CthThreadListener *l){
747                 struct CthThreadListener *p=B(t)->listener;
748                 if(p== NULL){ /* first listener */
749                         B(t)->listener=l;
750                         l->thread = t;
751                         l->next=NULL;
752                         return; 
753                 }
754                 /* Add l at end of current chain of listeners: */
755                 while(p->next != NULL){
756                         p = p->next;
757                 }
758                 p->next = l;
759                 l->next = NULL;
760                 l->thread = t;
761 }
762
763 /*************************** Stack-Copying Threads (obsolete) *******************
764 Basic idea: switch from thread A (currently running) to thread B by copying
765 A's stack from the system stack area into A's buffer in the heap, then
766 copy B's stack from its heap buffer onto the system stack.
767
768 This allows thread migration, because the system stack is in the same
769 location on every processor; but the context-switching overhead (especially
770 for threads with deep stacks) is extremely high.
771
772 Written by Josh Yelon around May 1999
773
774 stack grows down like:
775 lo   <- savedptr    <- savedstack
776
777 ...
778
779 high <- stackbase
780
781 NOTE: this only works when system stack base is same on all processors.
782 Which is not the case on my FC4 laptop ?!
783
784 extended it to work for tcharm and registered user data migration
785 tested platforms: opteron, Cygwin.
786
787 For Fedora and Ubuntu, run the following command as root
788 echo 0 > /proc/sys/kernel/randomize_va_space
789 will disable the randomization of the stack pointer
790
791 Gengbin Zheng March, 2006
792 */
793
794 #if CMK_THREADS_USE_STACKCOPY
795
796 #define SWITCHBUF_SIZE 32768
797
798 typedef struct CthProcInfo *CthProcInfo;
799
800 typedef struct CthThreadStruct
801 {
802   CthThreadBase base;
803   CthVoidFn  startfn;    /* function that thread will execute */
804   void      *startarg;   /* argument that start function will be passed */
805   qt_t      *savedstack; /* pointer to saved stack */
806   int        savedsize;  /* length of saved stack (zero when running) */        
807   int        stacklen;   /* length of the allocated savedstack >= savedsize */
808   qt_t      *savedptr;   /* stack pointer */    
809 } CthThreadStruct;
810
811 int CthMigratable()
812 {
813   return 1;
814 }
815
816 CthThread CthPup(pup_er p, CthThread t)
817 {
818     if (pup_isUnpacking(p))
819       { t = (CthThread) malloc(sizeof(CthThreadStruct));_MEMCHECK(t);}
820     pup_bytes(p, (void*) t, sizeof(CthThreadStruct)); 
821     CthPupBase(p,&t->base,0);
822     pup_int(p,&t->savedsize);
823     if (pup_isUnpacking(p)) {
824       t->savedstack = (qt_t*) malloc(t->savedsize);_MEMCHECK(t->savedstack);
825       t->stacklen = t->savedsize;       /* reflect actual size */
826     }
827     pup_bytes(p, (void*) t->savedstack, t->savedsize);
828
829       /* assume system stacks are same on all processors !! */
830     pup_bytes(p,&t->savedptr,sizeof(t->savedptr));  
831
832     if (pup_isDeleting(p))
833       {CthFree(t);t=0;}
834     return t;
835 }
836
837
838
839 struct CthProcInfo
840 {
841   qt_t      *stackbase;
842   qt_t      *switchbuf_sp;
843   qt_t      *switchbuf;
844 };
845
846 CthCpvDeclare(CthProcInfo, CthProc);
847
848 static void CthThreadInit(CthThread t, CthVoidFn fn, void *arg)
849 {
850   CthThreadBaseInit(&t->base);
851   t->startfn = fn;
852   t->startarg = arg;
853   t->savedstack = 0;
854   t->savedsize = 0;
855   t->stacklen = 0;
856   t->savedptr = 0;
857 }
858
859 static void CthThreadFree(CthThread t)
860 {
861   CthThreadBaseFree(&t->base);
862   if (t->savedstack) free(t->savedstack);
863   free(t);
864 }
865
866 void CthFree(t)
867 CthThread t;
868 {
869   if (t==NULL) return;
870   CthProcInfo proc = CthCpvAccess(CthProc);     
871
872   if (t != CthSelf()) {
873     CthThreadFree(t);
874   } else
875     t->base.exiting = 1;
876 }
877
878 void CthDummy() { }
879
880 void CthInit(char **argv)
881 {
882   CthThread t; CthProcInfo p; qt_t *switchbuf, *sp;
883
884   CthCpvInitialize(CthProcInfo, CthProc);
885
886   CthBaseInit(argv);
887   t = (CthThread)malloc(sizeof(struct CthThreadStruct));
888   _MEMCHECK(t);
889   CthCpvAccess(CthCurrent)=t;
890   CthThreadInit(t,0,0);
891
892   p = (CthProcInfo)malloc(sizeof(struct CthProcInfo));
893   _MEMCHECK(p);
894   CthCpvAccess(CthProc)=p;
895
896   /* leave some space for current stack frame < 256 bytes */
897   /* sp must be same on all processors for migration to work ! */
898   sp = (qt_t*)(((size_t)&t) & ~((size_t)0xFF));
899 /*printf("[%d] System stack base: %p\n", CmiMyPe(), sp);*/
900   p->stackbase = QT_SP(sp, 0x100);
901
902   /* printf("sp: %p\n", sp); */
903
904   switchbuf = (qt_t*)malloc(QT_STKALIGN + SWITCHBUF_SIZE);
905   _MEMCHECK(switchbuf);
906   switchbuf = (qt_t*)((((size_t)switchbuf)+QT_STKALIGN) & ~(QT_STKALIGN-1));
907   p->switchbuf = switchbuf;
908   sp = QT_SP(switchbuf, SWITCHBUF_SIZE);
909   sp = QT_ARGS(sp,0,0,0,(qt_only_t*)CthDummy);
910   p->switchbuf_sp = sp;
911
912   CmiThreadIs_flag |= CMI_THREAD_IS_STACKCOPY;
913 }
914
915 static void CthOnly(CthThread t, void *dum1, void *dum2)
916 {
917   t->startfn(t->startarg);
918   CthThreadFinished(t);
919 }
920
921 #define USE_SPECIAL_STACKPOINTER    1
922
923 /* p is a pointer on stack */
924 size_t CthStackOffset(CthThread t, char *p)
925 {
926   CthProcInfo proc = CthCpvAccess(CthProc);
927   return p - (char *)proc->stackbase;
928 }
929
930 char * CthPointer(CthThread t, size_t pos)
931 {
932   char *stackbase;
933   CmiAssert(t);
934   CthProcInfo proc = CthCpvAccess(CthProc);
935   if (CthCpvAccess(CthCurrent) == t)    /* current thread uses current stack */
936     stackbase = (char *)proc->stackbase;
937   else                                  /* sleep thread uses its saved stack */
938     stackbase = (char *)t->savedstack;
939 #ifdef QT_GROW_DOWN
940   char *p = stackbase + t->savedsize + pos;
941 #else
942   char *p = stackbase + pos;
943 #endif
944   return p;
945 }
946
947 static void CthResume1(qt_t *sp, CthProcInfo proc, CthThread t)
948 {
949   int bytes; qt_t *lo, *hi;
950   CthThread old = CthCpvAccess(CthCurrent);
951   CthBaseResume(t);
952   if (old->base.exiting) {
953     CthThreadFree(old);
954   } else {
955 #ifdef QT_GROW_DOWN
956     lo = sp; hi = proc->stackbase;
957 #else
958     hi = sp; lo = proc->stackbase;
959 #endif
960     bytes = ((size_t)hi)-((size_t)lo);
961     if(bytes > old->stacklen) {
962       if(old->savedstack) free((void *)old->savedstack);
963       old->savedstack = (qt_t*)malloc(bytes);
964       _MEMCHECK(old->savedstack);
965       old->stacklen = bytes;
966     }
967     old->savedsize = bytes;
968     old->savedptr = sp;
969     memcpy(old->savedstack, lo, bytes);
970   }
971   if (t->savedstack) {
972 #ifdef QT_GROW_DOWN
973     lo = t->savedptr;
974 #else
975     lo = proc->stackbase;
976 #endif
977     memcpy(lo, t->savedstack, t->savedsize);
978     t->savedsize=0;
979     sp = t->savedptr;
980   } else {
981     sp = proc->stackbase;
982     sp = QT_ARGS(sp,t,0,0,(qt_only_t*)CthOnly);
983   }
984   QT_ABORT((qt_helper_t*)CthDummy,0,0,sp);
985 }
986
987 void CthResume(t)
988 CthThread t;
989 {
990   CthProcInfo proc = CthCpvAccess(CthProc);
991   QT_BLOCK((qt_helper_t*)CthResume1, proc, t, proc->switchbuf_sp);
992 }
993
994 CthThread CthCreate(CthVoidFn fn,void *arg,int size)
995 {
996   CthThread result = (CthThread)malloc(sizeof(struct CthThreadStruct));
997   _MEMCHECK(result);
998   CthThreadInit(result, fn, arg);
999   return result;
1000 }
1001 CthThread CthCreateMigratable(CthVoidFn fn,void *arg,int size)
1002 {
1003   /*All threads are migratable under stack copying*/
1004   return CthCreate(fn,arg,size);
1005 }
1006
1007 /**************************************************************************
1008 QuickThreads does not work on Win32-- our stack-shifting large allocas
1009 fail a stack depth check.  Windows NT and 98 provide a user-level thread 
1010 interface called "Fibers", used here.
1011
1012 Written by Sameer Paranjpye around October 2000
1013 */
1014 #elif  CMK_THREADS_ARE_WIN32_FIBERS
1015 #include <windows.h>
1016 #include <winbase.h>
1017
1018 #ifndef _WIN32_WINNT
1019 #define _WIN32_WINNT  0x0400
1020 #endif
1021
1022 #if(_WIN32_WINNT >= 0x0400)
1023 typedef VOID (WINAPI *PFIBER_START_ROUTINE)(
1024     LPVOID lpFiberParameter
1025     );
1026 typedef PFIBER_START_ROUTINE LPFIBER_START_ROUTINE;
1027 #endif
1028
1029 #if(_WIN32_WINNT >= 0x0400)
1030 WINBASEAPI
1031 LPVOID
1032 WINAPI
1033 CreateFiber(
1034     DWORD dwStackSize,
1035     LPFIBER_START_ROUTINE lpStartAddress,
1036     LPVOID lpParameter
1037     );
1038
1039 WINBASEAPI
1040 LPVOID 
1041 WINAPI 
1042 CreateFiberEx(
1043     SIZE_T dwStackCommitSize,
1044     SIZE_T dwStackReserveSize,
1045     DWORD dwFlags,
1046     LPFIBER_START_ROUTINE lpStartAddress,
1047     LPVOID lpParameter
1048 );
1049
1050
1051 WINBASEAPI
1052 VOID
1053 WINAPI
1054 DeleteFiber(
1055     LPVOID lpFiber
1056     );
1057
1058 WINBASEAPI
1059 LPVOID
1060 WINAPI
1061 ConvertThreadToFiber(
1062     LPVOID lpParameter
1063     );
1064
1065 WINBASEAPI
1066 VOID
1067 WINAPI
1068 SwitchToFiber(
1069     LPVOID lpFiber
1070     );
1071
1072 WINBASEAPI
1073 BOOL
1074 WINAPI
1075 SwitchToThread(
1076     VOID
1077     );
1078 #endif /* _WIN32_WINNT >= 0x0400 */
1079
1080
1081 struct CthThreadStruct
1082 {
1083   CthThreadBase base;
1084   LPVOID     fiber;
1085 };
1086
1087 CthCpvStatic(CthThread,  CthPrevious);
1088
1089 typedef CthThread *threadTable;
1090 CthCpvStatic(int,     tablesize);
1091 CthCpvStatic(threadTable, exitThreads);
1092 CthCpvStatic(int,     nExit);
1093
1094 static void CthThreadInit(CthThread t)
1095 {
1096   CthThreadBaseInit(&t->base);
1097 }
1098
1099 void CthInit(char **argv)
1100 {
1101   CthThread t;
1102   int i;
1103
1104   CthCpvInitialize(CthThread,  CthPrevious);
1105   CthCpvInitialize(int,        nExit);
1106   CthCpvInitialize(threadTable,        exitThreads);
1107   CthCpvInitialize(int, tablesize);
1108
1109 #define INITIALSIZE 128
1110   CthCpvAccess(tablesize) = INITIALSIZE;   /* initial size */
1111   CthCpvAccess(exitThreads) = (threadTable)malloc(sizeof(CthThread)*INITIALSIZE);
1112   for (i=0; i<INITIALSIZE; i++) CthCpvAccess(exitThreads)[i] = NULL;
1113
1114   CthCpvAccess(CthPrevious)=0;
1115   CthCpvAccess(nExit)=0;
1116
1117   CthBaseInit(argv);  
1118   t = (CthThread)malloc(sizeof(struct CthThreadStruct));
1119   _MEMCHECK(t);
1120   CthCpvAccess(CthCurrent)=t;
1121   CthThreadInit(t);
1122   t->fiber = ConvertThreadToFiber(t);
1123   _MEMCHECK(t->fiber);
1124
1125   CmiThreadIs_flag |= CMI_THREAD_IS_FIBERS;
1126 }
1127
1128 void CthThreadFree(CthThread old)
1129 {
1130   CthThreadBaseFree(&old->base);
1131   if (old->fiber) DeleteFiber((PVOID)old->fiber);
1132   free(old);
1133 }
1134
1135 static void CthClearThreads()
1136 {
1137   int i,p,m;
1138   int n = CthCpvAccess(nExit);
1139   CthThread tc = CthCpvAccess(CthCurrent);
1140   CthThread tp = CthCpvAccess(CthPrevious);
1141   m = n;
1142   p=0;
1143   for (i=0; i<m; i++) {
1144     CthThread t = CthCpvAccess(exitThreads)[i];
1145     if (t && t != tc && t != tp) {
1146       CthThreadFree(t);
1147       CthCpvAccess(nExit) --;
1148     }
1149     else {
1150       if (p != i) CthCpvAccess(exitThreads)[p] = t;
1151       p++;
1152     }
1153   }
1154   if (m!=p)
1155   for (i=m; i<n; i++,p++) {
1156       CthCpvAccess(exitThreads)[p] = CthCpvAccess(exitThreads)[i];
1157   }
1158 }
1159
1160 void CthFree(CthThread t)
1161 {
1162   int i;
1163   if (t==NULL) return;
1164
1165   if(CthCpvAccess(nExit) >= CthCpvAccess(tablesize)) {   /* expand */
1166     threadTable newtable;
1167     int oldsize = CthCpvAccess(tablesize);
1168     CthCpvAccess(tablesize) *= 2;
1169     newtable = (threadTable)malloc(sizeof(CthThread)*CthCpvAccess(tablesize));
1170     for (i=0; i<CthCpvAccess(tablesize); i++) newtable[i] = NULL;
1171     for (i=0; i<oldsize; i++) newtable[i] = CthCpvAccess(exitThreads)[i];
1172     free(CthCpvAccess(exitThreads));
1173     CthCpvAccess(exitThreads) = newtable;
1174   }
1175
1176   /* store into exiting threads table to avoid delete thread itself */
1177   CthCpvAccess(exitThreads)[CthCpvAccess(nExit)++] = t;
1178   if (t==CthCpvAccess(CthCurrent)) 
1179   {
1180      t->base.exiting = 1;
1181   } 
1182   else 
1183   {
1184     CthClearThreads();
1185 /*  was
1186     if (t->data) free(t->data);
1187     DeleteFiber(t->fiber);
1188     free(t);
1189 */
1190   }
1191 }
1192
1193 #if 0
1194 void CthFiberBlock(CthThread t)
1195 {
1196   CthThread tp;
1197   
1198   SwitchToFiber(t->fiber);
1199   tp = CthCpvAccess(CthPrevious);
1200   if (tp != 0 && tp->killed == 1)
1201     CthThreadFree(tp);
1202 }
1203 #endif
1204
1205 void CthResume(CthThread t)
1206 {
1207   CthThread tc;
1208
1209   tc = CthCpvAccess(CthCurrent);
1210   if (t == tc) return;
1211   CthBaseResume(t);
1212   CthCpvAccess(CthPrevious)=tc;
1213 #if 0
1214   if (tc->base.exiting) 
1215   {
1216     SwitchToFiber(t->fiber);
1217   } 
1218   else 
1219     CthFiberBlock(t);
1220 #endif
1221   SwitchToFiber(t->fiber);
1222 }
1223
1224 VOID CALLBACK FiberSetUp(PVOID fiberData)
1225 {
1226   void **ptr = (void **) fiberData;
1227   qt_userf_t* fn = (qt_userf_t *)ptr[0];
1228   void *arg = ptr[1];
1229   CthThread  t = CthSelf();
1230
1231   CthClearThreads();
1232
1233   fn(arg);
1234
1235   CthCpvAccess(exitThreads)[CthCpvAccess(nExit)++] = t;
1236   CthThreadFinished(t);
1237 }
1238
1239 CthThread CthCreate(CthVoidFn fn, void *arg, int size)
1240 {
1241   CthThread result; 
1242   void**    fiberData;
1243   fiberData = (void**)malloc(2*sizeof(void *));
1244   fiberData[0] = (void *)fn;
1245   fiberData[1] = arg;
1246   
1247   result = (CthThread)malloc(sizeof(struct CthThreadStruct));
1248   _MEMCHECK(result);
1249   CthThreadInit(result);
1250   /* result->fiber = CreateFiber(size, FiberSetUp, (PVOID) fiberData); */
1251   result->fiber = CreateFiberEx(size, size, 0, FiberSetUp, (PVOID) fiberData);
1252   if (!result->fiber)
1253     CmiAbort("CthCreate failed to create fiber!\n");
1254   
1255   return result;
1256 }
1257
1258 int CthMigratable()
1259 {
1260   return 0;
1261 }
1262 CthThread CthPup(pup_er p, CthThread t)
1263 {
1264   CmiAbort("CthPup not implemented.\n");
1265   return 0;
1266 }
1267 CthThread CthCreateMigratable(CthVoidFn fn,void *arg,int size)
1268 {
1269   /*Fibers are never migratable, unless we can figure out how to set their stacks*/
1270   return CthCreate(fn,arg,size);
1271 }
1272
1273 /***************************************************
1274 Use Posix Threads to simulate cooperative user-level
1275 threads.  This version is very portable but inefficient.
1276
1277 Written by Milind Bhandarkar around November 2000
1278
1279 IMPORTANT:  for SUN, must link with -mt compiler flag
1280 Rewritten by Gengbin Zheng
1281 */
1282 #elif CMK_THREADS_USE_PTHREADS
1283
1284 #include <pthread.h>
1285 #include <errno.h> /* for perror */
1286
1287 struct CthThreadStruct
1288 {
1289   CthThreadBase base;
1290   pthread_t  self;
1291   pthread_cond_t cond;
1292   pthread_cond_t *creator;
1293   CthVoidFn  fn;
1294   void      *arg;
1295   char       inited;
1296 };
1297
1298 /**
1299   The sched_mutex is the current token of execution.
1300   Only the running thread holds this lock; all other threads
1301   have released the lock and are waiting on their condition variable.
1302 */
1303 CthCpvStatic(pthread_mutex_t, sched_mutex);
1304
1305 static void CthThreadInit(t)
1306 CthThread t;
1307 {
1308   CthThreadBaseInit(&t->base);
1309   t->inited = 0;
1310   pthread_cond_init(&(t->cond) , (pthread_condattr_t *) 0);
1311 }
1312
1313 void CthInit(char **argv)
1314 {
1315   CthThread t;
1316
1317   CthCpvInitialize(pthread_mutex_t, sched_mutex);
1318
1319   pthread_mutex_init(&CthCpvAccess(sched_mutex), (pthread_mutexattr_t *) 0);
1320   pthread_mutex_lock(&CthCpvAccess(sched_mutex));
1321   CthBaseInit(argv); 
1322   t = (CthThread)malloc(sizeof(struct CthThreadStruct));
1323   _MEMCHECK(t);
1324   CthCpvAccess(CthCurrent)=t;
1325   CthThreadInit(t);
1326   t->self = pthread_self();
1327
1328   CmiThreadIs_flag |= CMI_THREAD_IS_PTHREADS;
1329 }
1330
1331 void CthFree(t)
1332 CthThread t;
1333 {
1334   if (t==NULL) return;
1335   if (t==CthCpvAccess(CthCurrent)) {
1336     t->base.exiting = 1;
1337   } else {
1338     CthThreadBaseFree(&t->base);
1339     free(t);
1340   }
1341 }
1342
1343 void CthResume(CthThread t)
1344 {
1345   CthThread tc = CthCpvAccess(CthCurrent);
1346   if (t == tc) return;
1347   CthBaseResume(t);
1348   pthread_cond_signal(&(t->cond)); /* wake up the next thread */
1349   if (tc->base.exiting) {
1350     pthread_mutex_unlock(&CthCpvAccess(sched_mutex));
1351     pthread_exit(0);
1352   } else {
1353     /* pthread_cond_wait might (with low probability) return when the 
1354       condition variable has not been signaled, guarded with 
1355       predicate checks */
1356     do {
1357     pthread_cond_wait(&(tc->cond), &CthCpvAccess(sched_mutex));
1358     } while (tc!=CthCpvAccess(CthCurrent)) ;
1359   }
1360 }
1361
1362 static void *CthOnly(void * arg)
1363 {
1364   CthThread th = (CthThread)arg;
1365   th->inited = 1;
1366   pthread_detach(pthread_self());
1367   pthread_mutex_lock(&CthCpvAccess(sched_mutex));
1368   pthread_cond_signal(th->creator);
1369   do {
1370   pthread_cond_wait(&(th->cond), &CthCpvAccess(sched_mutex));
1371   } while (arg!=CthCpvAccess(CthCurrent)) ;
1372   th->fn(th->arg);
1373   CthThreadFinished(th);
1374   return 0;
1375 }
1376
1377 CthThread CthCreate(CthVoidFn fn, void *arg, int size)
1378 {
1379   static int reported = 0;
1380   pthread_attr_t attr;
1381   int r;
1382   CthThread result;
1383   CthThread self = CthSelf();
1384   /* size is ignored in this version */
1385   result = (CthThread)malloc(sizeof(struct CthThreadStruct));
1386   _MEMCHECK(result);
1387   CthThreadInit(result);
1388   result->fn = fn;
1389   result->arg = arg;
1390   result->creator = &(self->cond);
1391
1392   /* try set pthread stack, not necessarily supported on all platforms */
1393   pthread_attr_init(&attr);
1394   /* pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); */
1395   if (size<1024) size = CthCpvAccess(_defaultStackSize);
1396   if (0!=(r=pthread_attr_setstacksize(&attr,size))) {
1397       if (!reported) {
1398         CmiPrintf("Warning: pthread_attr_setstacksize failed\n");
1399         errno = r;
1400         perror("pthread_attr_setstacksize");
1401         reported = 1;
1402       }
1403   }
1404         
1405   /* **CWL** Am assuming Gengbin left this unchanged because the macro
1406      re-definition of pthread_create would not happen before this part of
1407      the code. If the assumption is not true, then we can simply replace
1408      this hash-if with the else portion.
1409   */
1410 #if CMK_WITH_TAU
1411   r = tau_pthread_create(&(result->self), &attr, CthOnly, (void*) result);
1412 #else
1413   r = pthread_create(&(result->self), &attr, CthOnly, (void*) result);
1414 #endif
1415   if (0 != r) {
1416     CmiPrintf("pthread_create failed with %d\n", r);
1417     CmiAbort("CthCreate failed to created a new pthread\n");
1418   }
1419   do {
1420   pthread_cond_wait(&(self->cond), &CthCpvAccess(sched_mutex));
1421   } while (result->inited==0);
1422   return result;
1423 }
1424
1425 int CthMigratable()
1426 {
1427   return 0;
1428 }
1429 CthThread CthPup(pup_er p, CthThread t)
1430 {
1431   CmiAbort("CthPup not implemented.\n");
1432   return 0;
1433 }
1434 CthThread CthCreateMigratable(CthVoidFn fn,void *arg,int size)
1435 {
1436   /*Pthreads are never migratable, unless we can figure out how to set their stacks*/
1437   return CthCreate(fn,arg,size);
1438 }
1439
1440 /***************************************************************
1441 Use SysV r3 setcontext/getcontext calls instead of
1442 quickthreads.  This works on lots of architectures (such as
1443 SUN, IBM SP, O2K, DEC Alpha, IA64, Cray X1, Linux with newer version of 
1444  glibc such as the one with RH9) 
1445 On some machine such as IA64 and Cray X1, the context version is the 
1446 only thread package that is working. 
1447
1448 Porting should be easy. To port context threads, one need to set the 
1449 direction of the thread stack properly in conv-mach.h.
1450
1451 Note: on some machine like Sun and IBM SP, one needs to link with memory gnuold
1452  to have this context thread working.
1453
1454 Written by Gengbin Zheng around April 2001
1455
1456 For thread checkpoint/restart, isomalloc requires that iso region from all
1457 machines are same.
1458
1459 For Fedora and Ubuntu, run the following command as root
1460 echo 0 > /proc/sys/kernel/randomize_va_space
1461 will disable the randomization of the stack pointer
1462
1463 Gengbin Zheng October, 2007
1464
1465 */
1466 #elif (CMK_THREADS_USE_CONTEXT || CMK_THREADS_USE_JCONTEXT)
1467
1468 #include <signal.h>
1469 #include <errno.h>
1470
1471 #if CMK_THREADS_USE_CONTEXT
1472 /* system builtin context routines: */
1473 #include <ucontext.h>
1474
1475 #define uJcontext_t ucontext_t
1476 #define setJcontext setcontext
1477 #define getJcontext getcontext
1478 #define swapJcontext swapcontext
1479 #define makeJcontext makecontext
1480 typedef void (*uJcontext_fn_t)(void);
1481
1482 #else /* CMK_THREADS_USE_JCONTEXT */
1483 /* Orion's setjmp-based context routines: */
1484 #include <uJcontext.h>
1485 #include <uJcontext.c>
1486
1487 #endif
1488
1489
1490 struct CthThreadStruct
1491 {
1492   CthThreadBase base;
1493   double * dummy;
1494   uJcontext_t context;
1495 };
1496
1497
1498 static void CthThreadInit(t)
1499 CthThread t;
1500 {
1501   CthThreadBaseInit(&t->base);
1502 }
1503
1504 /* Threads waiting to be destroyed */
1505 CpvStaticDeclare(CthThread , doomedThreadPool);
1506
1507 void CthInit(char **argv)
1508 {
1509   CthThread t;
1510
1511   CthBaseInit(argv);
1512   t = (CthThread)malloc(sizeof(struct CthThreadStruct));
1513   _MEMCHECK(t);
1514   CthCpvAccess(CthCurrent)=t;
1515   if (0 != getJcontext(&t->context))
1516     CmiAbort("CthInit: getcontext failed.\n");
1517   CthThreadInit(t);
1518   CpvInitialize(CthThread, doomedThreadPool);
1519   CpvAccess(doomedThreadPool) = (CthThread)NULL;
1520
1521   /* don't trust the _defaultStackSize */
1522 #ifdef MINSIGSTKSZ
1523   if (CthCpvAccess(_defaultStackSize) < MINSIGSTKSZ) 
1524     CthCpvAccess(_defaultStackSize) = MINSIGSTKSZ;
1525 #endif
1526 #if CMK_THREADS_USE_CONTEXT
1527   CmiThreadIs_flag |= CMI_THREAD_IS_CONTEXT;
1528 #else
1529   CmiThreadIs_flag |= CMI_THREAD_IS_UJCONTEXT;
1530 #endif
1531 #if CMK_THREADS_ALIAS_STACK
1532   CmiThreadIs_flag |= CMI_THREAD_IS_ALIAS;
1533 #endif
1534 }
1535
1536 static void CthThreadFree(CthThread t)
1537 {
1538   /* avoid freeing thread while it is being used, store in pool and 
1539      free it next time. Note the last thread in pool won't be free'd! */
1540   CthThread doomed=CpvAccess(doomedThreadPool);
1541   CpvAccess(doomedThreadPool) = t;
1542   if (doomed != NULL) {
1543     CthThreadBaseFree(&doomed->base);
1544     free(doomed);
1545   }
1546 }
1547
1548 void CthFree(CthThread t)
1549 {
1550   if (t==NULL) return;
1551   if (t==CthCpvAccess(CthCurrent)) {
1552     t->base.exiting = 1; /* thread is already running-- free on next swap out */
1553   } else {
1554     CthThreadFree(t);
1555   }
1556 }
1557
1558 void CthResume(t)
1559 CthThread t;
1560 {
1561   CthThread tc;
1562   tc = CthCpvAccess(CthCurrent);
1563   if (t != tc) { /* Actually switch threads */
1564     CthBaseResume(t);
1565     if (!tc->base.exiting) 
1566     {
1567       if (0 != swapJcontext(&tc->context, &t->context)) 
1568         CmiAbort("CthResume: swapcontext failed.\n");
1569     } 
1570     else /* tc->base.exiting, so jump directly to next context */ 
1571     {
1572       CthThreadFree(tc);
1573       setJcontext(&t->context);
1574     }
1575   }
1576 /*This check will mistakenly fail if the thread migrates (changing tc)
1577   if (tc!=CthCpvAccess(CthCurrent)) { CmiAbort("Stack corrupted?\n"); }
1578 */
1579 }
1580
1581 #if CMK_THREADS_USE_CONTEXT && CMK_64BIT /* makecontext only pass integer arguments */
1582 void CthStartThread(CmiUInt4 fn1, CmiUInt4 fn2, CmiUInt4 arg1, CmiUInt4 arg2)
1583 {
1584   CmiUInt8 fn0 =  (((CmiUInt8)fn1) << 32) | fn2;
1585   CmiUInt8 arg0 = (((CmiUInt8)arg1) << 32) | arg2;
1586   void *arg = (void *)arg0;
1587   qt_userf_t *fn = (qt_userf_t*)fn0;
1588   (*fn)(arg);
1589   CthThreadFinished(CthSelf());
1590 }
1591 #else
1592 void CthStartThread(qt_userf_t fn,void *arg)
1593 {
1594   fn(arg);
1595   CthThreadFinished(CthSelf());
1596 }
1597 #endif
1598
1599 #define STP_STKALIGN(sp, alignment) \
1600   ((void *)((((qt_word_t)(sp)) + (alignment) - 1) & ~((alignment)-1)))
1601
1602 int ptrDiffLen(const void *a,const void *b) {
1603         char *ac=(char *)a, *bc=(char *)b;
1604         int ret=ac-bc;
1605         if (ret<0) ret=-ret;
1606         return ret;
1607 }
1608
1609 static CthThread CthCreateInner(CthVoidFn fn,void *arg,int size,int migratable)
1610 {
1611   CthThread result;
1612   char *stack, *ss_sp, *ss_end;
1613   result = (CthThread)malloc(sizeof(struct CthThreadStruct));
1614   _MEMCHECK(result);
1615   CthThreadInit(result);
1616 #ifdef MINSIGSTKSZ
1617   if (size<MINSIGSTKSZ) size = CthCpvAccess(_defaultStackSize);
1618 #endif
1619   CthAllocateStack(&result->base,&size,migratable);
1620   stack = result->base.stack;
1621   
1622   if (0 != getJcontext(&result->context))
1623     CmiAbort("CthCreateInner: getcontext failed.\n");
1624
1625   ss_end = stack + size;
1626
1627 /**
1628  Decide where to point the uc_stack.ss_sp field of our "context"
1629  structure.  The configuration values CMK_CONTEXT_STACKBEGIN, 
1630  CMK_CONTEXT_STACKEND, and CMK_CONTEXT_STACKMIDDLE determine where to
1631  point ss_sp: to the beginning, end, and middle of the stack buffer
1632  respectively.  The default, used by most machines, is CMK_CONTEXT_STACKBEGIN.
1633 */
1634 #if CMK_THREADS_USE_JCONTEXT /* Jcontext is always STACKBEGIN */
1635   ss_sp = stack;
1636 #elif CMK_CONTEXT_STACKEND /* ss_sp should point to *end* of buffer */
1637   ss_sp = stack+size-MINSIGSTKSZ; /* the MINSIGSTKSZ seems like a hack */
1638   ss_end = stack;
1639 #elif CMK_CONTEXT_STACKMIDDLE /* ss_sp should point to *middle* of buffer */
1640   ss_sp = stack+size/2;
1641 #else /* CMK_CONTEXT_STACKBEGIN, the usual case  */
1642   ss_sp = stack;
1643 #endif
1644   
1645   result->context.uc_stack.ss_sp = STP_STKALIGN(ss_sp,sizeof(char *)*8);
1646   result->context.uc_stack.ss_size = ptrDiffLen(result->context.uc_stack.ss_sp,ss_end);
1647   result->context.uc_stack.ss_flags = 0;
1648   result->context.uc_link = 0;
1649   
1650   CthAliasEnable(B(result)); /* Change to new thread's stack while building context */
1651   errno = 0;
1652 #if CMK_THREADS_USE_CONTEXT
1653   if (sizeof(void *) == 8) {
1654     CmiUInt4 fn1 = ((CmiUInt8)fn) >> 32;
1655     CmiUInt4 fn2 = (CmiUInt8)fn & 0xFFFFFFFF;
1656     CmiUInt4 arg1 = ((CmiUInt8)arg) >> 32;
1657     CmiUInt4 arg2 = (CmiUInt8)arg & 0xFFFFFFFF;
1658     makeJcontext(&result->context, (uJcontext_fn_t)CthStartThread, 4, fn1, fn2, arg1, arg2);
1659   }
1660   else
1661 #endif
1662     makeJcontext(&result->context, (uJcontext_fn_t)CthStartThread, 2, (void *)fn,(void *)arg);
1663   if(errno !=0) { 
1664     perror("makecontext"); 
1665     CmiAbort("CthCreateInner: makecontext failed.\n");
1666   }
1667   CthAliasEnable(B(CthCpvAccess(CthCurrent)));
1668   return result;  
1669 }
1670
1671 CthThread CthCreate(CthVoidFn fn,void *arg,int size)
1672 {
1673   return CthCreateInner(fn,arg,size,0);
1674 }
1675 CthThread CthCreateMigratable(CthVoidFn fn,void *arg,int size)
1676 {
1677   return CthCreateInner(fn,arg,size,1);
1678 }
1679
1680 int CthMigratable()
1681 {
1682   return CmiIsomallocEnabled();
1683 }
1684
1685 CthThread CthPup(pup_er p, CthThread t)
1686 {
1687   int flag;
1688   if (pup_isUnpacking(p)) {
1689           t=(CthThread)malloc(sizeof(struct CthThreadStruct));
1690           _MEMCHECK(t);
1691           CthThreadInit(t);
1692   }
1693   CthPupBase(p,&t->base,1);
1694   
1695   /*Pup the processor context as bytes-- this is not guarenteed to work!*/
1696   /* so far, context and context-memoryalias works for IA64, not ia32 */
1697   /* so far, uJcontext and context-memoryalias works for IA32, not ia64 */
1698   pup_bytes(p,&t->context,sizeof(t->context));
1699 #if !CMK_THREADS_USE_JCONTEXT && CMK_CONTEXT_FPU_POINTER
1700 #if ! CMK_CONTEXT_FPU_POINTER_UCREGS
1701     /* context is not portable for ia32 due to pointer in uc_mcontext.fpregs,
1702        pup it separately */
1703   if (!pup_isUnpacking(p)) flag = t->context.uc_mcontext.fpregs != NULL;
1704   pup_int(p,&flag);
1705   if (flag) {
1706     if (pup_isUnpacking(p)) {
1707       t->context.uc_mcontext.fpregs = malloc(sizeof(struct _libc_fpstate));
1708     }
1709     pup_bytes(p,t->context.uc_mcontext.fpregs,sizeof(struct _libc_fpstate));
1710   }
1711 #else             /* net-linux-ppc 32 bit */
1712   if (!pup_isUnpacking(p)) flag = t->context.uc_mcontext.uc_regs != NULL;
1713   pup_int(p,&flag);
1714   if (flag) {
1715     if (pup_isUnpacking(p)) {
1716       t->context.uc_mcontext.uc_regs = malloc(sizeof(mcontext_t));
1717     }
1718     pup_bytes(p,t->context.uc_mcontext.uc_regs,sizeof(mcontext_t));
1719   }
1720 #endif
1721 #endif
1722 #if !CMK_THREADS_USE_JCONTEXT && CMK_CONTEXT_V_REGS
1723     /* linux-ppc  64 bit */
1724   if (pup_isUnpacking(p)) {
1725       t->context.uc_mcontext.v_regs = malloc(sizeof(vrregset_t));
1726   }
1727   pup_bytes(p,t->context.uc_mcontext.v_regs,sizeof(vrregset_t));
1728 #endif
1729   if (pup_isUnpacking(p)) {
1730       t->context.uc_link = 0;
1731   }
1732   if (pup_isDeleting(p)) {
1733           CthFree(t);
1734           return 0;
1735   }
1736   return t;
1737 }
1738
1739 #else 
1740 /***************************************************************
1741 Basic qthreads implementation. 
1742
1743 These threads can also add a "protection block" of
1744 inaccessible memory to detect stack overflows, which
1745 would otherwise just trash the heap.
1746
1747 (7/13/2001 creation times on 300MHz AMD K6-3 x86, Linux 2.2.18:
1748 Qt setjmp, without stackprotect: 18.5 us
1749 Qt i386, without stackprotect: 17.9 us
1750 Qt setjmp, with stackprotect: 68.6 us
1751 )
1752
1753 Written by Josh Yelon around 1995
1754 */
1755
1756 #if defined(CMK_OPTIMIZE) || (!CMK_MEMORY_PROTECTABLE)
1757 #  define CMK_STACKPROTECT 0
1758
1759 #  define CthMemAlign(x,n) 0
1760 #  define CthMemoryProtect(m,p,l) CmiAbort("Shouldn't call CthMemoryProtect!\n")
1761 #  define CthMemoryUnprotect(m,p,l) CmiAbort("Shouldn't call CthMemoryUnprotect!\n")
1762 #else
1763 #  define CMK_STACKPROTECT 1
1764
1765   extern void setProtection(char*, char*, int, int);
1766 #  include "sys/mman.h"
1767 #  define CthMemAlign(x,n) memalign((x),(n))
1768 #  define CthMemoryProtect(m,p,l) mprotect(p,l,PROT_NONE);setProtection((char*)m,p,l,1);
1769 #  define CthMemoryUnprotect(m,p,l) mprotect(p,l,PROT_READ | PROT_WRITE);setProtection((char*)m,p,l,0);
1770 #endif
1771
1772 struct CthThreadStruct
1773 {
1774   CthThreadBase base;
1775
1776   char      *protect;
1777   int        protlen;
1778
1779   qt_t      *stack;
1780   qt_t      *stackp;
1781 };
1782
1783 static CthThread CthThreadInit(void)
1784 {
1785   CthThread ret=(CthThread)malloc(sizeof(struct CthThreadStruct));
1786   _MEMCHECK(ret);
1787   CthThreadBaseInit(&ret->base);
1788   ret->protect = 0;
1789   ret->protlen = 0;
1790   
1791   return ret;
1792 }
1793
1794 static void CthThreadFree(CthThread t)
1795 {
1796   if (t->protlen!=0) {
1797     CthMemoryUnprotect(t->stack, t->protect, t->protlen);
1798   }
1799   CthThreadBaseFree(&t->base);
1800   free(t);
1801 }
1802
1803 void CthInit(char **argv)
1804 {
1805   CthThread mainThread;
1806
1807   CthBaseInit(argv);  
1808   mainThread=CthThreadInit();
1809   CthCpvAccess(CthCurrent)=mainThread;
1810   /* mainThread->base.suspendable=0;*/ /*Can't suspend main thread (trashes Quickthreads jump buffer)*/
1811
1812   CmiThreadIs_flag |= CMI_THREAD_IS_QT;
1813 #if CMK_THREADS_ALIAS_STACK
1814   CmiThreadIs_flag |= CMI_THREAD_IS_ALIAS;
1815 #endif
1816 }
1817
1818 void CthFree(CthThread t)
1819 {
1820   if (t==NULL) return;
1821   if (t==CthCpvAccess(CthCurrent)) {
1822     t->base.exiting = 1;
1823   } else {
1824     CthThreadFree(t);
1825   }
1826 }
1827
1828 static void *CthAbortHelp(qt_t *sp, CthThread old, void *null)
1829 {
1830   CthThreadFree(old);
1831   return (void *) 0;
1832 }
1833
1834 static void *CthBlockHelp(qt_t *sp, CthThread old, void *null)
1835 {
1836   old->stackp = sp;
1837   return (void *) 0;
1838 }
1839
1840 void CthResume(t)
1841 CthThread t;
1842 {
1843   CthThread tc = CthCpvAccess(CthCurrent);
1844   if (t == tc) return;
1845   CthBaseResume(t);
1846   if (tc->base.exiting) {
1847     QT_ABORT((qt_helper_t*)CthAbortHelp, tc, 0, t->stackp);
1848   } else {
1849     QT_BLOCK((qt_helper_t*)CthBlockHelp, tc, 0, t->stackp);
1850   }
1851 /*This check will mistakenly fail if the thread migrates (changing tc)
1852   if (tc!=CthCpvAccess(CthCurrent)) { CmiAbort("Stack corrupted?\n"); }
1853 */
1854 }
1855
1856 static void CthOnly(void *arg, void *vt, qt_userf_t fn)
1857 {
1858   fn(arg);
1859   CthThreadFinished(CthSelf());
1860 }
1861
1862 static CthThread CthCreateInner(CthVoidFn fn, void *arg, int size,int Migratable)
1863 {
1864   CthThread result; qt_t *stack, *stackbase, *stackp;
1865   int doProtect=(!Migratable) && CMK_STACKPROTECT;
1866   result=CthThreadInit();
1867   if (doProtect) 
1868   { /*Can only protect on a page boundary-- allocate an extra page and align stack*/
1869           if (size==0) size=CthCpvAccess(_defaultStackSize);
1870           size = (size+(CMK_MEMORY_PAGESIZE*2)-1) & ~(CMK_MEMORY_PAGESIZE-1);
1871           stack = (qt_t*)CthMemAlign(CMK_MEMORY_PAGESIZE, size);
1872           B(result)->stack = stack;
1873   } else
1874           stack=CthAllocateStack(&result->base,&size,Migratable);
1875   CthAliasEnable(B(result)); /* Change to new thread's stack while setting args */
1876   stackbase = QT_SP(stack, size);
1877   stackp = QT_ARGS(stackbase, arg, result, (qt_userf_t *)fn, CthOnly);
1878   CthAliasEnable(B(CthCpvAccess(CthCurrent)));
1879   result->stack = stack;
1880   result->stackp = stackp;
1881   if (doProtect) {
1882 #ifdef QT_GROW_UP
1883   /*Stack grows up-- protect highest page of stack*/
1884     result->protect = ((char*)stack) + size - CMK_MEMORY_PAGESIZE;
1885 #else
1886   /*Stack grows down-- protect lowest page in stack*/
1887     result->protect = ((char*)stack);
1888 #endif
1889     result->protlen = CMK_MEMORY_PAGESIZE;
1890     CthMemoryProtect(stack, result->protect, result->protlen);
1891   }
1892   return result;
1893 }
1894 CthThread CthCreate(CthVoidFn fn, void *arg, int size)
1895 { return CthCreateInner(fn,arg,size,0);}
1896
1897 CthThread CthCreateMigratable(CthVoidFn fn, void *arg, int size)
1898 { return CthCreateInner(fn,arg,size,1);}
1899
1900 int CthMigratable()
1901 {
1902 #if CMK_THREADS_ALIAS_STACK
1903   return 1;
1904 #else
1905   return CmiIsomallocEnabled();
1906 #endif
1907 }
1908
1909 CthThread CthPup(pup_er p, CthThread t)
1910 {
1911   if (pup_isUnpacking(p)) {
1912           t=CthThreadInit();
1913   }
1914 #if CMK_THREADS_ALIAS_STACK
1915   CthPupBase(p,&t->base,0);
1916 #else
1917   CthPupBase(p,&t->base,1);
1918 #endif
1919   
1920   /*Pup the stack pointer as bytes-- this works because stack is migratable*/
1921   pup_bytes(p,&t->stackp,sizeof(t->stackp));
1922
1923   /*Don't worry about stack protection on migration*/  
1924
1925   if (pup_isDeleting(p)) {
1926           CthFree(t);
1927           return 0;
1928   }
1929   return t;
1930 }
1931
1932 /* Functions that help debugging of out-of-core emulation in BigSim */
1933 void CthPrintThdStack(CthThread t){
1934     CmiPrintf("thread=%p, base stack=%p, stack pointer=%p\n", t, t->base.stack, t->stackp);
1935 }
1936 #endif
1937
1938 #if ! USE_SPECIAL_STACKPOINTER
1939 size_t CthStackOffset(CthThread t, char *p)
1940 {
1941   size_t s;
1942   CmiAssert(t);
1943   if (B(t)->stack == NULL)      /* fiber, pthread */
1944     s = p - (char *)t;
1945   else
1946     s = p - (char *)B(t)->stack;
1947   /* size_t s = (size_t)p; */
1948   return s;
1949 }
1950
1951 char * CthPointer(CthThread t, size_t pos)
1952 {
1953   char *p;
1954   CmiAssert(t);
1955   if (B(t)->stack == NULL)      /* fiber, pthread */
1956     p = (char*)t + pos;
1957   else
1958     p = (char *)B(t)->stack + pos;
1959   /* char *p = (char *)size; */
1960   return p;
1961 }
1962 #endif
1963
1964
1965 void CthTraceResume(CthThread t)
1966 {
1967   traceResume(&t->base.tid);
1968 }
1969
1970 /* Functions that help debugging of out-of-core emulation in BigSim */
1971 void CthPrintThdMagic(CthThread t){
1972     CmiPrintf("CthThread[%p]'s magic: %x\n", t, t->base.magic);
1973 }
1974