KD System Rewrite:
[reactos.git] / reactos / ntoskrnl / ke / event.c
index c71303f..6dd6533 100644 (file)
@@ -1,20 +1,17 @@
 /*
+ *
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS kernel
  * FILE:            ntoskrnl/ke/event.c
  * PURPOSE:         Implements events
- * PROGRAMMER:      David Welch (welch@mcmail.com)
- * UPDATE HISTORY:
- *                  Created 22/05/98
+ * 
+ * PROGRAMMERS:     Alex Ionescu (alex@relsoft.net)
+ *                  David Welch (welch@mcmail.com)
  */
 
 /* INCLUDES *****************************************************************/
 
-#include <ddk/ntddk.h>
-#include <internal/ke.h>
-#include <internal/id.h>
-#include <internal/ps.h>
-
+#include <ntoskrnl.h>
 #define NDEBUG
 #include <internal/debug.h>
 
 /*
  * @implemented
  */
-VOID STDCALL KeClearEvent (PKEVENT Event)
+VOID 
+STDCALL 
+KeClearEvent(PKEVENT Event)
 {
-   DPRINT("KeClearEvent(Event %x)\n", Event);
-   Event->Header.SignalState = FALSE;
+    DPRINT("KeClearEvent(Event %x)\n", Event);
+    
+    /* Reset Signal State */
+    Event->Header.SignalState = FALSE;
 }
 
 /*
  * @implemented
  */
-VOID STDCALL KeInitializeEvent (PKEVENT                Event,
-                               EVENT_TYPE      Type,
-                               BOOLEAN         State)
+VOID 
+STDCALL 
+KeInitializeEvent(PKEVENT Event,
+                  EVENT_TYPE Type,
+                  BOOLEAN State)
 {
-   ULONG IType;
-   
-   if (Type == NotificationEvent)
-     {
-       IType = InternalNotificationEvent;
-     }
-   else if (Type == SynchronizationEvent)
-     {
-       IType = InternalSynchronizationEvent;
-     }
-   else
-     {
-       assert(FALSE);
-       return;
-     }
-   
-   KeInitializeDispatcherHeader(&(Event->Header),
-                               IType,
-                               sizeof(Event)/sizeof(ULONG),State);
-   InitializeListHead(&(Event->Header.WaitListHead));
+    DPRINT("KeInitializeEvent(Event %x)\n", Event);
+    
+    /* Initialize the Dispatcher Header */
+    KeInitializeDispatcherHeader(&Event->Header,
+                                 Type,
+                                 sizeof(Event) / sizeof(ULONG),
+                                 State);
 }
 
 /*
  * @implemented
  */
-LONG STDCALL KeReadStateEvent (PKEVENT Event)
+VOID 
+STDCALL 
+KeInitializeEventPair(PKEVENT_PAIR EventPair)
 {
-   return(Event->Header.SignalState);
+    DPRINT("KeInitializeEventPair(Event %x)\n", EventPair);
+    
+    /* Initialize the Event Pair Type and Size */
+    EventPair->Type = EventPairObject;
+    EventPair->Size = sizeof(KEVENT_PAIR);
+    
+    /* Initialize the two Events */
+    KeInitializeEvent(&EventPair->LowEvent, SynchronizationEvent, FALSE);
+    KeInitializeEvent(&EventPair->HighEvent, SynchronizationEvent, FALSE);
 }
 
 /*
  * @implemented
  */
