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

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. win32oneshot.c
  5. Abstract:
  6. one time initialization
  7. per process or per user or per machine
  8. optionally thread safe, if per process
  9. get code out of dllmain(dll_process_attach)
  10. get code out of setup (eliminate setup) (like, don't populate registry with defaults)
  11. Author:
  12. Jay Krell (JayKrell) August 2001
  13. design per discussion with Michael Grier (MGrier)
  14. Revision History:
  15. --*/
  16. #include <nt.h>
  17. #include <ntrtl.h>
  18. #include <nturtl.h>
  19. #include "windows.h"
  20. #include "win32oneshot.h"
  21. #include "fusionntdll.h"
  22. #define INTERLOCKED_INCREMENT_OR_INCREMENT(f, pl) ((f) ? InterlockedIncrement(pl) : (++*pl))
  23. //
  24. // internally, we may expand this signature to allow for per-oneshot spinlocks or critical sections
  25. //
  26. VOID
  27. Win32OneShot_TakeLock(
  28. PVOID* LockCookie
  29. )
  30. {
  31. FusionpLdrLockLoaderLock(0, NULL, LockCookie);
  32. }
  33. VOID
  34. Win32OneShot_ReleaseLock(
  35. PVOID LockCookie
  36. )
  37. {
  38. if (LockCookie != NULL)
  39. FusionpLdrUnlockLoaderLock(0, LockCookie);
  40. }
  41. VOID
  42. Win32OneShot_GetDetailedResults(
  43. ULONG Flags,
  44. LONG NumberOfSuccesses,
  45. LONG NumberOfFailures,
  46. PWIN32_ONE_SHOT_CALL_OUT out
  47. )
  48. {
  49. if (NumberOfSuccesses != 0)
  50. Flags |= WIN32_ONE_SHOT_CALL_FLAG_OUT_ANY_CALLBACKS_SUCCEEDED;
  51. if (NumberOfSuccesses > 1)
  52. Flags |= WIN32_ONE_SHOT_CALL_FLAG_OUT_MULTIPLE_CALLBACKS_SUCCEEDED;
  53. if (NumberOfFailures != 0)
  54. Flags |= WIN32_ONE_SHOT_CALL_FLAG_OUT_ANY_CALLBACKS_FAILED;
  55. if (NumberOfFailures > 1)
  56. Flags |= WIN32_ONE_SHOT_CALL_FLAG_OUT_MULTIPLE_CALLBACKS_FAILED;
  57. out->dwFlagsOut |= Flags | WIN32_ONE_SHOT_CALL_FLAG_OUT_DETAILED_RESULTS_VALID;
  58. }
  59. BOOL
  60. WINAPI
  61. Win32OneShotW(
  62. PWIN32_ONE_SHOT_CALL_IN in,
  63. PWIN32_ONE_SHOT_CALL_OUT out
  64. )
  65. {
  66. BOOL Result = FALSE;
  67. PVOID LockCookie;
  68. LONG NumberOfSuccesses = 0;
  69. LONG NumberOfFailures = 0;
  70. ULONG OutFlags;
  71. BOOL NeedInterlocked;
  72. BOOL ExactlyOnce;
  73. BOOL RetryOnFailure = FALSE;
  74. BOOL WantDetailedResults;
  75. BOOL Done = FALSE;
  76. PWIN32_ONE_SHOT_OPAQUE_STATIC_STATE StaticState;
  77. ULONG FlagsIn;
  78. //
  79. // optimize the usual case a lot
  80. //
  81. StaticState = in->lpOpaqueStaticState;
  82. FlagsIn = in->dwFlagsIn;
  83. WantDetailedResults = ((FlagsIn & WIN32_ONE_SHOT_CALL_FLAG_IN_ALWAYS_WANT_DETAILED_RESULTS) != 0);
  84. NumberOfSuccesses = StaticState->u.s.WinbasePrivate_NumberOfSuccesses;
  85. if (NumberOfSuccesses != 0) {
  86. Done = TRUE;
  87. Result = TRUE;
  88. }
  89. else {
  90. NumberOfFailures = StaticState->u.s.WinbasePrivate_NumberOfFailures;
  91. RetryOnFailure = ((FlagsIn & WIN32_ONE_SHOT_CALL_FLAG_IN_RETRY_ON_FAILURE) != 0);
  92. if (NumberOfFailures != 0 && !RetryOnFailure) {
  93. Result = FALSE;
  94. Done = TRUE;
  95. }
  96. }
  97. if (Done) {
  98. out->dwUserDefinedDisposition = in->lpOpaqueStaticState->u.s.WinbasePrivate_UserDefinedDisposition;
  99. if (WantDetailedResults) {
  100. out->dwFlagsOut = 0;
  101. Win32OneShot_GetDetailedResults(
  102. 0,
  103. NumberOfSuccesses,
  104. Result ? StaticState->u.s.WinbasePrivate_NumberOfFailures : NumberOfFailures,
  105. out
  106. );
  107. }
  108. return Result;
  109. }
  110. //
  111. // now some slower cases
  112. //
  113. Result = FALSE;
  114. LockCookie = 0;
  115. OutFlags = 0;
  116. // parameter validation here
  117. // out init
  118. out->dwFlagsOut = 0;
  119. out->dwUserDefinedDisposition = 0;
  120. ExactlyOnce = ((FlagsIn & WIN32_ONE_SHOT_CALL_FLAG_IN_EXACTLY_ONCE) != 0);
  121. if (ExactlyOnce) {
  122. NeedInterlocked = FALSE;
  123. Win32OneShot_TakeLock(&LockCookie);
  124. } else {
  125. NeedInterlocked = TRUE;
  126. }
  127. __try {
  128. if (ExactlyOnce) {
  129. NumberOfFailures = StaticState->u.s.WinbasePrivate_NumberOfFailures;
  130. NumberOfSuccesses = StaticState->u.s.WinbasePrivate_NumberOfSuccesses;
  131. if (NumberOfSuccesses != 0) {
  132. out->dwUserDefinedDisposition = StaticState->u.s.WinbasePrivate_UserDefinedDisposition;
  133. Result = TRUE;
  134. goto Exit;
  135. }
  136. if (NumberOfFailures != 0 && !RetryOnFailure) {
  137. goto Exit;
  138. }
  139. }
  140. Result = (*in->lpfnUserDefinedInitializer)(in, out);
  141. OutFlags |= WIN32_ONE_SHOT_CALL_FLAG_OUT_THIS_TIME_RAN_CALLBACK;
  142. if (NumberOfFailures != 0)
  143. OutFlags |= WIN32_ONE_SHOT_CALL_FLAG_OUT_THIS_TIME_RAN_CALLBACK_RETRIED;
  144. if (Result) {
  145. OutFlags |= WIN32_ONE_SHOT_CALL_FLAG_OUT_THIS_TIME_CALLBACK_SUCCEEDED;
  146. NumberOfSuccesses = INTERLOCKED_INCREMENT_OR_INCREMENT(NeedInterlocked, &StaticState->u.s.WinbasePrivate_NumberOfSuccesses);
  147. } else {
  148. OutFlags |= WIN32_ONE_SHOT_CALL_FLAG_OUT_THIS_TIME_CALLBACK_FAILED;
  149. NumberOfFailures = INTERLOCKED_INCREMENT_OR_INCREMENT(NeedInterlocked, &StaticState->u.s.WinbasePrivate_NumberOfFailures);
  150. }
  151. Exit:
  152. Win32OneShot_GetDetailedResults(
  153. OutFlags,
  154. NumberOfSuccesses,
  155. NumberOfFailures,
  156. out
  157. );
  158. } __finally {
  159. Win32OneShot_ReleaseLock(LockCookie);
  160. }
  161. return Result;
  162. }
  163. BOOL
  164. WINAPI
  165. Win32EnterOneShotW(
  166. ULONG Flags,
  167. PWIN32_ONE_SHOT_OPAQUE_STATIC_STATE Oneshot
  168. )
  169. {
  170. ULONG NumberOfEntries;
  171. ULONG OnceFlag;
  172. PVOID LockCookie = NULL;
  173. BOOL Result = FALSE;
  174. __try {
  175. if ((Flags & ~(
  176. WIN32_ENTER_ONE_SHOT_FLAG_EXACTLY_ONCE
  177. | WIN32_ENTER_ONE_SHOT_FLAG_AT_LEAST_ONCE)) != 0) {
  178. goto InvalidParameter;
  179. }
  180. OnceFlag = Flags & (WIN32_ENTER_ONE_SHOT_FLAG_EXACTLY_ONCE | WIN32_ENTER_ONE_SHOT_FLAG_AT_LEAST_ONCE);
  181. switch (OnceFlag)
  182. {
  183. default:
  184. goto InvalidParameter;
  185. case WIN32_ENTER_ONE_SHOT_FLAG_EXACTLY_ONCE:
  186. case WIN32_ENTER_ONE_SHOT_FLAG_AT_LEAST_ONCE:
  187. break;
  188. }
  189. NumberOfEntries = Oneshot->u.s2.WinbasePrivate_NumberOfEntries;
  190. if (NumberOfEntries != 0) {
  191. while (!Oneshot->u.s2.WinbasePrivate_Done) {
  192. /* SPIN */
  193. Sleep(0);
  194. }
  195. SetLastError(NO_ERROR);
  196. Result = FALSE;
  197. __leave;
  198. }
  199. if (OnceFlag == WIN32_ENTER_ONE_SHOT_FLAG_AT_LEAST_ONCE) {
  200. InterlockedIncrement(&Oneshot->u.s2.WinbasePrivate_NumberOfEntries);
  201. Result = TRUE;
  202. __leave;
  203. }
  204. Win32OneShot_TakeLock(&LockCookie);
  205. NumberOfEntries = Oneshot->u.s2.WinbasePrivate_NumberOfEntries;
  206. if (NumberOfEntries != 0) {
  207. Win32OneShot_ReleaseLock(LockCookie);
  208. LockCookie = NULL;
  209. /* ASSERT(Oneshot->u.s2.WinbasePrivate_Done); */
  210. while (!Oneshot->u.s2.WinbasePrivate_Done) {
  211. /* SPIN */
  212. Sleep(0);
  213. }
  214. SetLastError(NO_ERROR);
  215. Result = FALSE;
  216. __leave;
  217. }
  218. Oneshot->u.s2.WinbasePrivate_LockCookie = LockCookie;
  219. LockCookie = NULL;
  220. Result = TRUE;
  221. Oneshot->u.s2.WinbasePrivate_NumberOfEntries += 1;
  222. __leave;
  223. InvalidParameter:
  224. SetLastError(ERROR_INVALID_PARAMETER);
  225. Result = FALSE;
  226. __leave;
  227. } __finally {
  228. Win32OneShot_ReleaseLock(LockCookie);
  229. }
  230. return Result;
  231. }
  232. VOID
  233. WINAPI
  234. Win32LeaveOneShotW(
  235. DWORD Flags,
  236. PWIN32_ONE_SHOT_OPAQUE_STATIC_STATE Oneshot
  237. )
  238. {
  239. Win32OneShot_ReleaseLock(Oneshot->u.s2.WinbasePrivate_LockCookie);
  240. Oneshot->u.s2.WinbasePrivate_LockCookie = NULL;
  241. Oneshot->u.s2.WinbasePrivate_Done |= 1;
  242. }