Older binutils don't understand qword ptr
[reactos.git] / reactos / ntoskrnl / ex / rundown.c
1 /*
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)
7 * Thomas Weidenmueller
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <internal/debug.h>
15
16 /* FUNCTIONS *****************************************************************/
17
18 /*++
19 * @name ExfAcquireRundownProtection
20 * @implemented NT5.1
21 *
22 * The ExfAcquireRundownProtection routine acquires rundown protection for
23 * the specified descriptor.
24 *
25 * @param RunRef
26 * Pointer to a rundown reference descriptor.
27 *
28 * @return TRUE if access to the protected structure was granted, FALSE otherwise.
29 *
30 * @remarks Callers of ExfAcquireRundownProtection can be running at any IRQL.
31 *
32 *--*/
33 BOOLEAN
34 FASTCALL
35 ExfAcquireRundownProtection(IN PEX_RUNDOWN_REF RunRef)
36 {
37 ULONG_PTR Value = RunRef->Count, NewValue;
38
39 /* Make sure a rundown is not active */
40 if (Value & EX_RUNDOWN_ACTIVE) return FALSE;
41
42 /* Loop until successfully incremented the counter */
43 for (;;)
44 {
45 /* Add a reference */
46 NewValue = Value + EX_RUNDOWN_COUNT_INC;
47
48 /* Change the value */
49 Value = ExpChangeRundown(RunRef, NewValue, Value);
50 if (Value == NewValue) return TRUE;
51
52 /* Make sure a rundown is not active */
53 if (Value & EX_RUNDOWN_ACTIVE) return FALSE;
54 }
55 }
56
57 /*++
58 * @name ExfAcquireRundownProtectionEx
59 * @implemented NT5.2
60 *
61 * The ExfAcquireRundownProtectionEx routine acquires multiple rundown
62 * protection references for the specified descriptor.
63 *
64 * @param RunRef
65 * Pointer to a rundown reference descriptor.
66 *
67 * @param Count
68 * Number of times to reference the descriptor.
69 *
70 * @return TRUE if access to the protected structure was granted, FALSE otherwise.
71 *
72 * @remarks Callers of ExfAcquireRundownProtectionEx can be running at any IRQL.
73 *
74 *--*/
75 BOOLEAN
76 FASTCALL
77 ExfAcquireRundownProtectionEx(IN PEX_RUNDOWN_REF RunRef,
78 IN ULONG Count)
79 {
80 ULONG_PTR Value = RunRef->Count, NewValue;
81
82 /* Make sure a rundown is not active */
83 if (Value & EX_RUNDOWN_ACTIVE) return FALSE;
84
85 /* Convert the count to our internal representation */
86 Count <<= EX_RUNDOWN_COUNT_SHIFT;
87
88 /* Loop until successfully incremented the counter */
89 for (;;)
90 {
91 /* Add references */
92 NewValue = Value + Count;
93
94 /* Change the value */
95 Value = ExpChangeRundown(RunRef, NewValue, Value);
96 if (Value == NewValue) return TRUE;
97
98 /* Make sure a rundown is not active */
99 if (Value & EX_RUNDOWN_ACTIVE) return FALSE;
100 }
101 }
102
103 /*++
104 * @name ExfInitializeRundownProtection
105 * @implemented NT5.1
106 *
107 * The ExfInitializeRundownProtection routine initializes a rundown
108 * protection descriptor.
109 *
110 * @param RunRef
111 * Pointer to a rundown reference descriptor.
112 *
113 * @return None.
114 *
115 * @remarks Callers of ExfInitializeRundownProtection can be running at any IRQL.
116 *
117 *--*/
118 VOID
119 FASTCALL
120 ExfInitializeRundownProtection(IN PEX_RUNDOWN_REF RunRef)
121 {
122 /* Set the count to zero */
123 RunRef->Count = 0;
124 }
125
126 /*++
127 * @name ExfReInitializeRundownProtection
128 * @implemented NT5.1
129 *
130 * The ExfReInitializeRundownProtection routine re-initializes a rundown
131 * protection descriptor.
132 *
133 * @param RunRef
134 * Pointer to a rundown reference descriptor.
135 *
136 * @return None.
137 *
138 * @remarks Callers of ExfReInitializeRundownProtection can be running at any IRQL.
139 *
140 *--*/
141 VOID
142 FASTCALL
143 ExfReInitializeRundownProtection(IN PEX_RUNDOWN_REF RunRef)
144 {
145 PAGED_CODE();
146
147 /* Sanity check */
148 ASSERT((RunRef->Count & EX_RUNDOWN_ACTIVE) != 0);
149
150 /* Reset the count */
151 InterlockedExchange((PLONG)&RunRef->Count, 0);
152 }
153
154 /*++
155 * @name ExfRundownCompleted
156 * @implemented NT5.1
157 *
158 * The ExfRundownCompleted routine completes the rundown of the specified
159 * descriptor by setting the active bit.
160 *
161 * @param RunRef
162 * Pointer to a rundown reference descriptor.
163 *
164 * @return None.
165 *
166 * @remarks Callers of ExfRundownCompleted must be running at IRQL <= APC_LEVEL.
167 *
168 *--*/
169 VOID
170 FASTCALL
171 ExfRundownCompleted(IN PEX_RUNDOWN_REF RunRef)
172 {
173 PAGED_CODE();
174
175 /* Sanity check */
176 ASSERT((RunRef->Count & EX_RUNDOWN_ACTIVE) != 0);
177
178 /* Mark the counter as active */
179 InterlockedExchange((PLONG)&RunRef->Count, EX_RUNDOWN_ACTIVE);
180 }
181
182 /*++
183 * @name ExfReleaseRundownProtection
184 * @implemented NT5.1
185 *
186 * The ExfReleaseRundownProtection routine releases the rundown protection
187 * reference for the specified descriptor.
188 *
189 * @param RunRef
190 * Pointer to a rundown reference descriptor.
191 *
192 * @return None.
193 *
194 * @remarks Callers of ExfReleaseRundownProtection can be running at any IRQL.
195 *
196 *--*/
197 VOID
198 FASTCALL
199 ExfReleaseRundownProtection(IN PEX_RUNDOWN_REF RunRef)
200 {
201 ULONG_PTR Value = RunRef->Count, NewValue;
202 PEX_RUNDOWN_WAIT_BLOCK WaitBlock;
203
204 /* Check if rundown is not active */
205 if (!(Value & EX_RUNDOWN_ACTIVE))
206 {
207 /* Loop until successfully incremented the counter */
208 for (;;)
209 {
210 /* Sanity check */
211 ASSERT((Value >= EX_RUNDOWN_COUNT_INC) || (KeNumberProcessors > 1));
212
213 /* Get the new value */
214 NewValue = Value - EX_RUNDOWN_COUNT_INC;
215
216 /* Change the value */
217 Value = ExpChangeRundown(RunRef, NewValue, Value);
218 if (Value == NewValue) return;
219
220 /* Loop again if we're still not active */
221 if (Value & EX_RUNDOWN_ACTIVE) break;
222 }
223 }
224
225 /* Get the wait block */
226 WaitBlock = (PEX_RUNDOWN_WAIT_BLOCK)(Value & ~EX_RUNDOWN_ACTIVE);
227 ASSERT((WaitBlock->Count > 0) || (KeNumberProcessors > 1));
228
229 /* Remove the one count */
230 if (InterlockedExchangeAddSizeT(&WaitBlock->Count, -1))
231 {
232 /* We're down to 0 now, so signal the event */
233 KeSetEvent(&WaitBlock->RundownEvent, IO_NO_INCREMENT, FALSE);
234 }
235 }
236
237 /*++
238 * @name ExfReleaseRundownProtectionEx
239 * @implemented NT5.2
240 *
241 * The ExfReleaseRundownProtectionEx routine releases multiple rundown
242 * protection references for the specified descriptor.
243 *
244 * @param RunRef
245 * Pointer to a rundown reference descriptor.
246 *
247 * @param Count
248 * Number of times to dereference the descriptor.
249 *
250 * @return None.
251 *
252 * @remarks Callers of ExfAcquireRundownProtectionEx can be running at any IRQL.
253 *
254 *--*/
255 VOID
256 FASTCALL
257 ExfReleaseRundownProtectionEx(IN PEX_RUNDOWN_REF RunRef,
258 IN ULONG Count)
259 {
260 ULONG_PTR Value = RunRef->Count, NewValue;
261 PEX_RUNDOWN_WAIT_BLOCK WaitBlock;
262
263 /* Check if rundown is not active */
264 if (!(Value & EX_RUNDOWN_ACTIVE))
265 {
266 /* Loop until successfully incremented the counter */
267 for (;;)
268 {
269 /* Sanity check */
270 ASSERT((Value >= EX_RUNDOWN_COUNT_INC * Count) || (KeNumberProcessors > 1));
271
272 /* Get the new value */
273 NewValue = Value - (Count * EX_RUNDOWN_COUNT_INC);
274
275 /* Change the value */
276 Value = ExpChangeRundown(RunRef, NewValue, Value);
277 if (Value == NewValue) return;
278
279 /* Loop again if we're still not active */
280 if (Value & EX_RUNDOWN_ACTIVE) break;
281 }
282 }
283
284 /* Get the wait block */
285 WaitBlock = (PEX_RUNDOWN_WAIT_BLOCK)(Value & ~EX_RUNDOWN_ACTIVE);
286 ASSERT((WaitBlock->Count >= Count) || (KeNumberProcessors > 1));
287
288 /* Remove the count */
289 if (InterlockedExchangeAddSizeT(WaitBlock->Count, -(LONG)Count) ==
290 (LONG)Count)
291 {
292 /* We're down to 0 now, so signal the event */
293 KeSetEvent(&WaitBlock->RundownEvent, IO_NO_INCREMENT, FALSE);
294 }
295 }
296
297 /*++
298 * @name ExfWaitForRundownProtectionRelease
299 * @implemented NT5.1
300 *
301 * The ExfWaitForRundownProtectionRelease routine waits until the specified
302 * rundown descriptor has been released.
303 *
304 * @param RunRef
305 * Pointer to a rundown reference descriptor.
306 *
307 * @return None.
308 *
309 * @remarks Callers of ExfWaitForRundownProtectionRelease must be running
310 * at IRQL <= APC_LEVEL.
311 *
312 *--*/
313 VOID
314 FASTCALL
315 ExfWaitForRundownProtectionRelease(IN PEX_RUNDOWN_REF RunRef)
316 {
317 ULONG_PTR Value, Count, NewValue;
318 EX_RUNDOWN_WAIT_BLOCK WaitBlock;
319 PEX_RUNDOWN_WAIT_BLOCK WaitBlockPointer;
320 PKEVENT Event;
321 PAGED_CODE();
322
323 /* Set the active bit */
324 Value = ExpChangeRundown(RunRef, EX_RUNDOWN_ACTIVE, 0);
325 if ((Value == 0) || (Value == EX_RUNDOWN_ACTIVE)) return;
326
327 /* No event for now */
328 Event = NULL;
329 WaitBlockPointer = (PEX_RUNDOWN_WAIT_BLOCK)((ULONG_PTR)&WaitBlock |
330 EX_RUNDOWN_ACTIVE);
331
332 /* Start waitblock set loop */
333 for(;;)
334 {
335 /* Save the count */
336 Count = Value >> EX_RUNDOWN_COUNT_SHIFT;
337
338 /* If the count is over one or we don't have en event yet, create it */
339 if (Count || !Event)
340 {
341 /* Initialize the event */
342 KeInitializeEvent(&WaitBlock.RundownEvent,
343 NotificationEvent,
344 FALSE);
345
346 /* Set the pointer */
347 Event = &WaitBlock.RundownEvent;
348 }
349
350 /* Set the count */
351 WaitBlock.Count = Count;
352
353 /* Now set the pointer */
354 NewValue = ExpChangeRundown(RunRef, PtrToUlong(WaitBlockPointer), Value);
355 if (NewValue == Value) break;
356
357 /* Loop again */
358 Value = NewValue;
359 ASSERT((Value & EX_RUNDOWN_ACTIVE) == 0);
360 }
361
362 /* If the count was 0, we're done */
363 if (!Count) return;
364
365 /* Wait for whoever needs to release to notify us */
366 KeWaitForSingleObject(Event, Executive, KernelMode, FALSE, NULL);
367 ASSERT(WaitBlock.Count == 0);
368 }
369
370 /* FIXME: STUBS **************************************************************/
371
372 /*
373 * @unimplemented NT5.2
374 */
375 BOOLEAN
376 FASTCALL
377 ExfAcquireRundownProtectionCacheAware(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware)
378 {
379 DBG_UNREFERENCED_PARAMETER(RunRefCacheAware);
380 UNIMPLEMENTED;
381 return FALSE;
382 }
383
384 /*
385 * @unimplemented NT5.2
386 */
387 BOOLEAN
388 FASTCALL
389 ExfAcquireRundownProtectionCacheAwareEx(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware,
390 IN ULONG Count)
391 {
392 DBG_UNREFERENCED_PARAMETER(RunRefCacheAware);
393 DBG_UNREFERENCED_PARAMETER(Count);
394 UNIMPLEMENTED;
395 return FALSE;
396 }
397
398 /*
399 * @unimplemented NT5.2
400 */
401 VOID
402 FASTCALL
403 ExfReleaseRundownProtectionCacheAware(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware)
404 {
405 DBG_UNREFERENCED_PARAMETER(RunRefCacheAware);
406 UNIMPLEMENTED;
407 }
408
409 /*
410 * @unimplemented NT5.2
411 */
412 VOID
413 FASTCALL
414 ExfReleaseRundownProtectionCacheAwareEx(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware,
415 IN ULONG Count)
416 {
417 DBG_UNREFERENCED_PARAMETER(RunRefCacheAware);
418 DBG_UNREFERENCED_PARAMETER(Count);
419 UNIMPLEMENTED;
420 }
421
422 /*
423 * @unimplemented NT5.2
424 */
425 VOID
426 FASTCALL
427 ExfWaitForRundownProtectionReleaseCacheAware(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware)
428 {
429 DBG_UNREFERENCED_PARAMETER(RunRefCacheAware);
430 UNIMPLEMENTED;
431 }
432
433 /*
434 * @unimplemented NT5.2
435 */
436 VOID
437 FASTCALL
438 ExfRundownCompletedCacheAware(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware)
439 {
440 DBG_UNREFERENCED_PARAMETER(RunRefCacheAware);
441 UNIMPLEMENTED;
442 }
443
444 /*
445 * @unimplemented NT5.2
446 */
447 VOID
448 FASTCALL
449 ExfReInitializeRundownProtectionCacheAware(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware)
450 {
451 DBG_UNREFERENCED_PARAMETER(RunRefCacheAware);
452 UNIMPLEMENTED;
453 }
454
455 /*
456 * @unimplemented NT5.2
457 */
458 PEX_RUNDOWN_REF_CACHE_AWARE
459 NTAPI
460 ExAllocateCacheAwareRundownProtection(IN POOL_TYPE PoolType,
461 IN ULONG Tag)
462 {
463 DBG_UNREFERENCED_PARAMETER(PoolType);
464 DBG_UNREFERENCED_PARAMETER(Tag);
465 UNIMPLEMENTED;
466 return NULL;
467 }
468
469 /*
470 * @unimplemented NT5.2
471 */
472 VOID
473 NTAPI
474 ExFreeCacheAwareRundownProtection(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware)
475 {
476 DBG_UNREFERENCED_PARAMETER(RunRefCacheAware);
477 UNIMPLEMENTED;
478 }
479
480 /*
481 * @unimplemented NT5.2
482 */
483 VOID
484 NTAPI
485 ExInitializeRundownProtectionCacheAware(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware,
486 IN ULONG Count)
487 {
488 DBG_UNREFERENCED_PARAMETER(RunRefCacheAware);
489 DBG_UNREFERENCED_PARAMETER(Count);
490 UNIMPLEMENTED;
491 }
492
493 /*
494 * @unimplemented NT5.2
495 */
496 SIZE_T
497 NTAPI
498 ExSizeOfRundownProtectionCacheAware(VOID)
499 {
500 UNIMPLEMENTED;
501 return 0;
502 }
503