Kernel Gates. Ultra-lightweight and exclusive Wait Objects used in NT 5.2+ as high-speed events. Code is untested, so it's not added to the build until I'm back in May. Modified: trunk/reactos/include/ddk/ketypes.h Modified: trunk/reactos/ntoskrnl/include/internal/ps.h Added: trunk/reactos/ntoskrnl/ke/gate.c _____
Modified: trunk/reactos/include/ddk/ketypes.h --- trunk/reactos/include/ddk/ketypes.h 2005-04-12 23:33:29 UTC (rev 14602) +++ trunk/reactos/include/ddk/ketypes.h 2005-04-13 01:12:08 UTC (rev 14603) @@ -88,6 +88,11 @@
LIST_ENTRY ThreadListHead; } KQUEUE, *PKQUEUE;
+typedef struct _KGATE +{ + DISPATCHER_HEADER Header; +} KGATE, *PKGATE; + struct _KDPC;
typedef struct _KTIMER _____
Modified: trunk/reactos/ntoskrnl/include/internal/ps.h --- trunk/reactos/ntoskrnl/include/internal/ps.h 2005-04-12 23:33:29 UTC (rev 14602) +++ trunk/reactos/ntoskrnl/include/internal/ps.h 2005-04-13 01:12:08 UTC (rev 14603) @@ -85,7 +85,10 @@
CHAR WaitMode; /* 55 */ UCHAR WaitNext; /* 56 */ UCHAR WaitReason; /* 57 */ - PKWAIT_BLOCK WaitBlockList; /* 58 */ + union { /* 58 */ + PKWAIT_BLOCK WaitBlockList; /* 58 */ + PKGATE GateObject; /* 58 */ + }; /* 58 */ LIST_ENTRY WaitListEntry; /* 5C */ ULONG WaitTime; /* 64 */ CHAR BasePriority; /* 68 */ _____
Added: trunk/reactos/ntoskrnl/ke/gate.c --- trunk/reactos/ntoskrnl/ke/gate.c 2005-04-12 23:33:29 UTC (rev 14602) +++ trunk/reactos/ntoskrnl/ke/gate.c 2005-04-13 01:12:08 UTC (rev 14603) @@ -0,0 +1,149 @@
+/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS Kernel + * FILE: ntoskrnl/ke/gate.c + * PURPOSE: Implements the Gate Dispatcher Object + * + * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) + */ + +/* INCLUDES *****************************************************************/ + +#include <ntoskrnl.h> +#define NDEBUG +#include <internal/debug.h> + +/* FUNCTIONS ****************************************************************/ + +VOID +FASTCALL +KeInitializeGate(PKGATE Gate) +{ + DPRINT1("KeInitializeGate(Gate %x)\n", Gate); + + /* Initialize the Dispatcher Header */ + KeInitializeDispatcherHeader(&Gate->Header, + GateObject, + sizeof(Gate) / sizeof(ULONG), + 0); +} + +VOID +FASTCALL +KeWaitForGate(PKGATE Gate, + KWAIT_REASON WaitReason, + KPROCESSOR_MODE WaitMode) +{ + KIRQL OldIrql; + PKTHREAD CurrentThread = KeGetCurrentThread(); + PKWAIT_BLOCK GateWaitBlock; + NTSTATUS Status; + + DPRINT1("KeWaitForGate(Gate %x)\n", Gate); + + do + { + /* Lock the APC Queue */ + KeAcquireSpinLock(&CurrentThread->ApcQueueLock, &OldIrql); + + /* Check if it's already signaled */ + if (!Gate->Header.SignalState) + { + /* Unsignal it */ + Gate->Header.SignalState = 0; + + /* Unlock the Queue and return */ + KeReleaseSpinLock(&CurrentThread->ApcQueueLock, OldIrql); + return; + } + + /* Setup a Wait Block */ + GateWaitBlock = &CurrentThread->WaitBlock[0]; + GateWaitBlock->Object = (PVOID)Gate; + GateWaitBlock->Thread = CurrentThread; + + /* Set the Thread Wait Data */ + CurrentThread->WaitReason = WaitReason; + CurrentThread->WaitMode = WaitMode; + CurrentThread->WaitIrql = OldIrql; + CurrentThread->GateObject = Gate; + + /* Insert into the Wait List */ + InsertTailList(&Gate->Header.WaitListHead, &GateWaitBlock->WaitListEntry); + + /* Handle Kernel Queues */ + if (CurrentThread->Queue) + { + DPRINT1("Waking Queue\n"); + KiWakeQueue(CurrentThread->Queue); + } + + /* Unlock the Queue*/ + KeReleaseSpinLock(&CurrentThread->ApcQueueLock, OldIrql); + + /* Block the Thread */ + DPRINT1("Blocking the Thread: %x\n", CurrentThread); + KiBlockThread(&Status, + CurrentThread->Alertable, + WaitMode, + WaitReason); + + /* Check if we were executing an APC */ + if (Status != STATUS_KERNEL_APC) return; + + DPRINT1("Looping Again\n"); + } while (TRUE); +} + +VOID +FASTCALL +KeSignalGateBoostPriority(PKGATE Gate) +{ + PKTHREAD WaitThread; + PKWAIT_BLOCK WaitBlock; + KIRQL OldIrql; + NTSTATUS WaitStatus = STATUS_SUCCESS; + + DPRINT1("KeSignalGateBoostPriority(EveGate %x)\n", Gate); + + /* Acquire Dispatcher Database Lock */ + OldIrql = KeAcquireDispatcherDatabaseLock(); + + /* Make sure we're not already signaled or that the list is empty */ + if (Gate->Header.SignalState) goto quit; + + /* If our wait list is empty, then signal the event and return */ + if (IsListEmpty(&Gate->Header.WaitListHead)) + { + Gate->Header.SignalState = 1; + goto quit; + } + + /* Get WaitBlock */ + WaitBlock = CONTAINING_RECORD(Gate->Header.WaitListHead.Flink, + KWAIT_BLOCK, + WaitListEntry); + /* Remove it */ + RemoveEntryList(&WaitBlock->WaitListEntry); + + /* Get the Associated thread */ + WaitThread = WaitBlock->Thread; + + /* Increment the Queue's active threads */ + if (WaitThread->Queue) + { + DPRINT1("Incrementing Queue's active threads\n"); + WaitThread->Queue->CurrentCount++; + } + + /* Reschedule the Thread */ + DPRINT1("Unblocking the Thread\n"); + KiUnblockThread(WaitThread, &WaitStatus, EVENT_INCREMENT); + return; + +quit: + /* Release the Dispatcher Database Lock */ + KeReleaseDispatcherDatabaseLock(OldIrql); +} + +/* EOF */