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.

445 lines
10 KiB

  1. /*++
  2. Copyright(c) 1999-2000 Microsoft Corporation
  3. Module Name:
  4. brdgwait.c
  5. Abstract:
  6. Ethernet MAC level bridge.
  7. WAIT_REFCOUNT implementation
  8. Author:
  9. Mark Aiken
  10. Environment:
  11. Kernel mode driver
  12. Revision History:
  13. Feb 2000 - Original version
  14. --*/
  15. #define NDIS_MINIPORT_DRIVER
  16. #define NDIS50_MINIPORT 1
  17. #define NDIS_WDM 1
  18. #pragma warning( push, 3 )
  19. #include <ndis.h>
  20. #include <ntddk.h>
  21. #pragma warning( pop )
  22. #include "bridge.h"
  23. // ===========================================================================
  24. //
  25. // PUBLIC FUNCTIONS
  26. //
  27. // ===========================================================================
  28. VOID
  29. BrdgInitializeWaitRef(
  30. IN PWAIT_REFCOUNT pRefcount,
  31. IN BOOLEAN bResettable
  32. )
  33. /*++
  34. Routine Description:
  35. Initializes a wait-refcount
  36. Arguments:
  37. pRefcount The wait-refcount to initialize
  38. Return Value:
  39. none
  40. --*/
  41. {
  42. NdisInitializeEvent(&pRefcount->Event);
  43. pRefcount->Refcount = 0L;
  44. pRefcount->state = WaitRefEnabled;
  45. pRefcount->bResettable = bResettable;
  46. NdisAllocateSpinLock( &pRefcount->lock );
  47. // The event starts life signaled since the refcount starts at zero
  48. NdisSetEvent(&pRefcount->Event);
  49. }
  50. BOOLEAN
  51. BrdgIncrementWaitRef(
  52. IN PWAIT_REFCOUNT pRefcount
  53. )
  54. /*++
  55. Routine Description:
  56. Increments (acquires) a wait-refcount
  57. Arguments:
  58. pRefcount The wait-refcount to acquire
  59. Return Value:
  60. TRUE if the wait-refcount was successfully acquired, FALSE otherwise (this can happen
  61. if the wait-refcount has been shut down)
  62. --*/
  63. {
  64. BOOLEAN bSuccess;
  65. LONG Scratch = 0L;
  66. SAFEASSERT( pRefcount != NULL );
  67. NdisAcquireSpinLock( &pRefcount->lock );
  68. if( pRefcount->state == WaitRefEnabled )
  69. {
  70. SAFEASSERT( pRefcount->Refcount >= 0L );
  71. Scratch = ++pRefcount->Refcount;
  72. bSuccess = TRUE;
  73. }
  74. else
  75. {
  76. // The wait-refcount isn't enabled.
  77. SAFEASSERT( (pRefcount->state == WaitRefShutdown) ||
  78. (pRefcount->state == WaitRefShuttingDown) );
  79. bSuccess = FALSE;
  80. }
  81. if( bSuccess && (Scratch == 1L) )
  82. {
  83. // We incremented from zero. Reset the event.
  84. NdisResetEvent( &pRefcount->Event );
  85. }
  86. NdisReleaseSpinLock( &pRefcount->lock );
  87. return bSuccess;
  88. }
  89. VOID
  90. BrdgReincrementWaitRef(
  91. IN PWAIT_REFCOUNT pRefcount
  92. )
  93. /*++
  94. Routine Description:
  95. Re-increments a wait-refcount. This is guaranteed to succeed.
  96. It is only legal to use this if the caller has already acquired the
  97. wait-refcount (i.e., it is guaranteed that the refcount is > 0).
  98. CALLING THIS WITHOUT HAVING FIRST ACQUIRED THE WAIT-REFCOUNT WITH
  99. BrdgIncrementWaitRef IS A GREAT WAY TO SCREW UP YOUR CODE!
  100. Arguments:
  101. pRefcount The wait-refcount to re-acquire
  102. Return Value:
  103. none
  104. --*/
  105. {
  106. LONG Scratch;
  107. SAFEASSERT( pRefcount != NULL );
  108. NdisAcquireSpinLock( &pRefcount->lock );
  109. SAFEASSERT( (pRefcount->state == WaitRefEnabled) ||
  110. (pRefcount->state == WaitRefShuttingDown) );
  111. SAFEASSERT( pRefcount->Refcount >= 0L );
  112. Scratch = ++pRefcount->Refcount;
  113. NdisReleaseSpinLock( &pRefcount->lock );
  114. // Should be impossible for us to have incremented from zero to one
  115. SAFEASSERT( Scratch >= 2L );
  116. }
  117. VOID
  118. BrdgDecrementWaitRef(
  119. IN PWAIT_REFCOUNT pRefcount
  120. )
  121. /*++
  122. Routine Description:
  123. Decrements (releases) a previously incremented (acquired) wait-refcount.
  124. Arguments:
  125. pRefcount The wait-refcount to decrement
  126. Return Value:
  127. none
  128. --*/
  129. {
  130. LONG Scratch;
  131. SAFEASSERT( pRefcount != NULL );
  132. NdisAcquireSpinLock( &pRefcount->lock );
  133. SAFEASSERT( (pRefcount->state == WaitRefEnabled) ||
  134. (pRefcount->state == WaitRefShuttingDown) );
  135. Scratch = --pRefcount->Refcount;
  136. SAFEASSERT( Scratch >= 0L );
  137. if( Scratch == 0L )
  138. {
  139. // Signal anyone waiting for the refount to go to zero
  140. NdisSetEvent( &pRefcount->Event );
  141. }
  142. NdisReleaseSpinLock( &pRefcount->lock );
  143. }
  144. VOID
  145. BrdgBlockWaitRef(
  146. IN PWAIT_REFCOUNT pRefcount
  147. )
  148. /*++
  149. Routine Description:
  150. Puts the wait-refcount in the shutting-down state, making it impossible
  151. for the refcount to be incremented anymore.
  152. This can be used to block further acquires of the wait-refcount in
  153. advance of the shutdown process. Because shutting down the wait-refcount
  154. involves waiting for it to hit zero, this can be called at high IRQL to
  155. prevent further acquires of the wait-refcount in advance of a low-IRQL
  156. call to BrdgShutdownWaitRef().
  157. Arguments:
  158. pRefcount The wait-refcount to block
  159. Return Value:
  160. none
  161. --*/
  162. {
  163. SAFEASSERT( pRefcount != NULL );
  164. NdisAcquireSpinLock( &pRefcount->lock );
  165. if( pRefcount->state == WaitRefEnabled )
  166. {
  167. pRefcount->state = WaitRefShuttingDown;
  168. }
  169. else
  170. {
  171. // Do nothing; the wait-refcount is already
  172. // shutting down or is already shut down.
  173. SAFEASSERT( (pRefcount->state == WaitRefShutdown) ||
  174. (pRefcount->state == WaitRefShuttingDown) );
  175. }
  176. NdisReleaseSpinLock( &pRefcount->lock );
  177. }
  178. BOOLEAN
  179. BrdgShutdownWaitRefInternal(
  180. IN PWAIT_REFCOUNT pRefcount,
  181. IN BOOLEAN bRequireBlockedState
  182. )
  183. /*++
  184. Routine Description:
  185. Blocks new acquisitions of the wait-refcount and waits for the
  186. number of consumers to go to zero. If TRUE is returned, the caller
  187. can free any resources protected by the wait-refcount
  188. Arguments:
  189. pRefcount The wait-refcount to shut down
  190. bRequireBlockedState TRUE means the shutdown attempt will fail if
  191. the wait-refcount isn't in the shutting-down
  192. state
  193. Return Value:
  194. TRUE if the wait-refcount was shut down
  195. FALSE indicates that either the wait-refcount was reset or that
  196. another thread of execution had already shut down the wait-refcount.
  197. In both cases, the shared resources protected by the wait-refcount
  198. should NOT be freed.
  199. --*/
  200. {
  201. BOOLEAN bSuccess;
  202. SAFEASSERT(CURRENT_IRQL == PASSIVE_LEVEL);
  203. SAFEASSERT( pRefcount != NULL );
  204. NdisAcquireSpinLock( &pRefcount->lock );
  205. if( pRefcount->state == WaitRefEnabled )
  206. {
  207. if( bRequireBlockedState )
  208. {
  209. // Caller was expecting the refcount to be shutting
  210. // down. It must have been reset. That had better
  211. // be OK!
  212. SAFEASSERT( pRefcount->bResettable );
  213. bSuccess = FALSE;
  214. }
  215. else
  216. {
  217. // Caller doesn't require that the refcount be
  218. // shutting down. Transition to the shutting-down
  219. // state.
  220. pRefcount->state = WaitRefShuttingDown;
  221. bSuccess = TRUE;
  222. }
  223. }
  224. else if( pRefcount->state == WaitRefShutdown )
  225. {
  226. // Someone else already shut down the waitref.
  227. // This always means failure.
  228. SAFEASSERT( pRefcount->Refcount == 0L );
  229. bSuccess = FALSE;
  230. }
  231. else
  232. {
  233. // The refcount is already shutting down.
  234. // This is always goodness.
  235. SAFEASSERT( pRefcount->state == WaitRefShuttingDown );
  236. bSuccess = TRUE;
  237. }
  238. NdisReleaseSpinLock( &pRefcount->lock );
  239. if( bSuccess )
  240. {
  241. // Wait for all consumers to be done
  242. NdisWaitEvent( &pRefcount->Event, 0/*Wait forever*/ );
  243. NdisAcquireSpinLock( &pRefcount->lock );
  244. if( pRefcount->state == WaitRefEnabled )
  245. {
  246. // Someone reactivated us while we were sleeping.
  247. SAFEASSERT( pRefcount->bResettable );
  248. bSuccess = FALSE;
  249. }
  250. else if( pRefcount->state == WaitRefShutdown )
  251. {
  252. // Someone else shut us down while we were sleeping.
  253. SAFEASSERT( pRefcount->Refcount == 0L );
  254. bSuccess = FALSE;
  255. }
  256. else
  257. {
  258. if( pRefcount->Refcount == 0L )
  259. {
  260. // We completed the shutdown.
  261. pRefcount->state = WaitRefShutdown;
  262. bSuccess = TRUE;
  263. }
  264. else
  265. {
  266. // The waitref must have been reactivated and
  267. // shut down again while we were asleep!
  268. SAFEASSERT( pRefcount->bResettable );
  269. bSuccess = FALSE;
  270. }
  271. }
  272. NdisReleaseSpinLock( &pRefcount->lock );
  273. }
  274. return bSuccess;
  275. }
  276. BOOLEAN
  277. BrdgShutdownWaitRef(
  278. IN PWAIT_REFCOUNT pRefcount
  279. )
  280. {
  281. return BrdgShutdownWaitRefInternal( pRefcount, FALSE );
  282. }
  283. BOOLEAN
  284. BrdgShutdownBlockedWaitRef(
  285. IN PWAIT_REFCOUNT pRefcount
  286. )
  287. {
  288. return BrdgShutdownWaitRefInternal( pRefcount, TRUE );
  289. }
  290. VOID
  291. BrdgResetWaitRef(
  292. IN PWAIT_REFCOUNT pRefcount
  293. )
  294. /*++
  295. Routine Description:
  296. Re-enables a wait-refcount. Safe to call in any refcount
  297. state; if the refcount is shut down, this will re-enable it.
  298. If the refcount is in the middle of shutting down, this
  299. will flag it to be re-enabled if the code shutting down the
  300. waitref is using BrdgShutdownOrResetWaitRef().
  301. Arguments:
  302. pRefcount The wait-refcount
  303. Return Value:
  304. none
  305. --*/
  306. {
  307. SAFEASSERT( pRefcount != NULL );
  308. NdisAcquireSpinLock( &pRefcount->lock );
  309. if( pRefcount->state == WaitRefShutdown )
  310. {
  311. // The wait-refcount is completely shut down. We
  312. // can reactivate it.
  313. SAFEASSERT( pRefcount->Refcount == 0L );
  314. pRefcount->state = WaitRefEnabled;
  315. }
  316. else if( pRefcount->state == WaitRefShuttingDown )
  317. {
  318. if( pRefcount->bResettable )
  319. {
  320. // Re-enable. The call to BrdgShutdownWaitRef()
  321. // or BrdgShutdownBlockedWaitRef() will return
  322. // FALSE.
  323. pRefcount->state = WaitRefEnabled;
  324. }
  325. else
  326. {
  327. // Not allowed to reset this refcount when
  328. // in the middle of shutting down
  329. SAFEASSERT( FALSE );
  330. }
  331. }
  332. else
  333. {
  334. // The wait-refcount is already enabled
  335. SAFEASSERT( pRefcount->state == WaitRefEnabled );
  336. }
  337. NdisReleaseSpinLock( &pRefcount->lock );
  338. }