tclUnixThrd.c

Go 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  doxygen 1.5.1