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

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * tclMacThrd.c --
  3.  *
  4.  * This file implements the Mac-specific thread support.
  5.  *
  6.  * Copyright (c) 1991-1994 The Regents of the University of California.
  7.  * Copyright (c) 1994-1998 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:  @(#) tclMacThrd.c 1.2 98/02/23 16:48:07
  13.  */
  14. #include "tclInt.h"
  15. #include "tclPort.h"
  16. #include "tclMacInt.h"
  17. #include <Threads.h>
  18. #include <Gestalt.h>
  19. #define TCL_MAC_THRD_DEFAULT_STACK (256*1024)
  20. typedef struct TclMacThrdData {
  21.     ThreadID threadID;
  22.     VOID *data;
  23.     struct TclMacThrdData *next;
  24. } TclMacThrdData;
  25. /*
  26.  * This is an array of the Thread Data Keys.  It is a process-wide table.
  27.  * Its size is originally set to 32, but it can grow if needed.
  28.  */
  29.  
  30. static TclMacThrdData **tclMacDataKeyArray;
  31. #define TCL_MAC_INITIAL_KEYSIZE 32
  32. /*
  33.  * These two bits of data store the current maximum number of keys
  34.  * and the keyCounter (which is the number of occupied slots in the
  35.  * KeyData array.
  36.  * 
  37.  */
  38.  
  39. static int maxNumKeys = 0;
  40. static int keyCounter = 0;
  41. /*
  42.  * Prototypes for functions used only in this file
  43.  */
  44.  
  45. TclMacThrdData *GetThreadDataStruct(Tcl_ThreadDataKey keyVal);
  46. TclMacThrdData *RemoveThreadDataStruct(Tcl_ThreadDataKey keyVal);
  47. /*
  48.  * Note: The race evoked by the emulation layer for joinable threads
  49.  * (see ../win/tclWinThrd.c) cannot occur on this platform due to
  50.  * the cooperative implementation of multithreading.
  51.  */
  52. /*
  53.  *----------------------------------------------------------------------
  54.  *
  55.  * TclMacHaveThreads --
  56.  *
  57.  * Do we have the Thread Manager?
  58.  *
  59.  * Results:
  60.  * 1 if the ThreadManager is present, 0 otherwise.
  61.  *
  62.  * Side effects:
  63.  * If this is the first time this is called, the return is cached.
  64.  *
  65.  *----------------------------------------------------------------------
  66.  */
  67. int
  68. TclMacHaveThreads(void)
  69. {
  70.     static initialized = false;
  71.     static int tclMacHaveThreads = false;
  72.     long response = 0;
  73.     OSErr err = noErr;
  74.     
  75.     if (!initialized) {
  76. err = Gestalt(gestaltThreadMgrAttr, &response);
  77. if (err == noErr) {
  78.     tclMacHaveThreads = response | (1 << gestaltThreadMgrPresent);
  79. }
  80.     }
  81.     return tclMacHaveThreads;
  82. }
  83. /*
  84.  *----------------------------------------------------------------------
  85.  *
  86.  * Tcl_CreateThread --
  87.  *
  88.  * This procedure creates a new thread.
  89.  *
  90.  * Results:
  91.  * TCL_OK if the thread could be created.  The thread ID is
  92.  * returned in a parameter.
  93.  *
  94.  * Side effects:
  95.  * A new thread is created.
  96.  *
  97.  *----------------------------------------------------------------------
  98.  */
  99. int
  100. Tcl_CreateThread(idPtr, proc, clientData, stackSize, flags)
  101.     Tcl_ThreadId *idPtr; /* Return, the ID of the thread */
  102.     Tcl_ThreadCreateProc proc; /* Main() function of the thread */
  103.     ClientData clientData; /* The one argument to Main() */
  104.     int stackSize; /* Size of stack for the new thread */
  105.     int flags; /* Flags controlling behaviour of
  106.  * the new thread */
  107. {
  108.     if (!TclMacHaveThreads()) {
  109.         return TCL_ERROR;
  110.     }
  111.     if (stackSize == TCL_THREAD_STACK_DEFAULT) {
  112.         stackSize = TCL_MAC_THRD_DEFAULT_STACK;
  113.     }
  114. #if TARGET_CPU_68K && TARGET_RT_MAC_CFM
  115.     {
  116.         ThreadEntryProcPtr entryProc;
  117.         entryProc = NewThreadEntryUPP(proc);
  118.         
  119.         NewThread(kCooperativeThread, entryProc, (void *) clientData, 
  120.             stackSize, kCreateIfNeeded, NULL, (ThreadID *) idPtr);
  121.     }
  122. #else
  123.     NewThread(kCooperativeThread, proc, (void *) clientData, 
  124.         stackSize, kCreateIfNeeded, NULL, (ThreadID *) idPtr);
  125. #endif        
  126.     if ((ThreadID) *idPtr == kNoThreadID) {
  127.         return TCL_ERROR;
  128.     } else {
  129.         if (flags & TCL_THREAD_JOINABLE) {
  130.     TclRememberJoinableThread (*idPtr);
  131. }
  132.         return TCL_OK;
  133.     }
  134. }
  135. /*
  136.  *----------------------------------------------------------------------
  137.  *
  138.  * Tcl_JoinThread --
  139.  *
  140.  * This procedure waits upon the exit of the specified thread.
  141.  *
  142.  * Results:
  143.  * TCL_OK if the wait was successful, TCL_ERROR else.
  144.  *
  145.  * Side effects:
  146.  * The result area is set to the exit code of the thread we
  147.  * waited upon.
  148.  *
  149.  *----------------------------------------------------------------------
  150.  */
  151. int
  152. Tcl_JoinThread(threadId, result)
  153.     Tcl_ThreadId threadId; /* Id of the thread to wait upon */
  154.     int*     result;    /* Reference to the storage the result
  155.     * of the thread we wait upon will be
  156.     * written into. */
  157. {
  158.     if (!TclMacHaveThreads()) {
  159.         return TCL_ERROR;
  160.     }
  161.     return TclJoinThread (threadId, result);
  162. }
  163. /*
  164.  *----------------------------------------------------------------------
  165.  *
  166.  * TclpThreadExit --
  167.  *
  168.  * This procedure terminates the current thread.
  169.  *
  170.  * Results:
  171.  * None.
  172.  *
  173.  * Side effects:
  174.  * This procedure terminates the current thread.
  175.  *
  176.  *----------------------------------------------------------------------
  177.  */
  178. void
  179. TclpThreadExit(status)
  180.     int status;
  181. {
  182.     ThreadID curThread;
  183.     
  184.     if (!TclMacHaveThreads()) {
  185.         return;
  186.     }
  187.     
  188.     GetCurrentThread(&curThread);
  189.     TclSignalExitThread ((Tcl_ThreadId) curThread, status);
  190.     DisposeThread(curThread, NULL, false);
  191. }
  192. /*
  193.  *----------------------------------------------------------------------
  194.  *
  195.  * Tcl_GetCurrentThread --
  196.  *
  197.  * This procedure returns the ID of the currently running thread.
  198.  *
  199.  * Results:
  200.  * A thread ID.
  201.  *
  202.  * Side effects:
  203.  * None.
  204.  *
  205.  *----------------------------------------------------------------------
  206.  */
  207. Tcl_ThreadId
  208. Tcl_GetCurrentThread()
  209. {
  210. #ifdef TCL_THREADS
  211.     ThreadID curThread;
  212.     if (!TclMacHaveThreads()) {
  213.         return (Tcl_ThreadId) 0;
  214.     } else {
  215.         GetCurrentThread(&curThread);
  216.         return (Tcl_ThreadId) curThread;
  217.     }
  218. #else
  219.     return (Tcl_ThreadId) 0;
  220. #endif
  221. }
  222. /*
  223.  *----------------------------------------------------------------------
  224.  *
  225.  * TclpInitLock
  226.  *
  227.  * This procedure is used to grab a lock that serializes initialization
  228.  * and finalization of Tcl.  On some platforms this may also initialize
  229.  * the mutex used to serialize creation of more mutexes and thread
  230.  * local storage keys.
  231.  *
  232.  * Results:
  233.  * None.
  234.  *
  235.  * Side effects:
  236.  * Acquire the initialization mutex.
  237.  *
  238.  *----------------------------------------------------------------------
  239.  */
  240. void
  241. TclpInitLock()
  242. {
  243. #ifdef TCL_THREADS
  244.     /* There is nothing to do on the Mac. */;
  245. #endif
  246. }
  247. /*
  248.  *----------------------------------------------------------------------
  249.  *
  250.  * TclpInitUnlock
  251.  *
  252.  * This procedure is used to release a lock that serializes initialization
  253.  * and finalization of Tcl.
  254.  *
  255.  * Results:
  256.  * None.
  257.  *
  258.  * Side effects:
  259.  * Release the initialization mutex.
  260.  *
  261.  *----------------------------------------------------------------------
  262.  */
  263. void
  264. TclpInitUnlock()
  265. {
  266. #ifdef TCL_THREADS
  267.     /* There is nothing to do on the Mac */;
  268. #endif
  269. }
  270. /*
  271.  *----------------------------------------------------------------------
  272.  *
  273.  * TclpMasterLock
  274.  *
  275.  * This procedure is used to grab a lock that serializes creation
  276.  * and finalization of serialization objects.  This interface is
  277.  * only needed in finalization; it is hidden during
  278.  * creation of the objects.
  279.  *
  280.  * This lock must be different than the initLock because the
  281.  * initLock is held during creation of syncronization objects.
  282.  *
  283.  * Results:
  284.  * None.
  285.  *
  286.  * Side effects:
  287.  * Acquire the master mutex.
  288.  *
  289.  *----------------------------------------------------------------------
  290.  */
  291. void
  292. TclpMasterLock()
  293. {
  294. #ifdef TCL_THREADS
  295.     /* There is nothing to do on the Mac */;
  296. #endif
  297. }
  298. /*
  299.  *----------------------------------------------------------------------
  300.  *
  301.  * TclpMasterUnlock
  302.  *
  303.  * This procedure is used to release a lock that serializes creation
  304.  * and finalization of synchronization objects.
  305.  *
  306.  * Results:
  307.  * None.
  308.  *
  309.  * Side effects:
  310.  * Release the master mutex.
  311.  *
  312.  *----------------------------------------------------------------------
  313.  */
  314. void
  315. TclpMasterUnlock()
  316. {
  317. #ifdef TCL_THREADS
  318.     /* There is nothing to do on the Mac */
  319. #endif
  320. }
  321. /*
  322.  *----------------------------------------------------------------------
  323.  *
  324.  * Tcl_GetAllocMutex
  325.  *
  326.  * This procedure returns a pointer to a statically initialized
  327.  * mutex for use by the memory allocator.  The alloctor must
  328.  * use this lock, because all other locks are allocated...
  329.  *
  330.  * Results:
  331.  * A pointer to a mutex that is suitable for passing to
  332.  * Tcl_MutexLock and Tcl_MutexUnlock.
  333.  *
  334.  * Side effects:
  335.  * None.
  336.  *
  337.  *----------------------------------------------------------------------
  338.  */
  339. Tcl_Mutex *
  340. Tcl_GetAllocMutex()
  341. {
  342.     /* There is nothing to do on the Mac */
  343.     return NULL;
  344. }
  345. #ifdef TCL_THREADS
  346. /*
  347.  *----------------------------------------------------------------------
  348.  *
  349.  * Tcl_MutexLock --
  350.  *
  351.  * This procedure is invoked to lock a mutex.  This procedure
  352.  * handles initializing the mutex, if necessary.  The caller
  353.  * can rely on the fact that Tcl_Mutex is an opaque pointer.
  354.  * This routine will change that pointer from NULL after first use.
  355.  *
  356.  * Results:
  357.  * None.
  358.  *
  359.  * Side effects:
  360.  * May block the current thread.  The mutex is aquired when
  361.  * this returns.  Will allocate memory for a pthread_mutex_t
  362.  * and initialize this the first time this Tcl_Mutex is used.
  363.  *
  364.  *----------------------------------------------------------------------
  365.  */
  366. void
  367. Tcl_MutexLock(mutexPtr)
  368.     Tcl_Mutex *mutexPtr; /* Really (pthread_mutex_t **) */
  369. {
  370. /* There is nothing to do on the Mac */
  371. }
  372. /*
  373.  *----------------------------------------------------------------------
  374.  *
  375.  * TclpMutexUnlock --
  376.  *
  377.  * This procedure is invoked to unlock a mutex.  The mutex must
  378.  * have been locked by Tcl_MutexLock.
  379.  *
  380.  * Results:
  381.  * None.
  382.  *
  383.  * Side effects:
  384.  * The mutex is released when this returns.
  385.  *
  386.  *----------------------------------------------------------------------
  387.  */
  388. void
  389. Tcl_MutexUnlock(mutexPtr)
  390.     Tcl_Mutex *mutexPtr; /* Really (pthread_mutex_t **) */
  391. {
  392. /* There is nothing to do on the Mac */
  393. }
  394. /*
  395.  *----------------------------------------------------------------------
  396.  *
  397.  * TclpFinalizeMutex --
  398.  *
  399.  * This procedure is invoked to clean up one mutex.  This is only
  400.  * safe to call at the end of time.
  401.  *
  402.  * This assumes the Master Lock is held.
  403.  *
  404.  * Results:
  405.  * None.
  406.  *
  407.  * Side effects:
  408.  * The mutex list is deallocated.
  409.  *
  410.  *----------------------------------------------------------------------
  411.  */
  412. void
  413. TclpFinalizeMutex(mutexPtr)
  414.     Tcl_Mutex *mutexPtr;
  415. {
  416. /* There is nothing to do on the Mac */
  417. }
  418. /*
  419.  *----------------------------------------------------------------------
  420.  *
  421.  * TclpThreadDataKeyInit --
  422.  *
  423.  * This procedure initializes a thread specific data block key.
  424.  * Each thread has table of pointers to thread specific data.
  425.  * all threads agree on which table entry is used by each module.
  426.  * this is remembered in a "data key", that is just an index into
  427.  * this table.  To allow self initialization, the interface
  428.  * passes a pointer to this key and the first thread to use
  429.  * the key fills in the pointer to the key.  The key should be
  430.  * a process-wide static.
  431.  *
  432.  *      There is no system-wide support for thread specific data on the 
  433.  * Mac.  So we implement this as an array of pointers.  The keys are
  434.  * allocated sequentially, and each key maps to a slot in the table.
  435.  *      The table element points to a linked list of the instances of
  436.  * the data for each thread.
  437.  *
  438.  * Results:
  439.  * None.
  440.  *
  441.  * Side effects:
  442.  * Will bump the key counter if this is the first time this key
  443.  *      has been initialized.  May grow the DataKeyArray if that is
  444.  * necessary.
  445.  *
  446.  *----------------------------------------------------------------------
  447.  */
  448. void
  449. TclpThreadDataKeyInit(keyPtr)
  450.     Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk,
  451.  * really (pthread_key_t **) */
  452. {
  453.             
  454.     if (*keyPtr == NULL) {
  455.         keyCounter += 1;
  456. *keyPtr = (Tcl_ThreadDataKey) keyCounter;
  457. if (keyCounter > maxNumKeys) {
  458.     TclMacThrdData **newArray;
  459.     int i, oldMax = maxNumKeys;
  460.      
  461.     maxNumKeys = maxNumKeys + TCL_MAC_INITIAL_KEYSIZE;
  462.      
  463.     newArray = (TclMacThrdData **) 
  464.             ckalloc(maxNumKeys * sizeof(TclMacThrdData *));
  465.      
  466.     for (i = 0; i < oldMax; i++) {
  467.         newArray[i] = tclMacDataKeyArray[i];
  468.     }
  469.     for (i = oldMax; i < maxNumKeys; i++) {
  470.         newArray[i] = NULL;
  471.     }
  472.      
  473.     if (tclMacDataKeyArray != NULL) {
  474. ckfree((char *) tclMacDataKeyArray);
  475.     }
  476.     tclMacDataKeyArray = newArray;
  477.      
  478. }             
  479. /* TclRememberDataKey(keyPtr); */
  480.     }
  481. }
  482. /*
  483.  *----------------------------------------------------------------------
  484.  *
  485.  * TclpThreadDataKeyGet --
  486.  *
  487.  * This procedure returns a pointer to a block of thread local storage.
  488.  *
  489.  * Results:
  490.  * A thread-specific pointer to the data structure, or NULL
  491.  * if the memory has not been assigned to this key for this thread.
  492.  *
  493.  * Side effects:
  494.  * None.
  495.  *
  496.  *----------------------------------------------------------------------
  497.  */
  498. VOID *
  499. TclpThreadDataKeyGet(keyPtr)
  500.     Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk,
  501.  * really (pthread_key_t **) */
  502. {
  503.     TclMacThrdData *dataPtr;
  504.     
  505.     dataPtr = GetThreadDataStruct(*keyPtr);
  506.     
  507.     if (dataPtr == NULL) {
  508.         return NULL;
  509.     } else {
  510.         return dataPtr->data;
  511.     }
  512. }
  513. /*
  514.  *----------------------------------------------------------------------
  515.  *
  516.  * TclpThreadDataKeySet --
  517.  *
  518.  * This procedure sets the pointer to a block of thread local storage.
  519.  *
  520.  * Results:
  521.  * None.
  522.  *
  523.  * Side effects:
  524.  * Sets up the thread so future calls to TclpThreadDataKeyGet with
  525.  * this key will return the data pointer.
  526.  *
  527.  *----------------------------------------------------------------------
  528.  */
  529. void
  530. TclpThreadDataKeySet(keyPtr, data)
  531.     Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk,
  532.  * really (pthread_key_t **) */
  533.     VOID *data; /* Thread local storage */
  534. {
  535.     TclMacThrdData *dataPtr;
  536.     ThreadID curThread;
  537.     
  538.     dataPtr = GetThreadDataStruct(*keyPtr);
  539.     
  540.     /* 
  541.      * Is it legal to reset the thread data like this?
  542.      * And if so, who owns the memory?
  543.      */
  544.      
  545.     if (dataPtr != NULL) {
  546.         dataPtr->data = data;
  547.     } else {
  548.         dataPtr = (TclMacThrdData *) ckalloc(sizeof(TclMacThrdData));
  549.         GetCurrentThread(&curThread);
  550.         dataPtr->threadID = curThread;
  551.         dataPtr->data = data;
  552.         dataPtr->next = tclMacDataKeyArray[(int) *keyPtr - 1];
  553.         tclMacDataKeyArray[(int) *keyPtr - 1] = dataPtr;
  554.    }
  555. }
  556. /*
  557.  *----------------------------------------------------------------------
  558.  *
  559.  * TclpFinalizeThreadData --
  560.  *
  561.  * This procedure cleans up the thread-local storage.  This is
  562.  * called once for each thread.
  563.  *
  564.  * Results:
  565.  * None.
  566.  *
  567.  * Side effects:
  568.  * Frees up all thread local storage.
  569.  *
  570.  *----------------------------------------------------------------------
  571.  */
  572. void
  573. TclpFinalizeThreadData(keyPtr)
  574.     Tcl_ThreadDataKey *keyPtr;
  575. {
  576.     TclMacThrdData *dataPtr;
  577.     
  578.     if (*keyPtr != NULL) {
  579.         dataPtr = RemoveThreadDataStruct(*keyPtr);
  580.         
  581. if ((dataPtr != NULL) && (dataPtr->data != NULL)) {
  582.     ckfree((char *) dataPtr->data);
  583.     ckfree((char *) dataPtr);
  584. }
  585.     }
  586. }
  587. /*
  588.  *----------------------------------------------------------------------
  589.  *
  590.  * TclpFinalizeThreadDataKey --
  591.  *
  592.  * This procedure is invoked to clean up one key.  This is a
  593.  * process-wide storage identifier.  The thread finalization code
  594.  * cleans up the thread local storage itself.
  595.  *
  596.  *      On the Mac, there is really nothing to do here, since the key
  597.  *      is just an array index.  But we set the key to 0 just in case
  598.  * someone else is relying on that.
  599.  *
  600.  * Results:
  601.  * None.
  602.  *
  603.  * Side effects:
  604.  * The keyPtr value is set to 0.
  605.  *
  606.  *----------------------------------------------------------------------
  607.  */
  608. void
  609. TclpFinalizeThreadDataKey(keyPtr)
  610.     Tcl_ThreadDataKey *keyPtr;
  611. {
  612.     ckfree((char *) tclMacDataKeyArray[(int) *keyPtr - 1]);
  613.     tclMacDataKeyArray[(int) *keyPtr - 1] = NULL;
  614.     *keyPtr = NULL;
  615. }
  616. /*
  617.  *----------------------------------------------------------------------
  618.  *
  619.  * GetThreadDataStruct --
  620.  *
  621.  * This procedure gets the data structure corresponding to
  622.  *      keyVal for the current process.
  623.  *
  624.  * Results:
  625.  * The requested key data.
  626.  *
  627.  * Side effects:
  628.  * None.
  629.  *
  630.  *----------------------------------------------------------------------
  631.  */
  632. TclMacThrdData *
  633. GetThreadDataStruct(keyVal)
  634.     Tcl_ThreadDataKey keyVal;
  635. {
  636.     ThreadID curThread;
  637.     TclMacThrdData *dataPtr;
  638.     
  639.     /*
  640.      * The keyPtr will only be greater than keyCounter is someone
  641.      * has passed us a key without getting the value from 
  642.      * TclpInitDataKey.
  643.      */
  644.      
  645.     if ((int) keyVal <= 0)  {
  646.         return NULL;
  647.     } else if ((int) keyVal > keyCounter) {
  648.         panic("illegal data key value");
  649.     }
  650.     
  651.     GetCurrentThread(&curThread);
  652.     
  653.     for (dataPtr = tclMacDataKeyArray[(int) keyVal - 1]; dataPtr != NULL;
  654.             dataPtr = dataPtr->next) {
  655.         if (dataPtr->threadID ==  curThread) {
  656.             break;
  657.         }
  658.     }
  659.     
  660.     return dataPtr;
  661. }
  662. /*
  663.  *----------------------------------------------------------------------
  664.  *
  665.  * RemoveThreadDataStruct --
  666.  *
  667.  * This procedure removes the data structure corresponding to
  668.  *      keyVal for the current process from the list kept for keyVal.
  669.  *
  670.  * Results:
  671.  * The requested key data is removed from the list, and a pointer 
  672.  *      to it is returned.
  673.  *
  674.  * Side effects:
  675.  * None.
  676.  *
  677.  *----------------------------------------------------------------------
  678.  */
  679. TclMacThrdData *
  680. RemoveThreadDataStruct(keyVal)
  681.     Tcl_ThreadDataKey keyVal;
  682. {
  683.     ThreadID curThread;
  684.     TclMacThrdData *dataPtr, *prevPtr;
  685.     
  686.      
  687.     if ((int) keyVal <= 0)  {
  688.         return NULL;
  689.     } else if ((int) keyVal > keyCounter) {
  690.         panic("illegal data key value");
  691.     }
  692.     
  693.     GetCurrentThread(&curThread);
  694.     
  695.     for (dataPtr = tclMacDataKeyArray[(int) keyVal - 1], prevPtr = NULL; 
  696.             dataPtr != NULL;
  697.             prevPtr = dataPtr, dataPtr = dataPtr->next) {
  698.         if (dataPtr->threadID == curThread) {
  699.             break;
  700.         }
  701.     }
  702.     
  703.     if (dataPtr == NULL) {
  704.         /* No body */
  705.     } else if ( prevPtr == NULL) {
  706.         tclMacDataKeyArray[(int) keyVal - 1] = dataPtr->next;
  707.     } else {
  708.         prevPtr->next = dataPtr->next;
  709.     }
  710.     
  711.     return dataPtr; 
  712. }
  713. /*
  714.  *----------------------------------------------------------------------
  715.  *
  716.  * Tcl_ConditionWait --
  717.  *
  718.  * This procedure is invoked to wait on a condition variable.
  719.  * On the Mac, mutexes are no-ops, and we just yield.  After
  720.  * all, it is the application's job to loop till the condition 
  721.  * variable is changed...
  722.  *
  723.  *
  724.  * Results:
  725.  * None.
  726.  *
  727.  * Side effects:
  728.  * Will block the current thread till someone else yields.
  729.  *
  730.  *----------------------------------------------------------------------
  731.  */
  732. void
  733. Tcl_ConditionWait(condPtr, mutexPtr, timePtr)
  734.     Tcl_Condition *condPtr; /* Really (pthread_cond_t **) */
  735.     Tcl_Mutex *mutexPtr; /* Really (pthread_mutex_t **) */
  736.     Tcl_Time *timePtr; /* Timeout on waiting period */
  737. {
  738.     if (TclMacHaveThreads()) {
  739.         YieldToAnyThread();
  740.     }
  741. }
  742. /*
  743.  *----------------------------------------------------------------------
  744.  *
  745.  * Tcl_ConditionNotify --
  746.  *
  747.  * This procedure is invoked to signal a condition variable.
  748.  *
  749.  * The mutex must be held during this call to avoid races,
  750.  * but this interface does not enforce that.
  751.  *
  752.  * Results:
  753.  * None.
  754.  *
  755.  * Side effects:
  756.  * May unblock another thread.
  757.  *
  758.  *----------------------------------------------------------------------
  759.  */
  760. void
  761. Tcl_ConditionNotify(condPtr)
  762.     Tcl_Condition *condPtr;
  763. {
  764.     if (TclMacHaveThreads()) {
  765.          YieldToAnyThread();
  766.     }
  767. }
  768. /*
  769.  *----------------------------------------------------------------------
  770.  *
  771.  * TclpFinalizeCondition --
  772.  *
  773.  * This procedure is invoked to clean up a condition variable.
  774.  * This is only safe to call at the end of time.
  775.  *
  776.  * This assumes the Master Lock is held.
  777.  *
  778.  * Results:
  779.  * None.
  780.  *
  781.  * Side effects:
  782.  * The condition variable is deallocated.
  783.  *
  784.  *----------------------------------------------------------------------
  785.  */
  786. void
  787. TclpFinalizeCondition(condPtr)
  788.     Tcl_Condition *condPtr;
  789. {
  790.     /* Nothing to do on the Mac */
  791. }
  792. #endif /* TCL_THREADS */