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