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