ReactOS  0.4.11-dev-721-g95bc44e
eventobj.c
Go to the documentation of this file.
1 /*
2  * PROJECT: ReactOS Kernel
3  * LICENSE: GPL - See COPYING in the top level directory
4  * FILE: ntoskrnl/ke/eventobj.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
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
38 {
39  /* Initialize the Dispatcher Header */
40  Event->Header.Type = Type;
41  //Event->Header.Signalling = FALSE; // fails in kmtest
42  Event->Header.Size = sizeof(KEVENT) / sizeof(ULONG);
43  Event->Header.SignalState = State;
44  InitializeListHead(&(Event->Header.WaitListHead));
45 }
46 
47 /*
48  * @implemented
49  */
50 VOID
51 NTAPI
53 {
54  /* Initialize the Event Pair Type and Size */
55  EventPair->Type = EventPairObject;
56  EventPair->Size = sizeof(KEVENT_PAIR);
57 
58  /* Initialize the two Events */
59  KeInitializeEvent(&EventPair->LowEvent, SynchronizationEvent, FALSE);
60  KeInitializeEvent(&EventPair->HighEvent, SynchronizationEvent, FALSE);
61 }
62 
63 /*
64  * @implemented
65  */
66 LONG
67 NTAPI
70  IN BOOLEAN Wait)
71 {
72  KIRQL OldIrql;
75  ASSERT_EVENT(Event);
77 
78  /* Lock the Dispatcher Database */
79  OldIrql = KiAcquireDispatcherLock();
80 
81  /* Save the Old State */
82  PreviousState = Event->Header.SignalState;
83 
84  /* Check if we are non-signaled and we have stuff in the Wait Queue */
85  if (!PreviousState && !IsListEmpty(&Event->Header.WaitListHead))
86  {
87  /* Set the Event to Signaled */
88  Event->Header.SignalState = 1;
89 
90  /* Wake the Event */
91  KiWaitTest(&Event->Header, Increment);
92  }
93 
94  /* Unsignal it */
95  Event->Header.SignalState = 0;
96 
97  /* Check what wait state was requested */
98  if (Wait == FALSE)
99  {
100  /* Wait not requested, release Dispatcher Database and return */
101  KiReleaseDispatcherLock(OldIrql);
102  }
103  else
104  {
105  /* Return Locked and with a Wait */
106  Thread = KeGetCurrentThread();
107  Thread->WaitNext = TRUE;
108  Thread->WaitIrql = OldIrql;
109  }
110 
111  /* Return the previous State */
112  return PreviousState;
113 }
114 
115 /*
116  * @implemented
117  */
118 LONG
119 NTAPI
121 {
122  ASSERT_EVENT(Event);
123 
124  /* Return the Signal State */
125  return Event->Header.SignalState;
126 }
127 
128 /*
129  * @implemented
130  */
131 LONG
132 NTAPI
134 {
135  KIRQL OldIrql;
137  ASSERT_EVENT(Event);
139 
140  /* Lock the Dispatcher Database */
141  OldIrql = KiAcquireDispatcherLock();
142 
143  /* Save the Previous State */
144  PreviousState = Event->Header.SignalState;
145 
146  /* Set it to zero */
147  Event->Header.SignalState = 0;
148 
149  /* Release Dispatcher Database and return previous state */
150  KiReleaseDispatcherLock(OldIrql);
151  return PreviousState;
152 }
153 
154 /*
155  * @implemented
156  */
157 LONG
158 NTAPI
161  IN BOOLEAN Wait)
162 {
163  KIRQL OldIrql;
166  ASSERT_EVENT(Event);
168 
169  /*
170  * Check if this is an signaled notification event without an upcoming wait.
171  * In this case, we can immediately return TRUE, without locking.
172  */
173  if ((Event->Header.Type == EventNotificationObject) &&
174  (Event->Header.SignalState == 1) &&
175  !(Wait))
176  {
177  /* Return the signal state (TRUE/Signalled) */
178  return TRUE;
179  }
180 
181  /* Lock the Dispathcer Database */
182  OldIrql = KiAcquireDispatcherLock();
183 
184  /* Save the Previous State */
185  PreviousState = Event->Header.SignalState;
186 
187  /* Set the Event to Signaled */
188  Event->Header.SignalState = 1;
189 
190  /* Check if the event just became signaled now, and it has waiters */
191  if (!(PreviousState) && !(IsListEmpty(&Event->Header.WaitListHead)))
192  {
193  /* Check the type of event */
194  if (Event->Header.Type == EventNotificationObject)
195  {
196  /* Unwait the thread */
197  KxUnwaitThread(&Event->Header, Increment);
198  }
199  else
200  {
201  /* Otherwise unwait the thread and unsignal the event */
202  KxUnwaitThreadForEvent(Event, Increment);
203  }
204  }
205 
206  /* Check what wait state was requested */
207  if (!Wait)
208  {
209  /* Wait not requested, release Dispatcher Database and return */
210  KiReleaseDispatcherLock(OldIrql);
211  }
212  else
213  {
214  /* Return Locked and with a Wait */
215  Thread = KeGetCurrentThread();
216  Thread->WaitNext = TRUE;
217  Thread->WaitIrql = OldIrql;
218  }
219 
220  /* Return the previous State */
221  return PreviousState;
222 }
223 
224 /*
225  * @implemented
226  */
227 VOID
228 NTAPI
230  IN PKTHREAD *WaitingThread OPTIONAL)
231 {
232  KIRQL OldIrql;
233  PKWAIT_BLOCK WaitBlock;
234  PKTHREAD Thread = KeGetCurrentThread(), WaitThread;
235  ASSERT(Event->Header.Type == EventSynchronizationObject);
237 
238  /* Acquire Dispatcher Database Lock */
239  OldIrql = KiAcquireDispatcherLock();
240 
241  /* Check if the list is empty */
242  if (IsListEmpty(&Event->Header.WaitListHead))
243  {
244  /* Set the Event to Signaled */
245  Event->Header.SignalState = 1;
246 
247  /* Return */
248  KiReleaseDispatcherLock(OldIrql);
249  return;
250  }
251 
252  /* Get the Wait Block */
253  WaitBlock = CONTAINING_RECORD(Event->Header.WaitListHead.Flink,
254  KWAIT_BLOCK,
255  WaitListEntry);
256 
257  /* Check if this is a WaitAll */
258  if (WaitBlock->WaitType == WaitAll)
259  {
260  /* Set the Event to Signaled */
261  Event->Header.SignalState = 1;
262 
263  /* Unwait the thread and unsignal the event */
265  }
266  else
267  {
268  /* Return waiting thread to caller */
269  WaitThread = WaitBlock->Thread;
270  if (WaitingThread) *WaitingThread = WaitThread;
271 
272  /* Calculate new priority */
273  Thread->Priority = KiComputeNewPriority(Thread, 0);
274 
275  /* Unlink the waiting thread */
276  KiUnlinkThread(WaitThread, STATUS_SUCCESS);
277 
278  /* Request priority boosting */
279  WaitThread->AdjustIncrement = Thread->Priority;
280  WaitThread->AdjustReason = AdjustBoost;
281 
282  /* Ready the thread */
283  KiReadyThread(WaitThread);
284  }
285 
286  /* Release the Dispatcher Database Lock */
287  KiReleaseDispatcherLock(OldIrql);
288 }
289 
290 /* EOF */
#define ASSERT_IRQL_LESS_OR_EQUAL(x)
Definition: debug.h:256
#define IN
Definition: typedefs.h:38
#define TRUE
Definition: types.h:120
Type
Definition: Type.h:6
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel)?(CompletionRoutine!=NULL):TRUE)
VOID NTAPI KeInitializeEventPair(IN PKEVENT_PAIR EventPair)
Definition: eventobj.c:52
FORCEINLINE VOID KxUnwaitThreadForEvent(IN PKEVENT Event, IN KPRIORITY Increment)
Definition: ke_x.h:1295
VOID FASTCALL KiUnlinkThread(IN PKTHREAD Thread, IN LONG_PTR WaitStatus)
Definition: wait.c:55
struct _KTHREAD * Thread
Definition: ketypes.h:453
SCHAR Priority
Definition: ketypes.h:1672
VOID FASTCALL KiWaitTest(PVOID Object, KPRIORITY Increment)
VOID NTAPI KeInitializeEvent(OUT PKEVENT Event, IN EVENT_TYPE Type, IN BOOLEAN State)
Definition: eventobj.c:35
struct _KEVENT_PAIR KEVENT_PAIR
LONG NTAPI KeSetEvent(IN PKEVENT Event, IN KPRIORITY Increment, IN BOOLEAN Wait)
Definition: eventobj.c:159
_Must_inspect_result_ FORCEINLINE BOOLEAN IsListEmpty(_In_ const LIST_ENTRY *ListHead)
Definition: rtlfuncs.h:57
LONG KPRIORITY
Definition: compat.h:454
#define ASSERT_EVENT(Object)
FORCEINLINE SCHAR KiComputeNewPriority(IN PKTHREAD Thread, IN SCHAR Adjustment)
Definition: ke_x.h:1458
UCHAR KIRQL
Definition: env_spec_w32.h:591
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
#define FALSE
Definition: types.h:117
long LONG
Definition: pedump.c:60
ULONG WaitNext
Definition: ketypes.h:1586
LONG NTAPI KePulseEvent(IN PKEVENT Event, IN KPRIORITY Increment, IN BOOLEAN Wait)
Definition: eventobj.c:68
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
VOID NTAPI KiReadyThread(IN PKTHREAD Thread)
Definition: thrdschd.c:429
enum _EVENT_TYPE EVENT_TYPE
unsigned char BOOLEAN
UCHAR WaitType
Definition: ketypes.h:446
_In_opt_ PFILE_OBJECT _In_opt_ PETHREAD Thread
Definition: fltkernel.h:2653
struct _KEVENT KEVENT
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:803
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
_In_ PLARGE_INTEGER _In_opt_ PTIMER_APC_ROUTINE _In_opt_ PVOID _In_ BOOLEAN _In_opt_ LONG _Out_opt_ PBOOLEAN PreviousState
Definition: zwfuncs.h:428
enum State_ State
Definition: pofuncs.h:54
#define EVENT_INCREMENT
Definition: iotypes.h:564
FORCEINLINE VOID KiReleaseDispatcherLock(IN KIRQL OldIrql)
Definition: ke_x.h:152
FORCEINLINE KIRQL KiAcquireDispatcherLock(VOID)
Definition: ke_x.h:144
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
_In_ BOOLEAN Wait
Definition: cctypes.h:23
#define OUT
Definition: typedefs.h:39
LONG NTAPI KeReadStateEvent(IN PKEVENT Event)
Definition: eventobj.c:120
LONG NTAPI KeResetEvent(IN PKEVENT Event)
Definition: eventobj.c:133
unsigned int ULONG
Definition: retypes.h:1
VOID NTAPI KeSetEventBoostPriority(IN PKEVENT Event, IN PKTHREAD *WaitingThread OPTIONAL)
Definition: eventobj.c:229
FORCEINLINE VOID KxUnwaitThread(IN DISPATCHER_HEADER *Object, IN KPRIORITY Increment)
Definition: ke_x.h:1250
#define KeGetCurrentThread
Definition: hal.h:44
VOID NTAPI KeClearEvent(IN PKEVENT Event)
Definition: eventobj.c:22
IN OUT PLONG IN OUT PLONG Addend IN OUT PLONG IN LONG Increment
Definition: CrNtStubs.h:42
return STATUS_SUCCESS
Definition: btrfs.c:2710
IN HDEVINFO IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
Definition: devinst.c:44
KIRQL WaitIrql
Definition: ketypes.h:1685