- Implement Pushlocks. Only Waking, and Exclusive Acquire/Release + Waits have been...
[reactos.git] / reactos / ntoskrnl / include / internal / ex.h
1 #ifndef __NTOSKRNL_INCLUDE_INTERNAL_EXECUTIVE_H
2 #define __NTOSKRNL_INCLUDE_INTERNAL_EXECUTIVE_H
3
4 /* GLOBAL VARIABLES *********************************************************/
5
6 extern TIME_ZONE_INFORMATION ExpTimeZoneInfo;
7 extern LARGE_INTEGER ExpTimeZoneBias;
8 extern ULONG ExpTimeZoneId;
9 extern POBJECT_TYPE ExEventPairObjectType;
10
11 #define EX_OBJ_TO_HDR(eob) ((POBJECT_HEADER)((ULONG_PTR)(eob) & \
12 ~(EX_HANDLE_ENTRY_PROTECTFROMCLOSE | EX_HANDLE_ENTRY_INHERITABLE | \
13 EX_HANDLE_ENTRY_AUDITONCLOSE)))
14 #define EX_HTE_TO_HDR(hte) ((POBJECT_HEADER)((ULONG_PTR)((hte)->u1.Object) & \
15 ~(EX_HANDLE_ENTRY_PROTECTFROMCLOSE | EX_HANDLE_ENTRY_INHERITABLE | \
16 EX_HANDLE_ENTRY_AUDITONCLOSE)))
17
18 /* INITIALIZATION FUNCTIONS *************************************************/
19
20 VOID
21 STDCALL
22 ExpWin32kInit(VOID);
23
24 VOID
25 STDCALL
26 ExInit2(VOID);
27
28 VOID
29 STDCALL
30 ExpInitTimeZoneInfo(VOID);
31
32 VOID
33 STDCALL
34 ExpInitializeWorkerThreads(VOID);
35
36 VOID
37 STDCALL
38 ExpInitLookasideLists(VOID);
39
40 VOID
41 STDCALL
42 ExpInitializeCallbacks(VOID);
43
44 VOID
45 STDCALL
46 ExpInitUuids(VOID);
47
48 VOID
49 STDCALL
50 ExpInitializeExecutive(VOID);
51
52 VOID
53 STDCALL
54 ExpInitializeEventImplementation(VOID);
55
56 VOID
57 STDCALL
58 ExpInitializeEventImplementation(VOID);
59
60 VOID
61 STDCALL
62 ExpInitializeEventPairImplementation(VOID);
63
64 VOID
65 STDCALL
66 ExpInitializeSemaphoreImplementation(VOID);
67
68 VOID
69 STDCALL
70 ExpInitializeMutantImplementation(VOID);
71
72 VOID
73 STDCALL
74 ExpInitializeTimerImplementation(VOID);
75
76 VOID
77 STDCALL
78 ExpInitializeProfileImplementation(VOID);
79
80 /* Rundown Functions ********************************************************/
81
82 VOID
83 FASTCALL
84 ExfInitializeRundownProtection(
85 OUT PEX_RUNDOWN_REF RunRef
86 );
87
88 VOID
89 FASTCALL
90 ExfReInitializeRundownProtection(
91 OUT PEX_RUNDOWN_REF RunRef
92 );
93
94 BOOLEAN
95 FASTCALL
96 ExfAcquireRundownProtection(
97 IN OUT PEX_RUNDOWN_REF RunRef
98 );
99
100 BOOLEAN
101 FASTCALL
102 ExfAcquireRundownProtectionEx(
103 IN OUT PEX_RUNDOWN_REF RunRef,
104 IN ULONG Count
105 );
106
107 VOID
108 FASTCALL
109 ExfReleaseRundownProtection(
110 IN OUT PEX_RUNDOWN_REF RunRef
111 );
112
113 VOID
114 FASTCALL
115 ExfReleaseRundownProtectionEx(
116 IN OUT PEX_RUNDOWN_REF RunRef,
117 IN ULONG Count
118 );
119
120 VOID
121 FASTCALL
122 ExfRundownCompleted(
123 OUT PEX_RUNDOWN_REF RunRef
124 );
125
126 VOID
127 FASTCALL
128 ExfWaitForRundownProtectionRelease(
129 IN OUT PEX_RUNDOWN_REF RunRef
130 );
131
132 /* HANDLE TABLE FUNCTIONS ***************************************************/
133
134 #define EX_HANDLE_ENTRY_LOCKED (1 << ((sizeof(PVOID) * 8) - 1))
135 #define EX_HANDLE_ENTRY_PROTECTFROMCLOSE (1 << 0)
136 #define EX_HANDLE_ENTRY_INHERITABLE (1 << 1)
137 #define EX_HANDLE_ENTRY_AUDITONCLOSE (1 << 2)
138
139 #define EX_HANDLE_TABLE_CLOSING 0x1
140
141 #define EX_HANDLE_ENTRY_FLAGSMASK (EX_HANDLE_ENTRY_LOCKED | \
142 EX_HANDLE_ENTRY_PROTECTFROMCLOSE | \
143 EX_HANDLE_ENTRY_INHERITABLE | \
144 EX_HANDLE_ENTRY_AUDITONCLOSE)
145
146 typedef VOID (STDCALL PEX_SWEEP_HANDLE_CALLBACK)(
147 PHANDLE_TABLE HandleTable,
148 PVOID Object,
149 ULONG GrantedAccess,
150 PVOID Context
151 );
152
153 typedef BOOLEAN (STDCALL PEX_DUPLICATE_HANDLE_CALLBACK)(
154 PHANDLE_TABLE HandleTable,
155 PHANDLE_TABLE_ENTRY HandleTableEntry,
156 PVOID Context
157 );
158
159 typedef BOOLEAN (STDCALL PEX_CHANGE_HANDLE_CALLBACK)(
160 PHANDLE_TABLE HandleTable,
161 PHANDLE_TABLE_ENTRY HandleTableEntry,
162 PVOID Context
163 );
164
165 VOID
166 ExpInitializeHandleTables(VOID);
167
168 PHANDLE_TABLE
169 ExCreateHandleTable(IN PEPROCESS QuotaProcess OPTIONAL);
170
171 VOID
172 ExDestroyHandleTable(
173 IN PHANDLE_TABLE HandleTable
174 );
175
176 VOID
177 ExSweepHandleTable(
178 IN PHANDLE_TABLE HandleTable,
179 IN PEX_SWEEP_HANDLE_CALLBACK SweepHandleCallback OPTIONAL,
180 IN PVOID Context OPTIONAL
181 );
182
183 PHANDLE_TABLE
184 ExDupHandleTable(
185 IN PEPROCESS QuotaProcess OPTIONAL,
186 IN PEX_DUPLICATE_HANDLE_CALLBACK DuplicateHandleCallback OPTIONAL,
187 IN PVOID Context OPTIONAL,
188 IN PHANDLE_TABLE SourceHandleTable
189 );
190
191 BOOLEAN
192 ExLockHandleTableEntry(
193 IN PHANDLE_TABLE HandleTable,
194 IN PHANDLE_TABLE_ENTRY Entry
195 );
196
197 VOID
198 ExUnlockHandleTableEntry(
199 IN PHANDLE_TABLE HandleTable,
200 IN PHANDLE_TABLE_ENTRY Entry
201 );
202
203 HANDLE
204 ExCreateHandle(
205 IN PHANDLE_TABLE HandleTable,
206 IN PHANDLE_TABLE_ENTRY Entry
207 );
208
209 BOOLEAN
210 ExDestroyHandle(
211 IN PHANDLE_TABLE HandleTable,
212 IN HANDLE Handle
213 );
214
215 VOID
216 ExDestroyHandleByEntry(
217 IN PHANDLE_TABLE HandleTable,
218 IN PHANDLE_TABLE_ENTRY Entry,
219 IN HANDLE Handle
220 );
221
222 PHANDLE_TABLE_ENTRY
223 ExMapHandleToPointer(
224 IN PHANDLE_TABLE HandleTable,
225 IN HANDLE Handle
226 );
227
228 BOOLEAN
229 ExChangeHandle(
230 IN PHANDLE_TABLE HandleTable,
231 IN HANDLE Handle,
232 IN PEX_CHANGE_HANDLE_CALLBACK ChangeHandleCallback,
233 IN PVOID Context
234 );
235
236 /* PSEH EXCEPTION HANDLING **************************************************/
237
238 LONG
239 STDCALL
240 ExSystemExceptionFilter(VOID);
241
242 static __inline _SEH_FILTER(_SEH_ExSystemExceptionFilter)
243 {
244 return ExSystemExceptionFilter();
245 }
246
247 /* RUNDOWN *******************************************************************/
248
249 #ifdef _WIN64
250 #define ExpChangeRundown(x, y, z) InterlockedCompareExchange64((PLONGLONG)x, y, z)
251 #define ExpSetRundown(x, y) InterlockedExchange64((PLONGLONG)x, y)
252 #else
253 #define ExpChangeRundown(x, y, z) InterlockedCompareExchange((PLONG)x, y, z)
254 #define ExpSetRundown(x, y) InterlockedExchange((PLONG)x, y)
255 #endif
256
257 /*++
258 * @name ExfAcquireRundownProtection
259 * INTERNAL MACRO
260 *
261 * The ExfAcquireRundownProtection routine acquires rundown protection for
262 * the specified descriptor.
263 *
264 * @param RunRef
265 * Pointer to a rundown reference descriptor.
266 *
267 * @return TRUE if access to the protected structure was granted, FALSE otherwise.
268 *
269 * @remarks This is the internal macro for system use only.In case the rundown
270 * was active, then the slow-path will be called through the exported
271 * function.
272 *
273 *--*/
274 BOOLEAN
275 FORCEINLINE
276 ExAcquireRundownProtection(IN PEX_RUNDOWN_REF RunRef)
277 {
278 ULONG_PTR Value, NewValue, OldValue;
279
280 /* Get the current value and mask the active bit */
281 Value = RunRef->Count &~ EX_RUNDOWN_ACTIVE;
282
283 /* Add a reference */
284 NewValue = Value + EX_RUNDOWN_COUNT_INC;
285
286 /* Change the value */
287 OldValue = ExpChangeRundown(RunRef, NewValue, Value);
288 if (OldValue != Value)
289 {
290 /* Rundown was active, use long path */
291 return ExfAcquireRundownProtection(RunRef);
292 }
293
294 /* Success */
295 return TRUE;
296 }
297
298 /*++
299 * @name ExReleaseRundownProtection
300 * INTERNAL MACRO
301 *
302 * The ExReleaseRundownProtection routine releases rundown protection for
303 * the specified descriptor.
304 *
305 * @param RunRef
306 * Pointer to a rundown reference descriptor.
307 *
308 * @return TRUE if access to the protected structure was granted, FALSE otherwise.
309 *
310 * @remarks This is the internal macro for system use only.In case the rundown
311 * was active, then the slow-path will be called through the exported
312 * function.
313 *
314 *--*/
315 VOID
316 FORCEINLINE
317 ExReleaseRundownProtection(IN PEX_RUNDOWN_REF RunRef)
318 {
319 ULONG_PTR Value, NewValue, OldValue;
320
321 /* Get the current value and mask the active bit */
322 Value = RunRef->Count &~ EX_RUNDOWN_ACTIVE;
323
324 /* Remove a reference */
325 NewValue = Value - EX_RUNDOWN_COUNT_INC;
326
327 /* Change the value */
328 OldValue = ExpChangeRundown(RunRef, NewValue, Value);
329
330 /* Check if the rundown was active */
331 if (OldValue != Value)
332 {
333 /* Rundown was active, use long path */
334 ExfReleaseRundownProtection(RunRef);
335 }
336 else
337 {
338 /* Sanity check */
339 ASSERT((Value >= EX_RUNDOWN_COUNT_INC) || (KeNumberProcessors > 1));
340 }
341 }
342
343 /*++
344 * @name ExInitializeRundownProtection
345 * INTERNAL MACRO
346 *
347 * The ExInitializeRundownProtection routine initializes a rundown
348 * protection descriptor.
349 *
350 * @param RunRef
351 * Pointer to a rundown reference descriptor.
352 *
353 * @return None.
354 *
355 * @remarks This is the internal macro for system use only.
356 *
357 *--*/
358 VOID
359 FORCEINLINE
360 ExInitializeRundownProtection(IN PEX_RUNDOWN_REF RunRef)
361 {
362 /* Set the count to zero */
363 RunRef->Count = 0;
364 }
365
366 /*++
367 * @name ExWaitForRundownProtectionRelease
368 * INTERNAL MACRO
369 *
370 * The ExWaitForRundownProtectionRelease routine waits until the specified
371 * rundown descriptor has been released.
372 *
373 * @param RunRef
374 * Pointer to a rundown reference descriptor.
375 *
376 * @return None.
377 *
378 * @remarks This is the internal macro for system use only. If a wait is actually
379 * necessary, then the slow path is taken through the exported function.
380 *
381 *--*/
382 VOID
383 FORCEINLINE
384 ExWaitForRundownProtectionRelease(IN PEX_RUNDOWN_REF RunRef)
385 {
386 ULONG_PTR Value;
387
388 /* Set the active bit */
389 Value = ExpChangeRundown(RunRef, EX_RUNDOWN_ACTIVE, 0);
390 if ((Value) || (Value != EX_RUNDOWN_ACTIVE))
391 {
392 /* If the the rundown wasn't already active, then take the long path */
393 ExfWaitForRundownProtectionRelease(RunRef);
394 }
395 }
396
397 /*++
398 * @name ExRundownCompleted
399 * INTERNAL MACRO
400 *
401 * The ExRundownCompleted routine completes the rundown of the specified
402 * descriptor by setting the active bit.
403 *
404 * @param RunRef
405 * Pointer to a rundown reference descriptor.
406 *
407 * @return None.
408 *
409 * @remarks This is the internal macro for system use only.
410 *
411 *--*/
412 VOID
413 FORCEINLINE
414 ExRundownCompleted(IN PEX_RUNDOWN_REF RunRef)
415 {
416 /* Sanity check */
417 ASSERT((RunRef->Count & EX_RUNDOWN_ACTIVE) != 0);
418
419 /* Mark the counter as active */
420 ExpSetRundown(&RunRef->Count, EX_RUNDOWN_ACTIVE);
421 }
422
423 /* PUSHLOCKS *****************************************************************/
424
425 /*++
426 * @name ExAcquirePushLockExclusive
427 * INTERNAL MACRO
428 *
429 * The ExAcquirePushLockExclusive macro exclusively acquires a PushLock.
430 *
431 * @params PushLock
432 * Pointer to the pushlock which is to be acquired.
433 *
434 * @return None.
435 *
436 * @remarks The function attempts the quickest route to acquire the lock, which is
437 * to simply set the lock bit.
438 * However, if the pushlock is already shared, the slower path is taken.
439 *
440 * Callers of ExAcquirePushLockShared must be running at IRQL <= APC_LEVEL.
441 * This macro should usually be paired up with KeAcquireCriticalRegion.
442 *
443 *--*/
444 VOID
445 FORCEINLINE
446 ExAcquirePushLockExclusive(PEX_PUSH_LOCK PushLock)
447 {
448 /* Try acquiring the lock */
449 if (InterlockedBitTestAndSet((PLONG)PushLock, EX_PUSH_LOCK_LOCK_V))
450 {
451 /* Someone changed it, use the slow path */
452 ExfAcquirePushLockExclusive(PushLock);
453 }
454
455 /* Sanity check */
456 ASSERT(PushLock->Locked);
457 }
458
459 /*++
460 * @name ExAcquirePushLockShared
461 * INTERNAL MACRO
462 *
463 * The ExAcquirePushLockShared macro acquires a shared PushLock.
464 *
465 * @params PushLock
466 * Pointer to the pushlock which is to be acquired.
467 *
468 * @return None.
469 *
470 * @remarks The function attempts the quickest route to acquire the lock, which is
471 * to simply set the lock bit and set the share count to one.
472 * However, if the pushlock is already shared, the slower path is taken.
473 *
474 * Callers of ExAcquirePushLockShared must be running at IRQL <= APC_LEVEL.
475 * This macro should usually be paired up with KeAcquireCriticalRegion.
476 *
477 *--*/
478 VOID
479 FORCEINLINE
480 ExAcquirePushLockShared(PEX_PUSH_LOCK PushLock)
481 {
482 EX_PUSH_LOCK NewValue;
483
484 /* Try acquiring the lock */
485 NewValue.Value = EX_PUSH_LOCK_LOCK | EX_PUSH_LOCK_SHARE_INC;
486 if (!InterlockedCompareExchangePointer(PushLock, NewValue.Ptr, 0))
487 {
488 /* Someone changed it, use the slow path */
489 ExfAcquirePushLockShared(PushLock);
490 }
491
492 /* Sanity checks */
493 ASSERT(PushLock->Locked);
494 ASSERT(PushLock->Waiting || PushLock->Shared > 0);
495 }
496
497 /*++
498 * @name ExWaitOnPushLock
499 * INTERNAL MACRO
500 *
501 * The ExWaitOnPushLock macro acquires and instantly releases a pushlock.
502 *
503 * @params PushLock
504 * Pointer to a pushlock.
505 *
506 * @return None.
507 *
508 * @remarks The function attempts to get any exclusive waiters out of their slow
509 * path by forcing an instant acquire/release operation.
510 *
511 * Callers of ExWaitOnPushLock must be running at IRQL <= APC_LEVEL.
512 *
513 *--*/
514 VOID
515 FORCEINLINE
516 ExWaitOnPushLock(PEX_PUSH_LOCK PushLock)
517 {
518 /* Acquire the lock */
519 ExfAcquirePushLockExclusive(PushLock);
520 ASSERT(PushLock->Locked);
521
522 /* Release it */
523 ExfReleasePushLockExclusive(PushLock);
524 }
525
526 /*++
527 * @name ExReleasePushLockShared
528 * INTERNAL MACRO
529 *
530 * The ExReleasePushLockShared macro releases a previously acquired PushLock.
531 *
532 * @params PushLock
533 * Pointer to a previously acquired pushlock.
534 *
535 * @return None.
536 *
537 * @remarks The function attempts the quickest route to release the lock, which is
538 * to simply decrease the share count and remove the lock bit.
539 * However, if the pushlock is being waited on then the long path is taken.
540 *
541 * Callers of ExReleasePushLockShared must be running at IRQL <= APC_LEVEL.
542 * This macro should usually be paired up with KeLeaveCriticalRegion.
543 *
544 *--*/
545 VOID
546 FORCEINLINE
547 ExReleasePushLockShared(PEX_PUSH_LOCK PushLock)
548 {
549 EX_PUSH_LOCK OldValue;
550
551 /* Sanity checks */
552 ASSERT(PushLock->Locked);
553 ASSERT(PushLock->Waiting || PushLock->Shared > 0);
554
555 /* Try to clear the pushlock */
556 OldValue.Value = EX_PUSH_LOCK_LOCK | EX_PUSH_LOCK_SHARE_INC;
557 if (InterlockedCompareExchangePointer(PushLock, 0, OldValue.Ptr) !=
558 OldValue.Ptr)
559 {
560 /* There are still other people waiting on it */
561 ExfReleasePushLockShared(PushLock);
562 }
563 }
564
565 /*++
566 * @name ExReleasePushLockExclusive
567 * INTERNAL MACRO
568 *
569 * The ExReleasePushLockExclusive macro releases a previously
570 * exclusively acquired PushLock.
571 *
572 * @params PushLock
573 * Pointer to a previously acquired pushlock.
574 *
575 * @return None.
576 *
577 * @remarks The function attempts the quickest route to release the lock, which is
578 * to simply clear the locked bit.
579 * However, if the pushlock is being waited on, the slow path is taken
580 * in an attempt to wake up the lock.
581 *
582 * Callers of ExReleasePushLockExclusive must be running at IRQL <= APC_LEVEL.
583 * This macro should usually be paired up with KeLeaveCriticalRegion.
584 *
585 *--*/
586 VOID
587 FORCEINLINE
588 ExReleasePushLockExclusive(PEX_PUSH_LOCK PushLock)
589 {
590 EX_PUSH_LOCK OldValue;
591
592 /* Sanity checks */
593 ASSERT(PushLock->Locked);
594 ASSERT(PushLock->Waiting || PushLock->Shared == 0);
595
596 /* Unlock the pushlock */
597 OldValue.Value = InterlockedExchangeAddSizeT((PLONG)PushLock, -1);
598
599 /* Sanity checks */
600 ASSERT(OldValue.Locked);
601 ASSERT(OldValue.Waiting || OldValue.Shared == 0);
602
603 /* Check if anyone is waiting on it and it's not already waking*/
604 if ((OldValue.Waiting) && !(OldValue.Waking))
605 {
606 /* Wake it up */
607 ExfTryToWakePushLock(PushLock);
608 }
609 }
610
611 /*++
612 * @name ExReleasePushLock
613 * INTERNAL MACRO
614 *
615 * The ExReleasePushLock macro releases a previously acquired PushLock.
616 *
617 * @params PushLock
618 * Pointer to a previously acquired pushlock.
619 *
620 * @return None.
621 *
622 * @remarks The function attempts the quickest route to release the lock, which is
623 * to simply clear all the fields and decrease the share count if required.
624 * However, if the pushlock is being waited on then the long path is taken.
625 *
626 * Callers of ExReleasePushLock must be running at IRQL <= APC_LEVEL.
627 * This macro should usually be paired up with KeLeaveCriticalRegion.
628 *
629 *--*/
630 VOID
631 FORCEINLINE
632 ExReleasePushLock(PEX_PUSH_LOCK PushLock)
633 {
634 EX_PUSH_LOCK OldValue = *PushLock;
635 EX_PUSH_LOCK NewValue;
636
637 /* Sanity checks */
638 ASSERT(OldValue.Locked);
639
640 /* Check if the pushlock is shared */
641 if (OldValue.Shared > 1)
642 {
643 /* Decrease the share count */
644 NewValue.Value = OldValue.Value &~ EX_PUSH_LOCK_SHARE_INC;
645 }
646 else
647 {
648 /* Clear the pushlock entirely */
649 NewValue.Value = 0;
650 }
651
652 /* Check if nobody is waiting on us and try clearing the lock here */
653 if ((OldValue.Waiting) ||
654 (InterlockedCompareExchangePointer(PushLock, NewValue.Ptr, OldValue.Ptr) ==
655 OldValue.Ptr))
656 {
657 /* We have waiters, use the long path */
658 ExfReleasePushLock(PushLock);
659 }
660 }
661
662 /* OTHER FUNCTIONS **********************************************************/
663
664 LONGLONG
665 FASTCALL
666 ExfpInterlockedExchange64(
667 LONGLONG volatile * Destination,
668 PLONGLONG Exchange
669 );
670
671 NTSTATUS
672 ExpSetTimeZoneInformation(PTIME_ZONE_INFORMATION TimeZoneInformation);
673
674 NTSTATUS
675 NTAPI
676 ExpAllocateLocallyUniqueId(OUT LUID *LocallyUniqueId);
677
678 VOID
679 STDCALL
680 ExTimerRundown(VOID);
681
682 #define InterlockedDecrementUL(Addend) \
683 (ULONG)InterlockedDecrement((PLONG)(Addend))
684
685 #define InterlockedIncrementUL(Addend) \
686 (ULONG)InterlockedIncrement((PLONG)(Addend))
687
688 #define InterlockedExchangeUL(Target, Value) \
689 (ULONG)InterlockedExchange((PLONG)(Target), (LONG)(Value))
690
691 #define InterlockedExchangeAddUL(Addend, Value) \
692 (ULONG)InterlockedExchangeAdd((PLONG)(Addend), (LONG)(Value))
693
694 #define InterlockedCompareExchangeUL(Destination, Exchange, Comperand) \
695 (ULONG)InterlockedCompareExchange((PLONG)(Destination), (LONG)(Exchange), (LONG)(Comperand))
696
697 #define ExfInterlockedCompareExchange64UL(Destination, Exchange, Comperand) \
698 (ULONGLONG)ExfInterlockedCompareExchange64((PLONGLONG)(Destination), (PLONGLONG)(Exchange), (PLONGLONG)(Comperand))
699
700 #define ExfpInterlockedExchange64UL(Target, Value) \
701 (ULONGLONG)ExfpInterlockedExchange64((PLONGLONG)(Target), (PLONGLONG)(Value))
702
703 #endif /* __NTOSKRNL_INCLUDE_INTERNAL_EXECUTIVE_H */