You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
360 lines
6.8 KiB
360 lines
6.8 KiB
/*++
|
|
|
|
Copyright (c) 2001-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
locks.c
|
|
|
|
Abstract:
|
|
|
|
Domain Name System (DNS) Library.
|
|
|
|
Helpful locking routines. These are not DNS specific.
|
|
|
|
Author:
|
|
|
|
Jim Gilroy (jamesg) September 2001
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
#include "local.h"
|
|
|
|
// Note: this modules requires only windows.h.
|
|
// local.h is included only to allow precompiled header
|
|
|
|
#include <windows.h>
|
|
|
|
//
|
|
// Init wait spin interval
|
|
//
|
|
|
|
#define CS_PROTECTED_INIT_INTERLOCK_WAIT (5) // 5ms
|
|
|
|
//
|
|
// In progress flag
|
|
//
|
|
|
|
INT g_CsInitInProgress = FALSE;
|
|
|
|
|
|
|
|
|
|
VOID
|
|
InitializeCriticalSectionProtected(
|
|
OUT PCRITICAL_SECTION pCritSec,
|
|
IN OUT PINT pInitialized
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Protected init of CS.
|
|
|
|
Purpose here is to do dynamic "on-demand" CS init
|
|
avoiding need to do these in dll load for CS that are
|
|
not generally used.
|
|
|
|
Arguments:
|
|
|
|
pCs -- ptr to CS to init
|
|
|
|
pInitialized -- addr of init state flag; this flag must be
|
|
initialized to zero (by loader or dll startup routine).
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// protect CS init with interlock
|
|
// - first thread through does CS init
|
|
// - any others racing, are not released until init
|
|
// completes
|
|
//
|
|
|
|
while ( ! *pInitialized )
|
|
{
|
|
if ( InterlockedIncrement( &g_CsInitInProgress ) == 1 )
|
|
{
|
|
if ( !*pInitialized )
|
|
{
|
|
InitializeCriticalSection( pCritSec );
|
|
*pInitialized = TRUE;
|
|
}
|
|
InterlockedDecrement( &g_CsInitInProgress );
|
|
break;
|
|
}
|
|
|
|
InterlockedDecrement( &g_CsInitInProgress );
|
|
Sleep( CS_PROTECTED_INIT_INTERLOCK_WAIT );
|
|
}
|
|
|
|
//
|
|
// implementation note: "StartLocked" feature
|
|
//
|
|
// considered having a "StartLocked" feature for callers who
|
|
// want to follow the CS init with other initialization;
|
|
// however the only service we could provide that is different
|
|
// than calling EnterCriticalSection() after this function, is
|
|
// to make sure the CS init thread gets the lock first;
|
|
// but this only protects changes that outcome when two init
|
|
// threads are in an extremely close race AND the issue of
|
|
// which thread initialized the CS is irrelevant
|
|
//
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
// Timed lock functions
|
|
//
|
|
// This is critical section functionality with a time-limited wait.
|
|
//
|
|
// DCR: timed lock
|
|
//
|
|
// non-wait locking
|
|
// - have a wait count, for faster locking
|
|
// - interlock increment coming in,
|
|
// problem is would either have to ResetEvent() -- and
|
|
// still racing another thread
|
|
// or other threads would have to be able to ResetEvent()
|
|
// safely
|
|
//
|
|
// other alternative is have non-auto-reset event
|
|
// (global event for all locks or unique if desired for perf)
|
|
// everyone waiting releases, and checks their individual locks
|
|
// when leaving lock with waiters threads always SetEvent
|
|
//
|
|
|
|
|
|
#if 0
|
|
typedef struct _TimedLock
|
|
{
|
|
HANDLE hEvent;
|
|
DWORD ThreadId;
|
|
LONG RecursionCount;
|
|
DWORD WaitTime;
|
|
}
|
|
TIMED_LOCK, *PTIMED_LOCK;
|
|
|
|
#define TIMED_LOCK_DEFAULT_WAIT (0xf0000000)
|
|
#endif
|
|
|
|
|
|
|
|
DWORD
|
|
TimedLock_Initialize(
|
|
OUT PTIMED_LOCK pTimedLock,
|
|
IN DWORD DefaultWait
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Init timed lock.
|
|
|
|
Arguments:
|
|
|
|
pTimedLock -- ptr to timed lock
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful.
|
|
Error code on failure.
|
|
|
|
--*/
|
|
{
|
|
HANDLE hevent;
|
|
|
|
RtlZeroMemory( pTimedLock, sizeof(*pTimedLock) );
|
|
|
|
//
|
|
// event
|
|
// - autoreset (satisfies only one waiting thread when signalled)
|
|
// - starts signalled (open)
|
|
//
|
|
|
|
hevent = CreateEvent(
|
|
NULL, // default security
|
|
FALSE, // auto-reset
|
|
TRUE, // start signalled
|
|
NULL // unnamed
|
|
);
|
|
if ( !hevent )
|
|
{
|
|
return GetLastError();
|
|
}
|
|
|
|
pTimedLock->hEvent = hevent;
|
|
|
|
//
|
|
// default wait
|
|
//
|
|
|
|
pTimedLock->WaitTime = DefaultWait;
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
TimedLock_Cleanup(
|
|
OUT PTIMED_LOCK pTimedLock
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Cleanup timed lock.
|
|
|
|
Arguments:
|
|
|
|
pTimedLock -- ptr to timed lock
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
// close event
|
|
|
|
if ( pTimedLock->hEvent )
|
|
{
|
|
CloseHandle( pTimedLock->hEvent );
|
|
pTimedLock->hEvent = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
TimedLock_Enter(
|
|
IN OUT PTIMED_LOCK pTimedLock,
|
|
IN DWORD WaitTime
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Timed lock.
|
|
|
|
Arguments:
|
|
|
|
pTimedLock -- ptr to timed lock
|
|
|
|
WaitTime -- time to wait for lock
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
DWORD threadId;
|
|
DWORD result;
|
|
|
|
//
|
|
// check for recursion
|
|
//
|
|
|
|
threadId = GetCurrentThreadId();
|
|
|
|
if ( pTimedLock->ThreadId == threadId )
|
|
{
|
|
pTimedLock->RecursionCount++;
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// if non-wait -- bail
|
|
// - special case just to avoid going into wait
|
|
// and yielding timeslice
|
|
//
|
|
|
|
if ( WaitTime == 0 )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// wait for event to be signalled (open)
|
|
//
|
|
|
|
result = WaitForSingleObject(
|
|
pTimedLock->hEvent,
|
|
( WaitTime != TIMED_LOCK_DEFAULT_WAIT )
|
|
? WaitTime
|
|
: pTimedLock->WaitTime );
|
|
|
|
if ( result == WAIT_OBJECT_0 )
|
|
{
|
|
ASSERT( pTimedLock->RecursionCount == 0 );
|
|
ASSERT( pTimedLock->ThreadId == 0 );
|
|
|
|
pTimedLock->RecursionCount = 1;
|
|
pTimedLock->ThreadId = threadId;
|
|
return TRUE;
|
|
}
|
|
|
|
ASSERT( result == WAIT_TIMEOUT );
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
TimedLock_Leave(
|
|
IN OUT PTIMED_LOCK pTimedLock
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Leave timed lock
|
|
|
|
Arguments:
|
|
|
|
pTimedLock -- ptr to timed lock
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// validate thread ID
|
|
//
|
|
// note that with this check, it's then safe to decrement the count
|
|
// unchecked because it can never reach zero without thread ID
|
|
// being cleared -- barring non-functional manipulation of structure
|
|
//
|
|
|
|
if ( pTimedLock->ThreadId != GetCurrentThreadId() )
|
|
{
|
|
ASSERT( FALSE );
|
|
return;
|
|
}
|
|
ASSERT( pTimedLock->RecursionCount > 0 );
|
|
|
|
if ( --(pTimedLock->RecursionCount) == 0 )
|
|
{
|
|
pTimedLock->ThreadId = 0;
|
|
SetEvent( pTimedLock->hEvent );
|
|
}
|
|
}
|
|
|
|
//
|
|
// End of locks.c
|
|
//
|
|
|
|
|