Merge 15329:15546 from trunk
[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 KeAcquireSpinLock(&CurrentThread->ApcQueueLock, &OldIrql);
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 KeReleaseSpinLock(&CurrentThread->ApcQueueLock, 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 /* Unlock the Queue*/
82 KeReleaseSpinLock(&CurrentThread->ApcQueueLock, OldIrql);
83
84 /* Block the Thread */
85 DPRINT("Blocking the Thread: %x\n", CurrentThread);
86 KiBlockThread(&Status,
87 CurrentThread->Alertable,
88 WaitMode,
89 WaitReason);
90
91 /* Check if we were executing an APC */
92 if (Status != STATUS_KERNEL_APC) return;
93
94 DPRINT("Looping Again\n");
95 } while (TRUE);
96 }
97
98 VOID
99 FASTCALL
100 KeSignalGateBoostPriority(PKGATE Gate)
101 {
102 PKTHREAD WaitThread;
103 PKWAIT_BLOCK WaitBlock;
104 KIRQL OldIrql;
105 NTSTATUS WaitStatus = STATUS_SUCCESS;
106
107 DPRINT("KeSignalGateBoostPriority(EveGate %x)\n", Gate);
108
109 /* Acquire Dispatcher Database Lock */
110 OldIrql = KeAcquireDispatcherDatabaseLock();
111
112 /* Make sure we're not already signaled or that the list is empty */
113 if (Gate->Header.SignalState) goto quit;
114
115 /* If our wait list is empty, then signal the event and return */
116 if (IsListEmpty(&Gate->Header.WaitListHead))
117 {
118 Gate->Header.SignalState = 1;
119 goto quit;
120 }
121
122 /* Get WaitBlock */
123 WaitBlock = CONTAINING_RECORD(Gate->Header.WaitListHead.Flink,
124 KWAIT_BLOCK,
125 WaitListEntry);
126 /* Remove it */
127 RemoveEntryList(&WaitBlock->WaitListEntry);
128
129 /* Get the Associated thread */
130 WaitThread = WaitBlock->Thread;
131
132 /* Increment the Queue's active threads */
133 if (WaitThread->Queue)
134 {
135 DPRINT("Incrementing Queue's active threads\n");
136 WaitThread->Queue->CurrentCount++;
137 }
138
139 /* Reschedule the Thread */
140 DPRINT("Unblocking the Thread\n");
141 KiUnblockThread(WaitThread, &WaitStatus, EVENT_INCREMENT);
142 return;
143
144 quit:
145 /* Release the Dispatcher Database Lock */
146 KeReleaseDispatcherDatabaseLock(OldIrql);
147 }
148
149 /* EOF */