-LONG STDCALL KeResetEvent (PKEVENT Event)
+LONG STDCALL
+KePulseEvent(IN PKEVENT Event,
+             IN KPRIORITY Increment,
+             IN BOOLEAN Wait)
 {
-   return(InterlockedExchange(&(Event->Header.SignalState),0));
+    KIRQL OldIrql;
+    LONG PreviousState;
+
+    DPRINT("KePulseEvent(Event %x, Wait %x)\n",Event,Wait);
+    
+    /* Lock the Dispatcher Database */
+    OldIrql = KeAcquireDispatcherDatabaseLock();
+    
+    /* Save the Old State */
+    PreviousState = Event->Header.SignalState;
+    
+    /* Check if we are non-signaled and we have stuff in the Wait Queue */
+    if (!PreviousState && !IsListEmpty(&Event->Header.WaitListHead)) {
+        
+        /* Set the Event to Signaled */
+        Event->Header.SignalState = 1;
+    
+        /* Wake the Event */
+        KiWaitTest(&Event->Header, Increment);
+    }
+    
+    /* Unsignal it */
+    Event->Header.SignalState = 0;
+    
+    /* Check what wait state was requested */
+    if (Wait == FALSE) {
+    
+        /* Wait not requested, release Dispatcher Database and return */    
+        KeReleaseDispatcherDatabaseLock(OldIrql);
+        
+    } else {
+        
+        /* Return Locked and with a Wait */
+        KTHREAD *Thread = KeGetCurrentThread();
+        Thread->WaitNext = TRUE;
+        Thread->WaitIrql = OldIrql;
+    }
+
+    /* Return the previous State */
+    return PreviousState;
 }
 
 /*
  * @implemented
  */
-LONG STDCALL KeSetEvent (PKEVENT               Event,
-                        KPRIORITY      Increment,
-                        BOOLEAN                Wait)
+LONG 
+STDCALL 
+KeReadStateEvent(PKEVENT Event)
 {
-  KIRQL OldIrql;
-  int ret;
-
-  DPRINT("KeSetEvent(Event %x, Wait %x)\n",Event,Wait);
+    /* Return the Signal State */
+    return Event->Header.SignalState;
+}
 
-  OldIrql = KeAcquireDispatcherDatabaseLock();
+/*
+ * @implemented
+ */
+LONG 
+STDCALL 
+KeResetEvent(PKEVENT Event)
+{
+    KIRQL OldIrql;
+    LONG PreviousState;
+    
+    DPRINT("KeResetEvent(Event %x)\n",Event);
+    
+    /* Lock the Dispatcher Database */
+    OldIrql = KeAcquireDispatcherDatabaseLock();
+    
+    /* Save the Previous State */
+    PreviousState = Event->Header.SignalState;
+    
+    /* Set it to zero */
+    Event->Header.SignalState = 0;
+    
+    /* Release Dispatcher Database and return previous state */    
+    KeReleaseDispatcherDatabaseLock(OldIrql);
+    return PreviousState;
+}
 
