tclUnixThrd.cGo to the documentation of this file.00001 /* 00002 * tclUnixThrd.c -- 00003 * 00004 * This file implements the UNIX-specific thread support. 00005 * 00006 * Copyright (c) 1991-1994 The Regents of the University of California. 00007 * Copyright (c) 1994-1997 Sun Microsystems, Inc. 00008 * 00009 * See the file "license.terms" for information on usage and redistribution of 00010 * this file, and for a DISCLAIMER OF ALL WARRANTIES. 00011 * 00012 * RCS: @(#) $Id: tclUnixThrd.c,v 1.57 2008/01/11 11:53:02 msofer Exp $ 00013 */ 00014 00015 #include "tclInt.h" 00016 00017 #ifdef TCL_THREADS 00018 00019 #include "pthread.h" 00020 00021 typedef struct ThreadSpecificData { 00022 char nabuf[16]; 00023 } ThreadSpecificData; 00024 00025 static Tcl_ThreadDataKey dataKey; 00026 00027 /* 00028 * masterLock is used to serialize creation of mutexes, condition variables, 00029 * and thread local storage. This is the only place that can count on the 00030 * ability to statically initialize the mutex. 00031 */ 00032 00033 static pthread_mutex_t masterLock = PTHREAD_MUTEX_INITIALIZER; 00034 00035 /* 00036 * initLock is used to serialize initialization and finalization of Tcl. It 00037 * cannot use any dyamically allocated storage. 00038 */ 00039 00040 static pthread_mutex_t initLock = PTHREAD_MUTEX_INITIALIZER; 00041 00042 /* 00043 * allocLock is used by Tcl's version of malloc for synchronization. For 00044 * obvious reasons, cannot use any dyamically allocated storage. 00045 */ 00046 00047 static pthread_mutex_t allocLock = PTHREAD_MUTEX_INITIALIZER; 00048 static pthread_mutex_t *allocLockPtr = &allocLock; 00049 00050 /* 00051 * These are for the critical sections inside this file. 00052 */ 00053 00054 #define MASTER_LOCK pthread_mutex_lock(&masterLock) 00055 #define MASTER_UNLOCK pthread_mutex_unlock(&masterLock) 00056 00057 #endif /* TCL_THREADS */ 00058 00059 00060 /* 00061 *---------------------------------------------------------------------- 00062 * 00063 * TclpThreadCreate -- 00064 * 00065 * This procedure creates a new thread. 00066 * 00067 * Results: 00068 * TCL_OK if the thread could be created. The thread ID is returned in a 00069 * parameter. 00070 * 00071 * Side effects: 00072 * A new thread is created. 00073 * 00074 *---------------------------------------------------------------------- 00075 */ 00076 00077 int 00078 TclpThreadCreate( 00079 Tcl_ThreadId *idPtr, /* Return, the ID of the thread */ 00080 Tcl_ThreadCreateProc proc, /* Main() function of the thread */ 00081 ClientData clientData, /* The one argument to Main() */ 00082 int stackSize, /* Size of stack for the new thread */ 00083 int flags) /* Flags controlling behaviour of the new 00084 * thread. */ 00085 { 00086 #ifdef TCL_THREADS 00087 pthread_attr_t attr; 00088 pthread_t theThread; 00089 int result; 00090 00091 pthread_attr_init(&attr); 00092 pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); 00093 00094 #ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE 00095 if (stackSize != TCL_THREAD_STACK_DEFAULT) { 00096 pthread_attr_setstacksize(&attr, (size_t) stackSize); 00097 #ifdef TCL_THREAD_STACK_MIN 00098 } else { 00099 /* 00100 * Certain systems define a thread stack size that by default is too 00101 * small for many operations. The user has the option of defining 00102 * TCL_THREAD_STACK_MIN to a value large enough to work for their 00103 * needs. This would look like (for 128K min stack): 00104 * make MEM_DEBUG_FLAGS=-DTCL_THREAD_STACK_MIN=131072L 00105 * 00106 * This solution is not optimal, as we should allow the user to 00107 * specify a size at runtime, but we don't want to slow this function 00108 * down, and that would still leave the main thread at the default. 00109 */ 00110 00111 size_t size; 00112 result = pthread_attr_getstacksize(&attr, &size); 00113 if (!result && (size < TCL_THREAD_STACK_MIN)) { 00114 pthread_attr_setstacksize(&attr, (size_t) TCL_THREAD_STACK_MIN); 00115 } 00116 #endif 00117 } 00118 #endif 00119 if (! (flags & TCL_THREAD_JOINABLE)) { 00120 pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); 00121 } 00122 00123 00124 if (pthread_create(&theThread, &attr, 00125 (void * (*)(void *))proc, (void *)clientData) && 00126 pthread_create(&theThread, NULL, 00127 (void * (*)(void *))proc, (void *)clientData)) { 00128 result = TCL_ERROR; 00129 } else { 00130 *idPtr = (Tcl_ThreadId)theThread; 00131 result = TCL_OK; 00132 } 00133 pthread_attr_destroy(&attr); 00134 return result; 00135 #else 00136 return TCL_ERROR; 00137 #endif /* TCL_THREADS */ 00138 } 00139 00140 /* 00141 *---------------------------------------------------------------------- 00142 * 00143 * Tcl_JoinThread -- 00144 * 00145 * This procedure waits upon the exit of the specified thread. 00146 * 00147 * Results: 00148 * TCL_OK if the wait was successful, TCL_ERROR else. 00149 * 00150 * Side effects: 00151 * The result area is set to the exit code of the thread we waited upon. 00152 * 00153 *---------------------------------------------------------------------- 00154 */ 00155 00156 int 00157 Tcl_JoinThread( 00158 Tcl_ThreadId threadId, /* Id of the thread to wait upon. */ 00159 int *state) /* Reference to the storage the result of the 00160 * thread we wait upon will be written into. 00161 * May be NULL. */ 00162 { 00163 #ifdef TCL_THREADS 00164 int result; 00165 unsigned long retcode, *retcodePtr = &retcode; 00166 00167 result = pthread_join((pthread_t) threadId, (void**) retcodePtr); 00168 if (state) { 00169 *state = (int) retcode; 00170 } 00171 return (result == 0) ? TCL_OK : TCL_ERROR; 00172 #else 00173 return TCL_ERROR; 00174 #endif 00175 } 00176 00177 #ifdef TCL_THREADS 00178 /* 00179 *---------------------------------------------------------------------- 00180 * 00181 * TclpThreadExit -- 00182 * 00183 * This procedure terminates the current thread. 00184 * 00185 * Results: 00186 * None. 00187 * 00188 * Side effects: 00189 * This procedure terminates the current thread. 00190 * 00191 *---------------------------------------------------------------------- 00192 */ 00193 00194 void 00195 TclpThreadExit( 00196 int status) 00197 { 00198 pthread_exit(INT2PTR(status)); 00199 } 00200 #endif /* TCL_THREADS */ 00201 00202 #ifdef TCL_THREADS 00203 /* 00204 *---------------------------------------------------------------------- 00205 * 00206 * TclpThreadGetStackSize -- 00207 * 00208 * This procedure returns the size of the current thread's stack. 00209 * 00210 * Results: 00211 * Stack size (in bytes?) or -1 for error or 0 for undeterminable. 00212 * 00213 * Side effects: 00214 * None. 00215 * 00216 *---------------------------------------------------------------------- 00217 */ 00218 00219 size_t 00220 TclpThreadGetStackSize(void) 00221 { 00222 size_t stackSize = 0; 00223 #if defined(HAVE_PTHREAD_ATTR_SETSTACKSIZE) && defined(TclpPthreadGetAttrs) 00224 pthread_attr_t threadAttr; /* This will hold the thread attributes for 00225 * the current thread. */ 00226 #ifdef __GLIBC__ 00227 /* 00228 * Fix for [Bug 1815573] 00229 * 00230 * DESCRIPTION: 00231 * On linux TclpPthreadGetAttrs (which is pthread_attr_get_np) may return 00232 * bogus values on the initial thread. 00233 * 00234 * ASSUMPTIONS: 00235 * There seems to be no api to determine if we are on the initial 00236 * thread. The simple scheme implemented here assumes: 00237 * 1. The first Tcl interp to be created lives in the initial thread. If 00238 * this assumption is not true, the fix is to call 00239 * TclpThreadGetStackSize from the initial thread previous to 00240 * creating any Tcl interpreter. In this case, especially if another 00241 * Tcl interpreter may be created in the initial thread, it might be 00242 * better to enable the second branch in the #if below 00243 * 2. There will be no races in creating the first Tcl interp - ie, the 00244 * second Tcl interp will be created only after the first call to 00245 * Tcl_CreateInterp returns. 00246 * 00247 * These assumptions are satisfied by tclsh. Embedders on linux may want 00248 * to check their validity, and possibly adapt the code on failing to meet 00249 * them. 00250 */ 00251 00252 static int initialized = 0; 00253 00254 if (!initialized) { 00255 initialized = 1; 00256 return 0; 00257 } else { 00258 #else 00259 { 00260 #endif 00261 if (pthread_attr_init(&threadAttr) != 0) { 00262 return -1; 00263 } 00264 if (TclpPthreadGetAttrs(pthread_self(), &threadAttr) != 0) { 00265 pthread_attr_destroy(&threadAttr); 00266 return (size_t)-1; 00267 } 00268 } 00269 00270 00271 if (pthread_attr_getstacksize(&threadAttr, &stackSize) != 0) { 00272 pthread_attr_destroy(&threadAttr); 00273 return (size_t)-1; 00274 } 00275 pthread_attr_destroy(&threadAttr); 00276 #elif defined(HAVE_PTHREAD_GET_STACKSIZE_NP) 00277 #ifdef __APPLE__ 00278 /* 00279 * On Darwin, the API below does not return the correct stack size for the 00280 * main thread (which is not a real pthread), so fallback to getrlimit(). 00281 */ 00282 if (!pthread_main_np()) 00283 #endif 00284 stackSize = pthread_get_stacksize_np(pthread_self()); 00285 #else 00286 /* 00287 * Cannot determine the real stack size of this thread. The caller might 00288 * want to try looking at the process accounting limits instead. 00289 */ 00290 #endif 00291 return stackSize; 00292 } 00293 #endif /* TCL_THREADS */ 00294 00295 /* 00296 *---------------------------------------------------------------------- 00297 * 00298 * Tcl_GetCurrentThread -- 00299 * 00300 * This procedure returns the ID of the currently running thread. 00301 * 00302 * Results: 00303 * A thread ID. 00304 * 00305 * Side effects: 00306 * None. 00307 * 00308 *---------------------------------------------------------------------- 00309 */ 00310 00311 Tcl_ThreadId 00312 Tcl_GetCurrentThread(void) 00313 { 00314 #ifdef TCL_THREADS 00315 return (Tcl_ThreadId) pthread_self(); 00316 #else 00317 return (Tcl_ThreadId) 0; 00318 #endif 00319 } 00320 00321 /* 00322 *---------------------------------------------------------------------- 00323 * 00324 * TclpInitLock 00325 * 00326 * This procedure is used to grab a lock that serializes initialization 00327 * and finalization of Tcl. On some platforms this may also initialize 00328 * the mutex used to serialize creation of more mutexes and thread local 00329 * storage keys. 00330 * 00331 * Results: 00332 * None. 00333 * 00334 * Side effects: 00335 * Acquire the initialization mutex. 00336 * 00337 *---------------------------------------------------------------------- 00338 */ 00339 00340 void 00341 TclpInitLock(void) 00342 { 00343 #ifdef TCL_THREADS 00344 pthread_mutex_lock(&initLock); 00345 #endif 00346 } 00347 00348 /* 00349 *---------------------------------------------------------------------- 00350 * 00351 * TclpFinalizeLock 00352 * 00353 * This procedure is used to destroy all private resources used in this 00354 * file. 00355 * 00356 * Results: 00357 * None. 00358 * 00359 * Side effects: 00360 * Destroys everything private. TclpInitLock must be held entering this 00361 * function. 00362 * 00363 *---------------------------------------------------------------------- 00364 */ 00365 00366 void 00367 TclFinalizeLock(void) 00368 { 00369 #ifdef TCL_THREADS 00370 /* 00371 * You do not need to destroy mutexes that were created with the 00372 * PTHREAD_MUTEX_INITIALIZER macro. These mutexes do not need any 00373 * destruction: masterLock, allocLock, and initLock. 00374 */ 00375 00376 pthread_mutex_unlock(&initLock); 00377 #endif 00378 } 00379 00380 /* 00381 *---------------------------------------------------------------------- 00382 * 00383 * TclpInitUnlock 00384 * 00385 * This procedure is used to release a lock that serializes 00386 * initialization and finalization of Tcl. 00387 * 00388 * Results: 00389 * None. 00390 * 00391 * Side effects: 00392 * Release the initialization mutex. 00393 * 00394 *---------------------------------------------------------------------- 00395 */ 00396 00397 void 00398 TclpInitUnlock(void) 00399 { 00400 #ifdef TCL_THREADS 00401 pthread_mutex_unlock(&initLock); 00402 #endif 00403 } 00404 00405 /* 00406 *---------------------------------------------------------------------- 00407 * 00408 * TclpMasterLock 00409 * 00410 * This procedure is used to grab a lock that serializes creation and 00411 * finalization of serialization objects. This interface is only needed 00412 * in finalization; it is hidden during creation of the objects. 00413 * 00414 * This lock must be different than the initLock because the initLock is 00415 * held during creation of syncronization objects. 00416 * 00417 * Results: 00418 * None. 00419 * 00420 * Side effects: 00421 * Acquire the master mutex. 00422 * 00423 *---------------------------------------------------------------------- 00424 */ 00425 00426 void 00427 TclpMasterLock(void) 00428 { 00429 #ifdef TCL_THREADS 00430 pthread_mutex_lock(&masterLock); 00431 #endif 00432 } 00433 00434 00435 /* 00436 *---------------------------------------------------------------------- 00437 * 00438 * TclpMasterUnlock 00439 * 00440 * This procedure is used to release a lock that serializes creation and 00441 * finalization of synchronization objects. 00442 * 00443 * Results: 00444 * None. 00445 * 00446 * Side effects: 00447 * Release the master mutex. 00448 * 00449 *---------------------------------------------------------------------- 00450 */ 00451 00452 void 00453 TclpMasterUnlock(void) 00454 { 00455 #ifdef TCL_THREADS 00456 pthread_mutex_unlock(&masterLock); 00457 #endif 00458 } 00459 00460 00461 /* 00462 *---------------------------------------------------------------------- 00463 * 00464 * Tcl_GetAllocMutex 00465 * 00466 * This procedure returns a pointer to a statically initialized mutex for 00467 * use by the memory allocator. The alloctor must use this lock, because 00468 * all other locks are allocated... 00469 * 00470 * Results: 00471 * A pointer to a mutex that is suitable for passing to Tcl_MutexLock and 00472 * Tcl_MutexUnlock. 00473 * 00474 * Side effects: 00475 * None. 00476 * 00477 *---------------------------------------------------------------------- 00478 */ 00479 00480 Tcl_Mutex * 00481 Tcl_GetAllocMutex(void) 00482 { 00483 #ifdef TCL_THREADS 00484 pthread_mutex_t **allocLockPtrPtr = &allocLockPtr; 00485 return (Tcl_Mutex *) allocLockPtrPtr; 00486 #else 00487 return NULL; 00488 #endif 00489 } 00490 00491 #ifdef TCL_THREADS 00492 00493 /* 00494 *---------------------------------------------------------------------- 00495 * 00496 * Tcl_MutexLock -- 00497 * 00498 * This procedure is invoked to lock a mutex. This procedure handles 00499 * initializing the mutex, if necessary. The caller can rely on the fact 00500 * that Tcl_Mutex is an opaque pointer. This routine will change that 00501 * pointer from NULL after first use. 00502 * 00503 * Results: 00504 * None. 00505 * 00506 * Side effects: 00507 * May block the current thread. The mutex is aquired when this returns. 00508 * Will allocate memory for a pthread_mutex_t and initialize this the 00509 * first time this Tcl_Mutex is used. 00510 * 00511 *---------------------------------------------------------------------- 00512 */ 00513 00514 void 00515 Tcl_MutexLock( 00516 Tcl_Mutex *mutexPtr) /* Really (pthread_mutex_t **) */ 00517 { 00518 pthread_mutex_t *pmutexPtr; 00519 if (*mutexPtr == NULL) { 00520 MASTER_LOCK; 00521 if (*mutexPtr == NULL) { 00522 /* 00523 * Double inside master lock check to avoid a race condition. 00524 */ 00525 00526 pmutexPtr = (pthread_mutex_t *)ckalloc(sizeof(pthread_mutex_t)); 00527 pthread_mutex_init(pmutexPtr, NULL); 00528 *mutexPtr = (Tcl_Mutex)pmutexPtr; 00529 TclRememberMutex(mutexPtr); 00530 } 00531 MASTER_UNLOCK; 00532 } 00533 pmutexPtr = *((pthread_mutex_t **)mutexPtr); 00534 pthread_mutex_lock(pmutexPtr); 00535 } 00536 00537 /* 00538 *---------------------------------------------------------------------- 00539 * 00540 * Tcl_MutexUnlock -- 00541 * 00542 * This procedure is invoked to unlock a mutex. The mutex must have been 00543 * locked by Tcl_MutexLock. 00544 * 00545 * Results: 00546 * None. 00547 * 00548 * Side effects: 00549 * The mutex is released when this returns. 00550 * 00551 *---------------------------------------------------------------------- 00552 */ 00553 00554 void 00555 Tcl_MutexUnlock( 00556 Tcl_Mutex *mutexPtr) /* Really (pthread_mutex_t **) */ 00557 { 00558 pthread_mutex_t *pmutexPtr = *(pthread_mutex_t **)mutexPtr; 00559 pthread_mutex_unlock(pmutexPtr); 00560 } 00561 00562 /* 00563 *---------------------------------------------------------------------- 00564 * 00565 * TclpFinalizeMutex -- 00566 * 00567 * This procedure is invoked to clean up one mutex. This is only safe to 00568 * call at the end of time. 00569 * 00570 * This assumes the Master Lock is held. 00571 * 00572 * Results: 00573 * None. 00574 * 00575 * Side effects: 00576 * The mutex list is deallocated. 00577 * 00578 *---------------------------------------------------------------------- 00579 */ 00580 00581 void 00582 TclpFinalizeMutex( 00583 Tcl_Mutex *mutexPtr) 00584 { 00585 pthread_mutex_t *pmutexPtr = *(pthread_mutex_t **)mutexPtr; 00586 if (pmutexPtr != NULL) { 00587 pthread_mutex_destroy(pmutexPtr); 00588 ckfree((char *) pmutexPtr); 00589 *mutexPtr = NULL; 00590 } 00591 } 00592 00593 /* 00594 *---------------------------------------------------------------------- 00595 * 00596 * Tcl_ConditionWait -- 00597 * 00598 * This procedure is invoked to wait on a condition variable. The mutex 00599 * is automically released as part of the wait, and automatically grabbed 00600 * when the condition is signaled. 00601 * 00602 * The mutex must be held when this procedure is called. 00603 * 00604 * Results: 00605 * None. 00606 * 00607 * Side effects: 00608 * May block the current thread. The mutex is aquired when this returns. 00609 * Will allocate memory for a pthread_mutex_t and initialize this the 00610 * first time this Tcl_Mutex is used. 00611 * 00612 *---------------------------------------------------------------------- 00613 */ 00614 00615 void 00616 Tcl_ConditionWait( 00617 Tcl_Condition *condPtr, /* Really (pthread_cond_t **) */ 00618 Tcl_Mutex *mutexPtr, /* Really (pthread_mutex_t **) */ 00619 Tcl_Time *timePtr) /* Timeout on waiting period */ 00620 { 00621 pthread_cond_t *pcondPtr; 00622 pthread_mutex_t *pmutexPtr; 00623 struct timespec ptime; 00624 00625 if (*condPtr == NULL) { 00626 MASTER_LOCK; 00627 00628 /* 00629 * Double check inside mutex to avoid race, then initialize condition 00630 * variable if necessary. 00631 */ 00632 00633 if (*condPtr == NULL) { 00634 pcondPtr = (pthread_cond_t *) ckalloc(sizeof(pthread_cond_t)); 00635 pthread_cond_init(pcondPtr, NULL); 00636 *condPtr = (Tcl_Condition)pcondPtr; 00637 TclRememberCondition(condPtr); 00638 } 00639 MASTER_UNLOCK; 00640 } 00641 pmutexPtr = *((pthread_mutex_t **)mutexPtr); 00642 pcondPtr = *((pthread_cond_t **)condPtr); 00643 if (timePtr == NULL) { 00644 pthread_cond_wait(pcondPtr, pmutexPtr); 00645 } else { 00646 Tcl_Time now; 00647 00648 /* 00649 * Make sure to take into account the microsecond component of the 00650 * current time, including possible overflow situations. [Bug #411603] 00651 */ 00652 00653 Tcl_GetTime(&now); 00654 ptime.tv_sec = timePtr->sec + now.sec + 00655 (timePtr->usec + now.usec) / 1000000; 00656 ptime.tv_nsec = 1000 * ((timePtr->usec + now.usec) % 1000000); 00657 pthread_cond_timedwait(pcondPtr, pmutexPtr, &ptime); 00658 } 00659 } 00660 00661 /* 00662 *---------------------------------------------------------------------- 00663 * 00664 * Tcl_ConditionNotify -- 00665 * 00666 * This procedure is invoked to signal a condition variable. 00667 * 00668 * The mutex must be held during this call to avoid races, but this 00669 * interface does not enforce that. 00670 * 00671 * Results: 00672 * None. 00673 * 00674 * Side effects: 00675 * May unblock another thread. 00676 * 00677 *---------------------------------------------------------------------- 00678 */ 00679 00680 void 00681 Tcl_ConditionNotify( 00682 Tcl_Condition *condPtr) 00683 { 00684 pthread_cond_t *pcondPtr = *((pthread_cond_t **)condPtr); 00685 if (pcondPtr != NULL) { 00686 pthread_cond_broadcast(pcondPtr); 00687 } else { 00688 /* 00689 * Noone has used the condition variable, so there are no waiters. 00690 */ 00691 } 00692 } 00693 00694 /* 00695 *---------------------------------------------------------------------- 00696 * 00697 * TclpFinalizeCondition -- 00698 * 00699 * This procedure is invoked to clean up a condition variable. This is 00700 * only safe to call at the end of time. 00701 * 00702 * This assumes the Master Lock is held. 00703 * 00704 * Results: 00705 * None. 00706 * 00707 * Side effects: 00708 * The condition variable is deallocated. 00709 * 00710 *---------------------------------------------------------------------- 00711 */ 00712 00713 void 00714 TclpFinalizeCondition( 00715 Tcl_Condition *condPtr) 00716 { 00717 pthread_cond_t *pcondPtr = *(pthread_cond_t **)condPtr; 00718 if (pcondPtr != NULL) { 00719 pthread_cond_destroy(pcondPtr); 00720 ckfree((char *) pcondPtr); 00721 *condPtr = NULL; 00722 } 00723 } 00724 #endif /* TCL_THREADS */ 00725 00726 /* 00727 *---------------------------------------------------------------------- 00728 * 00729 * TclpReaddir, TclpLocaltime, TclpGmtime, TclpInetNtoa -- 00730 * 00731 * These procedures replace core C versions to be used in a threaded 00732 * environment. 00733 * 00734 * Results: 00735 * See documentation of C functions. 00736 * 00737 * Side effects: 00738 * See documentation of C functions. 00739 * 00740 * Notes: 00741 * TclpReaddir is no longer used by the core (see 1095909), but it 00742 * appears in the internal stubs table (see #589526). 00743 * 00744 *---------------------------------------------------------------------- 00745 */ 00746 00747 Tcl_DirEntry * 00748 TclpReaddir( 00749 DIR * dir) 00750 { 00751 return TclOSreaddir(dir); 00752 } 00753 00754 char * 00755 TclpInetNtoa( 00756 struct in_addr addr) 00757 { 00758 #ifdef TCL_THREADS 00759 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); 00760 unsigned char *b = (unsigned char*) &addr.s_addr; 00761 00762 sprintf(tsdPtr->nabuf, "%u.%u.%u.%u", b[0], b[1], b[2], b[3]); 00763 return tsdPtr->nabuf; 00764 #else 00765 return inet_ntoa(addr); 00766 #endif 00767 } 00768 00769 #ifdef TCL_THREADS 00770 /* 00771 * Additions by AOL for specialized thread memory allocator. 00772 */ 00773 00774 #ifdef USE_THREAD_ALLOC 00775 static volatile int initialized = 0; 00776 static pthread_key_t key; 00777 00778 typedef struct allocMutex { 00779 Tcl_Mutex tlock; 00780 pthread_mutex_t plock; 00781 } allocMutex; 00782 00783 Tcl_Mutex * 00784 TclpNewAllocMutex(void) 00785 { 00786 struct allocMutex *lockPtr; 00787 register pthread_mutex_t *plockPtr; 00788 00789 lockPtr = malloc(sizeof(struct allocMutex)); 00790 if (lockPtr == NULL) { 00791 Tcl_Panic("could not allocate lock"); 00792 } 00793 plockPtr = &lockPtr->plock; 00794 lockPtr->tlock = (Tcl_Mutex) plockPtr; 00795 pthread_mutex_init(&lockPtr->plock, NULL); 00796 return &lockPtr->tlock; 00797 } 00798 00799 void 00800 TclpFreeAllocMutex( 00801 Tcl_Mutex *mutex) /* The alloc mutex to free. */ 00802 { 00803 allocMutex* lockPtr = (allocMutex*) mutex; 00804 if (!lockPtr) { 00805 return; 00806 } 00807 pthread_mutex_destroy(&lockPtr->plock); 00808 free(lockPtr); 00809 } 00810 00811 void 00812 TclpFreeAllocCache( 00813 void *ptr) 00814 { 00815 if (ptr != NULL) { 00816 /* 00817 * Called by the pthread lib when a thread exits 00818 */ 00819 00820 TclFreeAllocCache(ptr); 00821 00822 } else if (initialized) { 00823 /* 00824 * Called by us in TclFinalizeThreadAlloc() during the library 00825 * finalization initiated from Tcl_Finalize() 00826 */ 00827 00828 pthread_key_delete(key); 00829 initialized = 0; 00830 } 00831 } 00832 00833 void * 00834 TclpGetAllocCache(void) 00835 { 00836 if (!initialized) { 00837 pthread_mutex_lock(allocLockPtr); 00838 if (!initialized) { 00839 pthread_key_create(&key, TclpFreeAllocCache); 00840 initialized = 1; 00841 } 00842 pthread_mutex_unlock(allocLockPtr); 00843 } 00844 return pthread_getspecific(key); 00845 } 00846 00847 void 00848 TclpSetAllocCache( 00849 void *arg) 00850 { 00851 pthread_setspecific(key, arg); 00852 } 00853 #endif /* USE_THREAD_ALLOC */ 00854 #endif /* TCL_THREADS */ 00855 00856 /* 00857 * Local Variables: 00858 * mode: c 00859 * c-basic-offset: 4 00860 * fill-column: 78 00861 * End: 00862 */
Generated on Wed Mar 12 12:18:26 2008 by 1.5.1 |