0388cb408b3a796615ff271962c0c82aeb765243
[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     pthread_exit(0);
1224   } else {
1225     /* pthread_cond_wait might (with low probability) return when the 
1226       condition variable has not been signaled, guarded with 
1227       predicate checks */
1228     do {
1229     pthread_cond_wait(&(tc->cond), &CthCpvAccess(sched_mutex));
1230     } while (tc!=CthCpvAccess(CthCurrent)) ;
1231   }
1232 }
1233
1234 static void *CthOnly(void * arg)
1235 {
1236   CthThread th = (CthThread)arg;
1237   th->inited = 1;
1238   pthread_detach(pthread_self());
1239   pthread_mutex_lock(&CthCpvAccess(sched_mutex));
1240   pthread_cond_signal(th->creator);
1241   do {
1242   pthread_cond_wait(&(th->cond), &CthCpvAccess(sched_mutex));
1243   } while (arg!=CthCpvAccess(CthCurrent)) ;
1244   th->fn(th->arg);
1245   CthThreadFinished(th);
1246   return 0;
1247 }
1248
1249 CthThread CthCreate(CthVoidFn fn, void *arg, int size)
1250 {
1251   static int reported = 0;
1252   pthread_attr_t attr;
1253   int r;
1254   CthThread result;
1255   CthThread self = CthSelf();
1256   /* size is ignored in this version */
1257   result = (CthThread)malloc(sizeof(struct CthThreadStruct));
1258   _MEMCHECK(result);
1259   CthThreadInit(result);
1260   result->fn = fn;
1261   result->arg = arg;
1262   result->creator = &(self->cond);
1263
1264   /* try set pthread stack, not necessarily supported on all platforms */
1265   pthread_attr_init(&attr);
1266   /* pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); */
1267   if (size<1024) size = CthCpvAccess(_defaultStackSize);
1268   if (0!=(r=pthread_attr_setstacksize(&attr,size))) {
1269       if (!reported) {
1270         CmiPrintf("Warning: pthread_attr_setstacksize failed");
1271         errno = r;
1272         perror("pthread_attr_setstacksize");
1273         reported = 1;
1274       }
1275   }
1276
1277   r = pthread_create(&(result->self), &attr, CthOnly, (void*) result);
1278   if (0 != r) {
1279     CmiPrintf("pthread_create failed with %d\n", r);
1280     CmiAbort("CthCreate failed to created a new pthread\n");
1281   }
1282   do {
1283   pthread_cond_wait(&(self->cond), &CthCpvAccess(sched_mutex));
1284   } while (result->inited==0);
1285   return result;
1286 }
1287
1288 CthThread CthPup(pup_er p, CthThread t)
1289 {
1290   CmiAbort("CthPup not implemented.\n");
1291   return 0;
1292 }
1293 CthThread CthCreateMigratable(CthVoidFn fn,void *arg,int size)
1294 {
1295   /*Pthreads are never migratable, unless we can figure out how to set their stacks*/
1296   return CthCreate(fn,arg,size);
1297 }
1298
1299 /***************************************************************
1300 Use SysV r3 setcontext/getcontext calls instead of
1301 quickthreads.  This works on lots of architectures (such as
1302 SUN, IBM SP, O2K, DEC Alpha, IA64, Cray X1, Linux with newer version of 
1303  glibc such as the one with RH9) 
1304 On some machine such as IA64 and Cray X1, the context version is the 
1305 only thread package that is working. 
1306
1307 Porting should be easy. To port context threads, one need to set the 
1308 direction of the thread stack properly in conv-mach.h.
1309
1310 Note: on some machine like Sun and IBM SP, one needs to link with memory gnuold
1311  to have this context thread working.
1312
1313 Written by Gengbin Zheng around April 2001
1314
1315 For thread checkpoint/restart, isomalloc requires that iso region from all
1316 machines are same.
1317
1318 For Fedora and Ubuntu, run the following command as root
1319 echo 0 > /proc/sys/kernel/randomize_va_space
1320 will disable the randomization of the stack pointer
1321
1322 Gengbin Zheng October, 2007
1323
1324 */
1325 #elif (CMK_THREADS_USE_CONTEXT || CMK_THREADS_USE_JCONTEXT)
1326
1327 #include <signal.h>
1328 #include <errno.h>
1329
1330 #if CMK_THREADS_USE_CONTEXT
1331 /* system builtin context routines: */
1332 #include <ucontext.h>
1333
1334 #define uJcontext_t ucontext_t
1335 #define setJcontext setcontext
1336 #define getJcontext getcontext
1337 #define swapJcontext swapcontext
1338 #define makeJcontext makecontext
1339 typedef void (*uJcontext_fn_t)(void);
1340
1341 #else /* CMK_THREADS_USE_JCONTEXT */
1342 /* Orion's setjmp-based context routines: */
1343 #include <uJcontext.h>
1344 #include <uJcontext.c>
1345
1346 #endif
1347
1348
1349 struct CthThreadStruct
1350 {
1351   CthThreadBase base;
1352   double * dummy;
1353   uJcontext_t context;
1354 };
1355
1356
1357 static void CthThreadInit(t)
1358 CthThread t;
1359 {
1360   CthThreadBaseInit(&t->base);
1361 }
1362
1363 /* Threads waiting to be destroyed */
1364 CpvStaticDeclare(CthThread , doomedThreadPool);
1365
1366 void CthInit(char **argv)
1367 {
1368   CthThread t;
1369
1370   CthBaseInit(argv);
1371   t = (CthThread)malloc(sizeof(struct CthThreadStruct));
1372   _MEMCHECK(t);
1373   CthCpvAccess(CthCurrent)=t;
1374   if (0 != getJcontext(&t->context))
1375     CmiAbort("CthInit: getcontext failed.\n");
1376   CthThreadInit(t);
1377   CpvInitialize(CthThread, doomedThreadPool);
1378   CpvAccess(doomedThreadPool) = (CthThread)NULL;
1379
1380   /* don't trust the _defaultStackSize */
1381 #ifdef MINSIGSTKSZ
1382   if (CthCpvAccess(_defaultStackSize) < MINSIGSTKSZ) 
1383     CthCpvAccess(_defaultStackSize) = MINSIGSTKSZ;
1384 #endif
1385 #if CMK_THREADS_USE_CONTEXT
1386   CmiThreadIs_flag |= CMI_THREAD_IS_CONTEXT;
1387 #else
1388   CmiThreadIs_flag |= CMI_THREAD_IS_UJCONTEXT;
1389 #endif
1390 #if CMK_THREADS_ALIAS_STACK
1391   CmiThreadIs_flag |= CMI_THREAD_IS_ALIAS;
1392 #endif
1393 }
1394
1395 static void CthThreadFree(CthThread t)
1396 {
1397   /* avoid freeing thread while it is being used, store in pool and 
1398      free it next time. Note the last thread in pool won't be free'd! */
1399   CthThread doomed=CpvAccess(doomedThreadPool);
1400   CpvAccess(doomedThreadPool) = t;
1401   if (doomed != NULL) {
1402     CthThreadBaseFree(&doomed->base);
1403     free(doomed);
1404   }
1405 }
1406
1407 void CthFree(CthThread t)
1408 {
1409   if (t==NULL) return;
1410   if (t==CthCpvAccess(CthCurrent)) {
1411     t->base.exiting = 1; /* thread is already running-- free on next swap out */
1412   } else {
1413     CthThreadFree(t);
1414   }
1415 }
1416
1417 void CthResume(t)
1418 CthThread t;
1419 {
1420   CthThread tc;
1421   tc = CthCpvAccess(CthCurrent);
1422   if (t != tc) { /* Actually switch threads */
1423     CthBaseResume(t);
1424     if (!tc->base.exiting) 
1425     {
1426       if (0 != swapJcontext(&tc->context, &t->context)) 
1427         CmiAbort("CthResume: swapcontext failed.\n");
1428     } 
1429     else /* tc->base.exiting, so jump directly to next context */ 
1430     {
1431       CthThreadFree(tc);
1432       setJcontext(&t->context);
1433     }
1434   }
1435 /*This check will mistakenly fail if the thread migrates (changing tc)
1436   if (tc!=CthCpvAccess(CthCurrent)) { CmiAbort("Stack corrupted?\n"); }
1437 */
1438 }
1439
1440 #if CMK_THREADS_USE_CONTEXT && CMK_64BIT /* makecontext only pass integer arguments */
1441 void CthStartThread(CmiUInt4 fn1, CmiUInt4 fn2, CmiUInt4 arg1, CmiUInt4 arg2)
1442 {
1443   CmiUInt8 fn0 = (((CmiUInt8)fn1) << 32) | fn2;
1444   CmiUInt8 arg0 = (((CmiUInt8)arg1) << 32) | arg2;
1445   void *arg = (void *)arg0;
1446   qt_userf_t *fn = (qt_userf_t*)fn0;
1447   (*fn)(arg);
1448   CthThreadFinished(CthSelf());
1449 }
1450 #else
1451 void CthStartThread(qt_userf_t fn,void *arg)
1452 {
1453   fn(arg);
1454   CthThreadFinished(CthSelf());
1455 }
1456 #endif
1457
1458 #define STP_STKALIGN(sp, alignment) \
1459   ((void *)((((qt_word_t)(sp)) + (alignment) - 1) & ~((alignment)-1)))
1460
1461 int ptrDiffLen(const void *a,const void *b) {
1462         char *ac=(char *)a, *bc=(char *)b;
1463         int ret=ac-bc;
1464         if (ret<0) ret=-ret;
1465         return ret;
1466 }
1467
1468 static CthThread CthCreateInner(CthVoidFn fn,void *arg,int size,int migratable)
1469 {
1470   CthThread result;
1471   char *stack, *ss_sp, *ss_end;
1472   result = (CthThread)malloc(sizeof(struct CthThreadStruct));
1473   _MEMCHECK(result);
1474   CthThreadInit(result);
1475 #ifdef MINSIGSTKSZ
1476   if (size<MINSIGSTKSZ) size = CthCpvAccess(_defaultStackSize);
1477 #endif
1478   CthAllocateStack(&result->base,&size,migratable);
1479   stack = result->base.stack;
1480   
1481   if (0 != getJcontext(&result->context))
1482     CmiAbort("CthCreateInner: getcontext failed.\n");
1483
1484   ss_end = stack + size;
1485
1486 /**
1487  Decide where to point the uc_stack.ss_sp field of our "context"
1488  structure.  The configuration values CMK_CONTEXT_STACKBEGIN, 
1489  CMK_CONTEXT_STACKEND, and CMK_CONTEXT_STACKMIDDLE determine where to
1490  point ss_sp: to the beginning, end, and middle of the stack buffer
1491  respectively.  The default, used by most machines, is CMK_CONTEXT_STACKBEGIN.
1492 */
1493 #if CMK_THREADS_USE_JCONTEXT /* Jcontext is always STACKBEGIN */
1494   ss_sp = stack;
1495 #elif CMK_CONTEXT_STACKEND /* ss_sp should point to *end* of buffer */
1496   ss_sp = stack+size-MINSIGSTKSZ; /* the MINSIGSTKSZ seems like a hack */
1497   ss_end = stack;
1498 #elif CMK_CONTEXT_STACKMIDDLE /* ss_sp should point to *middle* of buffer */
1499   ss_sp = stack+size/2;
1500 #else /* CMK_CONTEXT_STACKBEGIN, the usual case  */
1501   ss_sp = stack;
1502 #endif
1503   
1504   result->context.uc_stack.ss_sp = STP_STKALIGN(ss_sp,sizeof(char *)*8);
1505   result->context.uc_stack.ss_size = ptrDiffLen(result->context.uc_stack.ss_sp,ss_end);
1506   result->context.uc_stack.ss_flags = 0;
1507   result->context.uc_link = 0;
1508   
1509   CthAliasEnable(B(result)); /* Change to new thread's stack while building context */
1510   errno = 0;
1511 #if CMK_THREADS_USE_CONTEXT
1512   if (sizeof(void *) == 8) {
1513     int fn1 = ((CmiUInt8)fn) >> 32;
1514     int fn2 = (CmiUInt8)fn & 0xFFFFFFFF;
1515     int arg1 = ((CmiUInt8)arg) >> 32;
1516     int arg2 = (CmiUInt8)arg & 0xFFFFFFFF;
1517     makeJcontext(&result->context, (uJcontext_fn_t)CthStartThread, 4, fn1, fn2, arg1, arg2);
1518   }
1519   else
1520 #endif
1521     makeJcontext(&result->context, (uJcontext_fn_t)CthStartThread, 2, (void *)fn,(void *)arg);
1522   if(errno !=0) { 
1523     perror("makecontext"); 
1524     CmiAbort("CthCreateInner: makecontext failed.\n");
1525   }
1526   CthAliasEnable(B(CthCpvAccess(CthCurrent)));
1527   return result;  
1528 }
1529
1530 CthThread CthCreate(CthVoidFn fn,void *arg,int size)
1531 {
1532   return CthCreateInner(fn,arg,size,0);
1533 }
1534 CthThread CthCreateMigratable(CthVoidFn fn,void *arg,int size)
1535 {
1536   return CthCreateInner(fn,arg,size,1);
1537 }
1538
1539 CthThread CthPup(pup_er p, CthThread t)
1540 {
1541   int flag;
1542   if (pup_isUnpacking(p)) {
1543           t=(CthThread)malloc(sizeof(struct CthThreadStruct));
1544           _MEMCHECK(t);
1545           CthThreadInit(t);
1546   }
1547   CthPupBase(p,&t->base,1);
1548   
1549   /*Pup the processor context as bytes-- this is not guarenteed to work!*/
1550   /* so far, context and context-memoryalias works for IA64, not ia32 */
1551   /* so far, uJcontext and context-memoryalias works for IA32, not ia64 */
1552   pup_bytes(p,&t->context,sizeof(t->context));
1553 #if !CMK_THREADS_USE_JCONTEXT && CMK_CONTEXT_FPU_POINTER
1554 #if ! CMK_CONTEXT_FPU_POINTER_UCREGS
1555     /* context is not portable for ia32 due to pointer in uc_mcontext.fpregs,
1556        pup it separately */
1557   if (!pup_isUnpacking(p)) flag = t->context.uc_mcontext.fpregs != NULL;
1558   pup_int(p,&flag);
1559   if (flag) {
1560     if (pup_isUnpacking(p)) {
1561       t->context.uc_mcontext.fpregs = malloc(sizeof(struct _libc_fpstate));
1562     }
1563     pup_bytes(p,t->context.uc_mcontext.fpregs,sizeof(struct _libc_fpstate));
1564   }
1565 #else             /* net-linux-ppc 32 bit */
1566   if (!pup_isUnpacking(p)) flag = t->context.uc_mcontext.uc_regs != NULL;
1567   pup_int(p,&flag);
1568   if (flag) {
1569     if (pup_isUnpacking(p)) {
1570       t->context.uc_mcontext.uc_regs = malloc(sizeof(mcontext_t));
1571     }
1572     pup_bytes(p,t->context.uc_mcontext.uc_regs,sizeof(mcontext_t));
1573   }
1574 #endif
1575 #endif
1576 #if !CMK_THREADS_USE_JCONTEXT && CMK_CONTEXT_V_REGS
1577     /* linux-ppc  64 bit */
1578   if (pup_isUnpacking(p)) {
1579       t->context.uc_mcontext.v_regs = malloc(sizeof(vrregset_t));
1580   }
1581   pup_bytes(p,t->context.uc_mcontext.v_regs,sizeof(vrregset_t));
1582 #endif
1583   if (pup_isUnpacking(p)) {
1584       t->context.uc_link = 0;
1585   }
1586   if (pup_isDeleting(p)) {
1587           CthFree(t);
1588           return 0;
1589   }
1590   return t;
1591 }
1592
1593 #else 
1594 /***************************************************************
1595 Basic qthreads implementation. 
1596
1597 These threads can also add a "protection block" of
1598 inaccessible memory to detect stack overflows, which
1599 would otherwise just trash the heap.
1600
1601 (7/13/2001 creation times on 300MHz AMD K6-3 x86, Linux 2.2.18:
1602 Qt setjmp, without stackprotect: 18.5 us
1603 Qt i386, without stackprotect: 17.9 us
1604 Qt setjmp, with stackprotect: 68.6 us
1605 )
1606
1607 Written by Josh Yelon around 1995
1608 */
1609
1610 #if defined(CMK_OPTIMIZE) || (!CMK_MEMORY_PROTECTABLE)
1611 #  define CMK_STACKPROTECT 0
1612
1613 #  define CthMemAlign(x,n) 0
1614 #  define CthMemoryProtect(m,p,l) CmiAbort("Shouldn't call CthMemoryProtect!\n")
1615 #  define CthMemoryUnprotect(m,p,l) CmiAbort("Shouldn't call CthMemoryUnprotect!\n")
1616 #else
1617 #  define CMK_STACKPROTECT 1
1618
1619   extern void setProtection(char*, char*, int, int);
1620 #  include "sys/mman.h"
1621 #  define CthMemAlign(x,n) memalign((x),(n))
1622 #  define CthMemoryProtect(m,p,l) mprotect(p,l,PROT_NONE);setProtection((char*)m,p,l,1);
1623 #  define CthMemoryUnprotect(m,p,l) mprotect(p,l,PROT_READ | PROT_WRITE);setProtection((char*)m,p,l,0);
1624 #endif
1625
1626 struct CthThreadStruct
1627 {
1628   CthThreadBase base;
1629
1630   char      *protect;
1631   int        protlen;
1632
1633   qt_t      *stack;
1634   qt_t      *stackp;
1635 };
1636
1637 static CthThread CthThreadInit(void)
1638 {
1639   CthThread ret=(CthThread)malloc(sizeof(struct CthThreadStruct));
1640   _MEMCHECK(ret);
1641   CthThreadBaseInit(&ret->base);
1642   ret->protect = 0;
1643   ret->protlen = 0;
1644   
1645   return ret;
1646 }
1647
1648 static void CthThreadFree(CthThread t)
1649 {
1650   if (t->protlen!=0) {
1651     CthMemoryUnprotect(t->stack, t->protect, t->protlen);
1652   }
1653   CthThreadBaseFree(&t->base);
1654   free(t);
1655 }
1656
1657 void CthInit(char **argv)
1658 {
1659   CthThread mainThread;
1660
1661   CthBaseInit(argv);  
1662   mainThread=CthThreadInit();
1663   CthCpvAccess(CthCurrent)=mainThread;
1664   /* mainThread->base.suspendable=0;*/ /*Can't suspend main thread (trashes Quickthreads jump buffer)*/
1665
1666   CmiThreadIs_flag |= CMI_THREAD_IS_QT;
1667 #if CMK_THREADS_ALIAS_STACK
1668   CmiThreadIs_flag |= CMI_THREAD_IS_ALIAS;
1669 #endif
1670 }
1671
1672 void CthFree(CthThread t)
1673 {
1674   if (t==NULL) return;
1675   if (t==CthCpvAccess(CthCurrent)) {
1676     t->base.exiting = 1;
1677   } else {
1678     CthThreadFree(t);
1679   }
1680 }
1681
1682 static void *CthAbortHelp(qt_t *sp, CthThread old, void *null)
1683 {
1684   CthThreadFree(old);
1685   return (void *) 0;
1686 }
1687
1688 static void *CthBlockHelp(qt_t *sp, CthThread old, void *null)
1689 {
1690   old->stackp = sp;
1691   return (void *) 0;
1692 }
1693
1694 void CthResume(t)
1695 CthThread t;
1696 {
1697   CthThread tc = CthCpvAccess(CthCurrent);
1698   if (t == tc) return;
1699   CthBaseResume(t);
1700   if (tc->base.exiting) {
1701     QT_ABORT((qt_helper_t*)CthAbortHelp, tc, 0, t->stackp);
1702   } else {
1703     QT_BLOCK((qt_helper_t*)CthBlockHelp, tc, 0, t->stackp);
1704   }
1705 /*This check will mistakenly fail if the thread migrates (changing tc)
1706   if (tc!=CthCpvAccess(CthCurrent)) { CmiAbort("Stack corrupted?\n"); }
1707 */
1708 }
1709
1710 static void CthOnly(void *arg, void *vt, qt_userf_t fn)
1711 {
1712   fn(arg);
1713   CthThreadFinished(CthSelf());
1714 }
1715
1716 static CthThread CthCreateInner(CthVoidFn fn, void *arg, int size,int Migratable)
1717 {
1718   CthThread result; qt_t *stack, *stackbase, *stackp;
1719   int doProtect=(!Migratable) && CMK_STACKPROTECT;
1720   result=CthThreadInit();
1721   if (doProtect) 
1722   { /*Can only protect on a page boundary-- allocate an extra page and align stack*/
1723           if (size==0) size=CthCpvAccess(_defaultStackSize);
1724           size = (size+(CMK_MEMORY_PAGESIZE*2)-1) & ~(CMK_MEMORY_PAGESIZE-1);
1725           stack = (qt_t*)CthMemAlign(CMK_MEMORY_PAGESIZE, size);
1726           B(result)->stack = stack;
1727   } else
1728           stack=CthAllocateStack(&result->base,&size,Migratable);
1729   CthAliasEnable(B(result)); /* Change to new thread's stack while setting args */
1730   stackbase = QT_SP(stack, size);
1731   stackp = QT_ARGS(stackbase, arg, result, (qt_userf_t *)fn, CthOnly);
1732   CthAliasEnable(B(CthCpvAccess(CthCurrent)));
1733   result->stack = stack;
1734   result->stackp = stackp;
1735   if (doProtect) {
1736 #ifdef QT_GROW_UP
1737   /*Stack grows up-- protect highest page of stack*/
1738     result->protect = ((char*)stack) + size - CMK_MEMORY_PAGESIZE;
1739 #else
1740   /*Stack grows down-- protect lowest page in stack*/
1741     result->protect = ((char*)stack);
1742 #endif
1743     result->protlen = CMK_MEMORY_PAGESIZE;
1744     CthMemoryProtect(stack, result->protect, result->protlen);
1745   }
1746   return result;
1747 }
1748 CthThread CthCreate(CthVoidFn fn, void *arg, int size)
1749 { return CthCreateInner(fn,arg,size,0);}
1750
1751 CthThread CthCreateMigratable(CthVoidFn fn, void *arg, int size)
1752 { return CthCreateInner(fn,arg,size,1);}
1753
1754 CthThread CthPup(pup_er p, CthThread t)
1755 {
1756   if (pup_isUnpacking(p)) {
1757           t=CthThreadInit();
1758   }
1759 #if CMK_THREADS_ALIAS_STACK
1760   CthPupBase(p,&t->base,0);
1761 #else
1762   CthPupBase(p,&t->base,1);
1763 #endif
1764   
1765   /*Pup the stack pointer as bytes-- this works because stack is migratable*/
1766   pup_bytes(p,&t->stackp,sizeof(t->stackp));
1767
1768   /*Don't worry about stack protection on migration*/  
1769
1770   if (pup_isDeleting(p)) {
1771           CthFree(t);
1772           return 0;
1773   }
1774   return t;
1775 }
1776
1777 #endif
1778
1779 #if ! USE_SPECIAL_STACKPOINTER
1780 size_t CthStackOffset(CthThread t, char *p)
1781 {
1782   size_t s = p - (char *)B(t)->stack;
1783   /* size_t s = (size_t)p; */
1784   return s;
1785 }
1786
1787 char * CthPointer(CthThread t, size_t pos)
1788 {
1789   char *p;
1790   CmiAssert(t && B(t)->stack);
1791   p = (char *)B(t)->stack + pos;
1792   /* char *p = (char *)size; */
1793   return p;
1794 }
1795 #endif
1796
1797
1798 void CthTraceResume(CthThread t)
1799 {
1800   traceResume(&t->base.tid);
1801 }
1802