KD System Rewrite:
[reactos.git] / reactos / ntoskrnl / ke / event.c
1 /*
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ke/event.c
6 * PURPOSE: Implements events
7 *
8 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
9 * David Welch (welch@mcmail.com)
10 */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <ntoskrnl.h>
15 #define NDEBUG
16 #include <internal/debug.h>
17
18 /* FUNCTIONS ****************************************************************/
19
20 /*
21 * @implemented
22 */
23 VOID
24 STDCALL
25 KeClearEvent(PKEVENT Event)
26 {
27 DPRINT("KeClearEvent(Event %x)\n", Event);
28
29 /* Reset Signal State */
30 Event->Header.SignalState = FALSE;
31 }
32
33 /*
34 * @implemented
35 */
36 VOID
37 STDCALL
38 KeInitializeEvent(PKEVENT Event,
39 EVENT_TYPE Type,
40 BOOLEAN State)
41 {
42 DPRINT("KeInitializeEvent(Event %x)\n", Event);
43
44 /* Initialize the Dispatcher Header */
45 KeInitializeDispatcherHeader(&Event->Header,
46 Type,
47 sizeof(Event) / sizeof(ULONG),
48 State);
49 }
50
51 /*
52 * @implemented
53 */
54 VOID
55 STDCALL
56 KeInitializeEventPair(PKEVENT_PAIR EventPair)
57 {
58 DPRINT("KeInitializeEventPair(Event %x)\n", EventPair);
59
60 /* Initialize the Event Pair Type and Size */
61 EventPair->Type = EventPairObject;
62 EventPair->Size = sizeof(KEVENT_PAIR);
63
64 /* Initialize the two Events */
65 KeInitializeEvent(&EventPair->LowEvent, SynchronizationEvent, FALSE);
66 KeInitializeEvent(&EventPair->HighEvent, SynchronizationEvent, FALSE);
67 }
68
69 /*
70 * @implemented
71 */
72 LONG STDCALL
73 KePulseEvent(IN PKEVENT Event,
74 IN KPRIORITY Increment,
75 IN BOOLEAN Wait)
76 {
77 KIRQL OldIrql;
78 LONG PreviousState;
79
80 DPRINT("KePulseEvent(Event %x, Wait %x)\n",Event,Wait);
81
82 /* Lock the Dispatcher Database */
83 OldIrql = KeAcquireDispatcherDatabaseLock();
84
85 /* Save the Old State */
86 PreviousState = Event->Header.SignalState;
87
88 /* Check if we are non-signaled and we have stuff in the Wait Queue */
89 if (!PreviousState && !IsListEmpty(&Event->Header.WaitListHead)) {
90
91 /* Set the Event to Signaled */
92 Event->Header.SignalState = 1;
93
94 /* Wake the Event */
95 KiWaitTest(&Event->Header, Increment);
96 }
97
98 /* Unsignal it */
99 Event->Header.SignalState = 0;
100
101 /* Check what wait state was requested */
102 if (Wait == FALSE) {
103
104 /* Wait not requested, release Dispatcher Database and return */
105 KeReleaseDispatcherDatabaseLock(OldIrql);
106
107 } else {
108
109 /* Return Locked and with a Wait */
110 KTHREAD *Thread = KeGetCurrentThread();
111 Thread->WaitNext = TRUE;
112 Thread->WaitIrql = OldIrql;
113 }
114
115 /* Return the previous State */
116 return PreviousState;
117 }
118
119 /*
120 * @implemented
121 */
122 LONG
123 STDCALL
124 KeReadStateEvent(PKEVENT Event)
125 {
126 /* Return the Signal State */
127 return Event->Header.SignalState;
128 }
129
130 /*
131 * @implemented
132 */
133 LONG
134 STDCALL
135 KeResetEvent(PKEVENT Event)
136 {
137 KIRQL OldIrql;
138 LONG PreviousState;
139
140 DPRINT("KeResetEvent(Event %x)\n",Event);
141
142 /* Lock the Dispatcher Database */
143 OldIrql = KeAcquireDispatcherDatabaseLock();
144
145 /* Save the Previous State */
146 PreviousState = Event->Header.SignalState;
147
148 /* Set it to zero */
149 Event->Header.SignalState = 0;
150
151 /* Release Dispatcher Database and return previous state */
152 KeReleaseDispatcherDatabaseLock(OldIrql);
153 return PreviousState;
154 }
155
156 /*
157 * @implemented
158 */
159 LONG
160 STDCALL
161 KeSetEvent(PKEVENT Event,
162 KPRIORITY Increment,
163 BOOLEAN Wait)
164 {
165 KIRQL OldIrql;
166 LONG PreviousState;
167 PKWAIT_BLOCK WaitBlock;
168
169 DPRINT("KeSetEvent(Event %x, Wait %x)\n",Event,Wait);
170
171 /* Lock the Dispathcer Database */
172 OldIrql = KeAcquireDispatcherDatabaseLock();
173
174 /* Save the Previous State */
175 PreviousState = Event->Header.SignalState;
176
177 /* Check if we have stuff in the Wait Queue */
178 if (IsListEmpty(&Event->Header.WaitListHead)) {
179
180 /* Set the Event to Signaled */
181 DPRINT("Empty Wait Queue, Signal the Event\n");
182 Event->Header.SignalState = 1;
183
184 } else {
185
186 /* Get the Wait Block */
187 WaitBlock = CONTAINING_RECORD(Event->Header.WaitListHead.Flink,
188 KWAIT_BLOCK,
189 WaitListEntry);
190
191
192 /* Check the type of event */
193 if (Event->Header.Type == NotificationEvent || WaitBlock->WaitType == WaitAll) {
194
195 if (PreviousState == 0) {
196
197 /* We must do a full wait satisfaction */
198 DPRINT("Notification Event or WaitAll, Wait on the Event and Signal\n");
199 Event->Header.SignalState = 1;
200 KiWaitTest(&Event->Header, Increment);
201 }
202
203 } else {
204
205 /* We can satisfy wait simply by waking the thread, since our signal state is 0 now */
206 DPRINT("WaitAny or Sync Event, just unwait the thread\n");
207 KiAbortWaitThread(WaitBlock->Thread, WaitBlock->WaitKey, Increment);
208 }
209 }
210
211 /* Check what wait state was requested */
212 if (Wait == FALSE) {
213
214 /* Wait not requested, release Dispatcher Database and return */
215 KeReleaseDispatcherDatabaseLock(OldIrql);
216
217 } else {
218
219 /* Return Locked and with a Wait */
220 KTHREAD *Thread = KeGetCurrentThread();
221 Thread->WaitNext = TRUE;
222 Thread->WaitIrql = OldIrql;
223 }
224
225 /* Return the previous State */
226 DPRINT("Done: %d\n", PreviousState);
227 return PreviousState;
228 }
229
230 /*
231 * @implemented
232 */
233 VOID
234 STDCALL
235 KeSetEventBoostPriority(IN PKEVENT Event,
236 IN PKTHREAD *Thread OPTIONAL)
237 {
238 PKTHREAD WaitingThread;
239 KIRQL OldIrql;
240
241 DPRINT("KeSetEventBoostPriority(Event %x, Thread %x)\n",Event,Thread);
242
243 /* Acquire Dispatcher Database Lock */
244 OldIrql = KeAcquireDispatcherDatabaseLock();
245
246 /* If our wait list is empty, then signal the event and return */
247 if (IsListEmpty(&Event->Header.WaitListHead)) {
248
249 Event->Header.SignalState = 1;
250
251 } else {
252
253 /* Get Thread that is currently waiting. First get the Wait Block, then the Thread */
254 WaitingThread = CONTAINING_RECORD(Event->Header.WaitListHead.Flink,
255 KWAIT_BLOCK,
256 WaitListEntry)->Thread;
257
258 /* Return it to caller if requested */
259 if ARGUMENT_PRESENT(Thread) *Thread = WaitingThread;
260
261 /* Reset the Quantum and Unwait the Thread */
262 WaitingThread->Quantum = WaitingThread->ApcState.Process->ThreadQuantum;
263 KiAbortWaitThread(WaitingThread, STATUS_SUCCESS, EVENT_INCREMENT);
264 }
265
266 /* Release the Dispatcher Database Lock */
267 KeReleaseDispatcherDatabaseLock(OldIrql);
268 }
269
270 /* EOF */