diff options
Diffstat (limited to 'win/tclWinThrd.c')
| -rw-r--r-- | win/tclWinThrd.c | 262 |
1 files changed, 108 insertions, 154 deletions
diff --git a/win/tclWinThrd.c b/win/tclWinThrd.c index e8d4d4d..2413a78 100644 --- a/win/tclWinThrd.c +++ b/win/tclWinThrd.c @@ -3,9 +3,8 @@ * * This file implements the Windows-specific thread operations. * - * Copyright © 1998 Sun Microsystems, Inc. - * Copyright © 1999 Scriptics Corporation - * Copyright © 2008 George Peter Staplin + * Copyright (c) 1998 by Sun Microsystems, Inc. + * Copyright (c) 1999 by Scriptics Corporation * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -13,6 +12,8 @@ #include "tclWinInt.h" +#include <float.h> + /* Workaround for mingw versions which don't provide this in float.h */ #ifndef _MCW_EM # define _MCW_EM 0x0008001F /* Error masks */ @@ -22,15 +23,18 @@ _CRTIMP unsigned int __cdecl _controlfp (unsigned int unNew, unsigned int unMask #endif /* - * This is the global lock used to serialize access to other serialization + * This is the master lock used to serialize access to other serialization * data structures. */ -static CRITICAL_SECTION globalLock; -static int initialized = 0; +static CRITICAL_SECTION masterLock; +static int init = 0; +#define MASTER_LOCK TclpMasterLock() +#define MASTER_UNLOCK TclpMasterUnlock() + /* - * This is the global lock used to serialize initialization and finalization + * This is the master lock used to serialize initialization and finalization * of Tcl as a whole. */ @@ -38,10 +42,10 @@ static CRITICAL_SECTION initLock; /* * allocLock is used by Tcl's version of malloc for synchronization. For - * obvious reasons, cannot use any dynamically allocated storage. + * obvious reasons, cannot use any dyamically allocated storage. */ -#if TCL_THREADS +#ifdef TCL_THREADS static struct Tcl_Mutex_ { CRITICAL_SECTION crit; @@ -76,7 +80,7 @@ static CRITICAL_SECTION joinLock; * The per-thread event and queue pointers. */ -#if TCL_THREADS +#ifdef TCL_THREADS typedef struct ThreadSpecificData { HANDLE condEvent; /* Per-thread condition event */ @@ -105,7 +109,7 @@ static Tcl_ThreadDataKey dataKey; * the queue. */ -typedef struct { +typedef struct WinCondition { CRITICAL_SECTION condLock; /* Lock to serialize queuing on the * condition. */ struct ThreadSpecificData *firstPtr; /* Queue pointers */ @@ -117,9 +121,10 @@ typedef struct { */ #ifdef USE_THREAD_ALLOC +static int once; static DWORD tlsKey; -typedef struct { +typedef struct allocMutex { Tcl_Mutex tlock; CRITICAL_SECTION wlock; } allocMutex; @@ -130,7 +135,7 @@ typedef struct { * to TclWinThreadStart. */ -typedef struct { +typedef struct WinThread { LPTHREAD_START_ROUTINE lpStartAddress; /* Original startup routine */ LPVOID lpParameter; /* Original startup data */ unsigned int fpControl; /* Floating point control word from the @@ -162,6 +167,7 @@ TclWinThreadStart( * from TclpThreadCreate */ { WinThread *winThreadPtr = (WinThread *) lpParameter; + unsigned int fpmask; LPTHREAD_START_ROUTINE lpOrigStartAddress; LPVOID lpOrigParameter; @@ -169,16 +175,18 @@ TclWinThreadStart( return TCL_ERROR; } - _controlfp(winThreadPtr->fpControl, _MCW_EM | _MCW_RC | 0x03000000 /* _MCW_DN */ -#if !defined(_WIN64) - | _MCW_PC + fpmask = _MCW_EM | _MCW_RC | _MCW_PC; + +#if defined(_MSC_VER) && _MSC_VER >= 1200 + fpmask |= _MCW_DN; #endif - ); + + _controlfp(winThreadPtr->fpControl, fpmask); lpOrigStartAddress = winThreadPtr->lpStartAddress; lpOrigParameter = winThreadPtr->lpParameter; - ckfree(winThreadPtr); + ckfree((char *)winThreadPtr); return lpOrigStartAddress(lpOrigParameter); } @@ -202,13 +210,13 @@ TclWinThreadStart( int TclpThreadCreate( Tcl_ThreadId *idPtr, /* Return, the ID of the thread. */ - Tcl_ThreadCreateProc *proc, /* Main() function of the thread. */ - void *clientData, /* The one argument to Main(). */ - TCL_HASH_TYPE stackSize, /* Size of stack for the new thread. */ + Tcl_ThreadCreateProc proc, /* Main() function of the thread. */ + ClientData clientData, /* The one argument to Main(). */ + int stackSize, /* Size of stack for the new thread. */ int flags) /* Flags controlling behaviour of the new * thread. */ { - WinThread *winThreadPtr; /* Per-thread startup info */ + WinThread *winThreadPtr; /* Per-thread startup info */ HANDLE tHandle; winThreadPtr = (WinThread *)ckalloc(sizeof(WinThread)); @@ -219,14 +227,15 @@ TclpThreadCreate( EnterCriticalSection(&joinLock); *idPtr = 0; /* must initialize as Tcl_Thread is a pointer and - * on WIN64 sizeof void* != sizeof unsigned */ + * on WIN64 sizeof void* != sizeof unsigned + */ -#if defined(_MSC_VER) || defined(__MSVCRT__) - tHandle = (HANDLE) _beginthreadex(NULL, (unsigned)stackSize, +#if defined(_MSC_VER) || defined(__MSVCRT__) || defined(__BORLANDC__) + tHandle = (HANDLE) _beginthreadex(NULL, (unsigned) stackSize, (Tcl_ThreadCreateProc*) TclWinThreadStart, winThreadPtr, 0, (unsigned *)idPtr); #else - tHandle = CreateThread(NULL, (DWORD)stackSize, + tHandle = CreateThread(NULL, (DWORD) stackSize, TclWinThreadStart, winThreadPtr, 0, (LPDWORD)idPtr); #endif @@ -240,7 +249,7 @@ TclpThreadCreate( /* * The only purpose of this is to decrement the reference count so the - * OS resources will be reacquired when the thread closes. + * OS resources will be reaquired when the thread closes. */ CloseHandle(tHandle); @@ -299,7 +308,7 @@ TclpThreadExit( TclSignalExitThread(Tcl_GetCurrentThread(), status); LeaveCriticalSection(&joinLock); -#if defined(_MSC_VER) || defined(__MSVCRT__) +#if defined(_MSC_VER) || defined(__MSVCRT__) || defined(__BORLANDC__) _endthreadex((unsigned) status); #else ExitThread((DWORD) status); @@ -325,7 +334,7 @@ TclpThreadExit( Tcl_ThreadId Tcl_GetCurrentThread(void) { - return (Tcl_ThreadId)INT2PTR(GetCurrentThreadId()); + return (Tcl_ThreadId) INT2PTR(GetCurrentThreadId()); } /* @@ -350,7 +359,7 @@ Tcl_GetCurrentThread(void) void TclpInitLock(void) { - if (!initialized) { + if (!init) { /* * There is a fundamental race here that is solved by creating the * first Tcl interpreter in a single threaded environment. Once the @@ -358,10 +367,10 @@ TclpInitLock(void) * that create interpreters in parallel. */ - initialized = 1; + init = 1; InitializeCriticalSection(&joinLock); InitializeCriticalSection(&initLock); - InitializeCriticalSection(&globalLock); + InitializeCriticalSection(&masterLock); } EnterCriticalSection(&initLock); } @@ -392,27 +401,27 @@ TclpInitUnlock(void) /* *---------------------------------------------------------------------- * - * TclpGlobalLock + * TclpMasterLock * * This procedure is used to grab a lock that serializes creation of * mutexes, condition variables, and thread local storage keys. * * This lock must be different than the initLock because the initLock is - * held during creation of synchronization objects. + * held during creation of syncronization objects. * * Results: * None. * * Side effects: - * Acquire the global mutex. + * Acquire the master mutex. * *---------------------------------------------------------------------- */ void -TclpGlobalLock(void) +TclpMasterLock(void) { - if (!initialized) { + if (!init) { /* * There is a fundamental race here that is solved by creating the * first Tcl interpreter in a single threaded environment. Once the @@ -420,18 +429,18 @@ TclpGlobalLock(void) * that create interpreters in parallel. */ - initialized = 1; + init = 1; InitializeCriticalSection(&joinLock); InitializeCriticalSection(&initLock); - InitializeCriticalSection(&globalLock); + InitializeCriticalSection(&masterLock); } - EnterCriticalSection(&globalLock); + EnterCriticalSection(&masterLock); } /* *---------------------------------------------------------------------- * - * TclpGlobalUnlock + * TclpMasterUnlock * * This procedure is used to release a lock that serializes creation and * deletion of synchronization objects. @@ -440,15 +449,15 @@ TclpGlobalLock(void) * None. * * Side effects: - * Release the global mutex. + * Release the master mutex. * *---------------------------------------------------------------------- */ void -TclpGlobalUnlock(void) +TclpMasterUnlock(void) { - LeaveCriticalSection(&globalLock); + LeaveCriticalSection(&masterLock); } /* @@ -457,7 +466,7 @@ TclpGlobalUnlock(void) * Tcl_GetAllocMutex * * This procedure returns a pointer to a statically initialized mutex for - * use by the memory allocator. The allocator must use this lock, because + * use by the memory allocator. The alloctor must use this lock, because * all other locks are allocated... * * Results: @@ -473,7 +482,7 @@ TclpGlobalUnlock(void) Tcl_Mutex * Tcl_GetAllocMutex(void) { -#if TCL_THREADS +#ifdef TCL_THREADS if (!allocOnce) { InitializeCriticalSection(&allocLock.crit); allocOnce = 1; @@ -487,7 +496,7 @@ Tcl_GetAllocMutex(void) /* *---------------------------------------------------------------------- * - * TclFinalizeLock + * TclpFinalizeLock * * This procedure is used to destroy all private resources used in this * file. @@ -505,17 +514,17 @@ Tcl_GetAllocMutex(void) void TclFinalizeLock(void) { - TclpGlobalLock(); + MASTER_LOCK; DeleteCriticalSection(&joinLock); /* * Destroy the critical section that we are holding! */ - DeleteCriticalSection(&globalLock); - initialized = 0; + DeleteCriticalSection(&masterLock); + init = 0; -#if TCL_THREADS +#ifdef TCL_THREADS if (allocOnce) { DeleteCriticalSection(&allocLock.crit); allocOnce = 0; @@ -531,10 +540,10 @@ TclFinalizeLock(void) DeleteCriticalSection(&initLock); } -#if TCL_THREADS +#ifdef TCL_THREADS /* locally used prototype */ -static void FinalizeConditionEvent(void *data); +static void FinalizeConditionEvent(ClientData data); /* *---------------------------------------------------------------------- @@ -548,7 +557,7 @@ static void FinalizeConditionEvent(void *data); * None. * * Side effects: - * May block the current thread. The mutex is acquired when this returns. + * May block the current thread. The mutex is aquired when this returns. * *---------------------------------------------------------------------- */ @@ -560,19 +569,19 @@ Tcl_MutexLock( CRITICAL_SECTION *csPtr; if (*mutexPtr == NULL) { - TclpGlobalLock(); + MASTER_LOCK; /* - * Double inside global lock check to avoid a race. + * Double inside master lock check to avoid a race. */ if (*mutexPtr == NULL) { - csPtr = (CRITICAL_SECTION *)ckalloc(sizeof(CRITICAL_SECTION)); + csPtr = (CRITICAL_SECTION *) ckalloc(sizeof(CRITICAL_SECTION)); InitializeCriticalSection(csPtr); *mutexPtr = (Tcl_Mutex)csPtr; TclRememberMutex(mutexPtr); } - TclpGlobalUnlock(); + MASTER_UNLOCK; } csPtr = *((CRITICAL_SECTION **)mutexPtr); EnterCriticalSection(csPtr); @@ -628,7 +637,7 @@ TclpFinalizeMutex( if (csPtr != NULL) { DeleteCriticalSection(csPtr); - ckfree(csPtr); + ckfree((char *) csPtr); *mutexPtr = NULL; } } @@ -648,7 +657,7 @@ TclpFinalizeMutex( * None. * * Side effects: - * May block the current thread. The mutex is acquired when this returns. + * May block the current thread. The mutex is aquired when this returns. * Will allocate memory for a HANDLE and initialize this the first time * this Tcl_Condition is used. * @@ -659,7 +668,7 @@ void Tcl_ConditionWait( Tcl_Condition *condPtr, /* Really (WinCondition **) */ Tcl_Mutex *mutexPtr, /* Really (CRITICAL_SECTION **) */ - const Tcl_Time *timePtr) /* Timeout on waiting period */ + Tcl_Time *timePtr) /* Timeout on waiting period */ { WinCondition *winCondPtr; /* Per-condition queue head */ CRITICAL_SECTION *csPtr; /* Caller's Mutex, after casting */ @@ -674,57 +683,58 @@ Tcl_ConditionWait( */ if (tsdPtr->flags == WIN_THREAD_UNINIT) { - TclpGlobalLock(); + MASTER_LOCK; /* * Create the per-thread event and queue pointers. */ if (tsdPtr->flags == WIN_THREAD_UNINIT) { - tsdPtr->condEvent = CreateEventW(NULL, TRUE /* manual reset */, + tsdPtr->condEvent = CreateEvent(NULL, TRUE /* manual reset */, FALSE /* non signaled */, NULL); tsdPtr->nextPtr = NULL; tsdPtr->prevPtr = NULL; tsdPtr->flags = WIN_THREAD_RUNNING; doExit = 1; } - TclpGlobalUnlock(); + MASTER_UNLOCK; if (doExit) { /* * Create a per-thread exit handler to clean up the condEvent. We - * must be careful to do this outside the Global Lock because + * must be careful to do this outside the Master Lock because * Tcl_CreateThreadExitHandler uses its own ThreadSpecificData, - * and initializing that may drop back into the Global Lock. + * and initializing that may drop back into the Master Lock. */ - Tcl_CreateThreadExitHandler(FinalizeConditionEvent, tsdPtr); + Tcl_CreateThreadExitHandler(FinalizeConditionEvent, + (ClientData) tsdPtr); } } if (*condPtr == NULL) { - TclpGlobalLock(); + MASTER_LOCK; /* * Initialize the per-condition queue pointers and Mutex. */ if (*condPtr == NULL) { - winCondPtr = (WinCondition *)ckalloc(sizeof(WinCondition)); + winCondPtr = (WinCondition *) ckalloc(sizeof(WinCondition)); InitializeCriticalSection(&winCondPtr->condLock); winCondPtr->firstPtr = NULL; winCondPtr->lastPtr = NULL; *condPtr = (Tcl_Condition) winCondPtr; TclRememberCondition(condPtr); } - TclpGlobalUnlock(); + MASTER_UNLOCK; } csPtr = *((CRITICAL_SECTION **)mutexPtr); winCondPtr = *((WinCondition **)condPtr); if (timePtr == NULL) { wtime = INFINITE; } else { - wtime = (DWORD)timePtr->sec * 1000 + (DWORD)timePtr->usec / 1000; + wtime = timePtr->sec * 1000 + timePtr->usec / 1000; } /* @@ -759,8 +769,7 @@ Tcl_ConditionWait( while (!timeout && (tsdPtr->flags & WIN_THREAD_BLOCKED)) { ResetEvent(tsdPtr->condEvent); LeaveCriticalSection(&winCondPtr->condLock); - if (WaitForSingleObjectEx(tsdPtr->condEvent, wtime, - TRUE) == WAIT_TIMEOUT) { + if (WaitForSingleObject(tsdPtr->condEvent, wtime) == WAIT_TIMEOUT) { timeout = 1; } EnterCriticalSection(&winCondPtr->condLock); @@ -776,9 +785,9 @@ Tcl_ConditionWait( timeout = 0; } else { /* - * When dequeueing, we can leave the tsdPtr->nextPtr and + * When dequeuing, we can leave the tsdPtr->nextPtr and * tsdPtr->prevPtr with dangling pointers because they are - * reinitialized w/out reading them when the thread is enqueued + * reinitialilzed w/out reading them when the thread is enqueued * later. */ @@ -879,7 +888,7 @@ Tcl_ConditionNotify( static void FinalizeConditionEvent( - void *data) + ClientData data) { ThreadSpecificData *tsdPtr = (ThreadSpecificData *) data; @@ -895,7 +904,7 @@ FinalizeConditionEvent( * This procedure is invoked to clean up a condition variable. This is * only safe to call at the end of time. * - * This assumes the Global Lock is held. + * This assumes the Master Lock is held. * * Results: * None. @@ -921,7 +930,7 @@ TclpFinalizeCondition( if (winCondPtr != NULL) { DeleteCriticalSection(&winCondPtr->condLock); - ckfree(winCondPtr); + ckfree((char *) winCondPtr); *condPtr = NULL; } } @@ -937,9 +946,9 @@ TclpFinalizeCondition( Tcl_Mutex * TclpNewAllocMutex(void) { - allocMutex *lockPtr; + struct allocMutex *lockPtr; - lockPtr = (allocMutex *)malloc(sizeof(allocMutex)); + lockPtr = malloc(sizeof(struct allocMutex)); if (lockPtr == NULL) { Tcl_Panic("could not allocate lock"); } @@ -961,24 +970,24 @@ TclpFreeAllocMutex( free(lockPtr); } -void -TclpInitAllocCache(void) +void * +TclpGetAllocCache(void) { - /* - * We need to make sure that TclpFreeAllocCache is called on each - * thread that calls this, but only on threads that call this. - */ + VOID *result; + + if (!once) { + /* + * We need to make sure that TclpFreeAllocCache is called on each + * thread that calls this, but only on threads that call this. + */ - tlsKey = TlsAlloc(); - if (tlsKey == TLS_OUT_OF_INDEXES) { - Tcl_Panic("could not allocate thread local storage"); + tlsKey = TlsAlloc(); + once = 1; + if (tlsKey == TLS_OUT_OF_INDEXES) { + Tcl_Panic("could not allocate thread local storage"); + } } -} -void * -TclpGetAllocCache(void) -{ - void *result; result = TlsGetValue(tlsKey); if ((result == NULL) && (GetLastError() != NO_ERROR)) { Tcl_Panic("TlsGetValue failed from TclpGetAllocCache"); @@ -1005,10 +1014,8 @@ TclpFreeAllocCache( if (ptr != NULL) { /* - * Called by TclFinalizeThreadAlloc() and - * TclFinalizeThreadAllocThread() during Tcl_Finalize() or - * Tcl_FinalizeThread(). This function destroys the tsd key which - * stores allocator caches in thread local storage. + * Called by us in TclpFinalizeThreadData when a thread exits and + * destroys the tsd key which stores allocator caches. */ TclFreeAllocCache(ptr); @@ -1016,7 +1023,7 @@ TclpFreeAllocCache( if (!success) { Tcl_Panic("TlsSetValue failed from TclpFreeAllocCache"); } - } else { + } else if (once) { /* * Called by us in TclFinalizeThreadAlloc() during the library * finalization initiated from Tcl_Finalize() @@ -1026,64 +1033,11 @@ TclpFreeAllocCache( if (!success) { Tcl_Panic("TlsFree failed from TclpFreeAllocCache"); } - } -} -#endif /* USE_THREAD_ALLOC */ - - -void * -TclpThreadCreateKey(void) -{ - DWORD *key; - - key = (DWORD *)TclpSysAlloc(sizeof *key, 0); - if (key == NULL) { - Tcl_Panic("unable to allocate thread key!"); - } - - *key = TlsAlloc(); - - if (*key == TLS_OUT_OF_INDEXES) { - Tcl_Panic("unable to allocate thread-local storage"); + once = 0; /* reset for next time. */ } - return key; } - -void -TclpThreadDeleteKey( - void *keyPtr) -{ - DWORD *key = (DWORD *)keyPtr; - - if (!TlsFree(*key)) { - Tcl_Panic("unable to delete key"); - } - - TclpSysFree(keyPtr); -} - -void -TclpThreadSetGlobalTSD( - void *tsdKeyPtr, - void *ptr) -{ - DWORD *key = (DWORD *)tsdKeyPtr; - - if (!TlsSetValue(*key, ptr)) { - Tcl_Panic("unable to set global TSD value"); - } -} - -void * -TclpThreadGetGlobalTSD( - void *tsdKeyPtr) -{ - DWORD *key = (DWORD *)tsdKeyPtr; - - return TlsGetValue(*key); -} - +#endif /* USE_THREAD_ALLOC */ #endif /* TCL_THREADS */ /* |
