Leaked source code of windows server 2003
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.
 
 
 
 
 
 

277 lines
8.0 KiB

/*++
Copyright (c) Microsoft Corporation. All rights reserved.
Module Name:
win32oneshot.c
Abstract:
one time initialization
per process or per user or per machine
optionally thread safe, if per process
get code out of dllmain(dll_process_attach)
get code out of setup (eliminate setup) (like, don't populate registry with defaults)
Author:
Jay Krell (JayKrell) August 2001
design per discussion with Michael Grier (MGrier)
Revision History:
--*/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include "windows.h"
#include "win32oneshot.h"
#include "fusionntdll.h"
#define INTERLOCKED_INCREMENT_OR_INCREMENT(f, pl) ((f) ? InterlockedIncrement(pl) : (++*pl))
//
// internally, we may expand this signature to allow for per-oneshot spinlocks or critical sections
//
VOID
Win32OneShot_TakeLock(
PVOID* LockCookie
)
{
FusionpLdrLockLoaderLock(0, NULL, LockCookie);
}
VOID
Win32OneShot_ReleaseLock(
PVOID LockCookie
)
{
if (LockCookie != NULL)
FusionpLdrUnlockLoaderLock(0, LockCookie);
}
VOID
Win32OneShot_GetDetailedResults(
ULONG Flags,
LONG NumberOfSuccesses,
LONG NumberOfFailures,
PWIN32_ONE_SHOT_CALL_OUT out
)
{
if (NumberOfSuccesses != 0)
Flags |= WIN32_ONE_SHOT_CALL_FLAG_OUT_ANY_CALLBACKS_SUCCEEDED;
if (NumberOfSuccesses > 1)
Flags |= WIN32_ONE_SHOT_CALL_FLAG_OUT_MULTIPLE_CALLBACKS_SUCCEEDED;
if (NumberOfFailures != 0)
Flags |= WIN32_ONE_SHOT_CALL_FLAG_OUT_ANY_CALLBACKS_FAILED;
if (NumberOfFailures > 1)
Flags |= WIN32_ONE_SHOT_CALL_FLAG_OUT_MULTIPLE_CALLBACKS_FAILED;
out->dwFlagsOut |= Flags | WIN32_ONE_SHOT_CALL_FLAG_OUT_DETAILED_RESULTS_VALID;
}
BOOL
WINAPI
Win32OneShotW(
PWIN32_ONE_SHOT_CALL_IN in,
PWIN32_ONE_SHOT_CALL_OUT out
)
{
BOOL Result = FALSE;
PVOID LockCookie;
LONG NumberOfSuccesses = 0;
LONG NumberOfFailures = 0;
ULONG OutFlags;
BOOL NeedInterlocked;
BOOL ExactlyOnce;
BOOL RetryOnFailure = FALSE;
BOOL WantDetailedResults;
BOOL Done = FALSE;
PWIN32_ONE_SHOT_OPAQUE_STATIC_STATE StaticState;
ULONG FlagsIn;
//
// optimize the usual case a lot
//
StaticState = in->lpOpaqueStaticState;
FlagsIn = in->dwFlagsIn;
WantDetailedResults = ((FlagsIn & WIN32_ONE_SHOT_CALL_FLAG_IN_ALWAYS_WANT_DETAILED_RESULTS) != 0);
NumberOfSuccesses = StaticState->u.s.WinbasePrivate_NumberOfSuccesses;
if (NumberOfSuccesses != 0) {
Done = TRUE;
Result = TRUE;
}
else {
NumberOfFailures = StaticState->u.s.WinbasePrivate_NumberOfFailures;
RetryOnFailure = ((FlagsIn & WIN32_ONE_SHOT_CALL_FLAG_IN_RETRY_ON_FAILURE) != 0);
if (NumberOfFailures != 0 && !RetryOnFailure) {
Result = FALSE;
Done = TRUE;
}
}
if (Done) {
out->dwUserDefinedDisposition = in->lpOpaqueStaticState->u.s.WinbasePrivate_UserDefinedDisposition;
if (WantDetailedResults) {
out->dwFlagsOut = 0;
Win32OneShot_GetDetailedResults(
0,
NumberOfSuccesses,
Result ? StaticState->u.s.WinbasePrivate_NumberOfFailures : NumberOfFailures,
out
);
}
return Result;
}
//
// now some slower cases
//
Result = FALSE;
LockCookie = 0;
OutFlags = 0;
// parameter validation here
// out init
out->dwFlagsOut = 0;
out->dwUserDefinedDisposition = 0;
ExactlyOnce = ((FlagsIn & WIN32_ONE_SHOT_CALL_FLAG_IN_EXACTLY_ONCE) != 0);
if (ExactlyOnce) {
NeedInterlocked = FALSE;
Win32OneShot_TakeLock(&LockCookie);
} else {
NeedInterlocked = TRUE;
}
__try {
if (ExactlyOnce) {
NumberOfFailures = StaticState->u.s.WinbasePrivate_NumberOfFailures;
NumberOfSuccesses = StaticState->u.s.WinbasePrivate_NumberOfSuccesses;
if (NumberOfSuccesses != 0) {
out->dwUserDefinedDisposition = StaticState->u.s.WinbasePrivate_UserDefinedDisposition;
Result = TRUE;
goto Exit;
}
if (NumberOfFailures != 0 && !RetryOnFailure) {
goto Exit;
}
}
Result = (*in->lpfnUserDefinedInitializer)(in, out);
OutFlags |= WIN32_ONE_SHOT_CALL_FLAG_OUT_THIS_TIME_RAN_CALLBACK;
if (NumberOfFailures != 0)
OutFlags |= WIN32_ONE_SHOT_CALL_FLAG_OUT_THIS_TIME_RAN_CALLBACK_RETRIED;
if (Result) {
OutFlags |= WIN32_ONE_SHOT_CALL_FLAG_OUT_THIS_TIME_CALLBACK_SUCCEEDED;
NumberOfSuccesses = INTERLOCKED_INCREMENT_OR_INCREMENT(NeedInterlocked, &StaticState->u.s.WinbasePrivate_NumberOfSuccesses);
} else {
OutFlags |= WIN32_ONE_SHOT_CALL_FLAG_OUT_THIS_TIME_CALLBACK_FAILED;
NumberOfFailures = INTERLOCKED_INCREMENT_OR_INCREMENT(NeedInterlocked, &StaticState->u.s.WinbasePrivate_NumberOfFailures);
}
Exit:
Win32OneShot_GetDetailedResults(
OutFlags,
NumberOfSuccesses,
NumberOfFailures,
out
);
} __finally {
Win32OneShot_ReleaseLock(LockCookie);
}
return Result;
}
BOOL
WINAPI
Win32EnterOneShotW(
ULONG Flags,
PWIN32_ONE_SHOT_OPAQUE_STATIC_STATE Oneshot
)
{
ULONG NumberOfEntries;
ULONG OnceFlag;
PVOID LockCookie = NULL;
BOOL Result = FALSE;
__try {
if ((Flags & ~(
WIN32_ENTER_ONE_SHOT_FLAG_EXACTLY_ONCE
| WIN32_ENTER_ONE_SHOT_FLAG_AT_LEAST_ONCE)) != 0) {
goto InvalidParameter;
}
OnceFlag = Flags & (WIN32_ENTER_ONE_SHOT_FLAG_EXACTLY_ONCE | WIN32_ENTER_ONE_SHOT_FLAG_AT_LEAST_ONCE);
switch (OnceFlag)
{
default:
goto InvalidParameter;
case WIN32_ENTER_ONE_SHOT_FLAG_EXACTLY_ONCE:
case WIN32_ENTER_ONE_SHOT_FLAG_AT_LEAST_ONCE:
break;
}
NumberOfEntries = Oneshot->u.s2.WinbasePrivate_NumberOfEntries;
if (NumberOfEntries != 0) {
while (!Oneshot->u.s2.WinbasePrivate_Done) {
/* SPIN */
Sleep(0);
}
SetLastError(NO_ERROR);
Result = FALSE;
__leave;
}
if (OnceFlag == WIN32_ENTER_ONE_SHOT_FLAG_AT_LEAST_ONCE) {
InterlockedIncrement(&Oneshot->u.s2.WinbasePrivate_NumberOfEntries);
Result = TRUE;
__leave;
}
Win32OneShot_TakeLock(&LockCookie);
NumberOfEntries = Oneshot->u.s2.WinbasePrivate_NumberOfEntries;
if (NumberOfEntries != 0) {
Win32OneShot_ReleaseLock(LockCookie);
LockCookie = NULL;
/* ASSERT(Oneshot->u.s2.WinbasePrivate_Done); */
while (!Oneshot->u.s2.WinbasePrivate_Done) {
/* SPIN */
Sleep(0);
}
SetLastError(NO_ERROR);
Result = FALSE;
__leave;
}
Oneshot->u.s2.WinbasePrivate_LockCookie = LockCookie;
LockCookie = NULL;
Result = TRUE;
Oneshot->u.s2.WinbasePrivate_NumberOfEntries += 1;
__leave;
InvalidParameter:
SetLastError(ERROR_INVALID_PARAMETER);
Result = FALSE;
__leave;
} __finally {
Win32OneShot_ReleaseLock(LockCookie);
}
return Result;
}
VOID
WINAPI
Win32LeaveOneShotW(
DWORD Flags,
PWIN32_ONE_SHOT_OPAQUE_STATIC_STATE Oneshot
)
{
Win32OneShot_ReleaseLock(Oneshot->u.s2.WinbasePrivate_LockCookie);
Oneshot->u.s2.WinbasePrivate_LockCookie = NULL;
Oneshot->u.s2.WinbasePrivate_Done |= 1;
}