-  ret = InterlockedExchange(&(Event->Header.SignalState),1);
+/*
+ * @implemented
+ */
+LONG
+STDCALL 
+KeSetEvent(PKEVENT Event,
+           KPRIORITY Increment,
+           BOOLEAN Wait)
+{
+    KIRQL OldIrql;
+    LONG PreviousState;
+    PKWAIT_BLOCK WaitBlock;
 
-  KeDispatcherObjectWake((DISPATCHER_HEADER *)Event);
+    DPRINT("KeSetEvent(Event %x, Wait %x)\n",Event,Wait);
 
-  if (Wait == FALSE)
-    {
-      KeReleaseDispatcherDatabaseLock(OldIrql);
+    /* Lock the Dispathcer Database */
+    OldIrql = KeAcquireDispatcherDatabaseLock();
+    
+    /* Save the Previous State */
+    PreviousState = Event->Header.SignalState;
+    
+    /* Check if we have stuff in the Wait Queue */
+    if (IsListEmpty(&Event->Header.WaitListHead)) {
+        
+        /* Set the Event to Signaled */
+        DPRINT("Empty Wait Queue, Signal the Event\n");
+        Event->Header.SignalState = 1;
+        
+    } else {
+    
+        /* Get the Wait Block */
+        WaitBlock = CONTAINING_RECORD(Event->Header.WaitListHead.Flink,
+                                      KWAIT_BLOCK,
+                                      WaitListEntry);
+        
+        
+        /* Check the type of event */
+        if (Event->Header.Type == NotificationEvent || WaitBlock->WaitType == WaitAll) {
+            
+            if (PreviousState == 0) {
+                
+                /* We must do a full wait satisfaction */
+                DPRINT("Notification Event or WaitAll, Wait on the Event and Signal\n");
+                Event->Header.SignalState = 1;
+                KiWaitTest(&Event->Header, Increment);
+            }
+                
+        } else {
+        
+            /* We can satisfy wait simply by waking the thread, since our signal state is 0 now */        
+            DPRINT("WaitAny or Sync Event, just unwait the thread\n");
+            KiAbortWaitThread(WaitBlock->Thread, WaitBlock->WaitKey, Increment);
+        }
     }
-  else
-    {
-      KTHREAD *Thread = KeGetCurrentThread();
-      Thread->WaitNext = Wait;
-      Thread->WaitIrql = OldIrql;
+    
+    /* Check what wait state was requested */
+    if (Wait == FALSE) {
+    
+        /* Wait not requested, release Dispatcher Database and return */    
+        KeReleaseDispatcherDatabaseLock(OldIrql);
+        
+    } else {
+        
+        /* Return Locked and with a Wait */
+        KTHREAD *Thread = KeGetCurrentThread();
+        Thread->WaitNext = TRUE;
+        Thread->WaitIrql = OldIrql;
     }
 
-  return(ret);
+    /* Return the previous State */
+    DPRINT("Done: %d\n", PreviousState);
+    return PreviousState;
 }
 
 /*
  * @implemented
  */
-NTSTATUS STDCALL KePulseEvent (PKEVENT         Event,
-                              KPRIORITY        Increment,
-                              BOOLEAN          Wait)
+VOID
+STDCALL
+KeSetEventBoostPriority(IN PKEVENT Event,
+                        IN PKTHREAD *Thread OPTIONAL)
 {
-   KIRQL OldIrql;
-   int ret;
-
-   DPRINT("KePulseEvent(Event %x, Wait %x)\n",Event,Wait);
-   OldIrql = KeAcquireDispatcherDatabaseLock();
-   ret = InterlockedExchange(&(Event->Header.SignalState),1);
-   KeDispatcherObjectWake((DISPATCHER_HEADER *)Event);
-   InterlockedExchange(&(Event->Header.SignalState),0);
-
-  if (Wait == FALSE)
-    {
-      KeReleaseDispatcherDatabaseLock(OldIrql);
-    }
-  else
-    {
-      KTHREAD *Thread = KeGetCurrentThread();
-      Thread->WaitNext = Wait;
-      Thread->WaitIrql = OldIrql;
-    }
+    PKTHREAD WaitingThread;
+    KIRQL OldIrql;
+
+    DPRINT("KeSetEventBoostPriority(Event %x, Thread %x)\n",Event,Thread);
+    
+    /* Acquire Dispatcher Database Lock */
+    OldIrql = KeAcquireDispatcherDatabaseLock();
+    
+    /* If our wait list is empty, then signal the event and return */
+    if (IsListEmpty(&Event->Header.WaitListHead)) {
+    
+        Event->Header.SignalState = 1;
+    
+    } else {
+        
+        /* Get Thread that is currently waiting. First get the Wait Block, then the Thread */
+        WaitingThread = CONTAINING_RECORD(Event->Header.WaitListHead.Flink, 
+                                          KWAIT_BLOCK, 
+                                          WaitListEntry)->Thread;
 
-   return ((NTSTATUS)ret);
+        /* Return it to caller if requested */
+        if ARGUMENT_PRESENT(Thread) *Thread = WaitingThread;
+
+        /* Reset the Quantum and Unwait the Thread */
+        WaitingThread->Quantum = WaitingThread->ApcState.Process->ThreadQuantum;
+        KiAbortWaitThread(WaitingThread, STATUS_SUCCESS, EVENT_INCREMENT);
+    }
+   
+    /* Release the Dispatcher Database Lock */
+    KeReleaseDispatcherDatabaseLock(OldIrql);
 }
 
 /* EOF */