os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/unix/tclUnixThrd.c
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/unix/tclUnixThrd.c Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,921 @@
1.4 +/*
1.5 + * tclUnixThrd.c --
1.6 + *
1.7 + * This file implements the UNIX-specific thread support.
1.8 + *
1.9 + * Copyright (c) 1991-1994 The Regents of the University of California.
1.10 + * Copyright (c) 1994-1997 Sun Microsystems, Inc.
1.11 + * Portions Copyright (c) 2007-2008 Nokia Corporation and/or its subsidiaries. All rights reserved.
1.12 + *
1.13 + * See the file "license.terms" for information on usage and redistribution
1.14 + * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
1.15 + *
1.16 + * SCCS: @(#) tclUnixThrd.c 1.18 98/02/19 14:24:12
1.17 + */
1.18 +
1.19 +#include "tclInt.h"
1.20 +#include "tclPort.h"
1.21 +
1.22 +#ifdef TCL_THREADS
1.23 +
1.24 +#include "pthread.h"
1.25 +
1.26 +typedef struct ThreadSpecificData {
1.27 + char nabuf[16];
1.28 +} ThreadSpecificData;
1.29 +
1.30 +static Tcl_ThreadDataKey dataKey;
1.31 +
1.32 +/*
1.33 + * masterLock is used to serialize creation of mutexes, condition
1.34 + * variables, and thread local storage.
1.35 + * This is the only place that can count on the ability to statically
1.36 + * initialize the mutex.
1.37 + */
1.38 +
1.39 +static pthread_mutex_t masterLock = PTHREAD_MUTEX_INITIALIZER;
1.40 +
1.41 +/*
1.42 + * initLock is used to serialize initialization and finalization
1.43 + * of Tcl. It cannot use any dyamically allocated storage.
1.44 + */
1.45 +
1.46 +static pthread_mutex_t initLock = PTHREAD_MUTEX_INITIALIZER;
1.47 +
1.48 +/*
1.49 + * allocLock is used by Tcl's version of malloc for synchronization.
1.50 + * For obvious reasons, cannot use any dyamically allocated storage.
1.51 + */
1.52 +
1.53 +static pthread_mutex_t allocLock = PTHREAD_MUTEX_INITIALIZER;
1.54 +static pthread_mutex_t *allocLockPtr = &allocLock;
1.55 +
1.56 +/*
1.57 + * These are for the critical sections inside this file.
1.58 + */
1.59 +
1.60 +#define MASTER_LOCK pthread_mutex_lock(&masterLock)
1.61 +#define MASTER_UNLOCK pthread_mutex_unlock(&masterLock)
1.62 +
1.63 +#endif /* TCL_THREADS */
1.64 +
1.65 +
1.66 +/*
1.67 + *----------------------------------------------------------------------
1.68 + *
1.69 + * TclpThreadCreate --
1.70 + *
1.71 + * This procedure creates a new thread.
1.72 + *
1.73 + * Results:
1.74 + * TCL_OK if the thread could be created. The thread ID is
1.75 + * returned in a parameter.
1.76 + *
1.77 + * Side effects:
1.78 + * A new thread is created.
1.79 + *
1.80 + *----------------------------------------------------------------------
1.81 + */
1.82 +
1.83 +int
1.84 +TclpThreadCreate(idPtr, proc, clientData, stackSize, flags)
1.85 + Tcl_ThreadId *idPtr; /* Return, the ID of the thread */
1.86 + Tcl_ThreadCreateProc proc; /* Main() function of the thread */
1.87 + ClientData clientData; /* The one argument to Main() */
1.88 + int stackSize; /* Size of stack for the new thread */
1.89 + int flags; /* Flags controlling behaviour of
1.90 + * the new thread */
1.91 +{
1.92 +#ifdef TCL_THREADS
1.93 + pthread_attr_t attr;
1.94 + pthread_t theThread;
1.95 + int result;
1.96 +
1.97 + pthread_attr_init(&attr);
1.98 + pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
1.99 +
1.100 +#ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE
1.101 + if (stackSize != TCL_THREAD_STACK_DEFAULT) {
1.102 + pthread_attr_setstacksize(&attr, (size_t) stackSize);
1.103 +#ifdef TCL_THREAD_STACK_MIN
1.104 + } else {
1.105 + /*
1.106 + * Certain systems define a thread stack size that by default is
1.107 + * too small for many operations. The user has the option of
1.108 + * defining TCL_THREAD_STACK_MIN to a value large enough to work
1.109 + * for their needs. This would look like (for 128K min stack):
1.110 + * make MEM_DEBUG_FLAGS=-DTCL_THREAD_STACK_MIN=131072L
1.111 + *
1.112 + * This solution is not optimal, as we should allow the user to
1.113 + * specify a size at runtime, but we don't want to slow this function
1.114 + * down, and that would still leave the main thread at the default.
1.115 + */
1.116 +
1.117 + size_t size;
1.118 + result = pthread_attr_getstacksize(&attr, &size);
1.119 + if (!result && (size < TCL_THREAD_STACK_MIN)) {
1.120 + pthread_attr_setstacksize(&attr, (size_t) TCL_THREAD_STACK_MIN);
1.121 + }
1.122 +#endif
1.123 + }
1.124 +#endif
1.125 + if (! (flags & TCL_THREAD_JOINABLE)) {
1.126 + pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
1.127 + }
1.128 +
1.129 +
1.130 + if (pthread_create(&theThread, &attr,
1.131 + (void * (*)())proc, (void *)clientData) &&
1.132 + pthread_create(&theThread, NULL,
1.133 + (void * (*)())proc, (void *)clientData)) {
1.134 + result = TCL_ERROR;
1.135 + } else {
1.136 + *idPtr = (Tcl_ThreadId)theThread;
1.137 + result = TCL_OK;
1.138 + }
1.139 + pthread_attr_destroy(&attr);
1.140 + return result;
1.141 +#else
1.142 + return TCL_ERROR;
1.143 +#endif /* TCL_THREADS */
1.144 +}
1.145 +
1.146 +/*
1.147 + *----------------------------------------------------------------------
1.148 + *
1.149 + * Tcl_JoinThread --
1.150 + *
1.151 + * This procedure waits upon the exit of the specified thread.
1.152 + *
1.153 + * Results:
1.154 + * TCL_OK if the wait was successful, TCL_ERROR else.
1.155 + *
1.156 + * Side effects:
1.157 + * The result area is set to the exit code of the thread we
1.158 + * waited upon.
1.159 + *
1.160 + *----------------------------------------------------------------------
1.161 + */
1.162 +
1.163 +EXPORT_C int
1.164 +Tcl_JoinThread(threadId, state)
1.165 + Tcl_ThreadId threadId; /* Id of the thread to wait upon */
1.166 + int* state; /* Reference to the storage the result
1.167 + * of the thread we wait upon will be
1.168 + * written into. */
1.169 +{
1.170 +#ifdef TCL_THREADS
1.171 + int result;
1.172 +
1.173 + result = pthread_join ((pthread_t) threadId, (VOID**) state);
1.174 + return (result == 0) ? TCL_OK : TCL_ERROR;
1.175 +#else
1.176 + return TCL_ERROR;
1.177 +#endif
1.178 +}
1.179 +
1.180 +#ifdef TCL_THREADS
1.181 +/*
1.182 + *----------------------------------------------------------------------
1.183 + *
1.184 + * TclpThreadExit --
1.185 + *
1.186 + * This procedure terminates the current thread.
1.187 + *
1.188 + * Results:
1.189 + * None.
1.190 + *
1.191 + * Side effects:
1.192 + * This procedure terminates the current thread.
1.193 + *
1.194 + *----------------------------------------------------------------------
1.195 + */
1.196 +
1.197 +void
1.198 +TclpThreadExit(status)
1.199 + int status;
1.200 +{
1.201 + pthread_exit((VOID *)status);
1.202 +}
1.203 +#endif /* TCL_THREADS */
1.204 +
1.205 +/*
1.206 + *----------------------------------------------------------------------
1.207 + *
1.208 + * Tcl_GetCurrentThread --
1.209 + *
1.210 + * This procedure returns the ID of the currently running thread.
1.211 + *
1.212 + * Results:
1.213 + * A thread ID.
1.214 + *
1.215 + * Side effects:
1.216 + * None.
1.217 + *
1.218 + *----------------------------------------------------------------------
1.219 + */
1.220 +
1.221 +EXPORT_C Tcl_ThreadId
1.222 +Tcl_GetCurrentThread()
1.223 +{
1.224 +#ifdef TCL_THREADS
1.225 + return (Tcl_ThreadId) pthread_self();
1.226 +#else
1.227 + return (Tcl_ThreadId) 0;
1.228 +#endif
1.229 +}
1.230 +
1.231 +
1.232 +/*
1.233 + *----------------------------------------------------------------------
1.234 + *
1.235 + * TclpInitLock
1.236 + *
1.237 + * This procedure is used to grab a lock that serializes initialization
1.238 + * and finalization of Tcl. On some platforms this may also initialize
1.239 + * the mutex used to serialize creation of more mutexes and thread
1.240 + * local storage keys.
1.241 + *
1.242 + * Results:
1.243 + * None.
1.244 + *
1.245 + * Side effects:
1.246 + * Acquire the initialization mutex.
1.247 + *
1.248 + *----------------------------------------------------------------------
1.249 + */
1.250 +
1.251 +void
1.252 +TclpInitLock()
1.253 +{
1.254 +#ifdef TCL_THREADS
1.255 + pthread_mutex_lock(&initLock);
1.256 +#endif
1.257 +}
1.258 +
1.259 +/*
1.260 + *----------------------------------------------------------------------
1.261 + *
1.262 + * TclpFinalizeLock
1.263 + *
1.264 + * This procedure is used to destroy all private resources used in
1.265 + * this file.
1.266 + *
1.267 + * Results:
1.268 + * None.
1.269 + *
1.270 + * Side effects:
1.271 + * Destroys everything private. TclpInitLock must be held
1.272 + * entering this function.
1.273 + *
1.274 + *----------------------------------------------------------------------
1.275 + */
1.276 +
1.277 +void
1.278 +TclFinalizeLock ()
1.279 +{
1.280 +#ifdef TCL_THREADS
1.281 + /*
1.282 + * You do not need to destroy mutexes that were created with the
1.283 + * PTHREAD_MUTEX_INITIALIZER macro. These mutexes do not need
1.284 + * any destruction: masterLock, allocLock, and initLock.
1.285 + */
1.286 + pthread_mutex_unlock(&initLock);
1.287 +#endif
1.288 +}
1.289 +
1.290 +/*
1.291 + *----------------------------------------------------------------------
1.292 + *
1.293 + * TclpInitUnlock
1.294 + *
1.295 + * This procedure is used to release a lock that serializes initialization
1.296 + * and finalization of Tcl.
1.297 + *
1.298 + * Results:
1.299 + * None.
1.300 + *
1.301 + * Side effects:
1.302 + * Release the initialization mutex.
1.303 + *
1.304 + *----------------------------------------------------------------------
1.305 + */
1.306 +
1.307 +void
1.308 +TclpInitUnlock()
1.309 +{
1.310 +#ifdef TCL_THREADS
1.311 + pthread_mutex_unlock(&initLock);
1.312 +#endif
1.313 +}
1.314 +
1.315 +/*
1.316 + *----------------------------------------------------------------------
1.317 + *
1.318 + * TclpMasterLock
1.319 + *
1.320 + * This procedure is used to grab a lock that serializes creation
1.321 + * and finalization of serialization objects. This interface is
1.322 + * only needed in finalization; it is hidden during
1.323 + * creation of the objects.
1.324 + *
1.325 + * This lock must be different than the initLock because the
1.326 + * initLock is held during creation of syncronization objects.
1.327 + *
1.328 + * Results:
1.329 + * None.
1.330 + *
1.331 + * Side effects:
1.332 + * Acquire the master mutex.
1.333 + *
1.334 + *----------------------------------------------------------------------
1.335 + */
1.336 +
1.337 +void
1.338 +TclpMasterLock()
1.339 +{
1.340 +#ifdef TCL_THREADS
1.341 + pthread_mutex_lock(&masterLock);
1.342 +#endif
1.343 +}
1.344 +
1.345 +
1.346 +/*
1.347 + *----------------------------------------------------------------------
1.348 + *
1.349 + * TclpMasterUnlock
1.350 + *
1.351 + * This procedure is used to release a lock that serializes creation
1.352 + * and finalization of synchronization objects.
1.353 + *
1.354 + * Results:
1.355 + * None.
1.356 + *
1.357 + * Side effects:
1.358 + * Release the master mutex.
1.359 + *
1.360 + *----------------------------------------------------------------------
1.361 + */
1.362 +
1.363 +void
1.364 +TclpMasterUnlock()
1.365 +{
1.366 +#ifdef TCL_THREADS
1.367 + pthread_mutex_unlock(&masterLock);
1.368 +#endif
1.369 +}
1.370 +
1.371 +
1.372 +/*
1.373 + *----------------------------------------------------------------------
1.374 + *
1.375 + * Tcl_GetAllocMutex
1.376 + *
1.377 + * This procedure returns a pointer to a statically initialized
1.378 + * mutex for use by the memory allocator. The alloctor must
1.379 + * use this lock, because all other locks are allocated...
1.380 + *
1.381 + * Results:
1.382 + * A pointer to a mutex that is suitable for passing to
1.383 + * Tcl_MutexLock and Tcl_MutexUnlock.
1.384 + *
1.385 + * Side effects:
1.386 + * None.
1.387 + *
1.388 + *----------------------------------------------------------------------
1.389 + */
1.390 +
1.391 +EXPORT_C Tcl_Mutex *
1.392 +Tcl_GetAllocMutex()
1.393 +{
1.394 +#ifdef TCL_THREADS
1.395 + return (Tcl_Mutex *)&allocLockPtr;
1.396 +#else
1.397 + return NULL;
1.398 +#endif
1.399 +}
1.400 +
1.401 +#ifdef TCL_THREADS
1.402 +
1.403 +/*
1.404 + *----------------------------------------------------------------------
1.405 + *
1.406 + * Tcl_MutexLock --
1.407 + *
1.408 + * This procedure is invoked to lock a mutex. This procedure
1.409 + * handles initializing the mutex, if necessary. The caller
1.410 + * can rely on the fact that Tcl_Mutex is an opaque pointer.
1.411 + * This routine will change that pointer from NULL after first use.
1.412 + *
1.413 + * Results:
1.414 + * None.
1.415 + *
1.416 + * Side effects:
1.417 + * May block the current thread. The mutex is aquired when
1.418 + * this returns. Will allocate memory for a pthread_mutex_t
1.419 + * and initialize this the first time this Tcl_Mutex is used.
1.420 + *
1.421 + *----------------------------------------------------------------------
1.422 + */
1.423 +
1.424 +EXPORT_C void
1.425 +Tcl_MutexLock(mutexPtr)
1.426 + Tcl_Mutex *mutexPtr; /* Really (pthread_mutex_t **) */
1.427 +{
1.428 + pthread_mutex_t *pmutexPtr;
1.429 + if (*mutexPtr == NULL) {
1.430 + MASTER_LOCK;
1.431 + if (*mutexPtr == NULL) {
1.432 + /*
1.433 + * Double inside master lock check to avoid a race condition.
1.434 + */
1.435 +
1.436 + pmutexPtr = (pthread_mutex_t *)ckalloc(sizeof(pthread_mutex_t));
1.437 + pthread_mutex_init(pmutexPtr, NULL);
1.438 + *mutexPtr = (Tcl_Mutex)pmutexPtr;
1.439 + TclRememberMutex(mutexPtr);
1.440 + }
1.441 + MASTER_UNLOCK;
1.442 + }
1.443 + pmutexPtr = *((pthread_mutex_t **)mutexPtr);
1.444 + pthread_mutex_lock(pmutexPtr);
1.445 +}
1.446 +
1.447 +
1.448 +/*
1.449 + *----------------------------------------------------------------------
1.450 + *
1.451 + * Tcl_MutexUnlock --
1.452 + *
1.453 + * This procedure is invoked to unlock a mutex. The mutex must
1.454 + * have been locked by Tcl_MutexLock.
1.455 + *
1.456 + * Results:
1.457 + * None.
1.458 + *
1.459 + * Side effects:
1.460 + * The mutex is released when this returns.
1.461 + *
1.462 + *----------------------------------------------------------------------
1.463 + */
1.464 +
1.465 +EXPORT_C void
1.466 +Tcl_MutexUnlock(mutexPtr)
1.467 + Tcl_Mutex *mutexPtr; /* Really (pthread_mutex_t **) */
1.468 +{
1.469 + pthread_mutex_t *pmutexPtr = *(pthread_mutex_t **)mutexPtr;
1.470 + pthread_mutex_unlock(pmutexPtr);
1.471 +}
1.472 +
1.473 +
1.474 +/*
1.475 + *----------------------------------------------------------------------
1.476 + *
1.477 + * TclpFinalizeMutex --
1.478 + *
1.479 + * This procedure is invoked to clean up one mutex. This is only
1.480 + * safe to call at the end of time.
1.481 + *
1.482 + * This assumes the Master Lock is held.
1.483 + *
1.484 + * Results:
1.485 + * None.
1.486 + *
1.487 + * Side effects:
1.488 + * The mutex list is deallocated.
1.489 + *
1.490 + *----------------------------------------------------------------------
1.491 + */
1.492 +
1.493 +void
1.494 +TclpFinalizeMutex(mutexPtr)
1.495 + Tcl_Mutex *mutexPtr;
1.496 +{
1.497 + pthread_mutex_t *pmutexPtr = *(pthread_mutex_t **)mutexPtr;
1.498 + if (pmutexPtr != NULL) {
1.499 + pthread_mutex_destroy(pmutexPtr);
1.500 + ckfree((char *)pmutexPtr);
1.501 + *mutexPtr = NULL;
1.502 + }
1.503 +}
1.504 +
1.505 +
1.506 +/*
1.507 + *----------------------------------------------------------------------
1.508 + *
1.509 + * TclpThreadDataKeyInit --
1.510 + *
1.511 + * This procedure initializes a thread specific data block key.
1.512 + * Each thread has table of pointers to thread specific data.
1.513 + * all threads agree on which table entry is used by each module.
1.514 + * this is remembered in a "data key", that is just an index into
1.515 + * this table. To allow self initialization, the interface
1.516 + * passes a pointer to this key and the first thread to use
1.517 + * the key fills in the pointer to the key. The key should be
1.518 + * a process-wide static.
1.519 + *
1.520 + * Results:
1.521 + * None.
1.522 + *
1.523 + * Side effects:
1.524 + * Will allocate memory the first time this process calls for
1.525 + * this key. In this case it modifies its argument
1.526 + * to hold the pointer to information about the key.
1.527 + *
1.528 + *----------------------------------------------------------------------
1.529 + */
1.530 +
1.531 +void
1.532 +TclpThreadDataKeyInit(keyPtr)
1.533 + Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk,
1.534 + * really (pthread_key_t **) */
1.535 +{
1.536 + pthread_key_t *pkeyPtr;
1.537 +
1.538 + MASTER_LOCK;
1.539 + if (*keyPtr == NULL) {
1.540 + pkeyPtr = (pthread_key_t *)ckalloc(sizeof(pthread_key_t));
1.541 + pthread_key_create(pkeyPtr, NULL);
1.542 + *keyPtr = (Tcl_ThreadDataKey)pkeyPtr;
1.543 + TclRememberDataKey(keyPtr);
1.544 + }
1.545 + MASTER_UNLOCK;
1.546 +}
1.547 +
1.548 +/*
1.549 + *----------------------------------------------------------------------
1.550 + *
1.551 + * TclpThreadDataKeyGet --
1.552 + *
1.553 + * This procedure returns a pointer to a block of thread local storage.
1.554 + *
1.555 + * Results:
1.556 + * A thread-specific pointer to the data structure, or NULL
1.557 + * if the memory has not been assigned to this key for this thread.
1.558 + *
1.559 + * Side effects:
1.560 + * None.
1.561 + *
1.562 + *----------------------------------------------------------------------
1.563 + */
1.564 +
1.565 +VOID *
1.566 +TclpThreadDataKeyGet(keyPtr)
1.567 + Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk,
1.568 + * really (pthread_key_t **) */
1.569 +{
1.570 + pthread_key_t *pkeyPtr = *(pthread_key_t **)keyPtr;
1.571 + if (pkeyPtr == NULL) {
1.572 + return NULL;
1.573 + } else {
1.574 + return (VOID *)pthread_getspecific(*pkeyPtr);
1.575 + }
1.576 +}
1.577 +
1.578 +
1.579 +/*
1.580 + *----------------------------------------------------------------------
1.581 + *
1.582 + * TclpThreadDataKeySet --
1.583 + *
1.584 + * This procedure sets the pointer to a block of thread local storage.
1.585 + *
1.586 + * Results:
1.587 + * None.
1.588 + *
1.589 + * Side effects:
1.590 + * Sets up the thread so future calls to TclpThreadDataKeyGet with
1.591 + * this key will return the data pointer.
1.592 + *
1.593 + *----------------------------------------------------------------------
1.594 + */
1.595 +
1.596 +void
1.597 +TclpThreadDataKeySet(keyPtr, data)
1.598 + Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk,
1.599 + * really (pthread_key_t **) */
1.600 + VOID *data; /* Thread local storage */
1.601 +{
1.602 + pthread_key_t *pkeyPtr = *(pthread_key_t **)keyPtr;
1.603 + pthread_setspecific(*pkeyPtr, data);
1.604 +}
1.605 +
1.606 +/*
1.607 + *----------------------------------------------------------------------
1.608 + *
1.609 + * TclpFinalizeThreadData --
1.610 + *
1.611 + * This procedure cleans up the thread-local storage. This is
1.612 + * called once for each thread.
1.613 + *
1.614 + * Results:
1.615 + * None.
1.616 + *
1.617 + * Side effects:
1.618 + * Frees up all thread local storage.
1.619 + *
1.620 + *----------------------------------------------------------------------
1.621 + */
1.622 +
1.623 +void
1.624 +TclpFinalizeThreadData(keyPtr)
1.625 + Tcl_ThreadDataKey *keyPtr;
1.626 +{
1.627 + VOID *result;
1.628 + pthread_key_t *pkeyPtr;
1.629 +
1.630 + if (*keyPtr != NULL) {
1.631 + pkeyPtr = *(pthread_key_t **)keyPtr;
1.632 + result = (VOID *)pthread_getspecific(*pkeyPtr);
1.633 + if (result != NULL) {
1.634 + ckfree((char *)result);
1.635 + pthread_setspecific(*pkeyPtr, (void *)NULL);
1.636 + }
1.637 + }
1.638 +}
1.639 +
1.640 +/*
1.641 + *----------------------------------------------------------------------
1.642 + *
1.643 + * TclpFinalizeThreadDataKey --
1.644 + *
1.645 + * This procedure is invoked to clean up one key. This is a
1.646 + * process-wide storage identifier. The thread finalization code
1.647 + * cleans up the thread local storage itself.
1.648 + *
1.649 + * This assumes the master lock is held.
1.650 + *
1.651 + * Results:
1.652 + * None.
1.653 + *
1.654 + * Side effects:
1.655 + * The key is deallocated.
1.656 + *
1.657 + *----------------------------------------------------------------------
1.658 + */
1.659 +
1.660 +void
1.661 +TclpFinalizeThreadDataKey(keyPtr)
1.662 + Tcl_ThreadDataKey *keyPtr;
1.663 +{
1.664 + pthread_key_t *pkeyPtr;
1.665 + if (*keyPtr != NULL) {
1.666 + pkeyPtr = *(pthread_key_t **)keyPtr;
1.667 + pthread_key_delete(*pkeyPtr);
1.668 + ckfree((char *)pkeyPtr);
1.669 + *keyPtr = NULL;
1.670 + }
1.671 +}
1.672 +
1.673 +
1.674 +/*
1.675 + *----------------------------------------------------------------------
1.676 + *
1.677 + * Tcl_ConditionWait --
1.678 + *
1.679 + * This procedure is invoked to wait on a condition variable.
1.680 + * The mutex is automically released as part of the wait, and
1.681 + * automatically grabbed when the condition is signaled.
1.682 + *
1.683 + * The mutex must be held when this procedure is called.
1.684 + *
1.685 + * Results:
1.686 + * None.
1.687 + *
1.688 + * Side effects:
1.689 + * May block the current thread. The mutex is aquired when
1.690 + * this returns. Will allocate memory for a pthread_mutex_t
1.691 + * and initialize this the first time this Tcl_Mutex is used.
1.692 + *
1.693 + *----------------------------------------------------------------------
1.694 + */
1.695 +
1.696 +EXPORT_C void
1.697 +Tcl_ConditionWait(condPtr, mutexPtr, timePtr)
1.698 + Tcl_Condition *condPtr; /* Really (pthread_cond_t **) */
1.699 + Tcl_Mutex *mutexPtr; /* Really (pthread_mutex_t **) */
1.700 + Tcl_Time *timePtr; /* Timeout on waiting period */
1.701 +{
1.702 + pthread_cond_t *pcondPtr;
1.703 + pthread_mutex_t *pmutexPtr;
1.704 + struct timespec ptime;
1.705 +
1.706 + if (*condPtr == NULL) {
1.707 + MASTER_LOCK;
1.708 +
1.709 + /*
1.710 + * Double check inside mutex to avoid race,
1.711 + * then initialize condition variable if necessary.
1.712 + */
1.713 +
1.714 + if (*condPtr == NULL) {
1.715 + pcondPtr = (pthread_cond_t *)ckalloc(sizeof(pthread_cond_t));
1.716 + pthread_cond_init(pcondPtr, NULL);
1.717 + *condPtr = (Tcl_Condition)pcondPtr;
1.718 + TclRememberCondition(condPtr);
1.719 + }
1.720 + MASTER_UNLOCK;
1.721 + }
1.722 + pmutexPtr = *((pthread_mutex_t **)mutexPtr);
1.723 + pcondPtr = *((pthread_cond_t **)condPtr);
1.724 + if (timePtr == NULL) {
1.725 + pthread_cond_wait(pcondPtr, pmutexPtr);
1.726 + } else {
1.727 + Tcl_Time now;
1.728 +
1.729 + /*
1.730 + * Make sure to take into account the microsecond component of the
1.731 + * current time, including possible overflow situations. [Bug #411603]
1.732 + */
1.733 +
1.734 + Tcl_GetTime(&now);
1.735 + ptime.tv_sec = timePtr->sec + now.sec +
1.736 + (timePtr->usec + now.usec) / 1000000;
1.737 + ptime.tv_nsec = 1000 * ((timePtr->usec + now.usec) % 1000000);
1.738 + pthread_cond_timedwait(pcondPtr, pmutexPtr, &ptime);
1.739 + }
1.740 +}
1.741 +
1.742 +/*
1.743 + *----------------------------------------------------------------------
1.744 + *
1.745 + * Tcl_ConditionNotify --
1.746 + *
1.747 + * This procedure is invoked to signal a condition variable.
1.748 + *
1.749 + * The mutex must be held during this call to avoid races,
1.750 + * but this interface does not enforce that.
1.751 + *
1.752 + * Results:
1.753 + * None.
1.754 + *
1.755 + * Side effects:
1.756 + * May unblock another thread.
1.757 + *
1.758 + *----------------------------------------------------------------------
1.759 + */
1.760 +
1.761 +EXPORT_C void
1.762 +Tcl_ConditionNotify(condPtr)
1.763 + Tcl_Condition *condPtr;
1.764 +{
1.765 + pthread_cond_t *pcondPtr = *((pthread_cond_t **)condPtr);
1.766 + if (pcondPtr != NULL) {
1.767 + pthread_cond_broadcast(pcondPtr);
1.768 + } else {
1.769 + /*
1.770 + * Noone has used the condition variable, so there are no waiters.
1.771 + */
1.772 + }
1.773 +}
1.774 +
1.775 +
1.776 +/*
1.777 + *----------------------------------------------------------------------
1.778 + *
1.779 + * TclpFinalizeCondition --
1.780 + *
1.781 + * This procedure is invoked to clean up a condition variable.
1.782 + * This is only safe to call at the end of time.
1.783 + *
1.784 + * This assumes the Master Lock is held.
1.785 + *
1.786 + * Results:
1.787 + * None.
1.788 + *
1.789 + * Side effects:
1.790 + * The condition variable is deallocated.
1.791 + *
1.792 + *----------------------------------------------------------------------
1.793 + */
1.794 +
1.795 +void
1.796 +TclpFinalizeCondition(condPtr)
1.797 + Tcl_Condition *condPtr;
1.798 +{
1.799 + pthread_cond_t *pcondPtr = *(pthread_cond_t **)condPtr;
1.800 + if (pcondPtr != NULL) {
1.801 + pthread_cond_destroy(pcondPtr);
1.802 + ckfree((char *)pcondPtr);
1.803 + *condPtr = NULL;
1.804 + }
1.805 +}
1.806 +#endif /* TCL_THREADS */
1.807 +
1.808 +/*
1.809 + *----------------------------------------------------------------------
1.810 + *
1.811 + * TclpReaddir, TclpLocaltime, TclpGmtime, TclpInetNtoa --
1.812 + *
1.813 + * These procedures replace core C versions to be used in a
1.814 + * threaded environment.
1.815 + *
1.816 + * Results:
1.817 + * See documentation of C functions.
1.818 + *
1.819 + * Side effects:
1.820 + * See documentation of C functions.
1.821 + *
1.822 + * Notes:
1.823 + * TclpReaddir is no longer used by the core (see 1095909),
1.824 + * but it appears in the internal stubs table (see #589526).
1.825 + *----------------------------------------------------------------------
1.826 + */
1.827 +
1.828 +Tcl_DirEntry *
1.829 +TclpReaddir(DIR * dir)
1.830 +{
1.831 + return TclOSreaddir(dir);
1.832 +}
1.833 +
1.834 +char *
1.835 +TclpInetNtoa(struct in_addr addr)
1.836 +{
1.837 +#ifdef TCL_THREADS
1.838 + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
1.839 + unsigned char *b = (unsigned char*) &addr.s_addr;
1.840 +
1.841 + sprintf(tsdPtr->nabuf, "%u.%u.%u.%u", b[0], b[1], b[2], b[3]);
1.842 + return tsdPtr->nabuf;
1.843 +#else
1.844 + return inet_ntoa(addr);
1.845 +#endif
1.846 +}
1.847 +
1.848 +#if defined(TCL_THREADS) && defined(USE_THREAD_ALLOC) && !defined(TCL_MEM_DEBUG)
1.849 +/*
1.850 + * Additions by AOL for specialized thread memory allocator.
1.851 + */
1.852 +#ifdef USE_THREAD_ALLOC
1.853 +static volatile int initialized = 0;
1.854 +static pthread_key_t key;
1.855 +
1.856 +typedef struct allocMutex {
1.857 + Tcl_Mutex tlock;
1.858 + pthread_mutex_t plock;
1.859 +} allocMutex;
1.860 +
1.861 +Tcl_Mutex *
1.862 +TclpNewAllocMutex(void)
1.863 +{
1.864 + struct allocMutex *lockPtr;
1.865 +
1.866 + lockPtr = malloc(sizeof(struct allocMutex));
1.867 + if (lockPtr == NULL) {
1.868 + panic("could not allocate lock");
1.869 + }
1.870 + lockPtr->tlock = (Tcl_Mutex) &lockPtr->plock;
1.871 + pthread_mutex_init(&lockPtr->plock, NULL);
1.872 + return &lockPtr->tlock;
1.873 +}
1.874 +
1.875 +void
1.876 +TclpFreeAllocMutex(mutex)
1.877 + Tcl_Mutex *mutex; /* The alloc mutex to free. */
1.878 +{
1.879 + allocMutex* lockPtr = (allocMutex*) mutex;
1.880 + if (!lockPtr) return;
1.881 + pthread_mutex_destroy(&lockPtr->plock);
1.882 + free(lockPtr);
1.883 +}
1.884 +
1.885 +void TclpFreeAllocCache(ptr)
1.886 + void *ptr;
1.887 +{
1.888 + if (ptr != NULL) {
1.889 + /*
1.890 + * Called by the pthread lib when a thread exits
1.891 + */
1.892 + TclFreeAllocCache(ptr);
1.893 + } else if (initialized) {
1.894 + /*
1.895 + * Called by us in TclFinalizeThreadAlloc() during
1.896 + * the library finalization initiated from Tcl_Finalize()
1.897 + */
1.898 + pthread_key_delete(key);
1.899 + initialized = 0;
1.900 + }
1.901 +}
1.902 +
1.903 +void *
1.904 +TclpGetAllocCache(void)
1.905 +{
1.906 + if (!initialized) {
1.907 + pthread_mutex_lock(allocLockPtr);
1.908 + if (!initialized) {
1.909 + pthread_key_create(&key, TclpFreeAllocCache);
1.910 + initialized = 1;
1.911 + }
1.912 + pthread_mutex_unlock(allocLockPtr);
1.913 + }
1.914 + return pthread_getspecific(key);
1.915 +}
1.916 +
1.917 +void
1.918 +TclpSetAllocCache(void *arg)
1.919 +{
1.920 + pthread_setspecific(key, arg);
1.921 +}
1.922 +
1.923 +#endif /* USE_THREAD_ALLOC */
1.924 +#endif /* TCL_THREADS */