6530667b7b6eca3634bc5cd1d8aefc349d2555a6
[reactos.git] / reactos / ntoskrnl / ke / gate.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel
4 * FILE: ntoskrnl/ke/gate.c
5 * PURPOSE: Implements the Gate Dispatcher Object
6 *
7 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <internal/debug.h>
15
16 /* FUNCTIONS ****************************************************************/
17
18 VOID
19 FASTCALL
20 KeInitializeGate(PKGATE Gate)
21 {
22 DPRINT("KeInitializeGate(Gate %x)\n", Gate);
23
24 /* Initialize the Dispatcher Header */
25 KeInitializeDispatcherHeader(&Gate->Header,
26 GateObject,
27 sizeof(Gate) / sizeof(ULONG),
28 0);
29 }
30
31 VOID
32 FASTCALL
33 KeWaitForGate(PKGATE Gate,
34 KWAIT_REASON WaitReason,
35 KPROCESSOR_MODE WaitMode)
36 {
37 KIRQL OldIrql;
38 PKTHREAD CurrentThread = KeGetCurrentThread();
39 PKWAIT_BLOCK GateWaitBlock;
40 NTSTATUS Status;
41
42 DPRINT("KeWaitForGate(Gate %x)\n", Gate);
43
44 do
45 {
46 /* Lock the APC Queue */
47 OldIrql = KeAcquireDispatcherDatabaseLock();
48
49 /* Check if it's already signaled */
50 if (Gate->Header.SignalState)
51 {
52 /* Unsignal it */
53 Gate->Header.SignalState = 0;
54
55 /* Unlock the Queue and return */
56 KeReleaseDispatcherDatabaseLock(OldIrql);
57 return;
58 }
59
60 /* Setup a Wait Block */
61 GateWaitBlock = &CurrentThread->WaitBlock[0];
62 GateWaitBlock->Object = (PVOID)Gate;
63 GateWaitBlock->Thread = CurrentThread;
64
65 /* Set the Thread Wait Data */
66 CurrentThread->WaitReason = WaitReason;
67 CurrentThread->WaitMode = WaitMode;
68 CurrentThread->WaitIrql = OldIrql;
69 CurrentThread->GateObject = Gate;
70
71 /* Insert into the Wait List */
72 InsertTailList(&Gate->Header.WaitListHead, &GateWaitBlock->WaitListEntry);
73
74 /* Handle Kernel Queues */
75 if (CurrentThread->Queue)
76 {
77 DPRINT("Waking Queue\n");
78 KiWakeQueue(CurrentThread->Queue);
79 }
80
81 /* Block the Thread */
82 DPRINT("Blocking the Thread: %x\n", CurrentThread);
83 KiBlockThread(&Status,
84 CurrentThread->Alertable,
85 WaitMode,
86 WaitReason);
87
88 /* Check if we were executing an APC */
89 if (Status != STATUS_KERNEL_APC) return;
90
91 DPRINT("Looping Again\n");
92 } while (TRUE);
93 }
94
95 VOID
96 FASTCALL
97 KeSignalGateBoostPriority(PKGATE Gate)
98 {
99 PKTHREAD WaitThread;
100 PKWAIT_BLOCK WaitBlock;
101 KIRQL OldIrql;
102 NTSTATUS WaitStatus = STATUS_SUCCESS;
103
104 DPRINT("KeSignalGateBoostPriority(EveGate %x)\n", Gate);
105
106 /* Acquire Dispatcher Database Lock */
107 OldIrql = KeAcquireDispatcherDatabaseLock();
108
109 /* Make sure we're not already signaled or that the list is empty */
110 if (Gate->Header.SignalState) goto quit;
111
112 /* If our wait list is empty, then signal the event and return */
113 if (IsListEmpty(&Gate->Header.WaitListHead))
114 {
115 Gate->Header.SignalState = 1;
116 goto quit;
117 }
118
119 /* Get WaitBlock */
120 WaitBlock = CONTAINING_RECORD(Gate->Header.WaitListHead.Flink,
121 KWAIT_BLOCK,
122 WaitListEntry);
123 /* Remove it */
124 RemoveEntryList(&WaitBlock->WaitListEntry);
125
126 /* Get the Associated thread */
127 WaitThread = WaitBlock->Thread;
128
129 /* Increment the Queue's active threads */
130 if (WaitThread->Queue)
131 {
132 DPRINT("Incrementing Queue's active threads\n");
133 WaitThread->Queue->CurrentCount++;
134 }
135
136 /* Reschedule the Thread */
137 DPRINT("Unblocking the Thread\n");
138 KiUnblockThread(WaitThread, &WaitStatus, EVENT_INCREMENT);
139 return;
140
141 quit:
142 /* Release the Dispatcher Database Lock */
143 KeReleaseDispatcherDatabaseLock(OldIrql);
144 }
145
146 /* EOF */