Source code of Windows XP (NT5)
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.

165 lines
5.5 KiB

  1. /***
  2. *initcrit.c - CRT wrapper for InitializeCriticalSectionAndSpinCount
  3. *
  4. * Copyright (c) 1999-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * Contains __crtInitCritSecAndSpinCount, a wrapper for
  8. * the Win32 API InitializeCriticalSectionAndSpinCount which is only
  9. * available on NT4SP3 or better.
  10. *
  11. * *** For internal use only ***
  12. *
  13. *Revision History:
  14. * 10-14-99 PML Created.
  15. * 02-20-01 PML __crtInitCritSecAndSpinCount now returns on failure
  16. * Also, call InitializeCriticalSectionAndSpinCount if
  17. * available, instead of calling InitializeCriticalSection
  18. * and then SetCriticalSectionSpinCount. (vs7#172586)
  19. * 04-24-01 PML Use GetModuleHandle, not LoadLibrary/FreeLibrary which
  20. * aren't safe during DLL_PROCESS_ATTACH (vs7#244210)
  21. *
  22. *******************************************************************************/
  23. #ifdef _MT
  24. #include <cruntime.h>
  25. #include <windows.h>
  26. #include <internal.h>
  27. #include <rterr.h>
  28. #include <stdlib.h>
  29. typedef
  30. BOOL
  31. (WINAPI * PFN_INIT_CRITSEC_AND_SPIN_COUNT) (
  32. PCRITICAL_SECTION lpCriticalSection,
  33. DWORD dwSpinCount
  34. );
  35. /***
  36. *void __crtInitCritSecNoSpinCount() - InitializeCriticalSectionAndSpinCount
  37. * wrapper
  38. *
  39. *Purpose:
  40. * For systems where the Win32 API InitializeCriticalSectionAndSpinCount
  41. * is unavailable, this is called instead. It just calls
  42. * InitializeCriticalSection and ignores the spin count.
  43. *
  44. *Entry:
  45. * PCRITICAL_SECTION lpCriticalSection - ptr to critical section
  46. * DWORD dwSpinCount - initial spin count setting
  47. *
  48. *Exit:
  49. * Always returns TRUE
  50. *
  51. *Exceptions:
  52. * InitializeCriticalSection can raise a STATUS_NO_MEMORY exception.
  53. *
  54. *******************************************************************************/
  55. static BOOL WINAPI __crtInitCritSecNoSpinCount (
  56. PCRITICAL_SECTION lpCriticalSection,
  57. DWORD dwSpinCount
  58. )
  59. {
  60. InitializeCriticalSection(lpCriticalSection);
  61. return TRUE;
  62. }
  63. /***
  64. *int __crtInitCritSecAndSpinCount() - initialize critical section
  65. *
  66. *Purpose:
  67. * Calls InitializeCriticalSectionAndSpinCount, if available, otherwise
  68. * InitializeCriticalSection. On multiprocessor systems, a spin count
  69. * should be used with critical sections, but the appropriate APIs are
  70. * only available on NT4SP3 or later.
  71. *
  72. * Also handles the out of memory condition which is possible with
  73. * InitializeCriticalSection[AndSpinCount].
  74. *
  75. *Entry:
  76. * PCRITICAL_SECTION lpCriticalSection - ptr to critical section
  77. * DWORD dwSpinCount - initial spin count setting
  78. *
  79. *Exit:
  80. * Returns FALSE and sets Win32 last-error code to ERROR_NOT_ENOUGH_MEMORY
  81. * if InitializeCriticalSection[AndSpinCount] fails.
  82. *
  83. *Exceptions:
  84. *
  85. *******************************************************************************/
  86. int __cdecl __crtInitCritSecAndSpinCount (
  87. PCRITICAL_SECTION lpCriticalSection,
  88. DWORD dwSpinCount
  89. )
  90. {
  91. static PFN_INIT_CRITSEC_AND_SPIN_COUNT __crtInitCritSecAndSpinCount = NULL;
  92. int ret;
  93. if (__crtInitCritSecAndSpinCount == NULL) {
  94. /*
  95. * First time through, see if InitializeCriticalSectionAndSpinCount
  96. * is available. If not, use a wrapper over InitializeCriticalSection
  97. * instead.
  98. */
  99. if (_osplatform == VER_PLATFORM_WIN32_WINDOWS) {
  100. /*
  101. * Win98 and WinME export InitializeCriticalSectionAndSpinCount,
  102. * but it is non-functional (it should return a BOOL, but is
  103. * VOID instead, returning a useless return value). Use the
  104. * dummy API instead.
  105. */
  106. __crtInitCritSecAndSpinCount = __crtInitCritSecNoSpinCount;
  107. }
  108. else {
  109. HINSTANCE hKernel32 = GetModuleHandle("kernel32.dll");
  110. if (hKernel32 != NULL) {
  111. __crtInitCritSecAndSpinCount = (PFN_INIT_CRITSEC_AND_SPIN_COUNT)
  112. GetProcAddress(hKernel32,
  113. "InitializeCriticalSectionAndSpinCount");
  114. if (__crtInitCritSecAndSpinCount == NULL) {
  115. /*
  116. * InitializeCriticalSectionAndSpinCount not available,
  117. * use dummy API
  118. */
  119. __crtInitCritSecAndSpinCount = __crtInitCritSecNoSpinCount;
  120. }
  121. }
  122. else {
  123. /*
  124. * GetModuleHandle failed (should never happen),
  125. * use dummy API
  126. */
  127. __crtInitCritSecAndSpinCount = __crtInitCritSecNoSpinCount;
  128. }
  129. }
  130. }
  131. __try {
  132. /*
  133. * Call the real InitializeCriticalSectionAndSpinCount, or the
  134. * wrapper which just calls InitializeCriticalSection if the newer
  135. * API is not available.
  136. */
  137. ret = __crtInitCritSecAndSpinCount(lpCriticalSection, dwSpinCount);
  138. }
  139. __except (EXCEPTION_EXECUTE_HANDLER) {
  140. /*
  141. * Initialization failed by raising an exception, which is probably
  142. * STATUS_NO_MEMORY. It is not safe to set the CRT errno to ENOMEM,
  143. * since the per-thread data may not yet exist. Instead, set the Win32
  144. * error which can be mapped to ENOMEM later.
  145. */
  146. if (GetExceptionCode() == STATUS_NO_MEMORY) {
  147. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  148. }
  149. ret = FALSE;
  150. }
  151. return ret;
  152. }
  153. #endif /* _MT */