windows-nt/Source/XPSP1/NT/base/crts/crtw32/misc/initcrit.c
2020-09-26 16:20:57 +08:00

166 lines
5.5 KiB
C

/***
*initcrit.c - CRT wrapper for InitializeCriticalSectionAndSpinCount
*
* Copyright (c) 1999-2001, Microsoft Corporation. All rights reserved.
*
*Purpose:
* Contains __crtInitCritSecAndSpinCount, a wrapper for
* the Win32 API InitializeCriticalSectionAndSpinCount which is only
* available on NT4SP3 or better.
*
* *** For internal use only ***
*
*Revision History:
* 10-14-99 PML Created.
* 02-20-01 PML __crtInitCritSecAndSpinCount now returns on failure
* Also, call InitializeCriticalSectionAndSpinCount if
* available, instead of calling InitializeCriticalSection
* and then SetCriticalSectionSpinCount. (vs7#172586)
* 04-24-01 PML Use GetModuleHandle, not LoadLibrary/FreeLibrary which
* aren't safe during DLL_PROCESS_ATTACH (vs7#244210)
*
*******************************************************************************/
#ifdef _MT
#include <cruntime.h>
#include <windows.h>
#include <internal.h>
#include <rterr.h>
#include <stdlib.h>
typedef
BOOL
(WINAPI * PFN_INIT_CRITSEC_AND_SPIN_COUNT) (
PCRITICAL_SECTION lpCriticalSection,
DWORD dwSpinCount
);
/***
*void __crtInitCritSecNoSpinCount() - InitializeCriticalSectionAndSpinCount
* wrapper
*
*Purpose:
* For systems where the Win32 API InitializeCriticalSectionAndSpinCount
* is unavailable, this is called instead. It just calls
* InitializeCriticalSection and ignores the spin count.
*
*Entry:
* PCRITICAL_SECTION lpCriticalSection - ptr to critical section
* DWORD dwSpinCount - initial spin count setting
*
*Exit:
* Always returns TRUE
*
*Exceptions:
* InitializeCriticalSection can raise a STATUS_NO_MEMORY exception.
*
*******************************************************************************/
static BOOL WINAPI __crtInitCritSecNoSpinCount (
PCRITICAL_SECTION lpCriticalSection,
DWORD dwSpinCount
)
{
InitializeCriticalSection(lpCriticalSection);
return TRUE;
}
/***
*int __crtInitCritSecAndSpinCount() - initialize critical section
*
*Purpose:
* Calls InitializeCriticalSectionAndSpinCount, if available, otherwise
* InitializeCriticalSection. On multiprocessor systems, a spin count
* should be used with critical sections, but the appropriate APIs are
* only available on NT4SP3 or later.
*
* Also handles the out of memory condition which is possible with
* InitializeCriticalSection[AndSpinCount].
*
*Entry:
* PCRITICAL_SECTION lpCriticalSection - ptr to critical section
* DWORD dwSpinCount - initial spin count setting
*
*Exit:
* Returns FALSE and sets Win32 last-error code to ERROR_NOT_ENOUGH_MEMORY
* if InitializeCriticalSection[AndSpinCount] fails.
*
*Exceptions:
*
*******************************************************************************/
int __cdecl __crtInitCritSecAndSpinCount (
PCRITICAL_SECTION lpCriticalSection,
DWORD dwSpinCount
)
{
static PFN_INIT_CRITSEC_AND_SPIN_COUNT __crtInitCritSecAndSpinCount = NULL;
int ret;
if (__crtInitCritSecAndSpinCount == NULL) {
/*
* First time through, see if InitializeCriticalSectionAndSpinCount
* is available. If not, use a wrapper over InitializeCriticalSection
* instead.
*/
if (_osplatform == VER_PLATFORM_WIN32_WINDOWS) {
/*
* Win98 and WinME export InitializeCriticalSectionAndSpinCount,
* but it is non-functional (it should return a BOOL, but is
* VOID instead, returning a useless return value). Use the
* dummy API instead.
*/
__crtInitCritSecAndSpinCount = __crtInitCritSecNoSpinCount;
}
else {
HINSTANCE hKernel32 = GetModuleHandle("kernel32.dll");
if (hKernel32 != NULL) {
__crtInitCritSecAndSpinCount = (PFN_INIT_CRITSEC_AND_SPIN_COUNT)
GetProcAddress(hKernel32,
"InitializeCriticalSectionAndSpinCount");
if (__crtInitCritSecAndSpinCount == NULL) {
/*
* InitializeCriticalSectionAndSpinCount not available,
* use dummy API
*/
__crtInitCritSecAndSpinCount = __crtInitCritSecNoSpinCount;
}
}
else {
/*
* GetModuleHandle failed (should never happen),
* use dummy API
*/
__crtInitCritSecAndSpinCount = __crtInitCritSecNoSpinCount;
}
}
}
__try {
/*
* Call the real InitializeCriticalSectionAndSpinCount, or the
* wrapper which just calls InitializeCriticalSection if the newer
* API is not available.
*/
ret = __crtInitCritSecAndSpinCount(lpCriticalSection, dwSpinCount);
}
__except (EXCEPTION_EXECUTE_HANDLER) {
/*
* Initialization failed by raising an exception, which is probably
* STATUS_NO_MEMORY. It is not safe to set the CRT errno to ENOMEM,
* since the per-thread data may not yet exist. Instead, set the Win32
* error which can be mapped to ENOMEM later.
*/
if (GetExceptionCode() == STATUS_NO_MEMORY) {
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
}
ret = FALSE;
}
return ret;
}
#endif /* _MT */