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