tclUnixThrd.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:21k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * tclUnixThrd.c --
  3.  *
  4.  * This file implements the UNIX-specific thread support.
  5.  *
  6.  * Copyright (c) 1991-1994 The Regents of the University of California.
  7.  * Copyright (c) 1994-1997 Sun Microsystems, Inc.
  8.  *
  9.  * See the file "license.terms" for information on usage and redistribution
  10.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  11.  *
  12.  * SCCS:  @(#) tclUnixThrd.c 1.18 98/02/19 14:24:12
  13.  */
  14. #include "tclInt.h"
  15. #include "tclPort.h"
  16. #ifdef TCL_THREADS
  17. #include "pthread.h"
  18. typedef struct ThreadSpecificData {
  19.     char nabuf[16];
  20. } ThreadSpecificData;
  21. static Tcl_ThreadDataKey dataKey;
  22. /*
  23.  * masterLock is used to serialize creation of mutexes, condition
  24.  * variables, and thread local storage.
  25.  * This is the only place that can count on the ability to statically
  26.  * initialize the mutex.
  27.  */
  28. static pthread_mutex_t masterLock = PTHREAD_MUTEX_INITIALIZER;
  29. /*
  30.  * initLock is used to serialize initialization and finalization
  31.  * of Tcl.  It cannot use any dyamically allocated storage.
  32.  */
  33. static pthread_mutex_t initLock = PTHREAD_MUTEX_INITIALIZER;
  34. /*
  35.  * allocLock is used by Tcl's version of malloc for synchronization.
  36.  * For obvious reasons, cannot use any dyamically allocated storage.
  37.  */
  38. static pthread_mutex_t allocLock = PTHREAD_MUTEX_INITIALIZER;
  39. static pthread_mutex_t *allocLockPtr = &allocLock;
  40. /*
  41.  * These are for the critical sections inside this file.
  42.  */
  43. #define MASTER_LOCK pthread_mutex_lock(&masterLock)
  44. #define MASTER_UNLOCK pthread_mutex_unlock(&masterLock)
  45. #endif /* TCL_THREADS */
  46. /*
  47.  *----------------------------------------------------------------------
  48.  *
  49.  * TclpThreadCreate --
  50.  *
  51.  * This procedure creates a new thread.
  52.  *
  53.  * Results:
  54.  * TCL_OK if the thread could be created.  The thread ID is
  55.  * returned in a parameter.
  56.  *
  57.  * Side effects:
  58.  * A new thread is created.
  59.  *
  60.  *----------------------------------------------------------------------
  61.  */
  62. int
  63. TclpThreadCreate(idPtr, proc, clientData, stackSize, flags)
  64.     Tcl_ThreadId *idPtr; /* Return, the ID of the thread */
  65.     Tcl_ThreadCreateProc proc; /* Main() function of the thread */
  66.     ClientData clientData; /* The one argument to Main() */
  67.     int stackSize; /* Size of stack for the new thread */
  68.     int flags; /* Flags controlling behaviour of
  69.  * the new thread */
  70. {
  71. #ifdef TCL_THREADS
  72.     pthread_attr_t attr;
  73.     pthread_t theThread;
  74.     int result;
  75.     pthread_attr_init(&attr);
  76.     pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
  77. #ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE
  78.     if (stackSize != TCL_THREAD_STACK_DEFAULT) {
  79.         pthread_attr_setstacksize(&attr, (size_t) stackSize);
  80. #ifdef TCL_THREAD_STACK_MIN
  81.     } else {
  82.         /*
  83.  * Certain systems define a thread stack size that by default is
  84.  * too small for many operations.  The user has the option of
  85.  * defining TCL_THREAD_STACK_MIN to a value large enough to work
  86.  * for their needs.  This would look like (for 128K min stack):
  87.  *    make MEM_DEBUG_FLAGS=-DTCL_THREAD_STACK_MIN=131072L
  88.  *
  89.  * This solution is not optimal, as we should allow the user to
  90.  * specify a size at runtime, but we don't want to slow this function
  91.  * down, and that would still leave the main thread at the default.
  92.  */
  93.         size_t size;
  94. result = pthread_attr_getstacksize(&attr, &size);
  95. if (!result && (size < TCL_THREAD_STACK_MIN)) {
  96.     pthread_attr_setstacksize(&attr, (size_t) TCL_THREAD_STACK_MIN);
  97. }
  98. #endif
  99.     }
  100. #endif
  101.     if (! (flags & TCL_THREAD_JOINABLE)) {
  102.         pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
  103.     }
  104.     if (pthread_create(&theThread, &attr,
  105.     (void * (*)())proc, (void *)clientData) &&
  106.     pthread_create(&theThread, NULL,
  107.     (void * (*)())proc, (void *)clientData)) {
  108. result = TCL_ERROR;
  109.     } else {
  110. *idPtr = (Tcl_ThreadId)theThread;
  111. result = TCL_OK;
  112.     }
  113.     pthread_attr_destroy(&attr);
  114.     return result;
  115. #else
  116.     return TCL_ERROR;
  117. #endif /* TCL_THREADS */
  118. }
  119. /*
  120.  *----------------------------------------------------------------------
  121.  *
  122.  * Tcl_JoinThread --
  123.  *
  124.  * This procedure waits upon the exit of the specified thread.
  125.  *
  126.  * Results:
  127.  * TCL_OK if the wait was successful, TCL_ERROR else.
  128.  *
  129.  * Side effects:
  130.  * The result area is set to the exit code of the thread we
  131.  * waited upon.
  132.  *
  133.  *----------------------------------------------------------------------
  134.  */
  135. int
  136. Tcl_JoinThread(threadId, state)
  137.     Tcl_ThreadId threadId; /* Id of the thread to wait upon */
  138.     int*     state;    /* Reference to the storage the result
  139.     * of the thread we wait upon will be
  140.     * written into. */
  141. {
  142. #ifdef TCL_THREADS
  143.     int result;
  144.     unsigned long retcode;
  145.     result = pthread_join((pthread_t) threadId, (void**) &retcode);
  146.     if (state) {
  147. *state = (int) retcode;
  148.     }
  149.     return (result == 0) ? TCL_OK : TCL_ERROR;
  150. #else
  151.     return TCL_ERROR;
  152. #endif
  153. }
  154. #ifdef TCL_THREADS
  155. /*
  156.  *----------------------------------------------------------------------
  157.  *
  158.  * TclpThreadExit --
  159.  *
  160.  * This procedure terminates the current thread.
  161.  *
  162.  * Results:
  163.  * None.
  164.  *
  165.  * Side effects:
  166.  * This procedure terminates the current thread.
  167.  *
  168.  *----------------------------------------------------------------------
  169.  */
  170. void
  171. TclpThreadExit(status)
  172.     int status;
  173. {
  174.     pthread_exit((VOID *)status);
  175. }
  176. #endif /* TCL_THREADS */
  177. /*
  178.  *----------------------------------------------------------------------
  179.  *
  180.  * Tcl_GetCurrentThread --
  181.  *
  182.  * This procedure returns the ID of the currently running thread.
  183.  *
  184.  * Results:
  185.  * A thread ID.
  186.  *
  187.  * Side effects:
  188.  * None.
  189.  *
  190.  *----------------------------------------------------------------------
  191.  */
  192. Tcl_ThreadId
  193. Tcl_GetCurrentThread()
  194. {
  195. #ifdef TCL_THREADS
  196.     return (Tcl_ThreadId) pthread_self();
  197. #else
  198.     return (Tcl_ThreadId) 0;
  199. #endif
  200. }
  201. /*
  202.  *----------------------------------------------------------------------
  203.  *
  204.  * TclpInitLock
  205.  *
  206.  * This procedure is used to grab a lock that serializes initialization
  207.  * and finalization of Tcl.  On some platforms this may also initialize
  208.  * the mutex used to serialize creation of more mutexes and thread
  209.  * local storage keys.
  210.  *
  211.  * Results:
  212.  * None.
  213.  *
  214.  * Side effects:
  215.  * Acquire the initialization mutex.
  216.  *
  217.  *----------------------------------------------------------------------
  218.  */
  219. void
  220. TclpInitLock()
  221. {
  222. #ifdef TCL_THREADS
  223.     pthread_mutex_lock(&initLock);
  224. #endif
  225. }
  226. /*
  227.  *----------------------------------------------------------------------
  228.  *
  229.  * TclpFinalizeLock
  230.  *
  231.  * This procedure is used to destroy all private resources used in
  232.  * this file.
  233.  *
  234.  * Results:
  235.  * None.
  236.  *
  237.  * Side effects:
  238.  * Destroys everything private.  TclpInitLock must be held
  239.  * entering this function.
  240.  *
  241.  *----------------------------------------------------------------------
  242.  */
  243. void
  244. TclFinalizeLock ()
  245. {
  246. #ifdef TCL_THREADS
  247.     /*
  248.      * You do not need to destroy mutexes that were created with the
  249.      * PTHREAD_MUTEX_INITIALIZER macro.  These mutexes do not need
  250.      * any destruction: masterLock, allocLock, and initLock.
  251.      */
  252.     pthread_mutex_unlock(&initLock);
  253. #endif
  254. }
  255. /*
  256.  *----------------------------------------------------------------------
  257.  *
  258.  * TclpInitUnlock
  259.  *
  260.  * This procedure is used to release a lock that serializes initialization
  261.  * and finalization of Tcl.
  262.  *
  263.  * Results:
  264.  * None.
  265.  *
  266.  * Side effects:
  267.  * Release the initialization mutex.
  268.  *
  269.  *----------------------------------------------------------------------
  270.  */
  271. void
  272. TclpInitUnlock()
  273. {
  274. #ifdef TCL_THREADS
  275.     pthread_mutex_unlock(&initLock);
  276. #endif
  277. }
  278. /*
  279.  *----------------------------------------------------------------------
  280.  *
  281.  * TclpMasterLock
  282.  *
  283.  * This procedure is used to grab a lock that serializes creation
  284.  * and finalization of serialization objects.  This interface is
  285.  * only needed in finalization; it is hidden during
  286.  * creation of the objects.
  287.  *
  288.  * This lock must be different than the initLock because the
  289.  * initLock is held during creation of syncronization objects.
  290.  *
  291.  * Results:
  292.  * None.
  293.  *
  294.  * Side effects:
  295.  * Acquire the master mutex.
  296.  *
  297.  *----------------------------------------------------------------------
  298.  */
  299. void
  300. TclpMasterLock()
  301. {
  302. #ifdef TCL_THREADS
  303.     pthread_mutex_lock(&masterLock);
  304. #endif
  305. }
  306. /*
  307.  *----------------------------------------------------------------------
  308.  *
  309.  * TclpMasterUnlock
  310.  *
  311.  * This procedure is used to release a lock that serializes creation
  312.  * and finalization of synchronization objects.
  313.  *
  314.  * Results:
  315.  * None.
  316.  *
  317.  * Side effects:
  318.  * Release the master mutex.
  319.  *
  320.  *----------------------------------------------------------------------
  321.  */
  322. void
  323. TclpMasterUnlock()
  324. {
  325. #ifdef TCL_THREADS
  326.     pthread_mutex_unlock(&masterLock);
  327. #endif
  328. }
  329. /*
  330.  *----------------------------------------------------------------------
  331.  *
  332.  * Tcl_GetAllocMutex
  333.  *
  334.  * This procedure returns a pointer to a statically initialized
  335.  * mutex for use by the memory allocator.  The alloctor must
  336.  * use this lock, because all other locks are allocated...
  337.  *
  338.  * Results:
  339.  * A pointer to a mutex that is suitable for passing to
  340.  * Tcl_MutexLock and Tcl_MutexUnlock.
  341.  *
  342.  * Side effects:
  343.  * None.
  344.  *
  345.  *----------------------------------------------------------------------
  346.  */
  347. Tcl_Mutex *
  348. Tcl_GetAllocMutex()
  349. {
  350. #ifdef TCL_THREADS
  351.     return (Tcl_Mutex *)&allocLockPtr;
  352. #else
  353.     return NULL;
  354. #endif
  355. }
  356. #ifdef TCL_THREADS
  357. /*
  358.  *----------------------------------------------------------------------
  359.  *
  360.  * Tcl_MutexLock --
  361.  *
  362.  * This procedure is invoked to lock a mutex.  This procedure
  363.  * handles initializing the mutex, if necessary.  The caller
  364.  * can rely on the fact that Tcl_Mutex is an opaque pointer.
  365.  * This routine will change that pointer from NULL after first use.
  366.  *
  367.  * Results:
  368.  * None.
  369.  *
  370.  * Side effects:
  371.  * May block the current thread.  The mutex is aquired when
  372.  * this returns.  Will allocate memory for a pthread_mutex_t
  373.  * and initialize this the first time this Tcl_Mutex is used.
  374.  *
  375.  *----------------------------------------------------------------------
  376.  */
  377. void
  378. Tcl_MutexLock(mutexPtr)
  379.     Tcl_Mutex *mutexPtr; /* Really (pthread_mutex_t **) */
  380. {
  381.     pthread_mutex_t *pmutexPtr;
  382.     if (*mutexPtr == NULL) {
  383. MASTER_LOCK;
  384. if (*mutexPtr == NULL) {
  385.     /* 
  386.      * Double inside master lock check to avoid a race condition.
  387.      */
  388.     
  389.     pmutexPtr = (pthread_mutex_t *)ckalloc(sizeof(pthread_mutex_t));
  390.     pthread_mutex_init(pmutexPtr, NULL);
  391.     *mutexPtr = (Tcl_Mutex)pmutexPtr;
  392.     TclRememberMutex(mutexPtr);
  393. }
  394. MASTER_UNLOCK;
  395.     }
  396.     pmutexPtr = *((pthread_mutex_t **)mutexPtr);
  397.     pthread_mutex_lock(pmutexPtr);
  398. }
  399. /*
  400.  *----------------------------------------------------------------------
  401.  *
  402.  * Tcl_MutexUnlock --
  403.  *
  404.  * This procedure is invoked to unlock a mutex.  The mutex must
  405.  * have been locked by Tcl_MutexLock.
  406.  *
  407.  * Results:
  408.  * None.
  409.  *
  410.  * Side effects:
  411.  * The mutex is released when this returns.
  412.  *
  413.  *----------------------------------------------------------------------
  414.  */
  415. void
  416. Tcl_MutexUnlock(mutexPtr)
  417.     Tcl_Mutex *mutexPtr; /* Really (pthread_mutex_t **) */
  418. {
  419.     pthread_mutex_t *pmutexPtr = *(pthread_mutex_t **)mutexPtr;
  420.     pthread_mutex_unlock(pmutexPtr);
  421. }
  422. /*
  423.  *----------------------------------------------------------------------
  424.  *
  425.  * TclpFinalizeMutex --
  426.  *
  427.  * This procedure is invoked to clean up one mutex.  This is only
  428.  * safe to call at the end of time.
  429.  *
  430.  * This assumes the Master Lock is held.
  431.  *
  432.  * Results:
  433.  * None.
  434.  *
  435.  * Side effects:
  436.  * The mutex list is deallocated.
  437.  *
  438.  *----------------------------------------------------------------------
  439.  */
  440. void
  441. TclpFinalizeMutex(mutexPtr)
  442.     Tcl_Mutex *mutexPtr;
  443. {
  444.     pthread_mutex_t *pmutexPtr = *(pthread_mutex_t **)mutexPtr;
  445.     if (pmutexPtr != NULL) {
  446.         pthread_mutex_destroy(pmutexPtr);
  447. ckfree((char *)pmutexPtr);
  448. *mutexPtr = NULL;
  449.     }
  450. }
  451. /*
  452.  *----------------------------------------------------------------------
  453.  *
  454.  * TclpThreadDataKeyInit --
  455.  *
  456.  * This procedure initializes a thread specific data block key.
  457.  * Each thread has table of pointers to thread specific data.
  458.  * all threads agree on which table entry is used by each module.
  459.  * this is remembered in a "data key", that is just an index into
  460.  * this table.  To allow self initialization, the interface
  461.  * passes a pointer to this key and the first thread to use
  462.  * the key fills in the pointer to the key.  The key should be
  463.  * a process-wide static.
  464.  *
  465.  * Results:
  466.  * None.
  467.  *
  468.  * Side effects:
  469.  * Will allocate memory the first time this process calls for
  470.  * this key.  In this case it modifies its argument
  471.  * to hold the pointer to information about the key.
  472.  *
  473.  *----------------------------------------------------------------------
  474.  */
  475. void
  476. TclpThreadDataKeyInit(keyPtr)
  477.     Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk,
  478.  * really (pthread_key_t **) */
  479. {
  480.     pthread_key_t *pkeyPtr;
  481.     MASTER_LOCK;
  482.     if (*keyPtr == NULL) {
  483. pkeyPtr = (pthread_key_t *)ckalloc(sizeof(pthread_key_t));
  484. pthread_key_create(pkeyPtr, NULL);
  485. *keyPtr = (Tcl_ThreadDataKey)pkeyPtr;
  486. TclRememberDataKey(keyPtr);
  487.     }
  488.     MASTER_UNLOCK;
  489. }
  490. /*
  491.  *----------------------------------------------------------------------
  492.  *
  493.  * TclpThreadDataKeyGet --
  494.  *
  495.  * This procedure returns a pointer to a block of thread local storage.
  496.  *
  497.  * Results:
  498.  * A thread-specific pointer to the data structure, or NULL
  499.  * if the memory has not been assigned to this key for this thread.
  500.  *
  501.  * Side effects:
  502.  * None.
  503.  *
  504.  *----------------------------------------------------------------------
  505.  */
  506. VOID *
  507. TclpThreadDataKeyGet(keyPtr)
  508.     Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk,
  509.  * really (pthread_key_t **) */
  510. {
  511.     pthread_key_t *pkeyPtr = *(pthread_key_t **)keyPtr;
  512.     if (pkeyPtr == NULL) {
  513. return NULL;
  514.     } else {
  515. return (VOID *)pthread_getspecific(*pkeyPtr);
  516.     }
  517. }
  518. /*
  519.  *----------------------------------------------------------------------
  520.  *
  521.  * TclpThreadDataKeySet --
  522.  *
  523.  * This procedure sets the pointer to a block of thread local storage.
  524.  *
  525.  * Results:
  526.  * None.
  527.  *
  528.  * Side effects:
  529.  * Sets up the thread so future calls to TclpThreadDataKeyGet with
  530.  * this key will return the data pointer.
  531.  *
  532.  *----------------------------------------------------------------------
  533.  */
  534. void
  535. TclpThreadDataKeySet(keyPtr, data)
  536.     Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk,
  537.  * really (pthread_key_t **) */
  538.     VOID *data; /* Thread local storage */
  539. {
  540.     pthread_key_t *pkeyPtr = *(pthread_key_t **)keyPtr;
  541.     pthread_setspecific(*pkeyPtr, data);
  542. }
  543. /*
  544.  *----------------------------------------------------------------------
  545.  *
  546.  * TclpFinalizeThreadData --
  547.  *
  548.  * This procedure cleans up the thread-local storage.  This is
  549.  * called once for each thread.
  550.  *
  551.  * Results:
  552.  * None.
  553.  *
  554.  * Side effects:
  555.  * Frees up all thread local storage.
  556.  *
  557.  *----------------------------------------------------------------------
  558.  */
  559. void
  560. TclpFinalizeThreadData(keyPtr)
  561.     Tcl_ThreadDataKey *keyPtr;
  562. {
  563.     VOID *result;
  564.     pthread_key_t *pkeyPtr;
  565.     if (*keyPtr != NULL) {
  566. pkeyPtr = *(pthread_key_t **)keyPtr;
  567. result = (VOID *)pthread_getspecific(*pkeyPtr);
  568. if (result != NULL) {
  569.     ckfree((char *)result);
  570.     pthread_setspecific(*pkeyPtr, (void *)NULL);
  571. }
  572.     }
  573. }
  574. /*
  575.  *----------------------------------------------------------------------
  576.  *
  577.  * TclpFinalizeThreadDataKey --
  578.  *
  579.  * This procedure is invoked to clean up one key.  This is a
  580.  * process-wide storage identifier.  The thread finalization code
  581.  * cleans up the thread local storage itself.
  582.  *
  583.  * This assumes the master lock is held.
  584.  *
  585.  * Results:
  586.  * None.
  587.  *
  588.  * Side effects:
  589.  * The key is deallocated.
  590.  *
  591.  *----------------------------------------------------------------------
  592.  */
  593. void
  594. TclpFinalizeThreadDataKey(keyPtr)
  595.     Tcl_ThreadDataKey *keyPtr;
  596. {
  597.     pthread_key_t *pkeyPtr;
  598.     if (*keyPtr != NULL) {
  599. pkeyPtr = *(pthread_key_t **)keyPtr;
  600. pthread_key_delete(*pkeyPtr);
  601. ckfree((char *)pkeyPtr);
  602. *keyPtr = NULL;
  603.     }
  604. }
  605. /*
  606.  *----------------------------------------------------------------------
  607.  *
  608.  * Tcl_ConditionWait --
  609.  *
  610.  * This procedure is invoked to wait on a condition variable.
  611.  * The mutex is automically released as part of the wait, and
  612.  * automatically grabbed when the condition is signaled.
  613.  *
  614.  * The mutex must be held when this procedure is called.
  615.  *
  616.  * Results:
  617.  * None.
  618.  *
  619.  * Side effects:
  620.  * May block the current thread.  The mutex is aquired when
  621.  * this returns.  Will allocate memory for a pthread_mutex_t
  622.  * and initialize this the first time this Tcl_Mutex is used.
  623.  *
  624.  *----------------------------------------------------------------------
  625.  */
  626. void
  627. Tcl_ConditionWait(condPtr, mutexPtr, timePtr)
  628.     Tcl_Condition *condPtr; /* Really (pthread_cond_t **) */
  629.     Tcl_Mutex *mutexPtr; /* Really (pthread_mutex_t **) */
  630.     Tcl_Time *timePtr; /* Timeout on waiting period */
  631. {
  632.     pthread_cond_t *pcondPtr;
  633.     pthread_mutex_t *pmutexPtr;
  634.     struct timespec ptime;
  635.     if (*condPtr == NULL) {
  636. MASTER_LOCK;
  637. /* 
  638.  * Double check inside mutex to avoid race,
  639.  * then initialize condition variable if necessary.
  640.  */
  641. if (*condPtr == NULL) {
  642.     pcondPtr = (pthread_cond_t *)ckalloc(sizeof(pthread_cond_t));
  643.     pthread_cond_init(pcondPtr, NULL);
  644.     *condPtr = (Tcl_Condition)pcondPtr;
  645.     TclRememberCondition(condPtr);
  646. }
  647. MASTER_UNLOCK;
  648.     }
  649.     pmutexPtr = *((pthread_mutex_t **)mutexPtr);
  650.     pcondPtr = *((pthread_cond_t **)condPtr);
  651.     if (timePtr == NULL) {
  652. pthread_cond_wait(pcondPtr, pmutexPtr);
  653.     } else {
  654. Tcl_Time now;
  655. /*
  656.  * Make sure to take into account the microsecond component of the
  657.  * current time, including possible overflow situations. [Bug #411603]
  658.  */
  659. Tcl_GetTime(&now);
  660. ptime.tv_sec = timePtr->sec + now.sec +
  661.     (timePtr->usec + now.usec) / 1000000;
  662. ptime.tv_nsec = 1000 * ((timePtr->usec + now.usec) % 1000000);
  663. pthread_cond_timedwait(pcondPtr, pmutexPtr, &ptime);
  664.     }
  665. }
  666. /*
  667.  *----------------------------------------------------------------------
  668.  *
  669.  * Tcl_ConditionNotify --
  670.  *
  671.  * This procedure is invoked to signal a condition variable.
  672.  *
  673.  * The mutex must be held during this call to avoid races,
  674.  * but this interface does not enforce that.
  675.  *
  676.  * Results:
  677.  * None.
  678.  *
  679.  * Side effects:
  680.  * May unblock another thread.
  681.  *
  682.  *----------------------------------------------------------------------
  683.  */
  684. void
  685. Tcl_ConditionNotify(condPtr)
  686.     Tcl_Condition *condPtr;
  687. {
  688.     pthread_cond_t *pcondPtr = *((pthread_cond_t **)condPtr);
  689.     if (pcondPtr != NULL) {
  690. pthread_cond_broadcast(pcondPtr);
  691.     } else {
  692. /*
  693.  * Noone has used the condition variable, so there are no waiters.
  694.  */
  695.     }
  696. }
  697. /*
  698.  *----------------------------------------------------------------------
  699.  *
  700.  * TclpFinalizeCondition --
  701.  *
  702.  * This procedure is invoked to clean up a condition variable.
  703.  * This is only safe to call at the end of time.
  704.  *
  705.  * This assumes the Master Lock is held.
  706.  *
  707.  * Results:
  708.  * None.
  709.  *
  710.  * Side effects:
  711.  * The condition variable is deallocated.
  712.  *
  713.  *----------------------------------------------------------------------
  714.  */
  715. void
  716. TclpFinalizeCondition(condPtr)
  717.     Tcl_Condition *condPtr;
  718. {
  719.     pthread_cond_t *pcondPtr = *(pthread_cond_t **)condPtr;
  720.     if (pcondPtr != NULL) {
  721. pthread_cond_destroy(pcondPtr);
  722. ckfree((char *)pcondPtr);
  723. *condPtr = NULL;
  724.     }
  725. }
  726. #endif /* TCL_THREADS */
  727. /*
  728.  *----------------------------------------------------------------------
  729.  *
  730.  * TclpReaddir, TclpLocaltime, TclpGmtime, TclpInetNtoa --
  731.  *
  732.  * These procedures replace core C versions to be used in a
  733.  * threaded environment.
  734.  *
  735.  * Results:
  736.  * See documentation of C functions.
  737.  *
  738.  * Side effects:
  739.  * See documentation of C functions.
  740.  *
  741.  * Notes:
  742.  *  TclpReaddir is no longer used by the core (see 1095909),
  743.  *  but it appears in the internal stubs table (see #589526).
  744.  *----------------------------------------------------------------------
  745.  */
  746. Tcl_DirEntry *
  747. TclpReaddir(DIR * dir)
  748. {
  749.     return TclOSreaddir(dir);
  750. }
  751. char *
  752. TclpInetNtoa(struct in_addr addr)
  753. {
  754. #ifdef TCL_THREADS
  755.     ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
  756.     unsigned char *b = (unsigned char*) &addr.s_addr;
  757.     sprintf(tsdPtr->nabuf, "%u.%u.%u.%u", b[0], b[1], b[2], b[3]);
  758.     return tsdPtr->nabuf;
  759. #else
  760.     return inet_ntoa(addr);
  761. #endif
  762. }
  763. #if defined(TCL_THREADS) && defined(USE_THREAD_ALLOC) && !defined(TCL_MEM_DEBUG)
  764. /*
  765.  * Additions by AOL for specialized thread memory allocator.
  766.  */
  767. #ifdef USE_THREAD_ALLOC
  768. static volatile int initialized = 0;
  769. static pthread_key_t key;
  770. typedef struct allocMutex {
  771.     Tcl_Mutex       tlock;
  772.     pthread_mutex_t plock;
  773. } allocMutex;
  774. Tcl_Mutex *
  775. TclpNewAllocMutex(void)
  776. {
  777.     struct allocMutex *lockPtr;
  778.     lockPtr = malloc(sizeof(struct allocMutex));
  779.     if (lockPtr == NULL) {
  780. panic("could not allocate lock");
  781.     }
  782.     lockPtr->tlock = (Tcl_Mutex) &lockPtr->plock;
  783.     pthread_mutex_init(&lockPtr->plock, NULL);
  784.     return &lockPtr->tlock;
  785. }
  786. void
  787. TclpFreeAllocMutex(mutex)
  788.     Tcl_Mutex *mutex; /* The alloc mutex to free. */
  789. {
  790.     allocMutex* lockPtr = (allocMutex*) mutex;
  791.     if (!lockPtr) return;
  792.     pthread_mutex_destroy(&lockPtr->plock);
  793.     free(lockPtr);
  794. }
  795. void TclpFreeAllocCache(ptr)
  796.     void *ptr;
  797. {
  798.     if (ptr != NULL) {
  799.         /*
  800.          * Called by the pthread lib when a thread exits
  801.          */
  802.         TclFreeAllocCache(ptr);
  803.     } else if (initialized) {
  804.         /*
  805.          * Called by us in TclFinalizeThreadAlloc() during
  806.          * the library finalization initiated from Tcl_Finalize()
  807.          */
  808.         pthread_key_delete(key);
  809.         initialized = 0;
  810.     }
  811. }
  812. void *
  813. TclpGetAllocCache(void)
  814. {
  815.     if (!initialized) {
  816. pthread_mutex_lock(allocLockPtr);
  817. if (!initialized) {
  818.     pthread_key_create(&key, TclpFreeAllocCache);
  819.     initialized = 1;
  820. }
  821. pthread_mutex_unlock(allocLockPtr);
  822.     }
  823.     return pthread_getspecific(key);
  824. }
  825. void
  826. TclpSetAllocCache(void *arg)
  827. {
  828.     pthread_setspecific(key, arg);
  829. }
  830. #endif /* USE_THREAD_ALLOC */
  831. #endif /* TCL_THREADS */