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