os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/mac/tclMacThrd.c
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/mac/tclMacThrd.c Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,871 @@
1.4 +/*
1.5 + * tclMacThrd.c --
1.6 + *
1.7 + * This file implements the Mac-specific thread support.
1.8 + *
1.9 + * Copyright (c) 1991-1994 The Regents of the University of California.
1.10 + * Copyright (c) 1994-1998 Sun Microsystems, Inc.
1.11 + *
1.12 + * See the file "license.terms" for information on usage and redistribution
1.13 + * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
1.14 + *
1.15 + * SCCS: @(#) tclMacThrd.c 1.2 98/02/23 16:48:07
1.16 + */
1.17 +
1.18 +#include "tclInt.h"
1.19 +#include "tclPort.h"
1.20 +#include "tclMacInt.h"
1.21 +#include <Threads.h>
1.22 +#include <Gestalt.h>
1.23 +
1.24 +#define TCL_MAC_THRD_DEFAULT_STACK (256*1024)
1.25 +
1.26 +
1.27 +typedef struct TclMacThrdData {
1.28 + ThreadID threadID;
1.29 + VOID *data;
1.30 + struct TclMacThrdData *next;
1.31 +} TclMacThrdData;
1.32 +
1.33 +/*
1.34 + * This is an array of the Thread Data Keys. It is a process-wide table.
1.35 + * Its size is originally set to 32, but it can grow if needed.
1.36 + */
1.37 +
1.38 +static TclMacThrdData **tclMacDataKeyArray;
1.39 +#define TCL_MAC_INITIAL_KEYSIZE 32
1.40 +
1.41 +/*
1.42 + * These two bits of data store the current maximum number of keys
1.43 + * and the keyCounter (which is the number of occupied slots in the
1.44 + * KeyData array.
1.45 + *
1.46 + */
1.47 +
1.48 +static int maxNumKeys = 0;
1.49 +static int keyCounter = 0;
1.50 +
1.51 +/*
1.52 + * Prototypes for functions used only in this file
1.53 + */
1.54 +
1.55 +TclMacThrdData *GetThreadDataStruct(Tcl_ThreadDataKey keyVal);
1.56 +TclMacThrdData *RemoveThreadDataStruct(Tcl_ThreadDataKey keyVal);
1.57 +
1.58 +/*
1.59 + * Note: The race evoked by the emulation layer for joinable threads
1.60 + * (see ../win/tclWinThrd.c) cannot occur on this platform due to
1.61 + * the cooperative implementation of multithreading.
1.62 + */
1.63 +
1.64 +/*
1.65 + *----------------------------------------------------------------------
1.66 + *
1.67 + * TclMacHaveThreads --
1.68 + *
1.69 + * Do we have the Thread Manager?
1.70 + *
1.71 + * Results:
1.72 + * 1 if the ThreadManager is present, 0 otherwise.
1.73 + *
1.74 + * Side effects:
1.75 + * If this is the first time this is called, the return is cached.
1.76 + *
1.77 + *----------------------------------------------------------------------
1.78 + */
1.79 +
1.80 +int
1.81 +TclMacHaveThreads(void)
1.82 +{
1.83 + static initialized = false;
1.84 + static int tclMacHaveThreads = false;
1.85 + long response = 0;
1.86 + OSErr err = noErr;
1.87 +
1.88 + if (!initialized) {
1.89 + err = Gestalt(gestaltThreadMgrAttr, &response);
1.90 + if (err == noErr) {
1.91 + tclMacHaveThreads = response | (1 << gestaltThreadMgrPresent);
1.92 + }
1.93 + }
1.94 +
1.95 + return tclMacHaveThreads;
1.96 +}
1.97 +
1.98 +/*
1.99 + *----------------------------------------------------------------------
1.100 + *
1.101 + * Tcl_CreateThread --
1.102 + *
1.103 + * This procedure creates a new thread.
1.104 + *
1.105 + * Results:
1.106 + * TCL_OK if the thread could be created. The thread ID is
1.107 + * returned in a parameter.
1.108 + *
1.109 + * Side effects:
1.110 + * A new thread is created.
1.111 + *
1.112 + *----------------------------------------------------------------------
1.113 + */
1.114 +
1.115 +int
1.116 +Tcl_CreateThread(idPtr, proc, clientData, stackSize, flags)
1.117 + Tcl_ThreadId *idPtr; /* Return, the ID of the thread */
1.118 + Tcl_ThreadCreateProc proc; /* Main() function of the thread */
1.119 + ClientData clientData; /* The one argument to Main() */
1.120 + int stackSize; /* Size of stack for the new thread */
1.121 + int flags; /* Flags controlling behaviour of
1.122 + * the new thread */
1.123 +{
1.124 + if (!TclMacHaveThreads()) {
1.125 + return TCL_ERROR;
1.126 + }
1.127 +
1.128 + if (stackSize == TCL_THREAD_STACK_DEFAULT) {
1.129 + stackSize = TCL_MAC_THRD_DEFAULT_STACK;
1.130 + }
1.131 +
1.132 +#if TARGET_CPU_68K && TARGET_RT_MAC_CFM
1.133 + {
1.134 + ThreadEntryProcPtr entryProc;
1.135 + entryProc = NewThreadEntryUPP(proc);
1.136 +
1.137 + NewThread(kCooperativeThread, entryProc, (void *) clientData,
1.138 + stackSize, kCreateIfNeeded, NULL, (ThreadID *) idPtr);
1.139 + }
1.140 +#else
1.141 + NewThread(kCooperativeThread, proc, (void *) clientData,
1.142 + stackSize, kCreateIfNeeded, NULL, (ThreadID *) idPtr);
1.143 +#endif
1.144 + if ((ThreadID) *idPtr == kNoThreadID) {
1.145 + return TCL_ERROR;
1.146 + } else {
1.147 + if (flags & TCL_THREAD_JOINABLE) {
1.148 + TclRememberJoinableThread (*idPtr);
1.149 + }
1.150 +
1.151 + return TCL_OK;
1.152 + }
1.153 +
1.154 +}
1.155 +
1.156 +/*
1.157 + *----------------------------------------------------------------------
1.158 + *
1.159 + * Tcl_JoinThread --
1.160 + *
1.161 + * This procedure waits upon the exit of the specified thread.
1.162 + *
1.163 + * Results:
1.164 + * TCL_OK if the wait was successful, TCL_ERROR else.
1.165 + *
1.166 + * Side effects:
1.167 + * The result area is set to the exit code of the thread we
1.168 + * waited upon.
1.169 + *
1.170 + *----------------------------------------------------------------------
1.171 + */
1.172 +
1.173 +int
1.174 +Tcl_JoinThread(threadId, result)
1.175 + Tcl_ThreadId threadId; /* Id of the thread to wait upon */
1.176 + int* result; /* Reference to the storage the result
1.177 + * of the thread we wait upon will be
1.178 + * written into. */
1.179 +{
1.180 + if (!TclMacHaveThreads()) {
1.181 + return TCL_ERROR;
1.182 + }
1.183 +
1.184 + return TclJoinThread (threadId, result);
1.185 +}
1.186 +
1.187 +/*
1.188 + *----------------------------------------------------------------------
1.189 + *
1.190 + * TclpThreadExit --
1.191 + *
1.192 + * This procedure terminates the current thread.
1.193 + *
1.194 + * Results:
1.195 + * None.
1.196 + *
1.197 + * Side effects:
1.198 + * This procedure terminates the current thread.
1.199 + *
1.200 + *----------------------------------------------------------------------
1.201 + */
1.202 +
1.203 +void
1.204 +TclpThreadExit(status)
1.205 + int status;
1.206 +{
1.207 + ThreadID curThread;
1.208 +
1.209 + if (!TclMacHaveThreads()) {
1.210 + return;
1.211 + }
1.212 +
1.213 + GetCurrentThread(&curThread);
1.214 + TclSignalExitThread ((Tcl_ThreadId) curThread, status);
1.215 +
1.216 + DisposeThread(curThread, NULL, false);
1.217 +}
1.218 +
1.219 +
1.220 +/*
1.221 + *----------------------------------------------------------------------
1.222 + *
1.223 + * Tcl_GetCurrentThread --
1.224 + *
1.225 + * This procedure returns the ID of the currently running thread.
1.226 + *
1.227 + * Results:
1.228 + * A thread ID.
1.229 + *
1.230 + * Side effects:
1.231 + * None.
1.232 + *
1.233 + *----------------------------------------------------------------------
1.234 + */
1.235 +
1.236 +Tcl_ThreadId
1.237 +Tcl_GetCurrentThread()
1.238 +{
1.239 +#ifdef TCL_THREADS
1.240 + ThreadID curThread;
1.241 +
1.242 + if (!TclMacHaveThreads()) {
1.243 + return (Tcl_ThreadId) 0;
1.244 + } else {
1.245 + GetCurrentThread(&curThread);
1.246 + return (Tcl_ThreadId) curThread;
1.247 + }
1.248 +#else
1.249 + return (Tcl_ThreadId) 0;
1.250 +#endif
1.251 +}
1.252 +
1.253 +
1.254 +/*
1.255 + *----------------------------------------------------------------------
1.256 + *
1.257 + * TclpInitLock
1.258 + *
1.259 + * This procedure is used to grab a lock that serializes initialization
1.260 + * and finalization of Tcl. On some platforms this may also initialize
1.261 + * the mutex used to serialize creation of more mutexes and thread
1.262 + * local storage keys.
1.263 + *
1.264 + * Results:
1.265 + * None.
1.266 + *
1.267 + * Side effects:
1.268 + * Acquire the initialization mutex.
1.269 + *
1.270 + *----------------------------------------------------------------------
1.271 + */
1.272 +
1.273 +void
1.274 +TclpInitLock()
1.275 +{
1.276 +#ifdef TCL_THREADS
1.277 + /* There is nothing to do on the Mac. */;
1.278 +#endif
1.279 +}
1.280 +
1.281 +
1.282 +/*
1.283 + *----------------------------------------------------------------------
1.284 + *
1.285 + * TclpInitUnlock
1.286 + *
1.287 + * This procedure is used to release a lock that serializes initialization
1.288 + * and finalization of Tcl.
1.289 + *
1.290 + * Results:
1.291 + * None.
1.292 + *
1.293 + * Side effects:
1.294 + * Release the initialization mutex.
1.295 + *
1.296 + *----------------------------------------------------------------------
1.297 + */
1.298 +
1.299 +void
1.300 +TclpInitUnlock()
1.301 +{
1.302 +#ifdef TCL_THREADS
1.303 + /* There is nothing to do on the Mac */;
1.304 +#endif
1.305 +}
1.306 +
1.307 +/*
1.308 + *----------------------------------------------------------------------
1.309 + *
1.310 + * TclpMasterLock
1.311 + *
1.312 + * This procedure is used to grab a lock that serializes creation
1.313 + * and finalization of serialization objects. This interface is
1.314 + * only needed in finalization; it is hidden during
1.315 + * creation of the objects.
1.316 + *
1.317 + * This lock must be different than the initLock because the
1.318 + * initLock is held during creation of syncronization objects.
1.319 + *
1.320 + * Results:
1.321 + * None.
1.322 + *
1.323 + * Side effects:
1.324 + * Acquire the master mutex.
1.325 + *
1.326 + *----------------------------------------------------------------------
1.327 + */
1.328 +
1.329 +void
1.330 +TclpMasterLock()
1.331 +{
1.332 +#ifdef TCL_THREADS
1.333 + /* There is nothing to do on the Mac */;
1.334 +#endif
1.335 +}
1.336 +
1.337 +
1.338 +/*
1.339 + *----------------------------------------------------------------------
1.340 + *
1.341 + * TclpMasterUnlock
1.342 + *
1.343 + * This procedure is used to release a lock that serializes creation
1.344 + * and finalization of synchronization objects.
1.345 + *
1.346 + * Results:
1.347 + * None.
1.348 + *
1.349 + * Side effects:
1.350 + * Release the master mutex.
1.351 + *
1.352 + *----------------------------------------------------------------------
1.353 + */
1.354 +
1.355 +void
1.356 +TclpMasterUnlock()
1.357 +{
1.358 +#ifdef TCL_THREADS
1.359 + /* There is nothing to do on the Mac */
1.360 +#endif
1.361 +}
1.362 +
1.363 +
1.364 +/*
1.365 + *----------------------------------------------------------------------
1.366 + *
1.367 + * Tcl_GetAllocMutex
1.368 + *
1.369 + * This procedure returns a pointer to a statically initialized
1.370 + * mutex for use by the memory allocator. The alloctor must
1.371 + * use this lock, because all other locks are allocated...
1.372 + *
1.373 + * Results:
1.374 + * A pointer to a mutex that is suitable for passing to
1.375 + * Tcl_MutexLock and Tcl_MutexUnlock.
1.376 + *
1.377 + * Side effects:
1.378 + * None.
1.379 + *
1.380 + *----------------------------------------------------------------------
1.381 + */
1.382 +
1.383 +Tcl_Mutex *
1.384 +Tcl_GetAllocMutex()
1.385 +{
1.386 + /* There is nothing to do on the Mac */
1.387 + return NULL;
1.388 +}
1.389 +
1.390 +#ifdef TCL_THREADS
1.391 +
1.392 +/*
1.393 + *----------------------------------------------------------------------
1.394 + *
1.395 + * Tcl_MutexLock --
1.396 + *
1.397 + * This procedure is invoked to lock a mutex. This procedure
1.398 + * handles initializing the mutex, if necessary. The caller
1.399 + * can rely on the fact that Tcl_Mutex is an opaque pointer.
1.400 + * This routine will change that pointer from NULL after first use.
1.401 + *
1.402 + * Results:
1.403 + * None.
1.404 + *
1.405 + * Side effects:
1.406 + * May block the current thread. The mutex is aquired when
1.407 + * this returns. Will allocate memory for a pthread_mutex_t
1.408 + * and initialize this the first time this Tcl_Mutex is used.
1.409 + *
1.410 + *----------------------------------------------------------------------
1.411 + */
1.412 +
1.413 +void
1.414 +Tcl_MutexLock(mutexPtr)
1.415 + Tcl_Mutex *mutexPtr; /* Really (pthread_mutex_t **) */
1.416 +{
1.417 +/* There is nothing to do on the Mac */
1.418 +}
1.419 +
1.420 +
1.421 +/*
1.422 + *----------------------------------------------------------------------
1.423 + *
1.424 + * TclpMutexUnlock --
1.425 + *
1.426 + * This procedure is invoked to unlock a mutex. The mutex must
1.427 + * have been locked by Tcl_MutexLock.
1.428 + *
1.429 + * Results:
1.430 + * None.
1.431 + *
1.432 + * Side effects:
1.433 + * The mutex is released when this returns.
1.434 + *
1.435 + *----------------------------------------------------------------------
1.436 + */
1.437 +
1.438 +void
1.439 +Tcl_MutexUnlock(mutexPtr)
1.440 + Tcl_Mutex *mutexPtr; /* Really (pthread_mutex_t **) */
1.441 +{
1.442 +/* There is nothing to do on the Mac */
1.443 +}
1.444 +
1.445 +
1.446 +/*
1.447 + *----------------------------------------------------------------------
1.448 + *
1.449 + * TclpFinalizeMutex --
1.450 + *
1.451 + * This procedure is invoked to clean up one mutex. This is only
1.452 + * safe to call at the end of time.
1.453 + *
1.454 + * This assumes the Master Lock is held.
1.455 + *
1.456 + * Results:
1.457 + * None.
1.458 + *
1.459 + * Side effects:
1.460 + * The mutex list is deallocated.
1.461 + *
1.462 + *----------------------------------------------------------------------
1.463 + */
1.464 +
1.465 +void
1.466 +TclpFinalizeMutex(mutexPtr)
1.467 + Tcl_Mutex *mutexPtr;
1.468 +{
1.469 +/* There is nothing to do on the Mac */
1.470 +}
1.471 +
1.472 +
1.473 +/*
1.474 + *----------------------------------------------------------------------
1.475 + *
1.476 + * TclpThreadDataKeyInit --
1.477 + *
1.478 + * This procedure initializes a thread specific data block key.
1.479 + * Each thread has table of pointers to thread specific data.
1.480 + * all threads agree on which table entry is used by each module.
1.481 + * this is remembered in a "data key", that is just an index into
1.482 + * this table. To allow self initialization, the interface
1.483 + * passes a pointer to this key and the first thread to use
1.484 + * the key fills in the pointer to the key. The key should be
1.485 + * a process-wide static.
1.486 + *
1.487 + * There is no system-wide support for thread specific data on the
1.488 + * Mac. So we implement this as an array of pointers. The keys are
1.489 + * allocated sequentially, and each key maps to a slot in the table.
1.490 + * The table element points to a linked list of the instances of
1.491 + * the data for each thread.
1.492 + *
1.493 + * Results:
1.494 + * None.
1.495 + *
1.496 + * Side effects:
1.497 + * Will bump the key counter if this is the first time this key
1.498 + * has been initialized. May grow the DataKeyArray if that is
1.499 + * necessary.
1.500 + *
1.501 + *----------------------------------------------------------------------
1.502 + */
1.503 +
1.504 +void
1.505 +TclpThreadDataKeyInit(keyPtr)
1.506 + Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk,
1.507 + * really (pthread_key_t **) */
1.508 +{
1.509 +
1.510 + if (*keyPtr == NULL) {
1.511 + keyCounter += 1;
1.512 + *keyPtr = (Tcl_ThreadDataKey) keyCounter;
1.513 + if (keyCounter > maxNumKeys) {
1.514 + TclMacThrdData **newArray;
1.515 + int i, oldMax = maxNumKeys;
1.516 +
1.517 + maxNumKeys = maxNumKeys + TCL_MAC_INITIAL_KEYSIZE;
1.518 +
1.519 + newArray = (TclMacThrdData **)
1.520 + ckalloc(maxNumKeys * sizeof(TclMacThrdData *));
1.521 +
1.522 + for (i = 0; i < oldMax; i++) {
1.523 + newArray[i] = tclMacDataKeyArray[i];
1.524 + }
1.525 + for (i = oldMax; i < maxNumKeys; i++) {
1.526 + newArray[i] = NULL;
1.527 + }
1.528 +
1.529 + if (tclMacDataKeyArray != NULL) {
1.530 + ckfree((char *) tclMacDataKeyArray);
1.531 + }
1.532 + tclMacDataKeyArray = newArray;
1.533 +
1.534 + }
1.535 + /* TclRememberDataKey(keyPtr); */
1.536 + }
1.537 +}
1.538 +
1.539 +/*
1.540 + *----------------------------------------------------------------------
1.541 + *
1.542 + * TclpThreadDataKeyGet --
1.543 + *
1.544 + * This procedure returns a pointer to a block of thread local storage.
1.545 + *
1.546 + * Results:
1.547 + * A thread-specific pointer to the data structure, or NULL
1.548 + * if the memory has not been assigned to this key for this thread.
1.549 + *
1.550 + * Side effects:
1.551 + * None.
1.552 + *
1.553 + *----------------------------------------------------------------------
1.554 + */
1.555 +
1.556 +VOID *
1.557 +TclpThreadDataKeyGet(keyPtr)
1.558 + Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk,
1.559 + * really (pthread_key_t **) */
1.560 +{
1.561 + TclMacThrdData *dataPtr;
1.562 +
1.563 + dataPtr = GetThreadDataStruct(*keyPtr);
1.564 +
1.565 + if (dataPtr == NULL) {
1.566 + return NULL;
1.567 + } else {
1.568 + return dataPtr->data;
1.569 + }
1.570 +}
1.571 +
1.572 +
1.573 +/*
1.574 + *----------------------------------------------------------------------
1.575 + *
1.576 + * TclpThreadDataKeySet --
1.577 + *
1.578 + * This procedure sets the pointer to a block of thread local storage.
1.579 + *
1.580 + * Results:
1.581 + * None.
1.582 + *
1.583 + * Side effects:
1.584 + * Sets up the thread so future calls to TclpThreadDataKeyGet with
1.585 + * this key will return the data pointer.
1.586 + *
1.587 + *----------------------------------------------------------------------
1.588 + */
1.589 +
1.590 +void
1.591 +TclpThreadDataKeySet(keyPtr, data)
1.592 + Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk,
1.593 + * really (pthread_key_t **) */
1.594 + VOID *data; /* Thread local storage */
1.595 +{
1.596 + TclMacThrdData *dataPtr;
1.597 + ThreadID curThread;
1.598 +
1.599 + dataPtr = GetThreadDataStruct(*keyPtr);
1.600 +
1.601 + /*
1.602 + * Is it legal to reset the thread data like this?
1.603 + * And if so, who owns the memory?
1.604 + */
1.605 +
1.606 + if (dataPtr != NULL) {
1.607 + dataPtr->data = data;
1.608 + } else {
1.609 + dataPtr = (TclMacThrdData *) ckalloc(sizeof(TclMacThrdData));
1.610 + GetCurrentThread(&curThread);
1.611 + dataPtr->threadID = curThread;
1.612 + dataPtr->data = data;
1.613 + dataPtr->next = tclMacDataKeyArray[(int) *keyPtr - 1];
1.614 + tclMacDataKeyArray[(int) *keyPtr - 1] = dataPtr;
1.615 + }
1.616 +}
1.617 +
1.618 +/*
1.619 + *----------------------------------------------------------------------
1.620 + *
1.621 + * TclpFinalizeThreadData --
1.622 + *
1.623 + * This procedure cleans up the thread-local storage. This is
1.624 + * called once for each thread.
1.625 + *
1.626 + * Results:
1.627 + * None.
1.628 + *
1.629 + * Side effects:
1.630 + * Frees up all thread local storage.
1.631 + *
1.632 + *----------------------------------------------------------------------
1.633 + */
1.634 +
1.635 +void
1.636 +TclpFinalizeThreadData(keyPtr)
1.637 + Tcl_ThreadDataKey *keyPtr;
1.638 +{
1.639 + TclMacThrdData *dataPtr;
1.640 +
1.641 + if (*keyPtr != NULL) {
1.642 + dataPtr = RemoveThreadDataStruct(*keyPtr);
1.643 +
1.644 + if ((dataPtr != NULL) && (dataPtr->data != NULL)) {
1.645 + ckfree((char *) dataPtr->data);
1.646 + ckfree((char *) dataPtr);
1.647 + }
1.648 + }
1.649 +}
1.650 +
1.651 +/*
1.652 + *----------------------------------------------------------------------
1.653 + *
1.654 + * TclpFinalizeThreadDataKey --
1.655 + *
1.656 + * This procedure is invoked to clean up one key. This is a
1.657 + * process-wide storage identifier. The thread finalization code
1.658 + * cleans up the thread local storage itself.
1.659 + *
1.660 + * On the Mac, there is really nothing to do here, since the key
1.661 + * is just an array index. But we set the key to 0 just in case
1.662 + * someone else is relying on that.
1.663 + *
1.664 + * Results:
1.665 + * None.
1.666 + *
1.667 + * Side effects:
1.668 + * The keyPtr value is set to 0.
1.669 + *
1.670 + *----------------------------------------------------------------------
1.671 + */
1.672 +
1.673 +void
1.674 +TclpFinalizeThreadDataKey(keyPtr)
1.675 + Tcl_ThreadDataKey *keyPtr;
1.676 +{
1.677 + ckfree((char *) tclMacDataKeyArray[(int) *keyPtr - 1]);
1.678 + tclMacDataKeyArray[(int) *keyPtr - 1] = NULL;
1.679 + *keyPtr = NULL;
1.680 +}
1.681 +
1.682 +
1.683 +/*
1.684 + *----------------------------------------------------------------------
1.685 + *
1.686 + * GetThreadDataStruct --
1.687 + *
1.688 + * This procedure gets the data structure corresponding to
1.689 + * keyVal for the current process.
1.690 + *
1.691 + * Results:
1.692 + * The requested key data.
1.693 + *
1.694 + * Side effects:
1.695 + * None.
1.696 + *
1.697 + *----------------------------------------------------------------------
1.698 + */
1.699 +
1.700 +TclMacThrdData *
1.701 +GetThreadDataStruct(keyVal)
1.702 + Tcl_ThreadDataKey keyVal;
1.703 +{
1.704 + ThreadID curThread;
1.705 + TclMacThrdData *dataPtr;
1.706 +
1.707 + /*
1.708 + * The keyPtr will only be greater than keyCounter is someone
1.709 + * has passed us a key without getting the value from
1.710 + * TclpInitDataKey.
1.711 + */
1.712 +
1.713 + if ((int) keyVal <= 0) {
1.714 + return NULL;
1.715 + } else if ((int) keyVal > keyCounter) {
1.716 + panic("illegal data key value");
1.717 + }
1.718 +
1.719 + GetCurrentThread(&curThread);
1.720 +
1.721 + for (dataPtr = tclMacDataKeyArray[(int) keyVal - 1]; dataPtr != NULL;
1.722 + dataPtr = dataPtr->next) {
1.723 + if (dataPtr->threadID == curThread) {
1.724 + break;
1.725 + }
1.726 + }
1.727 +
1.728 + return dataPtr;
1.729 +}
1.730 +
1.731 +
1.732 +/*
1.733 + *----------------------------------------------------------------------
1.734 + *
1.735 + * RemoveThreadDataStruct --
1.736 + *
1.737 + * This procedure removes the data structure corresponding to
1.738 + * keyVal for the current process from the list kept for keyVal.
1.739 + *
1.740 + * Results:
1.741 + * The requested key data is removed from the list, and a pointer
1.742 + * to it is returned.
1.743 + *
1.744 + * Side effects:
1.745 + * None.
1.746 + *
1.747 + *----------------------------------------------------------------------
1.748 + */
1.749 +
1.750 +TclMacThrdData *
1.751 +RemoveThreadDataStruct(keyVal)
1.752 + Tcl_ThreadDataKey keyVal;
1.753 +{
1.754 + ThreadID curThread;
1.755 + TclMacThrdData *dataPtr, *prevPtr;
1.756 +
1.757 +
1.758 + if ((int) keyVal <= 0) {
1.759 + return NULL;
1.760 + } else if ((int) keyVal > keyCounter) {
1.761 + panic("illegal data key value");
1.762 + }
1.763 +
1.764 + GetCurrentThread(&curThread);
1.765 +
1.766 + for (dataPtr = tclMacDataKeyArray[(int) keyVal - 1], prevPtr = NULL;
1.767 + dataPtr != NULL;
1.768 + prevPtr = dataPtr, dataPtr = dataPtr->next) {
1.769 + if (dataPtr->threadID == curThread) {
1.770 + break;
1.771 + }
1.772 + }
1.773 +
1.774 + if (dataPtr == NULL) {
1.775 + /* No body */
1.776 + } else if ( prevPtr == NULL) {
1.777 + tclMacDataKeyArray[(int) keyVal - 1] = dataPtr->next;
1.778 + } else {
1.779 + prevPtr->next = dataPtr->next;
1.780 + }
1.781 +
1.782 + return dataPtr;
1.783 +}
1.784 +
1.785 +/*
1.786 + *----------------------------------------------------------------------
1.787 + *
1.788 + * Tcl_ConditionWait --
1.789 + *
1.790 + * This procedure is invoked to wait on a condition variable.
1.791 + * On the Mac, mutexes are no-ops, and we just yield. After
1.792 + * all, it is the application's job to loop till the condition
1.793 + * variable is changed...
1.794 + *
1.795 + *
1.796 + * Results:
1.797 + * None.
1.798 + *
1.799 + * Side effects:
1.800 + * Will block the current thread till someone else yields.
1.801 + *
1.802 + *----------------------------------------------------------------------
1.803 + */
1.804 +
1.805 +void
1.806 +Tcl_ConditionWait(condPtr, mutexPtr, timePtr)
1.807 + Tcl_Condition *condPtr; /* Really (pthread_cond_t **) */
1.808 + Tcl_Mutex *mutexPtr; /* Really (pthread_mutex_t **) */
1.809 + Tcl_Time *timePtr; /* Timeout on waiting period */
1.810 +{
1.811 + if (TclMacHaveThreads()) {
1.812 + YieldToAnyThread();
1.813 + }
1.814 +}
1.815 +
1.816 +/*
1.817 + *----------------------------------------------------------------------
1.818 + *
1.819 + * Tcl_ConditionNotify --
1.820 + *
1.821 + * This procedure is invoked to signal a condition variable.
1.822 + *
1.823 + * The mutex must be held during this call to avoid races,
1.824 + * but this interface does not enforce that.
1.825 + *
1.826 + * Results:
1.827 + * None.
1.828 + *
1.829 + * Side effects:
1.830 + * May unblock another thread.
1.831 + *
1.832 + *----------------------------------------------------------------------
1.833 + */
1.834 +
1.835 +void
1.836 +Tcl_ConditionNotify(condPtr)
1.837 + Tcl_Condition *condPtr;
1.838 +{
1.839 + if (TclMacHaveThreads()) {
1.840 + YieldToAnyThread();
1.841 + }
1.842 +}
1.843 +
1.844 +
1.845 +/*
1.846 + *----------------------------------------------------------------------
1.847 + *
1.848 + * TclpFinalizeCondition --
1.849 + *
1.850 + * This procedure is invoked to clean up a condition variable.
1.851 + * This is only safe to call at the end of time.
1.852 + *
1.853 + * This assumes the Master Lock is held.
1.854 + *
1.855 + * Results:
1.856 + * None.
1.857 + *
1.858 + * Side effects:
1.859 + * The condition variable is deallocated.
1.860 + *
1.861 + *----------------------------------------------------------------------
1.862 + */
1.863 +
1.864 +void
1.865 +TclpFinalizeCondition(condPtr)
1.866 + Tcl_Condition *condPtr;
1.867 +{
1.868 + /* Nothing to do on the Mac */
1.869 +}
1.870 +
1.871 +
1.872 +
1.873 +#endif /* TCL_THREADS */
1.874 +