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