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.

360 lines
6.8 KiB

  1. /*++
  2. Copyright (c) 2001-2001 Microsoft Corporation
  3. Module Name:
  4. locks.c
  5. Abstract:
  6. Domain Name System (DNS) Library.
  7. Helpful locking routines. These are not DNS specific.
  8. Author:
  9. Jim Gilroy (jamesg) September 2001
  10. Revision History:
  11. --*/
  12. #include "local.h"
  13. // Note: this modules requires only windows.h.
  14. // local.h is included only to allow precompiled header
  15. #include <windows.h>
  16. //
  17. // Init wait spin interval
  18. //
  19. #define CS_PROTECTED_INIT_INTERLOCK_WAIT (5) // 5ms
  20. //
  21. // In progress flag
  22. //
  23. INT g_CsInitInProgress = FALSE;
  24. VOID
  25. InitializeCriticalSectionProtected(
  26. OUT PCRITICAL_SECTION pCritSec,
  27. IN OUT PINT pInitialized
  28. )
  29. /*++
  30. Routine Description:
  31. Protected init of CS.
  32. Purpose here is to do dynamic "on-demand" CS init
  33. avoiding need to do these in dll load for CS that are
  34. not generally used.
  35. Arguments:
  36. pCs -- ptr to CS to init
  37. pInitialized -- addr of init state flag; this flag must be
  38. initialized to zero (by loader or dll startup routine).
  39. Return Value:
  40. None
  41. --*/
  42. {
  43. //
  44. // protect CS init with interlock
  45. // - first thread through does CS init
  46. // - any others racing, are not released until init
  47. // completes
  48. //
  49. while ( ! *pInitialized )
  50. {
  51. if ( InterlockedIncrement( &g_CsInitInProgress ) == 1 )
  52. {
  53. if ( !*pInitialized )
  54. {
  55. InitializeCriticalSection( pCritSec );
  56. *pInitialized = TRUE;
  57. }
  58. InterlockedDecrement( &g_CsInitInProgress );
  59. break;
  60. }
  61. InterlockedDecrement( &g_CsInitInProgress );
  62. Sleep( CS_PROTECTED_INIT_INTERLOCK_WAIT );
  63. }
  64. //
  65. // implementation note: "StartLocked" feature
  66. //
  67. // considered having a "StartLocked" feature for callers who
  68. // want to follow the CS init with other initialization;
  69. // however the only service we could provide that is different
  70. // than calling EnterCriticalSection() after this function, is
  71. // to make sure the CS init thread gets the lock first;
  72. // but this only protects changes that outcome when two init
  73. // threads are in an extremely close race AND the issue of
  74. // which thread initialized the CS is irrelevant
  75. //
  76. }
  77. //
  78. // Timed lock functions
  79. //
  80. // This is critical section functionality with a time-limited wait.
  81. //
  82. // DCR: timed lock
  83. //
  84. // non-wait locking
  85. // - have a wait count, for faster locking
  86. // - interlock increment coming in,
  87. // problem is would either have to ResetEvent() -- and
  88. // still racing another thread
  89. // or other threads would have to be able to ResetEvent()
  90. // safely
  91. //
  92. // other alternative is have non-auto-reset event
  93. // (global event for all locks or unique if desired for perf)
  94. // everyone waiting releases, and checks their individual locks
  95. // when leaving lock with waiters threads always SetEvent
  96. //
  97. #if 0
  98. typedef struct _TimedLock
  99. {
  100. HANDLE hEvent;
  101. DWORD ThreadId;
  102. LONG RecursionCount;
  103. DWORD WaitTime;
  104. }
  105. TIMED_LOCK, *PTIMED_LOCK;
  106. #define TIMED_LOCK_DEFAULT_WAIT (0xf0000000)
  107. #endif
  108. DWORD
  109. TimedLock_Initialize(
  110. OUT PTIMED_LOCK pTimedLock,
  111. IN DWORD DefaultWait
  112. )
  113. /*++
  114. Routine Description:
  115. Init timed lock.
  116. Arguments:
  117. pTimedLock -- ptr to timed lock
  118. Return Value:
  119. ERROR_SUCCESS if successful.
  120. Error code on failure.
  121. --*/
  122. {
  123. HANDLE hevent;
  124. RtlZeroMemory( pTimedLock, sizeof(*pTimedLock) );
  125. //
  126. // event
  127. // - autoreset (satisfies only one waiting thread when signalled)
  128. // - starts signalled (open)
  129. //
  130. hevent = CreateEvent(
  131. NULL, // default security
  132. FALSE, // auto-reset
  133. TRUE, // start signalled
  134. NULL // unnamed
  135. );
  136. if ( !hevent )
  137. {
  138. return GetLastError();
  139. }
  140. pTimedLock->hEvent = hevent;
  141. //
  142. // default wait
  143. //
  144. pTimedLock->WaitTime = DefaultWait;
  145. return NO_ERROR;
  146. }
  147. VOID
  148. TimedLock_Cleanup(
  149. OUT PTIMED_LOCK pTimedLock
  150. )
  151. /*++
  152. Routine Description:
  153. Cleanup timed lock.
  154. Arguments:
  155. pTimedLock -- ptr to timed lock
  156. Return Value:
  157. None
  158. --*/
  159. {
  160. // close event
  161. if ( pTimedLock->hEvent )
  162. {
  163. CloseHandle( pTimedLock->hEvent );
  164. pTimedLock->hEvent = NULL;
  165. }
  166. }
  167. BOOL
  168. TimedLock_Enter(
  169. IN OUT PTIMED_LOCK pTimedLock,
  170. IN DWORD WaitTime
  171. )
  172. /*++
  173. Routine Description:
  174. Timed lock.
  175. Arguments:
  176. pTimedLock -- ptr to timed lock
  177. WaitTime -- time to wait for lock
  178. Return Value:
  179. None
  180. --*/
  181. {
  182. DWORD threadId;
  183. DWORD result;
  184. //
  185. // check for recursion
  186. //
  187. threadId = GetCurrentThreadId();
  188. if ( pTimedLock->ThreadId == threadId )
  189. {
  190. pTimedLock->RecursionCount++;
  191. return TRUE;
  192. }
  193. //
  194. // if non-wait -- bail
  195. // - special case just to avoid going into wait
  196. // and yielding timeslice
  197. //
  198. if ( WaitTime == 0 )
  199. {
  200. return FALSE;
  201. }
  202. //
  203. // wait for event to be signalled (open)
  204. //
  205. result = WaitForSingleObject(
  206. pTimedLock->hEvent,
  207. ( WaitTime != TIMED_LOCK_DEFAULT_WAIT )
  208. ? WaitTime
  209. : pTimedLock->WaitTime );
  210. if ( result == WAIT_OBJECT_0 )
  211. {
  212. ASSERT( pTimedLock->RecursionCount == 0 );
  213. ASSERT( pTimedLock->ThreadId == 0 );
  214. pTimedLock->RecursionCount = 1;
  215. pTimedLock->ThreadId = threadId;
  216. return TRUE;
  217. }
  218. ASSERT( result == WAIT_TIMEOUT );
  219. return FALSE;
  220. }
  221. VOID
  222. TimedLock_Leave(
  223. IN OUT PTIMED_LOCK pTimedLock
  224. )
  225. /*++
  226. Routine Description:
  227. Leave timed lock
  228. Arguments:
  229. pTimedLock -- ptr to timed lock
  230. Return Value:
  231. None
  232. --*/
  233. {
  234. //
  235. // validate thread ID
  236. //
  237. // note that with this check, it's then safe to decrement the count
  238. // unchecked because it can never reach zero without thread ID
  239. // being cleared -- barring non-functional manipulation of structure
  240. //
  241. if ( pTimedLock->ThreadId != GetCurrentThreadId() )
  242. {
  243. ASSERT( FALSE );
  244. return;
  245. }
  246. ASSERT( pTimedLock->RecursionCount > 0 );
  247. if ( --(pTimedLock->RecursionCount) == 0 )
  248. {
  249. pTimedLock->ThreadId = 0;
  250. SetEvent( pTimedLock->hEvent );
  251. }
  252. }
  253. //
  254. // End of locks.c
  255. //