os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/win/tclWinThrd.c
Update contrib.
4 * This file implements the Windows-specific thread operations.
6 * Copyright (c) 1998 by Sun Microsystems, Inc.
7 * Copyright (c) 1999 by Scriptics Corporation
9 * See the file "license.terms" for information on usage and redistribution
10 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
12 * RCS: @(#) $Id: tclWinThrd.c,v 1.24.2.12 2007/03/24 09:31:11 vasiljevic Exp $
15 #include "tclWinInt.h"
22 * This is the master lock used to serialize access to other
23 * serialization data structures.
26 static CRITICAL_SECTION masterLock;
28 #define MASTER_LOCK TclpMasterLock()
29 #define MASTER_UNLOCK TclpMasterUnlock()
33 * This is the master lock used to serialize initialization and finalization
37 static CRITICAL_SECTION initLock;
40 * allocLock is used by Tcl's version of malloc for synchronization.
41 * For obvious reasons, cannot use any dyamically allocated storage.
46 static CRITICAL_SECTION allocLock;
47 static Tcl_Mutex allocLockPtr = (Tcl_Mutex) &allocLock;
48 static int allocOnce = 0;
50 #endif /* TCL_THREADS */
53 * The joinLock serializes Create- and ExitThread. This is necessary to
54 * prevent a race where a new joinable thread exits before the creating
55 * thread had the time to create the necessary data structures in the
59 static CRITICAL_SECTION joinLock;
62 * Condition variables are implemented with a combination of a
63 * per-thread Windows Event and a per-condition waiting queue.
64 * The idea is that each thread has its own Event that it waits
65 * on when it is doing a ConditionWait; it uses the same event for
66 * all condition variables because it only waits on one at a time.
67 * Each condition variable has a queue of waiting threads, and a
68 * mutex used to serialize access to this queue.
70 * Special thanks to David Nichols and
71 * Jim Davidson for advice on the Condition Variable implementation.
75 * The per-thread event and queue pointers.
80 typedef struct ThreadSpecificData {
81 HANDLE condEvent; /* Per-thread condition event */
82 struct ThreadSpecificData *nextPtr; /* Queue pointers */
83 struct ThreadSpecificData *prevPtr;
84 int flags; /* See flags below */
86 static Tcl_ThreadDataKey dataKey;
88 #endif /* TCL_THREADS */
91 * Additions by AOL for specialized thread memory allocator.
94 #if defined(USE_THREAD_ALLOC) && !defined(TCL_MEM_DEBUG)
98 typedef struct allocMutex {
100 CRITICAL_SECTION wlock;
105 * State bits for the thread.
106 * WIN_THREAD_UNINIT Uninitialized. Must be zero because
107 * of the way ThreadSpecificData is created.
108 * WIN_THREAD_RUNNING Running, not waiting.
109 * WIN_THREAD_BLOCKED Waiting, or trying to wait.
112 #define WIN_THREAD_UNINIT 0x0
113 #define WIN_THREAD_RUNNING 0x1
114 #define WIN_THREAD_BLOCKED 0x2
117 * The per condition queue pointers and the
118 * Mutex used to serialize access to the queue.
121 typedef struct WinCondition {
122 CRITICAL_SECTION condLock; /* Lock to serialize queuing on the condition */
123 struct ThreadSpecificData *firstPtr; /* Queue pointers */
124 struct ThreadSpecificData *lastPtr;
129 *----------------------------------------------------------------------
131 * TclpThreadCreate --
133 * This procedure creates a new thread.
136 * TCL_OK if the thread could be created. The thread ID is
137 * returned in a parameter.
140 * A new thread is created.
142 *----------------------------------------------------------------------
146 TclpThreadCreate(idPtr, proc, clientData, stackSize, flags)
147 Tcl_ThreadId *idPtr; /* Return, the ID of the thread */
148 Tcl_ThreadCreateProc proc; /* Main() function of the thread */
149 ClientData clientData; /* The one argument to Main() */
150 int stackSize; /* Size of stack for the new thread */
151 int flags; /* Flags controlling behaviour of
156 EnterCriticalSection(&joinLock);
158 #if defined(_MSC_VER) || defined(__MSVCRT__) || defined(__BORLANDC__)
159 tHandle = (HANDLE) _beginthreadex(NULL, (unsigned) stackSize, proc,
160 clientData, 0, (unsigned *)idPtr);
162 tHandle = CreateThread(NULL, (DWORD) stackSize,
163 (LPTHREAD_START_ROUTINE) proc, (LPVOID) clientData,
164 (DWORD) 0, (LPDWORD)idPtr);
167 if (tHandle == NULL) {
168 LeaveCriticalSection(&joinLock);
171 if (flags & TCL_THREAD_JOINABLE) {
172 TclRememberJoinableThread (*idPtr);
176 * The only purpose of this is to decrement the reference count so the
177 * OS resources will be reaquired when the thread closes.
180 CloseHandle(tHandle);
181 LeaveCriticalSection(&joinLock);
187 *----------------------------------------------------------------------
191 * This procedure waits upon the exit of the specified thread.
194 * TCL_OK if the wait was successful, TCL_ERROR else.
197 * The result area is set to the exit code of the thread we
200 *----------------------------------------------------------------------
204 Tcl_JoinThread(threadId, result)
205 Tcl_ThreadId threadId; /* Id of the thread to wait upon */
206 int* result; /* Reference to the storage the result
207 * of the thread we wait upon will be
210 return TclJoinThread (threadId, result);
214 *----------------------------------------------------------------------
218 * This procedure terminates the current thread.
224 * This procedure terminates the current thread.
226 *----------------------------------------------------------------------
230 TclpThreadExit(status)
233 EnterCriticalSection(&joinLock);
234 TclSignalExitThread (Tcl_GetCurrentThread (), status);
235 LeaveCriticalSection(&joinLock);
237 #if defined(_MSC_VER) || defined(__MSVCRT__) || defined(__BORLANDC__)
238 _endthreadex((unsigned) status);
240 ExitThread((DWORD) status);
245 *----------------------------------------------------------------------
247 * Tcl_GetCurrentThread --
249 * This procedure returns the ID of the currently running thread.
257 *----------------------------------------------------------------------
261 Tcl_GetCurrentThread()
263 return (Tcl_ThreadId)GetCurrentThreadId();
267 *----------------------------------------------------------------------
271 * This procedure is used to grab a lock that serializes initialization
272 * and finalization of Tcl. On some platforms this may also initialize
273 * the mutex used to serialize creation of more mutexes and thread
274 * local storage keys.
280 * Acquire the initialization mutex.
282 *----------------------------------------------------------------------
290 * There is a fundamental race here that is solved by creating
291 * the first Tcl interpreter in a single threaded environment.
292 * Once the interpreter has been created, it is safe to create
293 * more threads that create interpreters in parallel.
296 InitializeCriticalSection(&joinLock);
297 InitializeCriticalSection(&initLock);
298 InitializeCriticalSection(&masterLock);
300 EnterCriticalSection(&initLock);
304 *----------------------------------------------------------------------
308 * This procedure is used to release a lock that serializes initialization
309 * and finalization of Tcl.
315 * Release the initialization mutex.
317 *----------------------------------------------------------------------
323 LeaveCriticalSection(&initLock);
327 *----------------------------------------------------------------------
331 * This procedure is used to grab a lock that serializes creation
332 * of mutexes, condition variables, and thread local storage keys.
334 * This lock must be different than the initLock because the
335 * initLock is held during creation of syncronization objects.
341 * Acquire the master mutex.
343 *----------------------------------------------------------------------
351 * There is a fundamental race here that is solved by creating
352 * the first Tcl interpreter in a single threaded environment.
353 * Once the interpreter has been created, it is safe to create
354 * more threads that create interpreters in parallel.
357 InitializeCriticalSection(&joinLock);
358 InitializeCriticalSection(&initLock);
359 InitializeCriticalSection(&masterLock);
361 EnterCriticalSection(&masterLock);
365 *----------------------------------------------------------------------
369 * This procedure is used to release a lock that serializes creation
370 * and deletion of synchronization objects.
376 * Release the master mutex.
378 *----------------------------------------------------------------------
384 LeaveCriticalSection(&masterLock);
388 *----------------------------------------------------------------------
392 * This procedure returns a pointer to a statically initialized
393 * mutex for use by the memory allocator. The alloctor must
394 * use this lock, because all other locks are allocated...
397 * A pointer to a mutex that is suitable for passing to
398 * Tcl_MutexLock and Tcl_MutexUnlock.
403 *----------------------------------------------------------------------
411 InitializeCriticalSection(&allocLock);
414 return &allocLockPtr;
421 *----------------------------------------------------------------------
425 * This procedure is used to destroy all private resources used in
432 * Destroys everything private. TclpInitLock must be held
433 * entering this function.
435 *----------------------------------------------------------------------
442 DeleteCriticalSection(&joinLock);
443 /* Destroy the critical section that we are holding! */
444 DeleteCriticalSection(&masterLock);
447 DeleteCriticalSection(&allocLock);
450 /* Destroy the critical section that we are holding! */
451 DeleteCriticalSection(&initLock);
456 /* locally used prototype */
457 static void FinalizeConditionEvent(ClientData data);
461 *----------------------------------------------------------------------
465 * This procedure is invoked to lock a mutex. This is a self
466 * initializing mutex that is automatically finalized during
473 * May block the current thread. The mutex is aquired when
476 *----------------------------------------------------------------------
480 Tcl_MutexLock(mutexPtr)
481 Tcl_Mutex *mutexPtr; /* The lock */
483 CRITICAL_SECTION *csPtr;
484 if (*mutexPtr == NULL) {
488 * Double inside master lock check to avoid a race.
491 if (*mutexPtr == NULL) {
492 csPtr = (CRITICAL_SECTION *)ckalloc(sizeof(CRITICAL_SECTION));
493 InitializeCriticalSection(csPtr);
494 *mutexPtr = (Tcl_Mutex)csPtr;
495 TclRememberMutex(mutexPtr);
499 csPtr = *((CRITICAL_SECTION **)mutexPtr);
500 EnterCriticalSection(csPtr);
504 *----------------------------------------------------------------------
508 * This procedure is invoked to unlock a mutex.
514 * The mutex is released when this returns.
516 *----------------------------------------------------------------------
520 Tcl_MutexUnlock(mutexPtr)
521 Tcl_Mutex *mutexPtr; /* The lock */
523 CRITICAL_SECTION *csPtr = *((CRITICAL_SECTION **)mutexPtr);
524 LeaveCriticalSection(csPtr);
528 *----------------------------------------------------------------------
530 * TclpFinalizeMutex --
532 * This procedure is invoked to clean up one mutex. This is only
533 * safe to call at the end of time.
539 * The mutex list is deallocated.
541 *----------------------------------------------------------------------
545 TclpFinalizeMutex(mutexPtr)
548 CRITICAL_SECTION *csPtr = *(CRITICAL_SECTION **)mutexPtr;
550 DeleteCriticalSection(csPtr);
551 ckfree((char *)csPtr);
557 *----------------------------------------------------------------------
559 * TclpThreadDataKeyInit --
561 * This procedure initializes a thread specific data block key.
562 * Each thread has table of pointers to thread specific data.
563 * all threads agree on which table entry is used by each module.
564 * this is remembered in a "data key", that is just an index into
565 * this table. To allow self initialization, the interface
566 * passes a pointer to this key and the first thread to use
567 * the key fills in the pointer to the key. The key should be
568 * a process-wide static.
574 * Will allocate memory the first time this process calls for
575 * this key. In this case it modifies its argument
576 * to hold the pointer to information about the key.
578 *----------------------------------------------------------------------
582 TclpThreadDataKeyInit(keyPtr)
583 Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk,
584 * really (DWORD **) */
590 if (*keyPtr == NULL) {
591 indexPtr = (DWORD *)ckalloc(sizeof(DWORD));
593 if (newKey != TLS_OUT_OF_INDEXES) {
596 panic("TlsAlloc failed from TclpThreadDataKeyInit!"); /* this should be a fatal error */
598 *keyPtr = (Tcl_ThreadDataKey)indexPtr;
599 TclRememberDataKey(keyPtr);
605 *----------------------------------------------------------------------
607 * TclpThreadDataKeyGet --
609 * This procedure returns a pointer to a block of thread local storage.
612 * A thread-specific pointer to the data structure, or NULL
613 * if the memory has not been assigned to this key for this thread.
618 *----------------------------------------------------------------------
622 TclpThreadDataKeyGet(keyPtr)
623 Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk,
624 * really (DWORD **) */
626 DWORD *indexPtr = *(DWORD **)keyPtr;
628 if (indexPtr == NULL) {
631 result = TlsGetValue(*indexPtr);
632 if ((result == NULL) && (GetLastError() != NO_ERROR)) {
633 panic("TlsGetValue failed from TclpThreadDataKeyGet!");
640 *----------------------------------------------------------------------
642 * TclpThreadDataKeySet --
644 * This procedure sets the pointer to a block of thread local storage.
650 * Sets up the thread so future calls to TclpThreadDataKeyGet with
651 * this key will return the data pointer.
653 *----------------------------------------------------------------------
657 TclpThreadDataKeySet(keyPtr, data)
658 Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk,
659 * really (pthread_key_t **) */
660 VOID *data; /* Thread local storage */
662 DWORD *indexPtr = *(DWORD **)keyPtr;
664 success = TlsSetValue(*indexPtr, (void *)data);
666 panic("TlsSetValue failed from TclpThreadDataKeySet!");
671 *----------------------------------------------------------------------
673 * TclpFinalizeThreadData --
675 * This procedure cleans up the thread-local storage. This is
676 * called once for each thread.
682 * Frees up the memory.
684 *----------------------------------------------------------------------
688 TclpFinalizeThreadData(keyPtr)
689 Tcl_ThreadDataKey *keyPtr;
695 if (*keyPtr != NULL) {
696 indexPtr = *(DWORD **)keyPtr;
697 result = (VOID *)TlsGetValue(*indexPtr);
698 if (result != NULL) {
699 #if defined(USE_THREAD_ALLOC) && !defined(TCL_MEM_DEBUG)
700 if (indexPtr == &tlsKey) {
701 TclpFreeAllocCache(result);
705 ckfree((char *)result);
706 success = TlsSetValue(*indexPtr, (void *)NULL);
708 panic("TlsSetValue failed from TclpFinalizeThreadData!");
711 if (GetLastError() != NO_ERROR) {
712 panic("TlsGetValue failed from TclpFinalizeThreadData!");
719 *----------------------------------------------------------------------
721 * TclpFinalizeThreadDataKey --
723 * This procedure is invoked to clean up one key. This is a
724 * process-wide storage identifier. The thread finalization code
725 * cleans up the thread local storage itself.
727 * This assumes the master lock is held.
733 * The key is deallocated.
735 *----------------------------------------------------------------------
739 TclpFinalizeThreadDataKey(keyPtr)
740 Tcl_ThreadDataKey *keyPtr;
744 if (*keyPtr != NULL) {
745 indexPtr = *(DWORD **)keyPtr;
746 success = TlsFree(*indexPtr);
748 panic("TlsFree failed from TclpFinalizeThreadDataKey!");
750 ckfree((char *)indexPtr);
756 *----------------------------------------------------------------------
758 * Tcl_ConditionWait --
760 * This procedure is invoked to wait on a condition variable.
761 * The mutex is atomically released as part of the wait, and
762 * automatically grabbed when the condition is signaled.
764 * The mutex must be held when this procedure is called.
770 * May block the current thread. The mutex is aquired when
771 * this returns. Will allocate memory for a HANDLE
772 * and initialize this the first time this Tcl_Condition is used.
774 *----------------------------------------------------------------------
778 Tcl_ConditionWait(condPtr, mutexPtr, timePtr)
779 Tcl_Condition *condPtr; /* Really (WinCondition **) */
780 Tcl_Mutex *mutexPtr; /* Really (CRITICAL_SECTION **) */
781 Tcl_Time *timePtr; /* Timeout on waiting period */
783 WinCondition *winCondPtr; /* Per-condition queue head */
784 CRITICAL_SECTION *csPtr; /* Caller's Mutex, after casting */
785 DWORD wtime; /* Windows time value */
786 int timeout; /* True if we got a timeout */
787 int doExit = 0; /* True if we need to do exit setup */
788 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
791 * Self initialize the two parts of the condition.
792 * The per-condition and per-thread parts need to be
793 * handled independently.
796 if (tsdPtr->flags == WIN_THREAD_UNINIT) {
800 * Create the per-thread event and queue pointers.
803 if (tsdPtr->flags == WIN_THREAD_UNINIT) {
804 tsdPtr->condEvent = CreateEvent(NULL, TRUE /* manual reset */,
805 FALSE /* non signaled */, NULL);
806 tsdPtr->nextPtr = NULL;
807 tsdPtr->prevPtr = NULL;
808 tsdPtr->flags = WIN_THREAD_RUNNING;
815 * Create a per-thread exit handler to clean up the condEvent.
816 * We must be careful to do this outside the Master Lock
817 * because Tcl_CreateThreadExitHandler uses its own
818 * ThreadSpecificData, and initializing that may drop
819 * back into the Master Lock.
822 Tcl_CreateThreadExitHandler(FinalizeConditionEvent,
823 (ClientData) tsdPtr);
827 if (*condPtr == NULL) {
831 * Initialize the per-condition queue pointers and Mutex.
834 if (*condPtr == NULL) {
835 winCondPtr = (WinCondition *)ckalloc(sizeof(WinCondition));
836 InitializeCriticalSection(&winCondPtr->condLock);
837 winCondPtr->firstPtr = NULL;
838 winCondPtr->lastPtr = NULL;
839 *condPtr = (Tcl_Condition)winCondPtr;
840 TclRememberCondition(condPtr);
844 csPtr = *((CRITICAL_SECTION **)mutexPtr);
845 winCondPtr = *((WinCondition **)condPtr);
846 if (timePtr == NULL) {
849 wtime = timePtr->sec * 1000 + timePtr->usec / 1000;
853 * Queue the thread on the condition, using
854 * the per-condition lock for serialization.
857 tsdPtr->flags = WIN_THREAD_BLOCKED;
858 tsdPtr->nextPtr = NULL;
859 EnterCriticalSection(&winCondPtr->condLock);
860 tsdPtr->prevPtr = winCondPtr->lastPtr; /* A: */
861 winCondPtr->lastPtr = tsdPtr;
862 if (tsdPtr->prevPtr != NULL) {
863 tsdPtr->prevPtr->nextPtr = tsdPtr;
865 if (winCondPtr->firstPtr == NULL) {
866 winCondPtr->firstPtr = tsdPtr;
870 * Unlock the caller's mutex and wait for the condition, or a timeout.
871 * There is a minor issue here in that we don't count down the
872 * timeout if we get notified, but another thread grabs the condition
873 * before we do. In that race condition we'll wait again for the
874 * full timeout. Timed waits are dubious anyway. Either you have
875 * the locking protocol wrong and are masking a deadlock,
876 * or you are using conditions to pause your thread.
879 LeaveCriticalSection(csPtr);
881 while (!timeout && (tsdPtr->flags & WIN_THREAD_BLOCKED)) {
882 ResetEvent(tsdPtr->condEvent);
883 LeaveCriticalSection(&winCondPtr->condLock);
884 if (WaitForSingleObject(tsdPtr->condEvent, wtime) == WAIT_TIMEOUT) {
887 EnterCriticalSection(&winCondPtr->condLock);
891 * Be careful on timeouts because the signal might arrive right around
892 * the time limit and someone else could have taken us off the queue.
896 if (tsdPtr->flags & WIN_THREAD_RUNNING) {
900 * When dequeuing, we can leave the tsdPtr->nextPtr
901 * and tsdPtr->prevPtr with dangling pointers because
902 * they are reinitialilzed w/out reading them when the
903 * thread is enqueued later.
906 if (winCondPtr->firstPtr == tsdPtr) {
907 winCondPtr->firstPtr = tsdPtr->nextPtr;
909 tsdPtr->prevPtr->nextPtr = tsdPtr->nextPtr;
911 if (winCondPtr->lastPtr == tsdPtr) {
912 winCondPtr->lastPtr = tsdPtr->prevPtr;
914 tsdPtr->nextPtr->prevPtr = tsdPtr->prevPtr;
916 tsdPtr->flags = WIN_THREAD_RUNNING;
920 LeaveCriticalSection(&winCondPtr->condLock);
921 EnterCriticalSection(csPtr);
925 *----------------------------------------------------------------------
927 * Tcl_ConditionNotify --
929 * This procedure is invoked to signal a condition variable.
931 * The mutex must be held during this call to avoid races,
932 * but this interface does not enforce that.
938 * May unblock another thread.
940 *----------------------------------------------------------------------
944 Tcl_ConditionNotify(condPtr)
945 Tcl_Condition *condPtr;
947 WinCondition *winCondPtr;
948 ThreadSpecificData *tsdPtr;
950 if (condPtr != NULL) {
951 winCondPtr = *((WinCondition **)condPtr);
953 if (winCondPtr == NULL) {
958 * Loop through all the threads waiting on the condition
959 * and notify them (i.e., broadcast semantics). The queue
960 * manipulation is guarded by the per-condition coordinating mutex.
963 EnterCriticalSection(&winCondPtr->condLock);
964 while (winCondPtr->firstPtr != NULL) {
965 tsdPtr = winCondPtr->firstPtr;
966 winCondPtr->firstPtr = tsdPtr->nextPtr;
967 if (winCondPtr->lastPtr == tsdPtr) {
968 winCondPtr->lastPtr = NULL;
970 tsdPtr->flags = WIN_THREAD_RUNNING;
971 tsdPtr->nextPtr = NULL;
972 tsdPtr->prevPtr = NULL; /* Not strictly necessary, see A: */
973 SetEvent(tsdPtr->condEvent);
975 LeaveCriticalSection(&winCondPtr->condLock);
978 * Noone has used the condition variable, so there are no waiters.
984 *----------------------------------------------------------------------
986 * FinalizeConditionEvent --
988 * This procedure is invoked to clean up the per-thread
989 * event used to implement condition waiting.
990 * This is only safe to call at the end of time.
996 * The per-thread event is closed.
998 *----------------------------------------------------------------------
1002 FinalizeConditionEvent(data)
1005 ThreadSpecificData *tsdPtr = (ThreadSpecificData *)data;
1006 tsdPtr->flags = WIN_THREAD_UNINIT;
1007 CloseHandle(tsdPtr->condEvent);
1011 *----------------------------------------------------------------------
1013 * TclpFinalizeCondition --
1015 * This procedure is invoked to clean up a condition variable.
1016 * This is only safe to call at the end of time.
1018 * This assumes the Master Lock is held.
1024 * The condition variable is deallocated.
1026 *----------------------------------------------------------------------
1030 TclpFinalizeCondition(condPtr)
1031 Tcl_Condition *condPtr;
1033 WinCondition *winCondPtr = *(WinCondition **)condPtr;
1036 * Note - this is called long after the thread-local storage is
1037 * reclaimed. The per-thread condition waiting event is
1038 * reclaimed earlier in a per-thread exit handler, which is
1039 * called before thread local storage is reclaimed.
1042 if (winCondPtr != NULL) {
1043 DeleteCriticalSection(&winCondPtr->condLock);
1044 ckfree((char *)winCondPtr);
1050 * Additions by AOL for specialized thread memory allocator.
1053 #if defined(USE_THREAD_ALLOC) && !defined(TCL_MEM_DEBUG)
1055 TclpNewAllocMutex(void)
1057 struct allocMutex *lockPtr;
1059 lockPtr = malloc(sizeof(struct allocMutex));
1060 if (lockPtr == NULL) {
1061 panic("could not allocate lock");
1063 lockPtr->tlock = (Tcl_Mutex) &lockPtr->wlock;
1064 InitializeCriticalSection(&lockPtr->wlock);
1065 return &lockPtr->tlock;
1069 TclpFreeAllocMutex(mutex)
1070 Tcl_Mutex *mutex; /* The alloc mutex to free. */
1072 allocMutex* lockPtr = (allocMutex*) mutex;
1073 if (!lockPtr) return;
1074 DeleteCriticalSection(&lockPtr->wlock);
1079 TclpGetAllocCache(void)
1085 * We need to make sure that TclpFreeAllocCache is called
1086 * on each thread that calls this, but only on threads that
1089 tlsKey = TlsAlloc();
1091 if (tlsKey == TLS_OUT_OF_INDEXES) {
1092 panic("could not allocate thread local storage");
1096 result = TlsGetValue(tlsKey);
1097 if ((result == NULL) && (GetLastError() != NO_ERROR)) {
1098 panic("TlsGetValue failed from TclpGetAllocCache!");
1104 TclpSetAllocCache(void *ptr)
1107 success = TlsSetValue(tlsKey, ptr);
1109 panic("TlsSetValue failed from TclpSetAllocCache!");
1114 TclpFreeAllocCache(void *ptr)
1120 * Called by the pthread lib when a thread exits
1122 TclFreeAllocCache(ptr);
1123 success = TlsSetValue(tlsKey, NULL);
1125 panic("TlsSetValue failed from TclpFreeAllocCache!");
1129 * Called by us in TclFinalizeThreadAlloc() during
1130 * the library finalization initiated from Tcl_Finalize()
1132 success = TlsFree(tlsKey);
1134 Tcl_Panic("TlsFree failed from TclpFreeAllocCache!");
1136 once = 0; /* reset for next time. */
1140 #endif /* USE_THREAD_ALLOC */
1141 #endif /* TCL_THREADS */