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 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 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 52 KeInitializeEventPair(IN PKEVENT_PAIR EventPair) 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 68 KePulseEvent(IN PKEVENT Event, 69 IN KPRIORITY Increment, 70 IN BOOLEAN Wait) 71 { 72 KIRQL OldIrql; 73 LONG PreviousState; 74 PKTHREAD Thread; 75 ASSERT_EVENT(Event); 76 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 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 120 KeReadStateEvent(IN PKEVENT Event) 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 133 KeResetEvent(IN PKEVENT Event) 134 { 135 KIRQL OldIrql; 136 LONG PreviousState; 137 ASSERT_EVENT(Event); 138 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 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 159 KeSetEvent(IN PKEVENT Event, 160 IN KPRIORITY Increment, 161 IN BOOLEAN Wait) 162 { 163 KIRQL OldIrql; 164 LONG PreviousState; 165 PKTHREAD Thread; 166 ASSERT_EVENT(Event); 167 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 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 229 KeSetEventBoostPriority(IN PKEVENT Event, 230 IN PKTHREAD *WaitingThread OPTIONAL) 231 { 232 KIRQL OldIrql; 233 PKWAIT_BLOCK WaitBlock; 234 PKTHREAD Thread = KeGetCurrentThread(), WaitThread; 235 ASSERT(Event->Header.Type == EventSynchronizationObject); 236 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 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 */ 264 KxUnwaitThreadForEvent(Event, EVENT_INCREMENT); 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 */ 291