[CMAKE/NTOSKRNL]
[reactos.git] / ntoskrnl / ke / eventobj.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ke/event.c
5 * PURPOSE: Implements the Event Dispatcher Object
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* FUNCTIONS *****************************************************************/
16
17 /*
18 * @implemented
19 */
20 VOID
21 NTAPI
22 KeClearEvent(IN PKEVENT Event)
23 {
24 ASSERT_EVENT(Event);
25
26 /* Reset Signal State */
27 Event->Header.SignalState = FALSE;
28 }
29
30 /*
31 * @implemented
32 */
33 VOID
34 NTAPI
35 KeInitializeEvent(OUT PKEVENT Event,
36 IN EVENT_TYPE Type,
37 IN BOOLEAN State)
38 {
39 /* Initialize the Dispatcher Header */
40 KeInitializeDispatcherHeader(&Event->Header,
41 Type,
42 sizeof(*Event) / sizeof(ULONG),
43 State);
44 }
45
46 /*
47 * @implemented
48 */
49 VOID
50 NTAPI
51 KeInitializeEventPair(IN PKEVENT_PAIR EventPair)
52 {
53 /* Initialize the Event Pair Type and Size */
54 EventPair->Type = EventPairObject;
55 EventPair->Size = sizeof(KEVENT_PAIR);
56
57 /* Initialize the two Events */
58 KeInitializeEvent(&EventPair->LowEvent, SynchronizationEvent, FALSE);
59 KeInitializeEvent(&EventPair->HighEvent, SynchronizationEvent, FALSE);
60 }
61
62 /*
63 * @implemented
64 */
65 LONG
66 NTAPI
67 KePulseEvent(IN PKEVENT Event,
68 IN KPRIORITY Increment,
69 IN BOOLEAN Wait)
70 {
71 KIRQL OldIrql;
72 LONG PreviousState;
73 PKTHREAD Thread;
74 ASSERT_EVENT(Event);
75 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
76
77 /* Lock the Dispatcher Database */
78 OldIrql = KiAcquireDispatcherLock();
79
80 /* Save the Old State */
81 PreviousState = Event->Header.SignalState;
82
83 /* Check if we are non-signaled and we have stuff in the Wait Queue */
84 if (!PreviousState && !IsListEmpty(&Event->Header.WaitListHead))
85 {
86 /* Set the Event to Signaled */
87 Event->Header.SignalState = 1;
88
89 /* Wake the Event */
90 KiWaitTest(&Event->Header, Increment);
91 }
92
93 /* Unsignal it */
94 Event->Header.SignalState = 0;
95
96 /* Check what wait state was requested */
97 if (Wait == FALSE)
98 {
99 /* Wait not requested, release Dispatcher Database and return */
100 KiReleaseDispatcherLock(OldIrql);
101 }
102 else
103 {
104 /* Return Locked and with a Wait */
105 Thread = KeGetCurrentThread();
106 Thread->WaitNext = TRUE;
107 Thread->WaitIrql = OldIrql;
108 }
109
110 /* Return the previous State */
111 return PreviousState;
112 }
113
114 /*
115 * @implemented
116 */
117 LONG
118 NTAPI
119 KeReadStateEvent(IN PKEVENT Event)
120 {
121 ASSERT_EVENT(Event);
122
123 /* Return the Signal State */
124 return Event->Header.SignalState;
125 }
126
127 /*
128 * @implemented
129 */
130 LONG
131 NTAPI
132 KeResetEvent(IN PKEVENT Event)
133 {
134 KIRQL OldIrql;
135 LONG PreviousState;
136 ASSERT_EVENT(Event);
137 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
138
139 /* Lock the Dispatcher Database */
140 OldIrql = KiAcquireDispatcherLock();
141
142 /* Save the Previous State */
143 PreviousState = Event->Header.SignalState;
144
145 /* Set it to zero */
146 Event->Header.SignalState = 0;
147
148 /* Release Dispatcher Database and return previous state */
149 KiReleaseDispatcherLock(OldIrql);
150 return PreviousState;
151 }
152
153 /*
154 * @implemented
155 */
156 LONG
157 NTAPI
158 KeSetEvent(IN PKEVENT Event,
159 IN KPRIORITY Increment,
160 IN BOOLEAN Wait)
161 {
162 KIRQL OldIrql;
163 LONG PreviousState;
164 PKTHREAD Thread;
165 ASSERT_EVENT(Event);
166 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
167
168 /*
169 * Check if this is an signaled notification event without an upcoming wait.
170 * In this case, we can immediately return TRUE, without locking.
171 */
172 if ((Event->Header.Type == EventNotificationObject) &&
173 (Event->Header.SignalState == 1) &&
174 !(Wait))
175 {
176 /* Return the signal state (TRUE/Signalled) */
177 return TRUE;
178 }
179
180 /* Lock the Dispathcer Database */
181 OldIrql = KiAcquireDispatcherLock();
182
183 /* Save the Previous State */
184 PreviousState = Event->Header.SignalState;
185
186 /* Set the Event to Signaled */
187 Event->Header.SignalState = 1;
188
189 /* Check if the event just became signaled now, and it has waiters */
190 if (!(PreviousState) && !(IsListEmpty(&Event->Header.WaitListHead)))
191 {
192 /* Check the type of event */
193 if (Event->Header.Type == EventNotificationObject)
194 {
195 /* Unwait the thread */
196 KxUnwaitThread(&Event->Header, Increment);
197 }
198 else
199 {
200 /* Otherwise unwait the thread and unsignal the event */
201 KxUnwaitThreadForEvent(Event, Increment);
202 }
203 }
204
205 /* Check what wait state was requested */
206 if (!Wait)
207 {
208 /* Wait not requested, release Dispatcher Database and return */
209 KiReleaseDispatcherLock(OldIrql);
210 }
211 else
212 {
213 /* Return Locked and with a Wait */
214 Thread = KeGetCurrentThread();
215 Thread->WaitNext = TRUE;
216 Thread->WaitIrql = OldIrql;
217 }
218
219 /* Return the previous State */
220 return PreviousState;
221 }
222
223 /*
224 * @implemented
225 */
226 VOID
227 NTAPI
228 KeSetEventBoostPriority(IN PKEVENT Event,
229 IN PKTHREAD *WaitingThread OPTIONAL)
230 {
231 KIRQL OldIrql;
232 PKWAIT_BLOCK WaitBlock;
233 PKTHREAD Thread = KeGetCurrentThread(), WaitThread;
234 ASSERT(Event->Header.Type == EventSynchronizationObject);
235 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
236
237 /* Acquire Dispatcher Database Lock */
238 OldIrql = KiAcquireDispatcherLock();
239
240 /* Check if the list is empty */
241 if (IsListEmpty(&Event->Header.WaitListHead))
242 {
243 /* Set the Event to Signaled */
244 Event->Header.SignalState = 1;
245
246 /* Return */
247 KiReleaseDispatcherLock(OldIrql);
248 return;
249 }
250
251 /* Get the Wait Block */
252 WaitBlock = CONTAINING_RECORD(Event->Header.WaitListHead.Flink,
253 KWAIT_BLOCK,
254 WaitListEntry);
255
256 /* Check if this is a WaitAll */
257 if (WaitBlock->WaitType == WaitAll)
258 {
259 /* Set the Event to Signaled */
260 Event->Header.SignalState = 1;
261
262 /* Unwait the thread and unsignal the event */
263 KxUnwaitThreadForEvent(Event, EVENT_INCREMENT);
264 }
265 else
266 {
267 /* Return waiting thread to caller */
268 WaitThread = WaitBlock->Thread;
269 if (WaitingThread) *WaitingThread = WaitThread;
270
271 /* Calculate new priority */
272 Thread->Priority = KiComputeNewPriority(Thread, 0);
273
274 /* Unlink the waiting thread */
275 KiUnlinkThread(WaitThread, STATUS_SUCCESS);
276
277 /* Request priority boosting */
278 WaitThread->AdjustIncrement = Thread->Priority;
279 WaitThread->AdjustReason = AdjustBoost;
280
281 /* Ready the thread */
282 KiReadyThread(WaitThread);
283 }
284
285 /* Release the Dispatcher Database Lock */
286 KiReleaseDispatcherLock(OldIrql);
287 }
288
289 /* EOF */