test: eventobj.c Source File

Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

# eventobj.c

Go to the documentation of this file.

    00001 /*++
    00002
    00003 Copyright (c) 1989  Microsoft Corporation
    00004
    00005 Module Name:
    00006
    00007     eventobj.c
    00008
    00009 Abstract:
    00010
    00011     This module implements the kernel event objects. Functions are
    00012     provided to initialize, pulse, read, reset, and set event objects.
    00013
    00014 Author:
    00015
    00016     David N. Cutler (davec) 27-Feb-1989
    00017
    00018 Environment:
    00019
    00020     Kernel mode only.
    00021
    00022 Revision History:
    00023
    00024 --*/
    00025
    00026 #include "ki.h"
    00027 #undef KeClearEvent
    00028
    00029 //
    00030 // The following assert macro is used to check that an input event is
    00031 // really a kernel event and not something else, like deallocated pool.
    00032 //
    00033
    00034 #define ASSERT_EVENT(E) {                             \
    00035     ASSERT((E)->Header.Type == NotificationEvent ||   \
    00036            (E)->Header.Type == SynchronizationEvent); \
    00037 }
    00038
    00039 //
    00040 // The following assert macro is used to check that an input event is
    00041 // really a kernel event pair and not something else, like deallocated
    00042 // pool.
    00043 //
    00044
    00045 #define ASSERT_EVENT_PAIR(E) {                        \
    00046     ASSERT((E)->Type == EventPairObject);             \
    00047 }
    00048
    00049
    00050 #undef KeInitializeEvent
    00051
    00052 VOID
    00053 KeInitializeEvent (
    00054     IN PRKEVENT Event,
    00055     IN EVENT_TYPE Type,
    00056     IN BOOLEAN State
    00057     )
    00058
    00059 /*++
    00060
    00061 Routine Description:
    00062
    00063     This function initializes a kernel event object. The initial signal
    00064     state of the object is set to the specified value.
    00065
    00066 Arguments:
    00067
    00068     Event - Supplies a pointer to a dispatcher object of type event.
    00069
    00070     Type - Supplies the type of event; NotificationEvent or
    00071         SynchronizationEvent.
    00072
    00073     State - Supplies the initial signal state of the event object.
    00074
    00075 Return Value:
    00076
    00077     None.
    00078
    00079 --*/
    00080
    00081 {
    00082
    00083     //
    00084     // Initialize standard dispatcher object header, set initial signal
    00085     // state of event object, and set the type of event object.
    00086     //
    00087
    00088     Event->Header.Type = (UCHAR)Type;
    00089     Event->Header.Size = sizeof(KEVENT) / sizeof(LONG);
    00090     Event->Header.SignalState = State;
    00091     InitializeListHead(&Event->Header.WaitListHead);
    00092     return;
    00093 }
    00094
    00095 VOID
    00096 KeInitializeEventPair (
    00097     IN PKEVENT_PAIR EventPair
    00098     )
    00099
    00100 /*++
    00101
    00102 Routine Description:
    00103
    00104     This function initializes a kernel event pair object. A kernel event
    00105     pair object contains two separate synchronization event objects that
    00106     are used to provide a fast interprocess synchronization capability.
    00107
    00108 Arguments:
    00109
    00110     EventPair - Supplies a pointer to a control object of type event pair.
    00111
    00112 Return Value:
    00113
    00114     None.
    00115
    00116 --*/
    00117
    00118 {
    00119
    00120     //
    00121     // Initialize the type and size of the event pair object and initialize
    00122     // the two event object as synchronization events with an initial state
    00123     // of FALSE.
    00124     //
    00125
    00126     EventPair->Type = (USHORT)EventPairObject;
    00127     EventPair->Size = sizeof(KEVENT_PAIR);
    00128     KeInitializeEvent(&EventPair->EventLow, SynchronizationEvent, FALSE);
    00129     KeInitializeEvent(&EventPair->EventHigh, SynchronizationEvent, FALSE);
    00130     return;
    00131 }
    00132
    00133 VOID
    00134 KeClearEvent (
    00135     IN PRKEVENT Event
    00136     )
    00137
    00138 /*++
    00139
    00140 Routine Description:
    00141
    00142     This function clears the signal state of an event object.
    00143
    00144 Arguments:
    00145
    00146     Event - Supplies a pointer to a dispatcher object of type event.
    00147
    00148 Return Value:
    00149
    00150     None.
    00151
    00152 --*/
    00153
    00154 {
    00155
    00156     ASSERT_EVENT(Event);
    00157
    00158     //
    00159     // Clear signal state of event object.
    00160     //
    00161
    00162     Event->Header.SignalState = 0;
    00163     return;
    00164 }
    00165
    00166 LONG
    00167 KePulseEvent (
    00168     IN PRKEVENT Event,
    00169     IN KPRIORITY Increment,
    00170     IN BOOLEAN Wait
    00171     )
    00172
    00173 /*++
    00174
    00175 Routine Description:
    00176
    00177     This function atomically sets the signal state of an event object to
    00178     Signaled, attempts to satisfy as many Waits as possible, and then resets
    00179     the signal state of the event object to Not-Signaled. The previous signal
    00180     state of the event object is returned as the function value.
    00181
    00182 Arguments:
    00183
    00184     Event - Supplies a pointer to a dispatcher object of type event.
    00185
    00186     Increment - Supplies the priority increment that is to be applied
    00187        if setting the event causes a Wait to be satisfied.
    00188
    00189     Wait - Supplies a boolean value that signifies whether the call to
    00190        KePulseEvent will be immediately followed by a call to one of the
    00191        kernel Wait functions.
    00192
    00193 Return Value:
    00194
    00195     The previous signal state of the event object.
    00196
    00197 --*/
    00198
    00199 {
    00200
    00201     KIRQL OldIrql;
    00202     LONG OldState;
    00203     PRKTHREAD Thread;
    00204
    00205     ASSERT_EVENT(Event);
    00206     ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
    00207
    00208     //
    00209     // Raise IRQL to dispatcher level and lock dispatcher database.
    00210     //
    00211
    00212     KiLockDispatcherDatabase(&OldIrql);
    00213
    00214     //
    00215     // If the current state of the event object is Not-Signaled and
    00216     // the wait queue is not empty, then set the state of the event
    00217     // to Signaled, satisfy as many Waits as possible, and then reset
    00218     // the state of the event to Not-Signaled.
    00219     //
    00220
    00221     OldState = Event->Header.SignalState;
    00222     if ((OldState == 0) && (IsListEmpty(&Event->Header.WaitListHead) == FALSE)) {
    00223         Event->Header.SignalState = 1;
    00224         KiWaitTest(Event, Increment);
    00225     }
    00226
    00227     Event->Header.SignalState = 0;
    00228
    00229     //
    00230     // If the value of the Wait argument is TRUE, then return to the
    00231     // caller with IRQL raised and the dispatcher database locked. Else
    00232     // release the dispatcher database lock and lower IRQL to the
    00233     // previous value.
    00234     //
    00235
    00236     if (Wait != FALSE) {
    00237         Thread = KeGetCurrentThread();
    00238         Thread->WaitIrql = OldIrql;
    00239         Thread->WaitNext = Wait;
    00240
    00241     } else {
    00242        KiUnlockDispatcherDatabase(OldIrql);
    00243     }
    00244
    00245     //
    00246     // Return previous signal state of event object.
    00247     //
    00248
    00249     return OldState;
    00250 }
    00251
    00252 LONG
    00253 KeReadStateEvent (
    00254     IN PRKEVENT Event
    00255     )
    00256
    00257 /*++
    00258
    00259 Routine Description:
    00260
    00261     This function reads the current signal state of an event object.
    00262
    00263 Arguments:
    00264
    00265     Event - Supplies a pointer to a dispatcher object of type event.
    00266
    00267 Return Value:
    00268
    00269     The current signal state of the event object.
    00270
    00271 --*/
    00272
    00273 {
    00274
    00275     ASSERT_EVENT(Event);
    00276
    00277     //
    00278     // Return current signal state of event object.
    00279     //
    00280
    00281     return Event->Header.SignalState;
    00282 }
    00283
    00284 LONG
    00285 KeResetEvent (
    00286     IN PRKEVENT Event
    00287     )
    00288
    00289 /*++
    00290
    00291 Routine Description:
    00292
    00293     This function resets the signal state of an event object to
    00294     Not-Signaled. The previous state of the event object is returned
    00295     as the function value.
    00296
    00297 Arguments:
    00298
    00299     Event - Supplies a pointer to a dispatcher object of type event.
    00300
    00301 Return Value:
    00302
    00303     The previous signal state of the event object.
    00304
    00305 --*/
    00306
    00307 {
    00308
    00309     KIRQL OldIrql;
    00310     LONG OldState;
    00311
    00312     ASSERT_EVENT(Event);
    00313     ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
    00314
    00315     //
    00316     // Raise IRQL to dispatcher level and lock dispatcher database.
    00317     //
    00318
    00319     KiLockDispatcherDatabase(&OldIrql);
    00320
    00321     //
    00322     // Capture the current signal state of event object and then reset
    00323     // the state of the event object to Not-Signaled.
    00324     //
    00325
    00326     OldState = Event->Header.SignalState;
    00327     Event->Header.SignalState = 0;
    00328
    00329     //
    00330     // Unlock the dispatcher database and lower IRQL to its previous
    00331     // value.
    00332
    00333     KiUnlockDispatcherDatabase(OldIrql);
    00334
    00335     //
    00336     // Return previous signal state of event object.
    00337     //
    00338
    00339     return OldState;
    00340 }
    00341
    00342 LONG
    00343 KeSetEvent (
    00344     IN PRKEVENT Event,
    00345     IN KPRIORITY Increment,
    00346     IN BOOLEAN Wait
    00347     )
    00348
    00349 /*++
    00350
    00351 Routine Description:
    00352
    00353     This function sets the signal state of an event object to Signaled
    00354     and attempts to satisfy as many Waits as possible. The previous
    00355     signal state of the event object is returned as the function value.
    00356
    00357 Arguments:
    00358
    00359     Event - Supplies a pointer to a dispatcher object of type event.
    00360
    00361     Increment - Supplies the priority increment that is to be applied
    00362        if setting the event causes a Wait to be satisfied.
    00363
    00364     Wait - Supplies a boolean value that signifies whether the call to
    00365        KePulseEvent will be immediately followed by a call to one of the
    00366        kernel Wait functions.
    00367
    00368 Return Value:
    00369
    00370     The previous signal state of the event object.
    00371
    00372 --*/
    00373
    00374 {
    00375
    00376     KIRQL OldIrql;
    00377     LONG OldState;
    00378     PRKTHREAD Thread;
    00379     PRKWAIT_BLOCK WaitBlock;
    00380
    00381     ASSERT_EVENT(Event);
    00382     ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
    00383
    00384     //
    00385     // Collect call data.
    00386     //
    00387
    00388 #if defined(_COLLECT_SET_EVENT_CALLDATA_)
    00389
    00390     RECORD_CALL_DATA(&KiSetEventCallData);
    00391
    00392 #endif
    00393
    00394     //
    00395     // Raise IRQL to dispatcher level and lock dispatcher database.
    00396     //
    00397
    00398     KiLockDispatcherDatabase(&OldIrql);
    00399
    00400     //
    00401     // If the wait list is empty, then set the state of the event to signaled.
    00402     // Otherwise, check if the wait can be satisfied immediately.
    00403     //
    00404
    00405     OldState = Event->Header.SignalState;
    00406     if (IsListEmpty(&Event->Header.WaitListHead) != FALSE) {
    00407         Event->Header.SignalState = 1;
    00408
    00409     } else {
    00410
    00411         //
    00412         // If the event is a notification event or the wait is not a wait any,
    00413         // then set the state of the event to signaled and attempt to satisfy
    00414         // as many waits as possible. Otherwise, the wait can be satisfied by
    00415         // directly unwaiting the thread.
    00416         //
    00417
    00418         WaitBlock = CONTAINING_RECORD(Event->Header.WaitListHead.Flink,
    00419                                       KWAIT_BLOCK,
    00420                                       WaitListEntry);
    00421
    00422         if ((Event->Header.Type == NotificationEvent) ||
    00423             (WaitBlock->WaitType != WaitAny)) {
    00424             if (OldState == 0) {
    00425                 Event->Header.SignalState = 1;
    00426                 KiWaitTest(Event, Increment);
    00427             }
    00428
    00429         } else {
    00430             KiUnwaitThread(WaitBlock->Thread, (NTSTATUS)WaitBlock->WaitKey, Increment);
    00431         }
    00432     }
    00433
    00434     //
    00435     // If the value of the Wait argument is TRUE, then return to the
    00436     // caller with IRQL raised and the dispatcher database locked. Else
    00437     // release the dispatcher database lock and lower IRQL to its
    00438     // previous value.
    00439     //
    00440
    00441     if (Wait != FALSE) {
    00442        Thread = KeGetCurrentThread();
    00443        Thread->WaitNext = Wait;
    00444        Thread->WaitIrql = OldIrql;
    00445
    00446     } else {
    00447        KiUnlockDispatcherDatabase(OldIrql);
    00448     }
    00449
    00450     //
    00451     // Return previous signal state of event object.
    00452     //
    00453
    00454     return OldState;
    00455 }
    00456
    00457 VOID
    00458 KeSetEventBoostPriority (
    00459     IN PRKEVENT Event,
    00460     IN PRKTHREAD *Thread OPTIONAL
    00461     )
    00462
    00463 /*++
    00464
    00465 Routine Description:
    00466
    00467     This function conditionally sets the signal state of an event object
    00468     to Signaled, and attempts to unwait the first waiter, and optionally
    00469     returns the thread address of the unwatied thread.
    00470
    00471     N.B. This function can only be called with synchronization events
    00472          and is primarily for the purpose of implementing fast mutexes.
    00473          It is assumed that the waiter is NEVER waiting on multiple
    00474          objects.
    00475
    00476 Arguments:
    00477
    00478     Event - Supplies a pointer to a dispatcher object of type event.
    00479
    00480     Thread - Supplies an optional pointer to a variable that receives
    00481         the address of the thread that is awakened.
    00482
    00483 Return Value:
    00484
    00485     None.
    00486
    00487 --*/
    00488
    00489 {
    00490
    00491     KPRIORITY Increment;
    00492     KIRQL OldIrql;
    00493     PRKTHREAD WaitThread;
    00494
    00495     ASSERT(Event->Header.Type == SynchronizationEvent);
    00496     ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
    00497
    00498     //
    00499     // Raise IRQL to dispatcher level and lock dispatcher database.
    00500     //
    00501
    00502     KiLockDispatcherDatabase(&OldIrql);
    00503
    00504     //
    00505     // If the the wait list is not empty, then satisfy the wait of the
    00506     // first thread in the wait list. Otherwise, set the signal state
    00507     // of the event object.
    00508     //
    00509     // N.B. This function is only called for fast mutexes and exclusive
    00510     //      access to resources. All waits MUST be wait for single object.
    00511     //
    00512
    00513     if (IsListEmpty(&Event->Header.WaitListHead) != FALSE) {
    00514         Event->Header.SignalState = 1;
    00515
    00516     } else {
    00517
    00518         //
    00519         // Get the address of the waiting thread.
    00520         //
    00521
    00522         WaitThread = CONTAINING_RECORD(Event->Header.WaitListHead.Flink,
    00523                                        KWAIT_BLOCK,
    00524                                        WaitListEntry)->Thread;
    00525
    00526         //
    00527         // If specified, return the address of the thread that is awakened.
    00528         //
    00529
    00530         if (ARGUMENT_PRESENT(Thread)) {
    00531             *Thread = WaitThread;
    00532         }
    00533
    00534         //
    00535         // Give the new owner of the resource/fast mutex (the only callers) a
    00536         // full quantum, and unwait the thread with a standard event increment
    00537         // unless the system is a server system, in which case no boost if given.
    00538         //
    00539
    00540         WaitThread->Quantum = WaitThread->ApcState.Process->ThreadQuantum;
    00541         Increment = 0;
    00542         if (MmProductType == 0) {
    00543             Increment = EVENT_INCREMENT;
    00544         }
    00545
    00546         KiUnwaitThread(WaitThread, STATUS_SUCCESS, Increment);
    00547     }
    00548
    00549     //
    00550     // Unlock dispatcher database lock and lower IRQL to its previous
    00551     // value.
    00552     //
    00553
    00554     KiUnlockDispatcherDatabase(OldIrql);
    00555     return;
    00556 }