void TclFinalizeLock(void) { TclpMasterLock(); DeleteCriticalSection(&joinLock); /* * Destroy the critical section that we are holding! */ DeleteCriticalSection(&masterLock); initialized = 0; #ifdef TCL_THREADS if (allocOnce) { DeleteCriticalSection(&allocLock.crit); allocOnce = 0; } #endif LeaveCriticalSection(&initLock); /* * Destroy the critical section that we were holding. */ DeleteCriticalSection(&initLock); }
void Tcl_ConditionFinalize( Tcl_Condition *condPtr) { #ifdef TCL_THREADS TclpFinalizeCondition(condPtr); #endif TclpMasterLock(); ForgetSyncObject((char *) condPtr, &condRecord); TclpMasterUnlock(); }
void Tcl_MutexFinalize( Tcl_Mutex *mutexPtr) { #ifdef TCL_THREADS TclpFinalizeMutex(mutexPtr); #endif TclpMasterLock(); ForgetSyncObject((char *) mutexPtr, &mutexRecord); TclpMasterUnlock(); }
void TclMutexUnlockAndFinalize( Tcl_Mutex *mutexPtr) { Tcl_Mutex mutex; TclpMasterLock(); TclpMutexLock(); #ifdef TCL_THREADS mutex = *mutexPtr; *mutexPtr = NULL; /* Force it to be created again. */ Tcl_MutexUnlock(&mutex); TclpFinalizeMutex(&mutex); #endif ForgetSyncObject(mutexPtr, &mutexRecord); TclpMutexUnlock(); TclpMasterUnlock(); }
void Tcl_MutexLock( Tcl_Mutex *mutexPtr) /* The lock */ { CRITICAL_SECTION *csPtr; if (*mutexPtr == NULL) { TclpMasterLock(); /* * Double inside master lock check to avoid a race. */ if (*mutexPtr == NULL) { csPtr = ckalloc(sizeof(CRITICAL_SECTION)); InitializeCriticalSection(csPtr); *mutexPtr = (Tcl_Mutex)csPtr; TclRememberMutex(mutexPtr); } TclpMasterUnlock(); } csPtr = *((CRITICAL_SECTION **)mutexPtr); EnterCriticalSection(csPtr); }
void Tcl_ConditionWait( Tcl_Condition *condPtr, /* Really (WinCondition **) */ Tcl_Mutex *mutexPtr, /* Really (CRITICAL_SECTION **) */ const Tcl_Time *timePtr) /* Timeout on waiting period */ { WinCondition *winCondPtr; /* Per-condition queue head */ CRITICAL_SECTION *csPtr; /* Caller's Mutex, after casting */ DWORD wtime; /* Windows time value */ int timeout; /* True if we got a timeout */ int doExit = 0; /* True if we need to do exit setup */ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); /* * Self initialize the two parts of the condition. The per-condition and * per-thread parts need to be handled independently. */ if (tsdPtr->flags == WIN_THREAD_UNINIT) { TclpMasterLock(); /* * Create the per-thread event and queue pointers. */ if (tsdPtr->flags == WIN_THREAD_UNINIT) { tsdPtr->condEvent = CreateEvent(NULL, TRUE /* manual reset */, FALSE /* non signaled */, NULL); tsdPtr->nextPtr = NULL; tsdPtr->prevPtr = NULL; tsdPtr->flags = WIN_THREAD_RUNNING; doExit = 1; } TclpMasterUnlock(); if (doExit) { /* * Create a per-thread exit handler to clean up the condEvent. We * 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 Master Lock. */ Tcl_CreateThreadExitHandler(FinalizeConditionEvent, tsdPtr); } } if (*condPtr == NULL) { TclpMasterLock(); /* * Initialize the per-condition queue pointers and Mutex. */ if (*condPtr == NULL) { winCondPtr = ckalloc(sizeof(WinCondition)); InitializeCriticalSection(&winCondPtr->condLock); winCondPtr->firstPtr = NULL; winCondPtr->lastPtr = NULL; *condPtr = (Tcl_Condition) winCondPtr; TclRememberCondition(condPtr); } TclpMasterUnlock(); } csPtr = *((CRITICAL_SECTION **)mutexPtr); winCondPtr = *((WinCondition **)condPtr); if (timePtr == NULL) { wtime = INFINITE; } else { wtime = timePtr->sec * 1000 + timePtr->usec / 1000; } /* * Queue the thread on the condition, using the per-condition lock for * serialization. */ tsdPtr->flags = WIN_THREAD_BLOCKED; tsdPtr->nextPtr = NULL; EnterCriticalSection(&winCondPtr->condLock); tsdPtr->prevPtr = winCondPtr->lastPtr; /* A: */ winCondPtr->lastPtr = tsdPtr; if (tsdPtr->prevPtr != NULL) { tsdPtr->prevPtr->nextPtr = tsdPtr; } if (winCondPtr->firstPtr == NULL) { winCondPtr->firstPtr = tsdPtr; } /* * Unlock the caller's mutex and wait for the condition, or a timeout. * There is a minor issue here in that we don't count down the timeout if * we get notified, but another thread grabs the condition before we do. * In that race condition we'll wait again for the full timeout. Timed * waits are dubious anyway. Either you have the locking protocol wrong * and are masking a deadlock, or you are using conditions to pause your * thread. */ LeaveCriticalSection(csPtr); timeout = 0; while (!timeout && (tsdPtr->flags & WIN_THREAD_BLOCKED)) { ResetEvent(tsdPtr->condEvent); LeaveCriticalSection(&winCondPtr->condLock); if (WaitForSingleObjectEx(tsdPtr->condEvent, wtime, TRUE) == WAIT_TIMEOUT) { timeout = 1; } EnterCriticalSection(&winCondPtr->condLock); } /* * Be careful on timeouts because the signal might arrive right around the * time limit and someone else could have taken us off the queue. */ if (timeout) { if (tsdPtr->flags & WIN_THREAD_RUNNING) { timeout = 0; } else { /* * When dequeuing, we can leave the tsdPtr->nextPtr and * tsdPtr->prevPtr with dangling pointers because they are * reinitialilzed w/out reading them when the thread is enqueued * later. */ if (winCondPtr->firstPtr == tsdPtr) { winCondPtr->firstPtr = tsdPtr->nextPtr; } else { tsdPtr->prevPtr->nextPtr = tsdPtr->nextPtr; } if (winCondPtr->lastPtr == tsdPtr) { winCondPtr->lastPtr = tsdPtr->prevPtr; } else { tsdPtr->nextPtr->prevPtr = tsdPtr->prevPtr; } tsdPtr->flags = WIN_THREAD_RUNNING; } } LeaveCriticalSection(&winCondPtr->condLock); EnterCriticalSection(csPtr); }
void TclFinalizeSynchronization(void) { int i; void *blockPtr; Tcl_ThreadDataKey *keyPtr; #ifdef TCL_THREADS Tcl_Mutex *mutexPtr; Tcl_Condition *condPtr; TclpMasterLock(); #endif /* * If we're running unthreaded, the TSD blocks are simply stored inside * their thread data keys. Free them here. */ if (keyRecord.list != NULL) { for (i=0 ; i<keyRecord.num ; i++) { keyPtr = (Tcl_ThreadDataKey *) keyRecord.list[i]; blockPtr = (void *) *keyPtr; ckfree(blockPtr); } ckfree((char *) keyRecord.list); keyRecord.list = NULL; } keyRecord.max = 0; keyRecord.num = 0; #ifdef TCL_THREADS /* * Call thread storage master cleanup. */ TclFinalizeThreadStorage(); for (i=0 ; i<mutexRecord.num ; i++) { mutexPtr = (Tcl_Mutex *)mutexRecord.list[i]; if (mutexPtr != NULL) { TclpFinalizeMutex(mutexPtr); } } if (mutexRecord.list != NULL) { ckfree((char *) mutexRecord.list); mutexRecord.list = NULL; } mutexRecord.max = 0; mutexRecord.num = 0; for (i=0 ; i<condRecord.num ; i++) { condPtr = (Tcl_Condition *) condRecord.list[i]; if (condPtr != NULL) { TclpFinalizeCondition(condPtr); } } if (condRecord.list != NULL) { ckfree((char *) condRecord.list); condRecord.list = NULL; } condRecord.max = 0; condRecord.num = 0; TclpMasterUnlock(); #endif /* TCL_THREADS */ }