00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094 #include <stdio.h>
00095 #include <stdlib.h>
00096 #include <string.h>
00097 #if CMK_MEMORY_PROTECTABLE
00098 #if CMK_HAS_MALLOC_H
00099 #include <malloc.h>
00100 #endif
00101 #endif
00102 #if CMK_BLUEGENEL
00103 #include "rts.h"
00104 #endif
00105
00106 #include "converse.h"
00107 #include "qt.h"
00108
00109 #include "conv-trace.h"
00110 #include <sys/types.h>
00111
00112 #ifndef CMK_STACKSIZE_DEFAULT
00113 #define CMK_STACKSIZE_DEFAULT 32768
00114 #endif
00115
00116 #if ! CMK_THREADS_BUILD_DEFAULT
00117 #undef CMK_THREADS_USE_JCONTEXT
00118 #undef CMK_THREADS_USE_CONTEXT
00119 #undef CMK_THREADS_ARE_WIN32_FIBERS
00120 #undef CMK_THREADS_USE_PTHREADS
00121
00122 #if CMK_THREADS_BUILD_CONTEXT
00123 #define CMK_THREADS_USE_CONTEXT 1
00124 #elif CMK_THREADS_BUILD_JCONTEXT
00125 #define CMK_THREADS_USE_JCONTEXT 1
00126 #elif CMK_THREADS_BUILD_FIBERS
00127 #define CMK_THREADS_ARE_WIN32_FIBERS 1
00128 #elif CMK_THREADS_BUILD_PTHREADS
00129 #define CMK_THREADS_USE_PTHREADS 1
00130 #elif CMK_THREADS_BUILD_STACKCOPY
00131 #define CMK_THREADS_USE_STACKCOPY 1
00132 #endif
00133
00134 #endif
00135
00136 #if CMK_THREADS_BUILD_TLS
00137 #include "cmitls.h"
00138 #endif
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150 #define THD_MAGIC_NUM 0x12345678
00151
00152 typedef struct CthThreadBase
00153 {
00154 CthThreadToken *token;
00155 int scheduled;
00156
00157 CmiObjId tid;
00158 CthAwkFn awakenfn;
00159 CthThFn choosefn;
00160 CthThread next;
00161 int suspendable;
00162 int exiting;
00163
00164 char *data;
00165 int datasize;
00166
00167 int isMigratable;
00168 int aliasStackHandle;
00169 void *stack;
00170 int stacksize;
00171 struct CthThreadListener *listener;
00172
00173 #if CMK_THREADS_BUILD_TLS
00174 tlsseg_t tlsseg;
00175 #endif
00176
00177 int magic;
00178
00179 } CthThreadBase;
00180
00181
00182 static int CmiThreadIs_flag=0;
00183
00184 int CmiThreadIs(int flag)
00185 {
00186 return (CmiThreadIs_flag&flag)==flag;
00187 }
00188
00189
00190 #define B(t) ((CthThreadBase *)(t))
00191 #define S(t) ((CthThread)(t))
00192
00193
00194 CthThreadToken *CthGetToken(CthThread t){
00195 return B(t)->token;
00196 }
00197
00198 CpvStaticDeclare(int, Cth_serialNo);
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218 #ifndef CMK_THREADS_ALIAS_STACK
00219 #define CMK_THREADS_ALIAS_STACK 0
00220 #endif
00221
00223 #if CMK_OSF1
00224 #define CMK_THREADS_ALIAS_LOCATION ((void *)0xe00000000)
00225 #elif CMK_IA64
00226 #define CMK_THREADS_ALIAS_LOCATION ((void *)0x6000000000000000)
00227 #else
00228 #define CMK_THREADS_ALIAS_LOCATION ((void *)0xb0000000)
00229 #endif
00230
00231 #if CMK_THREADS_ALIAS_STACK
00232 #include <stdlib.h>
00233 #include <sys/mman.h>
00234 #include <errno.h>
00235 #include <unistd.h>
00236
00238 int CthAliasCreate(int stackSize)
00239 {
00240
00241 char tmpName[128];
00242 char lastByte=0;
00243 int fd;
00244 sprintf(tmpName,"/tmp/charmThreadStackXXXXXX");
00245 fd=mkstemp(tmpName);
00246 if (fd==-1) CmiAbort("threads.c> Cannot create /tmp file to contain thread stack");
00247 unlink(tmpName);
00248
00249
00250 lseek(fd,stackSize-sizeof(lastByte),SEEK_SET);
00251 write(fd,&lastByte,sizeof(lastByte));
00252
00253 return fd;
00254 }
00255
00256 void CthAliasFree(int fd) {
00257 close(fd);
00258 }
00259
00260 #endif
00261
00267 #if CMK_THREADS_ALIAS_STACK
00268 CthThreadBase *_curMappedStack=0;
00269 void CthAliasEnable(CthThreadBase *t) {
00270 void *s;
00271 int flags=MAP_FIXED|MAP_SHARED;
00272 if (!t->isMigratable) return;
00273 if (t==_curMappedStack) return;
00274 _curMappedStack=t;
00275 if (0) printf("Mmapping in thread %p from runtime stack %p\n",t,&s);
00276
00277 #if CMK_BLUEGENEL
00278
00279
00280
00281 {
00282 register char *dest=(char *)0x70000000;
00283 int alias_slot;
00284 rts_memory_alias(t->stack,dest,t->stacksize,&alias_slot);
00285 }
00286 #else
00287
00288
00289
00290 #if CMK_AIX
00291 if (_curMappedStack) munmap(_curMappedStack->stack,_curMappedStack->stacksize);
00292 #endif
00293 s=mmap(t->stack,t->stacksize,
00294 PROT_READ|PROT_WRITE|PROT_EXEC,
00295 flags, t->aliasStackHandle,0);
00296 if (s!=t->stack) {
00297 perror("threads.c CthAliasEnable mmap");
00298 CmiAbort("threads.c CthAliasEnable mmap failed");
00299 }
00300 #endif
00301 }
00302 #else
00303 #define CthAliasEnable(t)
00304 #endif
00305
00306
00307
00308
00309
00310
00311
00312 CthCpvStatic(CthThread, CthCurrent);
00313 CthCpvDeclare(char *, CthData);
00314 CthCpvStatic(int, CthDatasize);
00315
00316 void CthSetThreadID(CthThread th, int a, int b, int c)
00317 {
00318 B(th)->tid.id[0] = a;
00319 B(th)->tid.id[1] = b;
00320 B(th)->tid.id[2] = c;
00321 }
00322
00323
00324 CmiObjId *CthGetThreadID(CthThread th)
00325 {
00326 return &(B(th)->tid);
00327 }
00328
00329 char *CthGetData(CthThread t) { return B(t)->data; }
00330
00331
00332
00333
00334
00335 #if CMK_C_INLINE
00336 inline
00337 #endif
00338 static void CthFixData(CthThread t)
00339 {
00340 int newsize = CthCpvAccess(CthDatasize);
00341 int oldsize = B(t)->datasize;
00342 if (oldsize < newsize) {
00343 newsize = 2*newsize;
00344 B(t)->datasize = newsize;
00345
00346 B(t)->data = (char *)realloc(B(t)->data, newsize);
00347 memset(B(t)->data+oldsize, 0, newsize-oldsize);
00348 }
00349 }
00350
00355 int CthRegister(int size)
00356 {
00357 int datasize=CthCpvAccess(CthDatasize);
00358 CthThreadBase *th=(CthThreadBase *)CthCpvAccess(CthCurrent);
00359 int result, align = 1;
00360 while (size>align) align<<=1;
00361 datasize = (datasize+align-1) & ~(align-1);
00362 result = datasize;
00363 datasize += size;
00364 CthCpvAccess(CthDatasize) = datasize;
00365 CthFixData(S(th));
00366 CthCpvAccess(CthData) = th->data;
00367 return result;
00368 }
00369
00374 void CthRegistered(int maxOffset) {
00375 if (CthCpvAccess(CthDatasize)<maxOffset) {
00376 CthThreadBase *th=(CthThreadBase *)CthCpvAccess(CthCurrent);
00377 CthCpvAccess(CthDatasize) = maxOffset;
00378 CthFixData(S(th));
00379 CthCpvAccess(CthData) = th->data;
00380 }
00381 }
00382
00383
00384 CthCpvStatic(int, _defaultStackSize);
00385
00386 void CthSetSerialNo(CthThread t, int no)
00387 {
00388 B(t)->token->serialNo = no;
00389 }
00390
00391 static void CthThreadBaseInit(CthThreadBase *th)
00392 {
00393 static int serialno = 1;
00394 th->token = (CthThreadToken *)malloc(sizeof(CthThreadToken));
00395 th->token->thread = S(th);
00396 #if CMK_BIGSIM_CHARM
00397 th->token->serialNo = -1;
00398 #else
00399 th->token->serialNo = CpvAccess(Cth_serialNo)++;
00400 #endif
00401 th->scheduled = 0;
00402
00403 th->awakenfn = 0;
00404 th->choosefn = 0;
00405 th->next=0;
00406 th->suspendable = 1;
00407 th->exiting = 0;
00408
00409 th->data=0;
00410 th->datasize=0;
00411 CthFixData(S(th));
00412
00413 CthSetStrategyDefault(S(th));
00414
00415 th->isMigratable=0;
00416 th->aliasStackHandle=0;
00417 th->stack=NULL;
00418 th->stacksize=0;
00419
00420 th->tid.id[0] = CmiMyPe();
00421 th->tid.id[1] = serialno++;
00422 th->tid.id[2] = 0;
00423
00424 th->listener = NULL;
00425
00426
00427 th->magic = THD_MAGIC_NUM;
00428 }
00429
00430 static void *CthAllocateStack(CthThreadBase *th,int *stackSize,int useMigratable)
00431 {
00432 void *ret=NULL;
00433 if (*stackSize==0) *stackSize=CthCpvAccess(_defaultStackSize);
00434 th->stacksize=*stackSize;
00435 if (!useMigratable) {
00436 ret=malloc(*stackSize);
00437 } else {
00438 th->isMigratable=1;
00439 #if CMK_THREADS_ALIAS_STACK
00440 th->aliasStackHandle=CthAliasCreate(*stackSize);
00441 ret=CMK_THREADS_ALIAS_LOCATION;
00442 #else
00443 ret=CmiIsomalloc(*stackSize, (CthThread)th);
00444 #endif
00445 }
00446 _MEMCHECK(ret);
00447 th->stack=ret;
00448 return ret;
00449 }
00450 static void CthThreadBaseFree(CthThreadBase *th)
00451 {
00452 struct CthThreadListener *l,*lnext;
00453
00454
00455
00456 if(th->scheduled == 0){
00457 free(th->token);
00458 }else{
00459 th->token->thread = NULL;
00460 }
00461
00462
00463
00464 for(l=th->listener;l!=NULL;l=lnext){
00465 lnext=l->next;
00466 l->next=0;
00467 if (l->free) l->free(l);
00468 }
00469 free(th->data);
00470 if (th->isMigratable) {
00471 #if CMK_THREADS_ALIAS_STACK
00472 CthAliasFree(th->aliasStackHandle);
00473 #else
00474 #if !CMK_USE_MEMPOOL_ISOMALLOC
00475 CmiIsomallocFree(th->stack);
00476 #endif
00477 #endif
00478 }
00479 else if (th->stack!=NULL) {
00480 free(th->stack);
00481 }
00482 th->stack=NULL;
00483 }
00484
00485 CpvDeclare(int, _numSwitches);
00486
00487 static void CthBaseInit(char **argv)
00488 {
00489 CpvInitialize(int, _numSwitches);
00490 CpvAccess(_numSwitches) = 0;
00491
00492 CthCpvInitialize(int, _defaultStackSize);
00493 CthCpvAccess(_defaultStackSize)=CMK_STACKSIZE_DEFAULT;
00494 CmiGetArgIntDesc(argv,"+stacksize",&CthCpvAccess(_defaultStackSize),
00495 "Default user-level thread stack size");
00496
00497 CthCpvInitialize(CthThread, CthCurrent);
00498 CthCpvInitialize(char *, CthData);
00499 CthCpvInitialize(int, CthDatasize);
00500
00501 CthCpvAccess(CthData)=0;
00502 CthCpvAccess(CthDatasize)=0;
00503
00504 CpvInitialize(int, Cth_serialNo);
00505 CpvAccess(Cth_serialNo) = 1;
00506
00507 #if CMK_THREADS_BUILD_TLS
00508 CmiThreadIs_flag |= CMI_THREAD_IS_TLS;
00509 #endif
00510 }
00511
00512 int CthImplemented() { return 1; }
00513
00514 CthThread CthSelf()
00515 {
00516 return CthCpvAccess(CthCurrent);
00517 }
00518
00519 void CthPupBase(pup_er p,CthThreadBase *t,int useMigratable)
00520 {
00521 #if CMK_ERROR_CHECKING
00522 if ((CthThread)t==CthCpvAccess(CthCurrent))
00523 CmiAbort("CthPupBase: Cannot pack running thread!");
00524 #endif
00525
00526
00527
00528
00529
00530
00531 if(_BgOutOfCoreFlag!=0){
00532 pup_bytes(p, &t->token, sizeof(void *));
00533 if(!pup_isUnpacking(p)){
00534 t->token->thread = NULL;
00535 }
00536 pup_int(p, &t->scheduled);
00537 }
00538 if(pup_isUnpacking(p)){
00539 if(_BgOutOfCoreFlag==0){
00540 t->token = (CthThreadToken *)malloc(sizeof(CthThreadToken));
00541 t->token->thread = S(t);
00542 t->token->serialNo = CpvAccess(Cth_serialNo)++;
00543
00544
00545
00546 t->scheduled = 0;
00547 }else{
00548
00549
00550
00551
00552
00553 if(t->scheduled==0){
00554
00555 t->token = (CthThreadToken *)malloc(sizeof(CthThreadToken));
00556 }
00557 t->token->thread = S(t);
00558 t->token->serialNo = CpvAccess(Cth_serialNo)++;
00559 }
00560 }
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573 pup_bytes(p,&t->awakenfn,sizeof(t->awakenfn));
00574 pup_bytes(p,&t->choosefn,sizeof(t->choosefn));
00575 pup_bytes(p,&t->next,sizeof(t->next));
00576 pup_int(p,&t->suspendable);
00577 pup_int(p,&t->datasize);
00578 if (pup_isUnpacking(p)) {
00579 t->data = (char *) malloc(t->datasize);_MEMCHECK(t->data);
00580 }
00581 pup_bytes(p,(void *)t->data,t->datasize);
00582 pup_int(p,&t->isMigratable);
00583 pup_int(p,&t->stacksize);
00584 if (t->isMigratable) {
00585 #if CMK_THREADS_ALIAS_STACK
00586 if (pup_isUnpacking(p)) {
00587 CthAllocateStack(t,&t->stacksize,1);
00588 }
00589 CthAliasEnable(t);
00590 pup_bytes(p,t->stack,t->stacksize);
00591 #elif CMK_THREADS_USE_STACKCOPY
00592
00593 #else
00594 #if CMK_USE_MEMPOOL_ISOMALLOC
00595 pup_bytes(p,&t->stack,sizeof(char*));
00596 #else
00597 CmiIsomallocPup(p,&t->stack);
00598 #endif
00599 #endif
00600 }
00601 else {
00602 if (useMigratable)
00603 CmiAbort("You must use CthCreateMigratable to use CthPup!\n");
00604
00605 pup_bytes(p,&t->stack,sizeof(t->stack));
00606 }
00607 if (pup_isUnpacking(p)) {
00608
00609 t->listener = NULL;
00610 }
00611
00612 pup_int(p, &t->magic);
00613
00614 #if CMK_THREADS_BUILD_TLS
00615 void* aux;
00616 pup_bytes(p, &t->tlsseg, sizeof(tlsseg_t));
00617 aux = ((void*)(t->tlsseg.memseg)) - t->tlsseg.size;
00618
00619 #if CMK_USE_MEMPOOL_ISOMALLOC
00620 pup_bytes(p,&aux,sizeof(char*));
00621 #else
00622 CmiIsomallocPup(p, &aux);
00623 #endif
00624
00625 #endif
00626 }
00627
00628 static void CthThreadFinished(CthThread t)
00629 {
00630 B(t)->exiting=1;
00631 CthSuspend();
00632 }
00633
00634
00635
00636
00637 void CthSetSuspendable(CthThread t, int val) { B(t)->suspendable = val; }
00638 int CthIsSuspendable(CthThread t) { return B(t)->suspendable; }
00639
00640 void CthSetNext(CthThread t, CthThread v) { B(t)->next = v; }
00641 CthThread CthGetNext(CthThread t) { return B(t)->next; }
00642
00643 static void CthNoStrategy(void)
00644 {
00645 CmiAbort("Called CthAwaken or CthSuspend before calling CthSetStrategy.\n");
00646 }
00647
00648 void CthSetStrategy(CthThread t, CthAwkFn awkfn, CthThFn chsfn)
00649 {
00650 B(t)->awakenfn = awkfn;
00651 B(t)->choosefn = chsfn;
00652 }
00653
00654 #if CMK_C_INLINE
00655 inline
00656 #endif
00657 static void CthBaseResume(CthThread t)
00658 {
00659 struct CthThreadListener *l;
00660 for(l=B(t)->listener;l!=NULL;l=l->next){
00661 if (l->resume) l->resume(l);
00662 }
00663 CpvAccess(_numSwitches)++;
00664 CthFixData(t);
00665 CthCpvAccess(CthCurrent) = t;
00666 CthCpvAccess(CthData) = B(t)->data;
00667 CthAliasEnable(B(t));
00668 }
00669
00673 void CthSwitchThread(CthThread t)
00674 {
00675 CthBaseResume(t);
00676 }
00677
00678
00679
00680
00681 void CthSuspend(void)
00682 {
00683 CthThread next;
00684 struct CthThreadListener *l;
00685 CthThreadBase *cur=B(CthCpvAccess(CthCurrent));
00686
00687 if (cur->suspendable == 0)
00688 CmiAbort("Fatal Error> trying to suspend a non-suspendable thread!\n");
00689
00690
00691
00692
00693 for(l=cur->listener;l!=NULL;l=l->next){
00694 if (l->suspend) l->suspend(l);
00695 }
00696 if (cur->choosefn == 0) CthNoStrategy();
00697 next = cur->choosefn();
00698
00699
00703 if(cur->scheduled > 0)
00704 cur->scheduled--;
00705
00706 #if CMK_ERROR_CHECKING
00707 if(cur->scheduled<0)
00708 CmiAbort("A thread's scheduler should not be less than 0!\n");
00709 #endif
00710
00711 #if CMK_TRACE_ENABLED
00712 #if !CMK_TRACE_IN_CHARM
00713 if(CpvAccess(traceOn))
00714 traceSuspend();
00715 #endif
00716 #endif
00717 CthResume(next);
00718 }
00719
00720 void CthAwaken(CthThread th)
00721 {
00722 if (B(th)->awakenfn == 0) CthNoStrategy();
00723
00724
00725
00726
00727
00728
00729
00730 #if CMK_TRACE_ENABLED
00731 #if ! CMK_TRACE_IN_CHARM
00732 if(CpvAccess(traceOn))
00733 traceAwaken(th);
00734 #endif
00735 #endif
00736 B(th)->awakenfn(B(th)->token, CQS_QUEUEING_FIFO, 0, 0);
00737
00738
00739 B(th)->scheduled++;
00740 }
00741
00742 void CthYield()
00743 {
00744 CthAwaken(CthCpvAccess(CthCurrent));
00745 CthSuspend();
00746 }
00747
00748 void CthAwakenPrio(CthThread th, int s, int pb, unsigned int *prio)
00749 {
00750 if (B(th)->awakenfn == 0) CthNoStrategy();
00751 #if CMK_TRACE_ENABLED
00752 #if ! CMK_TRACE_IN_CHARM
00753 if(CpvAccess(traceOn))
00754 traceAwaken(th);
00755 #endif
00756 #endif
00757 B(th)->awakenfn(B(th)->token, s, pb, prio);
00758
00759
00760 B(th)->scheduled++;
00761 }
00762
00763 void CthYieldPrio(int s, int pb, unsigned int *prio)
00764 {
00765 CthAwakenPrio(CthCpvAccess(CthCurrent), s, pb, prio);
00766 CthSuspend();
00767 }
00768
00769
00770
00771
00772 void CthAddListener(CthThread t,struct CthThreadListener *l){
00773 struct CthThreadListener *p=B(t)->listener;
00774 if(p== NULL){
00775 B(t)->listener=l;
00776 l->thread = t;
00777 l->next=NULL;
00778 return;
00779 }
00780
00781 while(p->next != NULL){
00782 p = p->next;
00783 }
00784 p->next = l;
00785 l->next = NULL;
00786 l->thread = t;
00787 }
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819
00820 #if CMK_THREADS_USE_STACKCOPY
00821
00822 #define SWITCHBUF_SIZE 32768
00823
00824 typedef struct CthProcInfo *CthProcInfo;
00825
00826 typedef struct CthThreadStruct
00827 {
00828 CthThreadBase base;
00829 CthVoidFn startfn;
00830 void *startarg;
00831 qt_t *savedstack;
00832 int savedsize;
00833 int stacklen;
00834 qt_t *savedptr;
00835 } CthThreadStruct;
00836
00837 int CthMigratable()
00838 {
00839 return 1;
00840 }
00841
00842 CthThread CthPup(pup_er p, CthThread t)
00843 {
00844 if (pup_isUnpacking(p))
00845 { t = (CthThread) malloc(sizeof(CthThreadStruct));_MEMCHECK(t);}
00846 pup_bytes(p, (void*) t, sizeof(CthThreadStruct));
00847 CthPupBase(p,&t->base,0);
00848 pup_int(p,&t->savedsize);
00849 if (pup_isUnpacking(p)) {
00850 t->savedstack = (qt_t*) malloc(t->savedsize);_MEMCHECK(t->savedstack);
00851 t->stacklen = t->savedsize;
00852 }
00853 pup_bytes(p, (void*) t->savedstack, t->savedsize);
00854
00855
00856 pup_bytes(p,&t->savedptr,sizeof(t->savedptr));
00857
00858 if (pup_isDeleting(p))
00859 {CthFree(t);t=0;}
00860 return t;
00861 }
00862
00863
00864
00865 struct CthProcInfo
00866 {
00867 qt_t *stackbase;
00868 qt_t *switchbuf_sp;
00869 qt_t *switchbuf;
00870 };
00871
00872 CthCpvDeclare(CthProcInfo, CthProc);
00873
00874 static void CthThreadInit(CthThread t, CthVoidFn fn, void *arg)
00875 {
00876 CthThreadBaseInit(&t->base);
00877 t->startfn = fn;
00878 t->startarg = arg;
00879 t->savedstack = 0;
00880 t->savedsize = 0;
00881 t->stacklen = 0;
00882 t->savedptr = 0;
00883 }
00884
00885 static void CthThreadFree(CthThread t)
00886 {
00887 CthThreadBaseFree(&t->base);
00888 if (t->savedstack) free(t->savedstack);
00889 free(t);
00890 }
00891
00892 void CthFree(t)
00893 CthThread t;
00894 {
00895 if (t==NULL) return;
00896 CthProcInfo proc = CthCpvAccess(CthProc);
00897
00898 if (t != CthSelf()) {
00899 CthThreadFree(t);
00900 } else
00901 t->base.exiting = 1;
00902 }
00903
00904 void CthDummy() { }
00905
00906 void CthInit(char **argv)
00907 {
00908 CthThread t; CthProcInfo p; qt_t *switchbuf, *sp;
00909
00910 CthCpvInitialize(CthProcInfo, CthProc);
00911
00912 CthBaseInit(argv);
00913 t = (CthThread)malloc(sizeof(struct CthThreadStruct));
00914 _MEMCHECK(t);
00915 CthCpvAccess(CthCurrent)=t;
00916 CthThreadInit(t,0,0);
00917
00918 p = (CthProcInfo)malloc(sizeof(struct CthProcInfo));
00919 _MEMCHECK(p);
00920 CthCpvAccess(CthProc)=p;
00921
00922
00923
00924 sp = (qt_t*)(((size_t)&t) & ~((size_t)0xFF));
00925
00926 p->stackbase = QT_SP(sp, 0x100);
00927
00928
00929
00930 switchbuf = (qt_t*)malloc(QT_STKALIGN + SWITCHBUF_SIZE);
00931 _MEMCHECK(switchbuf);
00932 switchbuf = (qt_t*)((((size_t)switchbuf)+QT_STKALIGN) & ~(QT_STKALIGN-1));
00933 p->switchbuf = switchbuf;
00934 sp = QT_SP(switchbuf, SWITCHBUF_SIZE);
00935 sp = QT_ARGS(sp,0,0,0,(qt_only_t*)CthDummy);
00936 p->switchbuf_sp = sp;
00937
00938 CmiThreadIs_flag |= CMI_THREAD_IS_STACKCOPY;
00939 }
00940
00941 static void CthOnly(CthThread t, void *dum1, void *dum2)
00942 {
00943 t->startfn(t->startarg);
00944 CthThreadFinished(t);
00945 }
00946
00947 #define USE_SPECIAL_STACKPOINTER 1
00948
00949
00950 size_t CthStackOffset(CthThread t, char *p)
00951 {
00952 CthProcInfo proc = CthCpvAccess(CthProc);
00953 return p - (char *)proc->stackbase;
00954 }
00955
00956 char * CthPointer(CthThread t, size_t pos)
00957 {
00958 char *stackbase;
00959 CmiAssert(t);
00960 CthProcInfo proc = CthCpvAccess(CthProc);
00961 if (CthCpvAccess(CthCurrent) == t)
00962 stackbase = (char *)proc->stackbase;
00963 else
00964 stackbase = (char *)t->savedstack;
00965 #ifdef QT_GROW_DOWN
00966 char *p = stackbase + t->savedsize + pos;
00967 #else
00968 char *p = stackbase + pos;
00969 #endif
00970 return p;
00971 }
00972
00973 static void CthResume1(qt_t *sp, CthProcInfo proc, CthThread t)
00974 {
00975 int bytes; qt_t *lo, *hi;
00976 CthThread old = CthCpvAccess(CthCurrent);
00977 CthBaseResume(t);
00978 if (old->base.exiting) {
00979 CthThreadFree(old);
00980 } else {
00981 #ifdef QT_GROW_DOWN
00982 lo = sp; hi = proc->stackbase;
00983 #else
00984 hi = sp; lo = proc->stackbase;
00985 #endif
00986 bytes = ((size_t)hi)-((size_t)lo);
00987 if(bytes > old->stacklen) {
00988 if(old->savedstack) free((void *)old->savedstack);
00989 old->savedstack = (qt_t*)malloc(bytes);
00990 _MEMCHECK(old->savedstack);
00991 old->stacklen = bytes;
00992 }
00993 old->savedsize = bytes;
00994 old->savedptr = sp;
00995 memcpy(old->savedstack, lo, bytes);
00996 }
00997 if (t->savedstack) {
00998 #ifdef QT_GROW_DOWN
00999 lo = t->savedptr;
01000 #else
01001 lo = proc->stackbase;
01002 #endif
01003 memcpy(lo, t->savedstack, t->savedsize);
01004 t->savedsize=0;
01005 sp = t->savedptr;
01006 } else {
01007 sp = proc->stackbase;
01008 sp = QT_ARGS(sp,t,0,0,(qt_only_t*)CthOnly);
01009 }
01010 QT_ABORT((qt_helper_t*)CthDummy,0,0,sp);
01011 }
01012
01013 void CthResume(t)
01014 CthThread t;
01015 {
01016 CthProcInfo proc = CthCpvAccess(CthProc);
01017 QT_BLOCK((qt_helper_t*)CthResume1, proc, t, proc->switchbuf_sp);
01018 }
01019
01020 CthThread CthCreate(CthVoidFn fn,void *arg,int size)
01021 {
01022 CthThread result = (CthThread)malloc(sizeof(struct CthThreadStruct));
01023 _MEMCHECK(result);
01024 CthThreadInit(result, fn, arg);
01025 return result;
01026 }
01027 CthThread CthCreateMigratable(CthVoidFn fn,void *arg,int size)
01028 {
01029
01030 return CthCreate(fn,arg,size);
01031 }
01032
01033
01034
01035
01036
01037
01038
01039
01040 #elif CMK_THREADS_ARE_WIN32_FIBERS
01041 #include <windows.h>
01042 #include <winbase.h>
01043
01044 #ifndef _WIN32_WINNT
01045 #define _WIN32_WINNT 0x0400
01046 #endif
01047
01048 #if(_WIN32_WINNT >= 0x0400)
01049 typedef VOID (WINAPI *PFIBER_START_ROUTINE)(
01050 LPVOID lpFiberParameter
01051 );
01052 typedef PFIBER_START_ROUTINE LPFIBER_START_ROUTINE;
01053 #endif
01054
01055 #if(_WIN32_WINNT >= 0x0400)
01056 WINBASEAPI
01057 LPVOID
01058 WINAPI
01059 CreateFiber(
01060 DWORD dwStackSize,
01061 LPFIBER_START_ROUTINE lpStartAddress,
01062 LPVOID lpParameter
01063 );
01064
01065 WINBASEAPI
01066 LPVOID
01067 WINAPI
01068 CreateFiberEx(
01069 SIZE_T dwStackCommitSize,
01070 SIZE_T dwStackReserveSize,
01071 DWORD dwFlags,
01072 LPFIBER_START_ROUTINE lpStartAddress,
01073 LPVOID lpParameter
01074 );
01075
01076
01077 WINBASEAPI
01078 VOID
01079 WINAPI
01080 DeleteFiber(
01081 LPVOID lpFiber
01082 );
01083
01084 WINBASEAPI
01085 LPVOID
01086 WINAPI
01087 ConvertThreadToFiber(
01088 LPVOID lpParameter
01089 );
01090
01091 WINBASEAPI
01092 VOID
01093 WINAPI
01094 SwitchToFiber(
01095 LPVOID lpFiber
01096 );
01097
01098 WINBASEAPI
01099 BOOL
01100 WINAPI
01101 SwitchToThread(
01102 VOID
01103 );
01104 #endif
01105
01106
01107 struct CthThreadStruct
01108 {
01109 CthThreadBase base;
01110 LPVOID fiber;
01111 };
01112
01113 CthCpvStatic(CthThread, CthPrevious);
01114
01115 typedef CthThread *threadTable;
01116 CthCpvStatic(int, tablesize);
01117 CthCpvStatic(threadTable, exitThreads);
01118 CthCpvStatic(int, nExit);
01119
01120 static void CthThreadInit(CthThread t)
01121 {
01122 CthThreadBaseInit(&t->base);
01123 }
01124
01125 void CthInit(char **argv)
01126 {
01127 CthThread t;
01128 int i;
01129
01130 CthCpvInitialize(CthThread, CthPrevious);
01131 CthCpvInitialize(int, nExit);
01132 CthCpvInitialize(threadTable, exitThreads);
01133 CthCpvInitialize(int, tablesize);
01134
01135 #define INITIALSIZE 128
01136 CthCpvAccess(tablesize) = INITIALSIZE;
01137 CthCpvAccess(exitThreads) = (threadTable)malloc(sizeof(CthThread)*INITIALSIZE);
01138 for (i=0; i<INITIALSIZE; i++) CthCpvAccess(exitThreads)[i] = NULL;
01139
01140 CthCpvAccess(CthPrevious)=0;
01141 CthCpvAccess(nExit)=0;
01142
01143 CthBaseInit(argv);
01144 t = (CthThread)malloc(sizeof(struct CthThreadStruct));
01145 _MEMCHECK(t);
01146 CthCpvAccess(CthCurrent)=t;
01147 CthThreadInit(t);
01148 t->fiber = ConvertThreadToFiber(t);
01149 _MEMCHECK(t->fiber);
01150
01151 CmiThreadIs_flag |= CMI_THREAD_IS_FIBERS;
01152 }
01153
01154 void CthThreadFree(CthThread old)
01155 {
01156 CthThreadBaseFree(&old->base);
01157 if (old->fiber) DeleteFiber((PVOID)old->fiber);
01158 free(old);
01159 }
01160
01161 static void CthClearThreads()
01162 {
01163 int i,p,m;
01164 int n = CthCpvAccess(nExit);
01165 CthThread tc = CthCpvAccess(CthCurrent);
01166 CthThread tp = CthCpvAccess(CthPrevious);
01167 m = n;
01168 p=0;
01169 for (i=0; i<m; i++) {
01170 CthThread t = CthCpvAccess(exitThreads)[i];
01171 if (t && t != tc && t != tp) {
01172 CthThreadFree(t);
01173 CthCpvAccess(nExit) --;
01174 }
01175 else {
01176 if (p != i) CthCpvAccess(exitThreads)[p] = t;
01177 p++;
01178 }
01179 }
01180 if (m!=p)
01181 for (i=m; i<n; i++,p++) {
01182 CthCpvAccess(exitThreads)[p] = CthCpvAccess(exitThreads)[i];
01183 }
01184 }
01185
01186 void CthFree(CthThread t)
01187 {
01188 int i;
01189 if (t==NULL) return;
01190
01191 if(CthCpvAccess(nExit) >= CthCpvAccess(tablesize)) {
01192 threadTable newtable;
01193 int oldsize = CthCpvAccess(tablesize);
01194 CthCpvAccess(tablesize) *= 2;
01195 newtable = (threadTable)malloc(sizeof(CthThread)*CthCpvAccess(tablesize));
01196 for (i=0; i<CthCpvAccess(tablesize); i++) newtable[i] = NULL;
01197 for (i=0; i<oldsize; i++) newtable[i] = CthCpvAccess(exitThreads)[i];
01198 free(CthCpvAccess(exitThreads));
01199 CthCpvAccess(exitThreads) = newtable;
01200 }
01201
01202
01203 CthCpvAccess(exitThreads)[CthCpvAccess(nExit)++] = t;
01204 if (t==CthCpvAccess(CthCurrent))
01205 {
01206 t->base.exiting = 1;
01207 }
01208 else
01209 {
01210 CthClearThreads();
01211
01212
01213
01214
01215
01216 }
01217 }
01218
01219 #if 0
01220 void CthFiberBlock(CthThread t)
01221 {
01222 CthThread tp;
01223
01224 SwitchToFiber(t->fiber);
01225 tp = CthCpvAccess(CthPrevious);
01226 if (tp != 0 && tp->killed == 1)
01227 CthThreadFree(tp);
01228 }
01229 #endif
01230
01231 void CthResume(CthThread t)
01232 {
01233 CthThread tc;
01234
01235 tc = CthCpvAccess(CthCurrent);
01236 if (t == tc) return;
01237 CthBaseResume(t);
01238 CthCpvAccess(CthPrevious)=tc;
01239 #if 0
01240 if (tc->base.exiting)
01241 {
01242 SwitchToFiber(t->fiber);
01243 }
01244 else
01245 CthFiberBlock(t);
01246 #endif
01247 SwitchToFiber(t->fiber);
01248 }
01249
01250 VOID CALLBACK FiberSetUp(PVOID fiberData)
01251 {
01252 void **ptr = (void **) fiberData;
01253 qt_userf_t* fn = (qt_userf_t *)ptr[0];
01254 void *arg = ptr[1];
01255 CthThread t = CthSelf();
01256
01257 CthClearThreads();
01258
01259 fn(arg);
01260
01261 CthCpvAccess(exitThreads)[CthCpvAccess(nExit)++] = t;
01262 CthThreadFinished(t);
01263 }
01264
01265 CthThread CthCreate(CthVoidFn fn, void *arg, int size)
01266 {
01267 CthThread result;
01268 void** fiberData;
01269 fiberData = (void**)malloc(2*sizeof(void *));
01270 fiberData[0] = (void *)fn;
01271 fiberData[1] = arg;
01272
01273 result = (CthThread)malloc(sizeof(struct CthThreadStruct));
01274 _MEMCHECK(result);
01275 CthThreadInit(result);
01276
01277 result->fiber = CreateFiberEx(size, size, 0, FiberSetUp, (PVOID) fiberData);
01278 if (!result->fiber)
01279 CmiAbort("CthCreate failed to create fiber!\n");
01280
01281 return result;
01282 }
01283
01284 int CthMigratable()
01285 {
01286 return 0;
01287 }
01288 CthThread CthPup(pup_er p, CthThread t)
01289 {
01290 CmiAbort("CthPup not implemented.\n");
01291 return 0;
01292 }
01293 CthThread CthCreateMigratable(CthVoidFn fn,void *arg,int size)
01294 {
01295
01296 return CthCreate(fn,arg,size);
01297 }
01298
01299
01300
01301
01302
01303
01304
01305
01306
01307
01308 #elif CMK_THREADS_USE_PTHREADS
01309
01310 #include <pthread.h>
01311 #include <errno.h>
01312
01313 struct CthThreadStruct
01314 {
01315 CthThreadBase base;
01316 pthread_t self;
01317 pthread_cond_t cond;
01318 pthread_cond_t *creator;
01319 CthVoidFn fn;
01320 void *arg;
01321 char inited;
01322 };
01323
01329 CthCpvStatic(pthread_mutex_t, sched_mutex);
01330
01331 static void CthThreadInit(t)
01332 CthThread t;
01333 {
01334 CthThreadBaseInit(&t->base);
01335 t->inited = 0;
01336 pthread_cond_init(&(t->cond) , (pthread_condattr_t *) 0);
01337 }
01338
01339 void CthInit(char **argv)
01340 {
01341 CthThread t;
01342
01343 CthCpvInitialize(pthread_mutex_t, sched_mutex);
01344
01345 pthread_mutex_init(&CthCpvAccess(sched_mutex), (pthread_mutexattr_t *) 0);
01346 pthread_mutex_lock(&CthCpvAccess(sched_mutex));
01347 CthBaseInit(argv);
01348 t = (CthThread)malloc(sizeof(struct CthThreadStruct));
01349 _MEMCHECK(t);
01350 CthCpvAccess(CthCurrent)=t;
01351 CthThreadInit(t);
01352 t->self = pthread_self();
01353
01354 CmiThreadIs_flag |= CMI_THREAD_IS_PTHREADS;
01355 }
01356
01357 void CthFree(t)
01358 CthThread t;
01359 {
01360 if (t==NULL) return;
01361 if (t==CthCpvAccess(CthCurrent)) {
01362 t->base.exiting = 1;
01363 } else {
01364 CthThreadBaseFree(&t->base);
01365 free(t);
01366 }
01367 }
01368
01369 void CthResume(CthThread t)
01370 {
01371 CthThread tc = CthCpvAccess(CthCurrent);
01372 if (t == tc) return;
01373 CthBaseResume(t);
01374 pthread_cond_signal(&(t->cond));
01375 if (tc->base.exiting) {
01376 pthread_mutex_unlock(&CthCpvAccess(sched_mutex));
01377 pthread_exit(0);
01378 } else {
01379
01380
01381
01382 do {
01383 pthread_cond_wait(&(tc->cond), &CthCpvAccess(sched_mutex));
01384 } while (tc!=CthCpvAccess(CthCurrent)) ;
01385 }
01386 }
01387
01388 static void *CthOnly(void * arg)
01389 {
01390 CthThread th = (CthThread)arg;
01391 th->inited = 1;
01392 pthread_detach(pthread_self());
01393 pthread_mutex_lock(&CthCpvAccess(sched_mutex));
01394 pthread_cond_signal(th->creator);
01395 do {
01396 pthread_cond_wait(&(th->cond), &CthCpvAccess(sched_mutex));
01397 } while (arg!=CthCpvAccess(CthCurrent)) ;
01398 th->fn(th->arg);
01399 CthThreadFinished(th);
01400 return 0;
01401 }
01402
01403 CthThread CthCreate(CthVoidFn fn, void *arg, int size)
01404 {
01405 static int reported = 0;
01406 pthread_attr_t attr;
01407 int r;
01408 CthThread result;
01409 CthThread self = CthSelf();
01410
01411 result = (CthThread)malloc(sizeof(struct CthThreadStruct));
01412 _MEMCHECK(result);
01413 CthThreadInit(result);
01414 result->fn = fn;
01415 result->arg = arg;
01416 result->creator = &(self->cond);
01417
01418
01419 pthread_attr_init(&attr);
01420
01421 if (size<1024) size = CthCpvAccess(_defaultStackSize);
01422 if (0!=(r=pthread_attr_setstacksize(&attr,size))) {
01423 if (!reported) {
01424 CmiPrintf("Warning: pthread_attr_setstacksize failed\n");
01425 errno = r;
01426 perror("pthread_attr_setstacksize");
01427 reported = 1;
01428 }
01429 }
01430
01431
01432
01433
01434
01435
01436 #if CMK_WITH_TAU
01437 r = tau_pthread_create(&(result->self), &attr, CthOnly, (void*) result);
01438 #else
01439 r = pthread_create(&(result->self), &attr, CthOnly, (void*) result);
01440 #endif
01441 if (0 != r) {
01442 CmiPrintf("pthread_create failed with %d\n", r);
01443 CmiAbort("CthCreate failed to created a new pthread\n");
01444 }
01445 do {
01446 pthread_cond_wait(&(self->cond), &CthCpvAccess(sched_mutex));
01447 } while (result->inited==0);
01448 return result;
01449 }
01450
01451 int CthMigratable()
01452 {
01453 return 0;
01454 }
01455 CthThread CthPup(pup_er p, CthThread t)
01456 {
01457 CmiAbort("CthPup not implemented.\n");
01458 return 0;
01459 }
01460 CthThread CthCreateMigratable(CthVoidFn fn,void *arg,int size)
01461 {
01462
01463 return CthCreate(fn,arg,size);
01464 }
01465
01466
01467
01468
01469
01470
01471
01472
01473
01474
01475
01476
01477
01478
01479
01480
01481
01482
01483
01484
01485
01486
01487
01488
01489
01490
01491
01492 #elif (CMK_THREADS_USE_CONTEXT || CMK_THREADS_USE_JCONTEXT)
01493
01494 #include <signal.h>
01495 #include <errno.h>
01496
01497 #if CMK_THREADS_USE_CONTEXT
01498
01499 #include <ucontext.h>
01500
01501 #define uJcontext_t ucontext_t
01502 #define setJcontext setcontext
01503 #define getJcontext getcontext
01504 #define swapJcontext swapcontext
01505 #define makeJcontext makecontext
01506 typedef void (*uJcontext_fn_t)(void);
01507
01508 #else
01509
01510 #include "uJcontext.h"
01511 #include "uJcontext.c"
01512
01513 #endif
01514
01515
01516 struct CthThreadStruct
01517 {
01518 CthThreadBase base;
01519 double * dummy;
01520 uJcontext_t context;
01521 };
01522
01523
01524 static void CthThreadInit(t)
01525 CthThread t;
01526 {
01527 CthThreadBaseInit(&t->base);
01528 }
01529
01530
01531 CpvStaticDeclare(CthThread , doomedThreadPool);
01532
01533 void CthInit(char **argv)
01534 {
01535 CthThread t;
01536
01537 CthBaseInit(argv);
01538 t = (CthThread)malloc(sizeof(struct CthThreadStruct));
01539 _MEMCHECK(t);
01540 CthCpvAccess(CthCurrent)=t;
01541 if (0 != getJcontext(&t->context))
01542 CmiAbort("CthInit: getcontext failed.\n");
01543 CthThreadInit(t);
01544 CpvInitialize(CthThread, doomedThreadPool);
01545 CpvAccess(doomedThreadPool) = (CthThread)NULL;
01546
01547
01548 #ifdef MINSIGSTKSZ
01549 if (CthCpvAccess(_defaultStackSize) < MINSIGSTKSZ)
01550 CthCpvAccess(_defaultStackSize) = MINSIGSTKSZ;
01551 #endif
01552 #if CMK_THREADS_USE_CONTEXT
01553 CmiThreadIs_flag |= CMI_THREAD_IS_CONTEXT;
01554 #else
01555 CmiThreadIs_flag |= CMI_THREAD_IS_UJCONTEXT;
01556 #endif
01557 #if CMK_THREADS_ALIAS_STACK
01558 CmiThreadIs_flag |= CMI_THREAD_IS_ALIAS;
01559 #endif
01560 }
01561
01562 static void CthThreadFree(CthThread t)
01563 {
01564
01565
01566 CthThread doomed=CpvAccess(doomedThreadPool);
01567 CpvAccess(doomedThreadPool) = t;
01568 if (doomed != NULL) {
01569 CthThreadBaseFree(&doomed->base);
01570 free(doomed);
01571 }
01572 }
01573
01574 void CthFree(CthThread t)
01575 {
01576 if (t==NULL) return;
01577 if (t==CthCpvAccess(CthCurrent)) {
01578 t->base.exiting = 1;
01579 } else {
01580 CthThreadFree(t);
01581 }
01582 }
01583
01584 #if CMK_THREADS_BUILD_TLS
01585 void CthResume(CthThread) __attribute__((optimize(0)));
01586 #endif
01587
01588 void CthResume(t)
01589 CthThread t;
01590 {
01591 CthThread tc;
01592 tc = CthCpvAccess(CthCurrent);
01593
01594 #if CMK_THREADS_BUILD_TLS
01595 switchTLS(&B(tc)->tlsseg, &B(t)->tlsseg);
01596 #endif
01597
01598 if (t != tc) {
01599 CthBaseResume(t);
01600 if (!tc->base.exiting)
01601 {
01602 if (0 != swapJcontext(&tc->context, &t->context))
01603 CmiAbort("CthResume: swapcontext failed.\n");
01604 }
01605 else
01606 {
01607 CthThreadFree(tc);
01608 setJcontext(&t->context);
01609 }
01610 }
01611
01612
01613
01614 }
01615
01616 #if CMK_THREADS_USE_CONTEXT && CMK_64BIT
01617 void CthStartThread(CmiUInt4 fn1, CmiUInt4 fn2, CmiUInt4 arg1, CmiUInt4 arg2)
01618 {
01619 CmiUInt8 fn0 = (((CmiUInt8)fn1) << 32) | fn2;
01620 CmiUInt8 arg0 = (((CmiUInt8)arg1) << 32) | arg2;
01621 void *arg = (void *)arg0;
01622 qt_userf_t *fn = (qt_userf_t*)fn0;
01623 (*fn)(arg);
01624 CthThreadFinished(CthSelf());
01625 }
01626 #else
01627 void CthStartThread(qt_userf_t fn,void *arg)
01628 {
01629 fn(arg);
01630 CthThreadFinished(CthSelf());
01631 }
01632 #endif
01633
01634 #define STP_STKALIGN(sp, alignment) \
01635 ((void *)((((qt_word_t)(sp)) + (alignment) - 1) & ~((alignment)-1)))
01636
01637 int ptrDiffLen(const void *a,const void *b) {
01638 char *ac=(char *)a, *bc=(char *)b;
01639 int ret=ac-bc;
01640 if (ret<0) ret=-ret;
01641 return ret;
01642 }
01643
01644 static CthThread CthCreateInner(CthVoidFn fn,void *arg,int size,int migratable)
01645 {
01646 CthThread result;
01647 char *stack, *ss_sp, *ss_end;
01648
01649 result = (CthThread)malloc(sizeof(struct CthThreadStruct));
01650 _MEMCHECK(result);
01651 CthThreadInit(result);
01652 #ifdef MINSIGSTKSZ
01653
01654 if (size && size<MINSIGSTKSZ) size = MINSIGSTKSZ;
01655 #endif
01656 CthAllocateStack(&result->base,&size,migratable);
01657 stack = result->base.stack;
01658
01659 if (0 != getJcontext(&result->context))
01660 CmiAbort("CthCreateInner: getcontext failed.\n");
01661
01662 ss_end = stack + size;
01663
01671 #if CMK_THREADS_USE_JCONTEXT
01672 ss_sp = stack;
01673 #elif CMK_CONTEXT_STACKEND
01674 ss_sp = stack+size-MINSIGSTKSZ;
01675 ss_end = stack;
01676 #elif CMK_CONTEXT_STACKMIDDLE
01677 ss_sp = stack+size/2;
01678 #else
01679 ss_sp = stack;
01680 #endif
01681
01682 result->context.uc_stack.ss_sp = STP_STKALIGN(ss_sp,sizeof(char *)*8);
01683 result->context.uc_stack.ss_size = ptrDiffLen(result->context.uc_stack.ss_sp,ss_end);
01684 result->context.uc_stack.ss_flags = 0;
01685 result->context.uc_link = 0;
01686
01687 CthAliasEnable(B(result));
01688 errno = 0;
01689 #if CMK_THREADS_USE_CONTEXT
01690 if (sizeof(void *) == 8) {
01691 CmiUInt4 fn1 = ((CmiUInt8)fn) >> 32;
01692 CmiUInt4 fn2 = (CmiUInt8)fn & 0xFFFFFFFF;
01693 CmiUInt4 arg1 = ((CmiUInt8)arg) >> 32;
01694 CmiUInt4 arg2 = (CmiUInt8)arg & 0xFFFFFFFF;
01695 makeJcontext(&result->context, (uJcontext_fn_t)CthStartThread, 4, fn1, fn2, arg1, arg2);
01696 }
01697 else
01698 #endif
01699 makeJcontext(&result->context, (uJcontext_fn_t)CthStartThread, 2, (void *)fn,(void *)arg);
01700 if(errno !=0) {
01701 perror("makecontext");
01702 CmiAbort("CthCreateInner: makecontext failed.\n");
01703 }
01704 CthAliasEnable(B(CthCpvAccess(CthCurrent)));
01705
01706 #if CMK_THREADS_BUILD_TLS
01707 allocNewTLSSeg(&B(result)->tlsseg, result);
01708 #endif
01709
01710 return result;
01711 }
01712
01713 CthThread CthCreate(CthVoidFn fn,void *arg,int size)
01714 {
01715 return CthCreateInner(fn,arg,size,0);
01716 }
01717 CthThread CthCreateMigratable(CthVoidFn fn,void *arg,int size)
01718 {
01719 return CthCreateInner(fn,arg,size,1);
01720 }
01721
01722 int CthMigratable()
01723 {
01724 return CmiIsomallocEnabled();
01725 }
01726
01727 CthThread CthPup(pup_er p, CthThread t)
01728 {
01729 int flag;
01730 if (pup_isUnpacking(p)) {
01731 t=(CthThread)malloc(sizeof(struct CthThreadStruct));
01732 _MEMCHECK(t);
01733 CthThreadInit(t);
01734 }
01735 CthPupBase(p,&t->base,1);
01736
01737
01738
01739
01740 pup_bytes(p,&t->context,sizeof(t->context));
01741 #if !CMK_THREADS_USE_JCONTEXT && CMK_CONTEXT_FPU_POINTER
01742 #if ! CMK_CONTEXT_FPU_POINTER_UCREGS
01743
01744
01745 if (!pup_isUnpacking(p)) flag = t->context.uc_mcontext.fpregs != NULL;
01746 pup_int(p,&flag);
01747 if (flag) {
01748 if (pup_isUnpacking(p)) {
01749 t->context.uc_mcontext.fpregs = malloc(sizeof(struct _libc_fpstate));
01750 }
01751 pup_bytes(p,t->context.uc_mcontext.fpregs,sizeof(struct _libc_fpstate));
01752 }
01753 #else
01754 if (!pup_isUnpacking(p)) flag = t->context.uc_mcontext.uc_regs != NULL;
01755 pup_int(p,&flag);
01756 if (flag) {
01757 if (pup_isUnpacking(p)) {
01758 t->context.uc_mcontext.uc_regs = malloc(sizeof(mcontext_t));
01759 }
01760 pup_bytes(p,t->context.uc_mcontext.uc_regs,sizeof(mcontext_t));
01761 }
01762 #endif
01763 #endif
01764 #if !CMK_THREADS_USE_JCONTEXT && CMK_CONTEXT_V_REGS
01765
01766 if (pup_isUnpacking(p)) {
01767 t->context.uc_mcontext.v_regs = malloc(sizeof(vrregset_t));
01768 }
01769 pup_bytes(p,t->context.uc_mcontext.v_regs,sizeof(vrregset_t));
01770 #endif
01771 if (pup_isUnpacking(p)) {
01772 t->context.uc_link = 0;
01773 }
01774 if (pup_isDeleting(p)) {
01775 CthFree(t);
01776 return 0;
01777 }
01778 return t;
01779 }
01780
01781 #else
01782
01783
01784
01785
01786
01787
01788
01789
01790
01791
01792
01793
01794
01795
01796
01797
01798 #if !CMK_ERROR_CHECKING || (!CMK_MEMORY_PROTECTABLE)
01799 # define CMK_STACKPROTECT 0
01800
01801 # define CthMemAlign(x,n) 0
01802 # define CthMemoryProtect(m,p,l) CmiAbort("Shouldn't call CthMemoryProtect!\n")
01803 # define CthMemoryUnprotect(m,p,l) CmiAbort("Shouldn't call CthMemoryUnprotect!\n")
01804 #else
01805 # define CMK_STACKPROTECT 1
01806
01807 extern void setProtection(char*, char*, int, int);
01808 # include "sys/mman.h"
01809 # define CthMemAlign(x,n) memalign((x),(n))
01810 # define CthMemoryProtect(m,p,l) mprotect(p,l,PROT_NONE);setProtection((char*)m,p,l,1);
01811 # define CthMemoryUnprotect(m,p,l) mprotect(p,l,PROT_READ | PROT_WRITE);setProtection((char*)m,p,l,0);
01812 #endif
01813
01814 struct CthThreadStruct
01815 {
01816 CthThreadBase base;
01817
01818 char *protect;
01819 int protlen;
01820
01821 qt_t *stack;
01822 qt_t *stackp;
01823 };
01824
01825 static CthThread CthThreadInit(void)
01826 {
01827 CthThread ret=(CthThread)malloc(sizeof(struct CthThreadStruct));
01828 _MEMCHECK(ret);
01829 CthThreadBaseInit(&ret->base);
01830 ret->protect = 0;
01831 ret->protlen = 0;
01832
01833 return ret;
01834 }
01835
01836 static void CthThreadFree(CthThread t)
01837 {
01838 if (t->protlen!=0) {
01839 CthMemoryUnprotect(t->stack, t->protect, t->protlen);
01840 }
01841 CthThreadBaseFree(&t->base);
01842 free(t);
01843 }
01844
01845 void CthInit(char **argv)
01846 {
01847 CthThread mainThread;
01848
01849 CthBaseInit(argv);
01850 mainThread=CthThreadInit();
01851 CthCpvAccess(CthCurrent)=mainThread;
01852
01853
01854 CmiThreadIs_flag |= CMI_THREAD_IS_QT;
01855 #if CMK_THREADS_ALIAS_STACK
01856 CmiThreadIs_flag |= CMI_THREAD_IS_ALIAS;
01857 #endif
01858 }
01859
01860 void CthFree(CthThread t)
01861 {
01862 if (t==NULL) return;
01863 if (t==CthCpvAccess(CthCurrent)) {
01864 t->base.exiting = 1;
01865 } else {
01866 CthThreadFree(t);
01867 }
01868 }
01869
01870 static void *CthAbortHelp(qt_t *sp, CthThread old, void *null)
01871 {
01872 CthThreadFree(old);
01873 return (void *) 0;
01874 }
01875
01876 static void *CthBlockHelp(qt_t *sp, CthThread old, void *null)
01877 {
01878 old->stackp = sp;
01879 return (void *) 0;
01880 }
01881
01882 #if CMK_THREADS_BUILD_TLS
01883 void CthResume(CthThread) __attribute__((optimize(0)));
01884 #endif
01885
01886 void CthResume(t)
01887 CthThread t;
01888 {
01889 CthThread tc = CthCpvAccess(CthCurrent);
01890 if (t == tc) return;
01891
01892 #if CMK_THREADS_BUILD_TLS
01893 switchTLS(&B(tc)->tlsseg, &B(t)->tlsseg);
01894 #endif
01895
01896 CthBaseResume(t);
01897 if (tc->base.exiting) {
01898 QT_ABORT((qt_helper_t*)CthAbortHelp, tc, 0, t->stackp);
01899 } else {
01900 QT_BLOCK((qt_helper_t*)CthBlockHelp, tc, 0, t->stackp);
01901 }
01902
01903
01904
01905 }
01906
01907 static void CthOnly(void *arg, void *vt, qt_userf_t fn)
01908 {
01909 fn(arg);
01910 CthThreadFinished(CthSelf());
01911 }
01912
01913 static CthThread CthCreateInner(CthVoidFn fn, void *arg, int size,int Migratable)
01914 {
01915 CthThread result; qt_t *stack, *stackbase, *stackp;
01916 int doProtect=(!Migratable) && CMK_STACKPROTECT;
01917 result=CthThreadInit();
01918 if (doProtect)
01919 {
01920 if (size==0) size=CthCpvAccess(_defaultStackSize);
01921 size = (size+(CMK_MEMORY_PAGESIZE*2)-1) & ~(CMK_MEMORY_PAGESIZE-1);
01922 stack = (qt_t*)CthMemAlign(CMK_MEMORY_PAGESIZE, size);
01923 B(result)->stack = stack;
01924 } else
01925 stack=CthAllocateStack(&result->base,&size,Migratable);
01926 CthAliasEnable(B(result));
01927 stackbase = QT_SP(stack, size);
01928 stackp = QT_ARGS(stackbase, arg, result, (qt_userf_t *)fn, CthOnly);
01929 CthAliasEnable(B(CthCpvAccess(CthCurrent)));
01930 result->stack = stack;
01931 result->stackp = stackp;
01932 if (doProtect) {
01933 #ifdef QT_GROW_UP
01934
01935 result->protect = ((char*)stack) + size - CMK_MEMORY_PAGESIZE;
01936 #else
01937
01938 result->protect = ((char*)stack);
01939 #endif
01940 result->protlen = CMK_MEMORY_PAGESIZE;
01941 CthMemoryProtect(stack, result->protect, result->protlen);
01942 }
01943
01944 #if CMK_THREADS_BUILD_TLS
01945 allocNewTLSSeg(&B(result)->tlsseg, result);
01946 #endif
01947
01948 return result;
01949 }
01950
01951 CthThread CthCreate(CthVoidFn fn, void *arg, int size)
01952 { return CthCreateInner(fn,arg,size,0);}
01953
01954 CthThread CthCreateMigratable(CthVoidFn fn, void *arg, int size)
01955 { return CthCreateInner(fn,arg,size,1);}
01956
01957 int CthMigratable()
01958 {
01959 #if CMK_THREADS_ALIAS_STACK
01960 return 1;
01961 #else
01962 return CmiIsomallocEnabled();
01963 #endif
01964 }
01965
01966 CthThread CthPup(pup_er p, CthThread t)
01967 {
01968 if (pup_isUnpacking(p)) {
01969 t=CthThreadInit();
01970 }
01971 #if CMK_THREADS_ALIAS_STACK
01972 CthPupBase(p,&t->base,0);
01973 #else
01974 CthPupBase(p,&t->base,1);
01975 #endif
01976
01977
01978 pup_bytes(p,&t->stackp,sizeof(t->stackp));
01979
01980
01981
01982 if (pup_isDeleting(p)) {
01983 CthFree(t);
01984 return 0;
01985 }
01986 return t;
01987 }
01988
01989
01990 void CthPrintThdStack(CthThread t){
01991 CmiPrintf("thread=%p, base stack=%p, stack pointer=%p\n", t, t->base.stack, t->stackp);
01992 }
01993 #endif
01994
01995 #if ! USE_SPECIAL_STACKPOINTER
01996 size_t CthStackOffset(CthThread t, char *p)
01997 {
01998 size_t s;
01999 CmiAssert(t);
02000 if (B(t)->stack == NULL)
02001 s = p - (char *)t;
02002 else
02003 s = p - (char *)B(t)->stack;
02004
02005 return s;
02006 }
02007
02008 char * CthPointer(CthThread t, size_t pos)
02009 {
02010 char *p;
02011 CmiAssert(t);
02012 if (B(t)->stack == NULL)
02013 p = (char*)t + pos;
02014 else
02015 p = (char *)B(t)->stack + pos;
02016
02017 return p;
02018 }
02019 #endif
02020
02021
02022 void CthTraceResume(CthThread t)
02023 {
02024 traceResume(&t->base.tid);
02025 }
02026
02027
02028 void CthPrintThdMagic(CthThread t){
02029 CmiPrintf("CthThread[%p]'s magic: %x\n", t, t->base.magic);
02030 }
02031