2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel
4 * FILE: ntoskrnl/ex/rundown.c
5 * PURPOSE: Rundown and Cache-Aware Rundown Protection
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
10 /* INCLUDES *****************************************************************/
14 #include <internal/debug.h>
16 /* FUNCTIONS *****************************************************************/
19 * @name ExfAcquireRundownProtection
22 * The ExfAcquireRundownProtection routine acquires rundown protection for
23 * the specified descriptor.
26 * Pointer to a rundown reference descriptor.
28 * @return TRUE if access to the protected structure was granted, FALSE otherwise.
30 * @remarks Callers of ExfAcquireRundownProtection can be running at any IRQL.
35 ExfAcquireRundownProtection(IN PEX_RUNDOWN_REF RunRef
)
37 ULONG_PTR Value
= RunRef
->Count
, NewValue
;
39 /* Make sure a rundown is not active */
40 if (Value
& EX_RUNDOWN_ACTIVE
) return FALSE
;
42 /* Loop until successfully incremented the counter */
46 NewValue
= Value
+ EX_RUNDOWN_COUNT_INC
;
48 /* Change the value */
49 Value
= ExpChangeRundown(RunRef
, NewValue
, Value
);
50 if (Value
== NewValue
) return TRUE
;
52 /* Make sure a rundown is not active */
53 if (Value
& EX_RUNDOWN_ACTIVE
) return FALSE
;
58 * @name ExfAcquireRundownProtectionEx
61 * The ExfAcquireRundownProtectionEx routine acquires multiple rundown
62 * protection references for the specified descriptor.
65 * Pointer to a rundown reference descriptor.
68 * Number of times to reference the descriptor.
70 * @return TRUE if access to the protected structure was granted, FALSE otherwise.
72 * @remarks Callers of ExfAcquireRundownProtectionEx can be running at any IRQL.
77 ExfAcquireRundownProtectionEx(IN PEX_RUNDOWN_REF RunRef
,
80 ULONG_PTR Value
= RunRef
->Count
, NewValue
;
82 /* Make sure a rundown is not active */
83 if (Value
& EX_RUNDOWN_ACTIVE
) return FALSE
;
85 /* Convert the count to our internal representation */
86 Count
<<= EX_RUNDOWN_COUNT_SHIFT
;
88 /* Loop until successfully incremented the counter */
92 NewValue
= Value
+ Count
;
94 /* Change the value */
95 Value
= ExpChangeRundown(RunRef
, NewValue
, Value
);
96 if (Value
== NewValue
) return TRUE
;
98 /* Make sure a rundown is not active */
99 if (Value
& EX_RUNDOWN_ACTIVE
) return FALSE
;
104 * @name ExfInitializeRundownProtection
107 * The ExfInitializeRundownProtection routine initializes a rundown
108 * protection descriptor.
111 * Pointer to a rundown reference descriptor.
115 * @remarks Callers of ExfInitializeRundownProtection can be running at any IRQL.
120 ExfInitializeRundownProtection(IN PEX_RUNDOWN_REF RunRef
)
122 /* Set the count to zero */
127 * @name ExfReInitializeRundownProtection
130 * The ExfReInitializeRundownProtection routine re-initializes a rundown
131 * protection descriptor.
134 * Pointer to a rundown reference descriptor.
138 * @remarks Callers of ExfReInitializeRundownProtection can be running at any IRQL.
143 ExfReInitializeRundownProtection(IN PEX_RUNDOWN_REF RunRef
)
148 ASSERT((RunRef
->Count
& EX_RUNDOWN_ACTIVE
) != 0);
150 /* Reset the count */
151 InterlockedExchange((PLONG
)&RunRef
->Count
, 0);
155 * @name ExfRundownCompleted
158 * The ExfRundownCompleted routine completes the rundown of the specified
159 * descriptor by setting the active bit.
162 * Pointer to a rundown reference descriptor.
166 * @remarks Callers of ExfRundownCompleted must be running at IRQL <= APC_LEVEL.
171 ExfRundownCompleted(IN PEX_RUNDOWN_REF RunRef
)
176 ASSERT((RunRef
->Count
& EX_RUNDOWN_ACTIVE
) != 0);
178 /* Mark the counter as active */
179 InterlockedExchange((PLONG
)&RunRef
->Count
, EX_RUNDOWN_ACTIVE
);
183 * @name ExfReleaseRundownProtection
186 * The ExfReleaseRundownProtection routine releases the rundown protection
187 * reference for the specified descriptor.
190 * Pointer to a rundown reference descriptor.
194 * @remarks Callers of ExfReleaseRundownProtection can be running at any IRQL.
199 ExfReleaseRundownProtection(IN PEX_RUNDOWN_REF RunRef
)
201 ULONG_PTR Value
= RunRef
->Count
, NewValue
;
202 PEX_RUNDOWN_WAIT_BLOCK WaitBlock
;
204 /* Check if rundown is not active */
205 if (!(Value
& EX_RUNDOWN_ACTIVE
))
207 /* Loop until successfully incremented the counter */
211 ASSERT((Value
>= EX_RUNDOWN_COUNT_INC
) || (KeNumberProcessors
> 1));
213 /* Get the new value */
214 NewValue
= Value
- EX_RUNDOWN_COUNT_INC
;
216 /* Change the value */
217 Value
= ExpChangeRundown(RunRef
, NewValue
, Value
);
218 if (Value
== NewValue
) return;
220 /* Loop again if we're still not active */
221 if (Value
& EX_RUNDOWN_ACTIVE
) break;
225 /* Get the wait block */
226 WaitBlock
= (PEX_RUNDOWN_WAIT_BLOCK
)(Value
& ~EX_RUNDOWN_ACTIVE
);
227 ASSERT((WaitBlock
->Count
> 0) || (KeNumberProcessors
> 1));
229 /* Remove the one count */
230 if (InterlockedExchangeAddSizeT(&WaitBlock
->Count
, -1))
232 /* We're down to 0 now, so signal the event */
233 KeSetEvent(&WaitBlock
->RundownEvent
, IO_NO_INCREMENT
, FALSE
);
238 * @name ExfReleaseRundownProtectionEx
241 * The ExfReleaseRundownProtectionEx routine releases multiple rundown
242 * protection references for the specified descriptor.
245 * Pointer to a rundown reference descriptor.
248 * Number of times to dereference the descriptor.
252 * @remarks Callers of ExfAcquireRundownProtectionEx can be running at any IRQL.
257 ExfReleaseRundownProtectionEx(IN PEX_RUNDOWN_REF RunRef
,
260 ULONG_PTR Value
= RunRef
->Count
, NewValue
;
261 PEX_RUNDOWN_WAIT_BLOCK WaitBlock
;
263 /* Check if rundown is not active */
264 if (!(Value
& EX_RUNDOWN_ACTIVE
))
266 /* Loop until successfully incremented the counter */
270 ASSERT((Value
>= EX_RUNDOWN_COUNT_INC
* Count
) || (KeNumberProcessors
> 1));
272 /* Get the new value */
273 NewValue
= Value
- (Count
* EX_RUNDOWN_COUNT_INC
);
275 /* Change the value */
276 Value
= ExpChangeRundown(RunRef
, NewValue
, Value
);
277 if (Value
== NewValue
) return;
279 /* Loop again if we're still not active */
280 if (Value
& EX_RUNDOWN_ACTIVE
) break;
284 /* Get the wait block */
285 WaitBlock
= (PEX_RUNDOWN_WAIT_BLOCK
)(Value
& ~EX_RUNDOWN_ACTIVE
);
286 ASSERT((WaitBlock
->Count
>= Count
) || (KeNumberProcessors
> 1));
288 /* Remove the count */
289 if (InterlockedExchangeAddSizeT(WaitBlock
->Count
, -(LONG
)Count
) ==
292 /* We're down to 0 now, so signal the event */
293 KeSetEvent(&WaitBlock
->RundownEvent
, IO_NO_INCREMENT
, FALSE
);
298 * @name ExfWaitForRundownProtectionRelease
301 * The ExfWaitForRundownProtectionRelease routine waits until the specified
302 * rundown descriptor has been released.
305 * Pointer to a rundown reference descriptor.
309 * @remarks Callers of ExfWaitForRundownProtectionRelease must be running
310 * at IRQL <= APC_LEVEL.
315 ExfWaitForRundownProtectionRelease(IN PEX_RUNDOWN_REF RunRef
)
317 ULONG_PTR Value
, Count
, NewValue
;
318 EX_RUNDOWN_WAIT_BLOCK WaitBlock
;
319 PEX_RUNDOWN_WAIT_BLOCK WaitBlockPointer
;
323 /* Set the active bit */
324 Value
= ExpChangeRundown(RunRef
, EX_RUNDOWN_ACTIVE
, 0);
325 if ((Value
== 0) || (Value
== EX_RUNDOWN_ACTIVE
)) return;
327 /* No event for now */
329 WaitBlockPointer
= (PEX_RUNDOWN_WAIT_BLOCK
)((ULONG_PTR
)&WaitBlock
|
332 /* Start waitblock set loop */
336 Count
= Value
>> EX_RUNDOWN_COUNT_SHIFT
;
338 /* If the count is over one or we don't have en event yet, create it */
341 /* Initialize the event */
342 KeInitializeEvent(&WaitBlock
.RundownEvent
,
346 /* Set the pointer */
347 Event
= &WaitBlock
.RundownEvent
;
351 WaitBlock
.Count
= Count
;
353 /* Now set the pointer */
354 NewValue
= ExpChangeRundown(RunRef
, PtrToUlong(WaitBlockPointer
), Value
);
355 if (NewValue
== Value
) break;
359 ASSERT((Value
& EX_RUNDOWN_ACTIVE
) == 0);
362 /* If the count was 0, we're done */
365 /* Wait for whoever needs to release to notify us */
366 KeWaitForSingleObject(Event
, Executive
, KernelMode
, FALSE
, NULL
);
367 ASSERT(WaitBlock
.Count
== 0);
370 /* FIXME: STUBS **************************************************************/
373 * @unimplemented NT5.2
377 ExfAcquireRundownProtectionCacheAware(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware
)
379 DBG_UNREFERENCED_PARAMETER(RunRefCacheAware
);
385 * @unimplemented NT5.2
389 ExfAcquireRundownProtectionCacheAwareEx(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware
,
392 DBG_UNREFERENCED_PARAMETER(RunRefCacheAware
);
393 DBG_UNREFERENCED_PARAMETER(Count
);
399 * @unimplemented NT5.2
403 ExfReleaseRundownProtectionCacheAware(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware
)
405 DBG_UNREFERENCED_PARAMETER(RunRefCacheAware
);
410 * @unimplemented NT5.2
414 ExfReleaseRundownProtectionCacheAwareEx(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware
,
417 DBG_UNREFERENCED_PARAMETER(RunRefCacheAware
);
418 DBG_UNREFERENCED_PARAMETER(Count
);
423 * @unimplemented NT5.2
427 ExfWaitForRundownProtectionReleaseCacheAware(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware
)
429 DBG_UNREFERENCED_PARAMETER(RunRefCacheAware
);
434 * @unimplemented NT5.2
438 ExfRundownCompletedCacheAware(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware
)
440 DBG_UNREFERENCED_PARAMETER(RunRefCacheAware
);
445 * @unimplemented NT5.2
449 ExfReInitializeRundownProtectionCacheAware(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware
)
451 DBG_UNREFERENCED_PARAMETER(RunRefCacheAware
);
456 * @unimplemented NT5.2
458 PEX_RUNDOWN_REF_CACHE_AWARE
460 ExAllocateCacheAwareRundownProtection(IN POOL_TYPE PoolType
,
463 DBG_UNREFERENCED_PARAMETER(PoolType
);
464 DBG_UNREFERENCED_PARAMETER(Tag
);
470 * @unimplemented NT5.2
474 ExFreeCacheAwareRundownProtection(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware
)
476 DBG_UNREFERENCED_PARAMETER(RunRefCacheAware
);
481 * @unimplemented NT5.2
485 ExInitializeRundownProtectionCacheAware(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware
,
488 DBG_UNREFERENCED_PARAMETER(RunRefCacheAware
);
489 DBG_UNREFERENCED_PARAMETER(Count
);
494 * @unimplemented NT5.2
498 ExSizeOfRundownProtectionCacheAware(VOID
)