181 lines
4 KiB
C++
181 lines
4 KiB
C++
|
/*****************************************************************/
|
||
|
/** 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 <npcrit.h>
|
||
|
#include <npassert.h>
|
||
|
|
||
|
/*
|
||
|
* 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 */
|
||
|
|