166 lines
5.5 KiB
C
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 */
|