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