/*****************************************************************/ /** Microsoft Windows for Workgroups **/ /** Copyright (C) Microsoft Corp., 1993-1994 **/ /*****************************************************************/ /* npcrit.c -- Implementation of critical section classes. * * History: * 11/01/93 gregj Created */ #include "npcommon.h" #include #include /* * Very simple interlock routines, used to stop race conditions when * initializing and de-initializing critical sections. Do NOT use * these for anything other than infrequent extremely short-term locks, * since WaitForInterlock contains a spin loop with a millisecond delay! */ BYTE InterlockedSet(volatile BYTE *pByte) { BYTE bRet; _asm { mov edi, pByte mov al, 1 xchg [edi], al /* store non-zero value, get what was there before */ mov bRet, al } return bRet; } void WaitForInterlock(volatile BYTE *pByte) { for (;;) { BYTE bAlreadyOwned = InterlockedSet(pByte); /* attempt to grab the interlock */ if (!bAlreadyOwned) /* is someone else in there? */ break; /* nope, we now own it */ Sleep(1); /* yield to whomever owns it, then try again */ } } void ReleaseInterlock(volatile BYTE *pByte) { *pByte = 0; /* clear the interlock to release others */ } #if 0 // Remove CRITSEC code but keep for a while before deleting. /******************************************************************* NAME: CRITSEC::Init SYNOPSIS: Initializes a global critical section object ENTRY: pszName - name for the critical section EXIT: No return value NOTES: Currently pszName is not used; it will be used for named mutexes later. HISTORY: gregj 11/01/93 Created ********************************************************************/ void CRITSEC::Init(char *pszName) { WaitForInterlock(&_bInterlock); if (!_fInitialized) { ::InitializeCriticalSection(&_critsec); #ifdef DEBUG _wClaimCount = 0; #endif _fInitialized = 1; } ReleaseInterlock(&_bInterlock); _cClients++; } /******************************************************************* NAME: CRITSEC::Term SYNOPSIS: Cleans up resources allocated for a critical section ENTRY: No parameters EXIT: No return value NOTES: This function should be callled at process attach. It will take care of making sure it only deletes the critical section when the last process using it calls Term(). HISTORY: gregj 11/01/93 Created ********************************************************************/ void CRITSEC::Term() { WaitForInterlock(&_bInterlock); BOOL fShouldCleanUp = (--_cClients == 0); if (fShouldCleanUp) { ::DeleteCriticalSection(&_critsec); _fInitialized = 0; } ReleaseInterlock(&_bInterlock); } #ifdef DEBUG /* in retail, these are inline */ /******************************************************************* NAME: CRITSEC::Enter SYNOPSIS: Enters a critical section ENTRY: No parameters EXIT: No return value; critical section is owned by the calling thread NOTES: This function is private, and is invoked indirectly by the friend class TAKE_CRITSEC. HISTORY: gregj 11/01/93 Created ********************************************************************/ void CRITSEC::Enter() { #ifdef DEBUG UIASSERT(_fInitialized != 0); #endif ::EnterCriticalSection(&_critsec); #ifdef DEBUG _wClaimCount++; #endif } /******************************************************************* NAME: CRITSEC::Leave SYNOPSIS: Leaves a critical section ENTRY: No parameters EXIT: No return value; critical section is released NOTES: This function is private, and is invoked indirectly by the friend class TAKE_CRITSEC. HISTORY: gregj 11/01/93 Created ********************************************************************/ void CRITSEC::Leave() { #ifdef DEBUG UIASSERT(_fInitialized != 0); UIASSERT(_wClaimCount > 0); _wClaimCount--; #endif ::LeaveCriticalSection(&_critsec); } #endif /* DEBUG */ #endif /* 0 */