mirror of
https://github.com/reactos/reactos.git
synced 2025-02-22 16:36:33 +00:00
- Fix handle close bug. The ExDestroyHandleEntry API was only killing entries unless the table wasn't being destoyed, which it actually is during process termination, and through failing, was actually not closing the handle at all. This means any killed process leaked all its handles and they were never closed. These handles are now closed, reducing memory load/leaks and opening the door for new bugs :)
- Fix LPC process closing bug. - Rewrite executive timer support to make it thread-safe and use proper locking order and semantics as well as safe referencing. Also implement Windows 2003 feature of flushing DPCs when a timer is deleted, to avoid the timer from being fired after deletion. svn path=/trunk/; revision=25461
This commit is contained in:
parent
8eb1ea4802
commit
d673aa2616
10 changed files with 197 additions and 253 deletions
|
@ -144,7 +144,7 @@ SmpApiConnectedThread(PVOID pConnectedPort)
|
|||
break;
|
||||
case LPC_PORT_CLOSED:
|
||||
Reply = NULL;
|
||||
break;
|
||||
continue;
|
||||
default:
|
||||
if ((Request.SmHeader.ApiIndex) &&
|
||||
(Request.SmHeader.ApiIndex < (sizeof SmApi / sizeof SmApi[0])))
|
||||
|
|
|
@ -195,6 +195,12 @@ KeIsExecutingDpc(
|
|||
VOID
|
||||
);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
KeFlushQueuedDpcs(
|
||||
VOID
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
KiIpiServiceRoutine(
|
||||
|
|
|
@ -9,24 +9,20 @@
|
|||
// Failure to respect this will *ACHIEVE NOTHING*.
|
||||
//
|
||||
// Ex:
|
||||
// - Fixup existing code that talks to Ke.
|
||||
// - Implement Generic Callback mechanism.
|
||||
// - Use pushlocks for handle implementation.
|
||||
//
|
||||
// Lpc:
|
||||
// - Figure out why NTLPC-processes won't die anymore.
|
||||
//
|
||||
// Ke1:
|
||||
// - Implement KiInitMachineDependent.
|
||||
// - Implement Privileged Instruction Handler in Umode GPF.
|
||||
//
|
||||
// Fstub:
|
||||
// - Implement IoAssignDriveLetters using mount manager support.
|
||||
//
|
||||
// Hal:
|
||||
// - Use APC and DPC Interrupt Dispatchers.
|
||||
// - CMOS Initialization and CMOS Spinlock.
|
||||
//
|
||||
// Fstub:
|
||||
// - Implement IoAssignDriveLetters using mount manager support.
|
||||
//
|
||||
// Ke2:
|
||||
// - New optimized table-based tick-hashed timer implementation.
|
||||
// - New Thread Scheduler based on 2003.
|
||||
|
|
|
@ -866,8 +866,6 @@ ExDestroyHandleByEntry(IN PHANDLE_TABLE HandleTable,
|
|||
|
||||
DPRINT("DestroyHandleByEntry HT:0x%p Entry:0x%p\n", HandleTable, Entry);
|
||||
|
||||
if (!(HandleTable->Flags & EX_HANDLE_TABLE_CLOSING))
|
||||
{
|
||||
KeEnterCriticalRegion();
|
||||
ExAcquireHandleLockExclusive(HandleTable);
|
||||
|
||||
|
@ -879,7 +877,6 @@ ExDestroyHandleByEntry(IN PHANDLE_TABLE HandleTable,
|
|||
|
||||
ExReleaseHandleLock(HandleTable);
|
||||
KeLeaveCriticalRegion();
|
||||
}
|
||||
}
|
||||
|
||||
PHANDLE_TABLE_ENTRY
|
||||
|
|
|
@ -1,40 +1,18 @@
|
|||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS kernel
|
||||
* PROJECT: ReactOS Kernel
|
||||
* LICENSE: GPL - See COPYING in the top level directory
|
||||
* FILE: ntoskrnl/ex/timer.c
|
||||
* PURPOSE: Executive Timer Implementation
|
||||
*
|
||||
* PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
|
||||
* David Welch (welch@mcmail.com)
|
||||
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
/* INCLUDES ******************************************************************/
|
||||
|
||||
#include <ntoskrnl.h>
|
||||
#define NDEBUG
|
||||
#include <internal/debug.h>
|
||||
#include <debug.h>
|
||||
|
||||
#if defined (ALLOC_PRAGMA)
|
||||
#pragma alloc_text(INIT, ExpInitializeTimerImplementation)
|
||||
#endif
|
||||
|
||||
|
||||
/* TYPES ********************************************************************/
|
||||
|
||||
/* Executive Timer Object */
|
||||
typedef struct _ETIMER
|
||||
{
|
||||
KTIMER KeTimer;
|
||||
KAPC TimerApc;
|
||||
KDPC TimerDpc;
|
||||
LIST_ENTRY ActiveTimerListEntry;
|
||||
KSPIN_LOCK Lock;
|
||||
BOOLEAN ApcAssociated;
|
||||
BOOLEAN WakeTimer;
|
||||
LIST_ENTRY WakeTimerListEntry;
|
||||
} ETIMER, *PETIMER;
|
||||
|
||||
/* GLOBALS ******************************************************************/
|
||||
/* GLOBALS *******************************************************************/
|
||||
|
||||
/* Timer Object Type */
|
||||
POBJECT_TYPE ExTimerType = NULL;
|
||||
|
@ -55,56 +33,70 @@ static GENERIC_MAPPING ExpTimerMapping =
|
|||
static const INFORMATION_CLASS_INFO ExTimerInfoClass[] =
|
||||
{
|
||||
/* TimerBasicInformation */
|
||||
ICI_SQ_SAME( sizeof(TIMER_BASIC_INFORMATION), sizeof(ULONG), ICIF_QUERY ),
|
||||
ICI_SQ_SAME(sizeof(TIMER_BASIC_INFORMATION), sizeof(ULONG), ICIF_QUERY),
|
||||
};
|
||||
|
||||
/* FUNCTIONS *****************************************************************/
|
||||
/* PRIVATE FUNCTIONS *********************************************************/
|
||||
|
||||
VOID
|
||||
STDCALL
|
||||
NTAPI
|
||||
ExTimerRundown(VOID)
|
||||
{
|
||||
PETHREAD Thread = PsGetCurrentThread();
|
||||
KIRQL OldIrql;
|
||||
PLIST_ENTRY CurrentEntry;
|
||||
PETIMER Timer;
|
||||
ULONG DerefsToDo;
|
||||
|
||||
/* Lock the Thread's Active Timer List*/
|
||||
/* Lock the Thread's Active Timer List and loop it */
|
||||
KeAcquireSpinLock(&Thread->ActiveTimerListLock, &OldIrql);
|
||||
|
||||
while (!IsListEmpty(&Thread->ActiveTimerListHead))
|
||||
CurrentEntry = Thread->ActiveTimerListHead.Flink;
|
||||
while (CurrentEntry != &Thread->ActiveTimerListHead)
|
||||
{
|
||||
/* Remove a Timer */
|
||||
CurrentEntry = RemoveTailList(&Thread->ActiveTimerListHead);
|
||||
|
||||
/* Get the Timer */
|
||||
/* Get the timer */
|
||||
Timer = CONTAINING_RECORD(CurrentEntry, ETIMER, ActiveTimerListEntry);
|
||||
DPRINT("Timer, ThreadList: 0x%p, 0x%p\n", Timer, Thread);
|
||||
|
||||
/* Mark it as deassociated */
|
||||
ASSERT (Timer->ApcAssociated);
|
||||
Timer->ApcAssociated = FALSE;
|
||||
/* Reference it */
|
||||
ObReferenceObject(Timer);
|
||||
DerefsToDo = 1;
|
||||
|
||||
/* Unlock the list */
|
||||
KeReleaseSpinLock(&Thread->ActiveTimerListLock, OldIrql);
|
||||
|
||||
/* Lock the Timer */
|
||||
KeAcquireSpinLock(&Timer->Lock, &OldIrql);
|
||||
|
||||
/* Lock the list again */
|
||||
KeAcquireSpinLockAtDpcLevel(&Thread->ActiveTimerListLock);
|
||||
|
||||
/* Make sure that the timer is valid */
|
||||
if ((Timer->ApcAssociated) && (&Thread->Tcb == Timer->TimerApc.Thread))
|
||||
{
|
||||
/* Remove it from the list */
|
||||
RemoveEntryList(&Timer->ActiveTimerListEntry);
|
||||
Timer->ApcAssociated = FALSE;
|
||||
|
||||
/* Cancel the timer and remove its DPC and APC */
|
||||
KeCancelTimer(&Timer->KeTimer);
|
||||
KeRemoveQueueDpc(&Timer->TimerDpc);
|
||||
if (KeRemoveQueueApc(&Timer->TimerApc)) DerefsToDo = 2;
|
||||
|
||||
/* Add another dereference to do */
|
||||
DerefsToDo++;
|
||||
}
|
||||
|
||||
/* Unlock the list */
|
||||
KeReleaseSpinLockFromDpcLevel(&Thread->ActiveTimerListLock);
|
||||
|
||||
/* Lock the Timer */
|
||||
KeAcquireSpinLockAtDpcLevel(&Timer->Lock);
|
||||
|
||||
/* Cancel the timer and remove its DPC and APC */
|
||||
ASSERT(&Thread->Tcb == Timer->TimerApc.Thread);
|
||||
KeCancelTimer(&Timer->KeTimer);
|
||||
KeRemoveQueueDpc(&Timer->TimerDpc);
|
||||
KeRemoveQueueApc(&Timer->TimerApc);
|
||||
|
||||
/* Unlock the Timer */
|
||||
KeReleaseSpinLock(&Timer->Lock, OldIrql);
|
||||
|
||||
/* Dereference it */
|
||||
ObDereferenceObject(Timer);
|
||||
ObDereferenceObjectEx(Timer, DerefsToDo);
|
||||
|
||||
/* Loop again */
|
||||
KeAcquireSpinLock(&Thread->ActiveTimerListLock, &OldIrql);
|
||||
CurrentEntry = Thread->ActiveTimerListHead.Flink;
|
||||
}
|
||||
|
||||
/* Release lock and return */
|
||||
|
@ -113,133 +105,127 @@ ExTimerRundown(VOID)
|
|||
}
|
||||
|
||||
VOID
|
||||
STDCALL
|
||||
ExpDeleteTimer(PVOID ObjectBody)
|
||||
NTAPI
|
||||
ExpDeleteTimer(IN PVOID ObjectBody)
|
||||
{
|
||||
KIRQL OldIrql;
|
||||
PETIMER Timer = ObjectBody;
|
||||
DPRINT("ExpDeleteTimer(Timer: 0x%p)\n", Timer);
|
||||
|
||||
/* Check if it has a Wait List */
|
||||
if (Timer->WakeTimer)
|
||||
if (Timer->WakeTimerListEntry.Flink)
|
||||
{
|
||||
/* Lock the Wake List */
|
||||
KeAcquireSpinLock(&ExpWakeListLock, &OldIrql);
|
||||
|
||||
/* Check again, since it might've changed before we locked */
|
||||
if (Timer->WakeTimer)
|
||||
if (Timer->WakeTimerListEntry.Flink)
|
||||
{
|
||||
/* Remove it from the Wait List */
|
||||
DPRINT("Removing wake list\n");
|
||||
RemoveEntryList(&Timer->WakeTimerListEntry);
|
||||
Timer->WakeTimer = FALSE;
|
||||
Timer->WakeTimerListEntry.Flink = NULL;
|
||||
}
|
||||
|
||||
/* Release the Wake List */
|
||||
KeReleaseSpinLock(&ExpWakeListLock, OldIrql);
|
||||
}
|
||||
|
||||
/* Tell the Kernel to cancel the Timer */
|
||||
DPRINT("Cancelling Timer\n");
|
||||
/* Tell the Kernel to cancel the Timer and flush all queued DPCs */
|
||||
KeCancelTimer(&Timer->KeTimer);
|
||||
KeFlushQueuedDpcs();
|
||||
}
|
||||
|
||||
VOID
|
||||
STDCALL
|
||||
ExpTimerDpcRoutine(PKDPC Dpc,
|
||||
PVOID DeferredContext,
|
||||
PVOID SystemArgument1,
|
||||
PVOID SystemArgument2)
|
||||
NTAPI
|
||||
ExpTimerDpcRoutine(IN PKDPC Dpc,
|
||||
IN PVOID DeferredContext,
|
||||
IN PVOID SystemArgument1,
|
||||
IN PVOID SystemArgument2)
|
||||
{
|
||||
PETIMER Timer;
|
||||
KIRQL OldIrql;
|
||||
PETIMER Timer = DeferredContext;
|
||||
BOOLEAN Inserted = FALSE;
|
||||
|
||||
DPRINT("ExpTimerDpcRoutine(Dpc: 0x%p)\n", Dpc);
|
||||
|
||||
/* Get the Timer Object */
|
||||
Timer = (PETIMER)DeferredContext;
|
||||
/* Reference the timer */
|
||||
if (!ObReferenceObjectSafe(Timer)) return;
|
||||
|
||||
/* Lock the Timer */
|
||||
KeAcquireSpinLock(&Timer->Lock, &OldIrql);
|
||||
KeAcquireSpinLockAtDpcLevel(&Timer->Lock);
|
||||
|
||||
/* Queue the APC */
|
||||
if(Timer->ApcAssociated)
|
||||
/* Check if the timer is associated */
|
||||
if (Timer->ApcAssociated)
|
||||
{
|
||||
DPRINT("Queuing APC\n");
|
||||
KeInsertQueueApc(&Timer->TimerApc,
|
||||
SystemArgument1,
|
||||
SystemArgument2,
|
||||
IO_NO_INCREMENT);
|
||||
/* Queue the APC */
|
||||
Inserted = KeInsertQueueApc(&Timer->TimerApc,
|
||||
SystemArgument1,
|
||||
SystemArgument2,
|
||||
IO_NO_INCREMENT);
|
||||
}
|
||||
|
||||
/* Release the Timer */
|
||||
KeReleaseSpinLock(&Timer->Lock, OldIrql);
|
||||
return;
|
||||
KeReleaseSpinLockFromDpcLevel(&Timer->Lock);
|
||||
|
||||
/* Dereference it if we couldn't queue the APC */
|
||||
if (!Inserted) ObDereferenceObject(Timer);
|
||||
}
|
||||
|
||||
|
||||
VOID
|
||||
STDCALL
|
||||
ExpTimerApcKernelRoutine(PKAPC Apc,
|
||||
PKNORMAL_ROUTINE* NormalRoutine,
|
||||
PVOID* NormalContext,
|
||||
PVOID* SystemArgument1,
|
||||
PVOID* SystemArguemnt2)
|
||||
NTAPI
|
||||
ExpTimerApcKernelRoutine(IN PKAPC Apc,
|
||||
IN OUT PKNORMAL_ROUTINE* NormalRoutine,
|
||||
IN OUT PVOID* NormalContext,
|
||||
IN OUT PVOID* SystemArgument1,
|
||||
IN OUT PVOID* SystemArguemnt2)
|
||||
{
|
||||
PETIMER Timer;
|
||||
KIRQL OldIrql;
|
||||
PETHREAD CurrentThread = PsGetCurrentThread();
|
||||
ULONG DerefsToDo = 1;
|
||||
PETHREAD Thread = PsGetCurrentThread();
|
||||
|
||||
/* We need to find out which Timer we are */
|
||||
Timer = CONTAINING_RECORD(Apc, ETIMER, TimerApc);
|
||||
DPRINT("ExpTimerApcKernelRoutine(Apc: 0x%p. Timer: 0x%p)\n", Apc, Timer);
|
||||
|
||||
/* Lock the Timer */
|
||||
KeAcquireSpinLock(&Timer->Lock, &OldIrql);
|
||||
|
||||
/* Lock the Thread's Active Timer List*/
|
||||
KeAcquireSpinLockAtDpcLevel(&CurrentThread->ActiveTimerListLock);
|
||||
KeAcquireSpinLockAtDpcLevel(&Thread->ActiveTimerListLock);
|
||||
|
||||
/*
|
||||
* Make sure that the Timer is still valid, and that it belongs to this thread
|
||||
* Remove it if it's not periodic
|
||||
*/
|
||||
if ((Timer->ApcAssociated) &&
|
||||
(&CurrentThread->Tcb == Timer->TimerApc.Thread) &&
|
||||
(!Timer->KeTimer.Period))
|
||||
/* Make sure that the Timer is valid, and that it belongs to this thread */
|
||||
if ((Timer->ApcAssociated) && (&Thread->Tcb == Timer->TimerApc.Thread))
|
||||
{
|
||||
/* Remove it from the Active Timers List */
|
||||
DPRINT("Removing Timer\n");
|
||||
RemoveEntryList(&Timer->ActiveTimerListEntry);
|
||||
/* Check if it's not periodic */
|
||||
if (!Timer->Period)
|
||||
{
|
||||
/* Remove it from the Active Timers List */
|
||||
RemoveEntryList(&Timer->ActiveTimerListEntry);
|
||||
|
||||
/* Disable it */
|
||||
Timer->ApcAssociated = FALSE;
|
||||
|
||||
/* Release spinlocks */
|
||||
KeReleaseSpinLockFromDpcLevel(&CurrentThread->ActiveTimerListLock);
|
||||
KeReleaseSpinLock(&Timer->Lock, OldIrql);
|
||||
|
||||
/* Dereference the Timer Object */
|
||||
ObDereferenceObject(Timer);
|
||||
return;
|
||||
/* Disable it */
|
||||
Timer->ApcAssociated = FALSE;
|
||||
DerefsToDo = 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Clear the normal routine */
|
||||
*NormalRoutine = NULL;
|
||||
}
|
||||
|
||||
/* Release spinlocks */
|
||||
KeReleaseSpinLockFromDpcLevel(&CurrentThread->ActiveTimerListLock);
|
||||
/* Release locks */
|
||||
KeReleaseSpinLockFromDpcLevel(&Thread->ActiveTimerListLock);
|
||||
KeReleaseSpinLock(&Timer->Lock, OldIrql);
|
||||
|
||||
/* Dereference as needed */
|
||||
ObDereferenceObjectEx(Timer, DerefsToDo);
|
||||
}
|
||||
|
||||
VOID
|
||||
INIT_FUNCTION
|
||||
STDCALL
|
||||
NTAPI
|
||||
ExpInitializeTimerImplementation(VOID)
|
||||
{
|
||||
OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
|
||||
UNICODE_STRING Name;
|
||||
|
||||
DPRINT("Creating Timer Object Type\n");
|
||||
|
||||
/* Create the Event Pair Object Type */
|
||||
/* Create the Timer Object Type */
|
||||
RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
|
||||
RtlInitUnicodeString(&Name, L"Timer");
|
||||
ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
|
||||
|
@ -256,8 +242,10 @@ ExpInitializeTimerImplementation(VOID)
|
|||
InitializeListHead(&ExpWakeList);
|
||||
}
|
||||
|
||||
/* PUBLIC FUNCTIONS **********************************************************/
|
||||
|
||||
NTSTATUS
|
||||
STDCALL
|
||||
NTAPI
|
||||
NtCancelTimer(IN HANDLE TimerHandle,
|
||||
OUT PBOOLEAN CurrentState OPTIONAL)
|
||||
{
|
||||
|
@ -266,13 +254,12 @@ NtCancelTimer(IN HANDLE TimerHandle,
|
|||
BOOLEAN State;
|
||||
KIRQL OldIrql;
|
||||
PETHREAD TimerThread;
|
||||
BOOLEAN KillTimer = FALSE;
|
||||
ULONG DerefsToDo = 1;
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
PAGED_CODE();
|
||||
DPRINT("NtCancelTimer(0x%p, 0x%x)\n", TimerHandle, CurrentState);
|
||||
|
||||
/* Check Parameter Validity */
|
||||
if(CurrentState && PreviousMode != KernelMode)
|
||||
if ((CurrentState) && (PreviousMode != KernelMode))
|
||||
{
|
||||
_SEH_TRY
|
||||
{
|
||||
|
@ -283,7 +270,6 @@ NtCancelTimer(IN HANDLE TimerHandle,
|
|||
Status = _SEH_GetExceptionCode();
|
||||
}
|
||||
_SEH_END;
|
||||
|
||||
if(!NT_SUCCESS(Status)) return Status;
|
||||
}
|
||||
|
||||
|
@ -294,30 +280,23 @@ NtCancelTimer(IN HANDLE TimerHandle,
|
|||
PreviousMode,
|
||||
(PVOID*)&Timer,
|
||||
NULL);
|
||||
|
||||
/* Check for success */
|
||||
if(NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT("Timer Referenced: 0x%p\n", Timer);
|
||||
|
||||
/* Lock the Timer */
|
||||
KeAcquireSpinLock(&Timer->Lock, &OldIrql);
|
||||
|
||||
/* Check if it's enabled */
|
||||
if (Timer->ApcAssociated)
|
||||
{
|
||||
/*
|
||||
* First, remove it from the Thread's Active List
|
||||
* Get the Thread.
|
||||
*/
|
||||
/* Get the Thread. */
|
||||
TimerThread = CONTAINING_RECORD(Timer->TimerApc.Thread, ETHREAD, Tcb);
|
||||
DPRINT("Removing from Thread: 0x%p\n", TimerThread);
|
||||
|
||||
/* Lock its active list */
|
||||
KeAcquireSpinLockAtDpcLevel(&TimerThread->ActiveTimerListLock);
|
||||
|
||||
/* Remove it */
|
||||
RemoveEntryList(&TimerThread->ActiveTimerListHead);
|
||||
Timer->ApcAssociated = FALSE;
|
||||
|
||||
/* Unlock the list */
|
||||
KeReleaseSpinLockFromDpcLevel(&TimerThread->ActiveTimerListLock);
|
||||
|
@ -325,30 +304,27 @@ NtCancelTimer(IN HANDLE TimerHandle,
|
|||
/* Cancel the Timer */
|
||||
KeCancelTimer(&Timer->KeTimer);
|
||||
KeRemoveQueueDpc(&Timer->TimerDpc);
|
||||
KeRemoveQueueApc(&Timer->TimerApc);
|
||||
Timer->ApcAssociated = FALSE;
|
||||
KillTimer = TRUE;
|
||||
if (KeRemoveQueueApc(&Timer->TimerApc)) DerefsToDo = 2;
|
||||
DerefsToDo++;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If timer was disabled, we still need to cancel it */
|
||||
DPRINT("APC was not Associated. Cancelling Timer\n");
|
||||
KeCancelTimer(&Timer->KeTimer);
|
||||
}
|
||||
|
||||
/* Handle a Wake Timer */
|
||||
if (Timer->WakeTimer)
|
||||
if (Timer->WakeTimerListEntry.Flink)
|
||||
{
|
||||
/* Lock the Wake List */
|
||||
KeAcquireSpinLockAtDpcLevel(&ExpWakeListLock);
|
||||
|
||||
/* Check again, since it might've changed before we locked */
|
||||
if (Timer->WakeTimer)
|
||||
if (Timer->WakeTimerListEntry.Flink)
|
||||
{
|
||||
/* Remove it from the Wait List */
|
||||
DPRINT("Removing wake list\n");
|
||||
RemoveEntryList(&Timer->WakeTimerListEntry);
|
||||
Timer->WakeTimer = FALSE;
|
||||
Timer->WakeTimerListEntry.Flink = NULL;
|
||||
}
|
||||
|
||||
/* Release the Wake List */
|
||||
|
@ -362,14 +338,10 @@ NtCancelTimer(IN HANDLE TimerHandle,
|
|||
State = KeReadStateTimer(&Timer->KeTimer);
|
||||
|
||||
/* Dereference the Object */
|
||||
ObDereferenceObject(Timer);
|
||||
|
||||
/* Dereference if it was previously enabled */
|
||||
if (KillTimer) ObDereferenceObject(Timer);
|
||||
DPRINT1("Timer disabled\n");
|
||||
ObDereferenceObjectEx(Timer, DerefsToDo);
|
||||
|
||||
/* Make sure it's safe to write to the handle */
|
||||
if(CurrentState)
|
||||
if (CurrentState)
|
||||
{
|
||||
_SEH_TRY
|
||||
{
|
||||
|
@ -388,7 +360,7 @@ NtCancelTimer(IN HANDLE TimerHandle,
|
|||
}
|
||||
|
||||
NTSTATUS
|
||||
STDCALL
|
||||
NTAPI
|
||||
NtCreateTimer(OUT PHANDLE TimerHandle,
|
||||
IN ACCESS_MASK DesiredAccess,
|
||||
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
|
||||
|
@ -399,7 +371,6 @@ NtCreateTimer(OUT PHANDLE TimerHandle,
|
|||
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
PAGED_CODE();
|
||||
DPRINT("NtCreateTimer(Handle: 0x%p, Type: %d)\n", TimerHandle, TimerType);
|
||||
|
||||
/* Check Parameter Validity */
|
||||
if (PreviousMode != KernelMode)
|
||||
|
@ -413,14 +384,12 @@ NtCreateTimer(OUT PHANDLE TimerHandle,
|
|||
Status = _SEH_GetExceptionCode();
|
||||
}
|
||||
_SEH_END;
|
||||
|
||||
if(!NT_SUCCESS(Status)) return Status;
|
||||
}
|
||||
|
||||
/* Check for correct timer type */
|
||||
if ((TimerType != NotificationTimer) && (TimerType != SynchronizationTimer))
|
||||
{
|
||||
DPRINT1("Invalid Timer Type!\n");
|
||||
return STATUS_INVALID_PARAMETER_4;
|
||||
}
|
||||
|
||||
|
@ -434,23 +403,19 @@ NtCreateTimer(OUT PHANDLE TimerHandle,
|
|||
0,
|
||||
0,
|
||||
(PVOID*)&Timer);
|
||||
|
||||
/* Check for Success */
|
||||
if(NT_SUCCESS(Status))
|
||||
{
|
||||
/* Initialize the Kernel Timer */
|
||||
DPRINT("Initializing Timer: 0x%p\n", Timer);
|
||||
KeInitializeTimerEx(&Timer->KeTimer, TimerType);
|
||||
|
||||
/* Initialize the Timer Lock */
|
||||
KeInitializeSpinLock(&Timer->Lock);
|
||||
|
||||
/* Initialize the DPC */
|
||||
KeInitializeDpc(&Timer->TimerDpc, ExpTimerDpcRoutine, Timer);
|
||||
|
||||
/* Set Initial State */
|
||||
/* Initialize the Kernel Timer */
|
||||
KeInitializeTimerEx(&Timer->KeTimer, TimerType);
|
||||
|
||||
/* Initialize the timer fields */
|
||||
KeInitializeSpinLock(&Timer->Lock);
|
||||
Timer->ApcAssociated = FALSE;
|
||||
Timer->WakeTimer = FALSE;
|
||||
Timer->WakeTimerListEntry.Flink = NULL;
|
||||
|
||||
/* Insert the Timer */
|
||||
Status = ObInsertObject((PVOID)Timer,
|
||||
|
@ -459,7 +424,6 @@ NtCreateTimer(OUT PHANDLE TimerHandle,
|
|||
0,
|
||||
NULL,
|
||||
&hTimer);
|
||||
DPRINT("Timer Inserted\n");
|
||||
|
||||
/* Make sure it's safe to write to the handle */
|
||||
_SEH_TRY
|
||||
|
@ -478,7 +442,7 @@ NtCreateTimer(OUT PHANDLE TimerHandle,
|
|||
}
|
||||
|
||||
NTSTATUS
|
||||
STDCALL
|
||||
NTAPI
|
||||
NtOpenTimer(OUT PHANDLE TimerHandle,
|
||||
IN ACCESS_MASK DesiredAccess,
|
||||
IN POBJECT_ATTRIBUTES ObjectAttributes)
|
||||
|
@ -487,7 +451,6 @@ NtOpenTimer(OUT PHANDLE TimerHandle,
|
|||
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
PAGED_CODE();
|
||||
DPRINT("NtOpenTimer(TimerHandle: 0x%p)\n", TimerHandle);
|
||||
|
||||
/* Check Parameter Validity */
|
||||
if (PreviousMode != KernelMode)
|
||||
|
@ -501,7 +464,6 @@ NtOpenTimer(OUT PHANDLE TimerHandle,
|
|||
Status = _SEH_GetExceptionCode();
|
||||
}
|
||||
_SEH_END;
|
||||
|
||||
if(!NT_SUCCESS(Status)) return Status;
|
||||
}
|
||||
|
||||
|
@ -513,8 +475,6 @@ NtOpenTimer(OUT PHANDLE TimerHandle,
|
|||
DesiredAccess,
|
||||
NULL,
|
||||
&hTimer);
|
||||
|
||||
/* Check for success */
|
||||
if(NT_SUCCESS(Status))
|
||||
{
|
||||
/* Make sure it's safe to write to the handle */
|
||||
|
@ -533,35 +493,30 @@ NtOpenTimer(OUT PHANDLE TimerHandle,
|
|||
return Status;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS
|
||||
STDCALL
|
||||
NTAPI
|
||||
NtQueryTimer(IN HANDLE TimerHandle,
|
||||
IN TIMER_INFORMATION_CLASS TimerInformationClass,
|
||||
OUT PVOID TimerInformation,
|
||||
IN ULONG TimerInformationLength,
|
||||
OUT PULONG ReturnLength OPTIONAL)
|
||||
OUT PULONG ReturnLength OPTIONAL)
|
||||
{
|
||||
PETIMER Timer;
|
||||
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
PTIMER_BASIC_INFORMATION BasicInfo = (PTIMER_BASIC_INFORMATION)TimerInformation;
|
||||
NTSTATUS Status;
|
||||
PTIMER_BASIC_INFORMATION BasicInfo = TimerInformation;
|
||||
PAGED_CODE();
|
||||
DPRINT("NtQueryTimer(TimerHandle: 0x%p, Class: %d)\n", TimerHandle, TimerInformationClass);
|
||||
|
||||
/* Check Validity */
|
||||
Status = DefaultQueryInfoBufferCheck(TimerInformationClass,
|
||||
ExTimerInfoClass,
|
||||
sizeof(ExTimerInfoClass) / sizeof(ExTimerInfoClass[0]),
|
||||
sizeof(ExTimerInfoClass) /
|
||||
sizeof(ExTimerInfoClass[0]),
|
||||
TimerInformation,
|
||||
TimerInformationLength,
|
||||
ReturnLength,
|
||||
PreviousMode);
|
||||
if(!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("NtQueryTimer() failed, Status: 0x%x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
if(!NT_SUCCESS(Status)) return Status;
|
||||
|
||||
/* Get the Timer Object */
|
||||
Status = ObReferenceObjectByHandle(TimerHandle,
|
||||
|
@ -570,8 +525,6 @@ NtQueryTimer(IN HANDLE TimerHandle,
|
|||
PreviousMode,
|
||||
(PVOID*)&Timer,
|
||||
NULL);
|
||||
|
||||
/* Check for Success */
|
||||
if(NT_SUCCESS(Status))
|
||||
{
|
||||
/* Return the Basic Information */
|
||||
|
@ -585,10 +538,7 @@ NtQueryTimer(IN HANDLE TimerHandle,
|
|||
BasicInfo->SignalState = KeReadStateTimer(&Timer->KeTimer);
|
||||
|
||||
/* Return the buffer length if requested */
|
||||
if(ReturnLength != NULL) *ReturnLength = sizeof(TIMER_BASIC_INFORMATION);
|
||||
|
||||
DPRINT("Returning Information for Timer: 0x%p. Time Remaining: %I64x\n",
|
||||
Timer, BasicInfo->TimeRemaining.QuadPart);
|
||||
if(ReturnLength) *ReturnLength = sizeof(TIMER_BASIC_INFORMATION);
|
||||
}
|
||||
_SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
|
||||
{
|
||||
|
@ -605,7 +555,7 @@ NtQueryTimer(IN HANDLE TimerHandle,
|
|||
}
|
||||
|
||||
NTSTATUS
|
||||
STDCALL
|
||||
NTAPI
|
||||
NtSetTimer(IN HANDLE TimerHandle,
|
||||
IN PLARGE_INTEGER DueTime,
|
||||
IN PTIMER_APC_ROUTINE TimerApcRoutine OPTIONAL,
|
||||
|
@ -618,14 +568,12 @@ NtSetTimer(IN HANDLE TimerHandle,
|
|||
KIRQL OldIrql;
|
||||
BOOLEAN State;
|
||||
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
||||
PETHREAD CurrentThread = PsGetCurrentThread();
|
||||
PETHREAD Thread = PsGetCurrentThread();
|
||||
LARGE_INTEGER TimerDueTime;
|
||||
PETHREAD TimerThread;
|
||||
BOOLEAN KillTimer = FALSE;
|
||||
ULONG DerefsToDo = 1;
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
PAGED_CODE();
|
||||
DPRINT("NtSetTimer(TimerHandle: 0x%p, DueTime: %I64x, Apc: 0x%p, Period: %d)\n",
|
||||
TimerHandle, DueTime->QuadPart, TimerApcRoutine, Period);
|
||||
|
||||
/* Check Parameter Validity */
|
||||
if (PreviousMode != KernelMode)
|
||||
|
@ -633,27 +581,18 @@ NtSetTimer(IN HANDLE TimerHandle,
|
|||
_SEH_TRY
|
||||
{
|
||||
TimerDueTime = ProbeForReadLargeInteger(DueTime);
|
||||
|
||||
if(PreviousState)
|
||||
{
|
||||
ProbeForWriteBoolean(PreviousState);
|
||||
}
|
||||
if(PreviousState) ProbeForWriteBoolean(PreviousState);
|
||||
}
|
||||
_SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
|
||||
{
|
||||
Status = _SEH_GetExceptionCode();
|
||||
}
|
||||
_SEH_END;
|
||||
|
||||
if(!NT_SUCCESS(Status)) return Status;
|
||||
}
|
||||
|
||||
/* Check for a valid Period */
|
||||
if (Period < 0)
|
||||
{
|
||||
DPRINT1("Invalid Period for timer\n");
|
||||
return STATUS_INVALID_PARAMETER_6;
|
||||
}
|
||||
if (Period < 0) return STATUS_INVALID_PARAMETER_6;
|
||||
|
||||
/* Get the Timer Object */
|
||||
Status = ObReferenceObjectByHandle(TimerHandle,
|
||||
|
@ -666,7 +605,7 @@ NtSetTimer(IN HANDLE TimerHandle,
|
|||
/*
|
||||
* Tell the user we don't support Wake Timers...
|
||||
* when we have the ability to use/detect the Power Management
|
||||
* functionatliy required to support them, make this check dependent
|
||||
* functionality required to support them, make this check dependent
|
||||
* on the actual PM capabilities
|
||||
*/
|
||||
if (WakeTimer) Status = STATUS_TIMER_RESUME_IGNORED;
|
||||
|
@ -675,24 +614,22 @@ NtSetTimer(IN HANDLE TimerHandle,
|
|||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
/* Lock the Timer */
|
||||
DPRINT("Timer Referencced: 0x%p\n", Timer);
|
||||
KeAcquireSpinLock(&Timer->Lock, &OldIrql);
|
||||
|
||||
/* Cancel Running Timer */
|
||||
if (Timer->ApcAssociated)
|
||||
{
|
||||
/*
|
||||
* First, remove it from the Thread's Active List
|
||||
* Get the Thread.
|
||||
*/
|
||||
TimerThread = CONTAINING_RECORD(Timer->TimerApc.Thread, ETHREAD, Tcb);
|
||||
DPRINT("Thread already running. Removing from Thread: 0x%p\n", TimerThread);
|
||||
/* Get the Thread. */
|
||||
TimerThread = CONTAINING_RECORD(Timer->TimerApc.Thread,
|
||||
ETHREAD,
|
||||
Tcb);
|
||||
|
||||
/* Lock its active list */
|
||||
KeAcquireSpinLockAtDpcLevel(&TimerThread->ActiveTimerListLock);
|
||||
|
||||
/* Remove it */
|
||||
RemoveEntryList(&TimerThread->ActiveTimerListHead);
|
||||
Timer->ApcAssociated = FALSE;
|
||||
|
||||
/* Unlock the list */
|
||||
KeReleaseSpinLockFromDpcLevel(&TimerThread->ActiveTimerListLock);
|
||||
|
@ -700,14 +637,12 @@ NtSetTimer(IN HANDLE TimerHandle,
|
|||
/* Cancel the Timer */
|
||||
KeCancelTimer(&Timer->KeTimer);
|
||||
KeRemoveQueueDpc(&Timer->TimerDpc);
|
||||
KeRemoveQueueApc(&Timer->TimerApc);
|
||||
Timer->ApcAssociated = FALSE;
|
||||
KillTimer = TRUE;
|
||||
|
||||
} else {
|
||||
|
||||
if (KeRemoveQueueApc(&Timer->TimerApc)) DerefsToDo = 2;
|
||||
DerefsToDo++;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If timer was disabled, we still need to cancel it */
|
||||
DPRINT("No APCs. Simply cancelling\n");
|
||||
KeCancelTimer(&Timer->KeTimer);
|
||||
}
|
||||
|
||||
|
@ -715,29 +650,27 @@ NtSetTimer(IN HANDLE TimerHandle,
|
|||
State = KeReadStateTimer(&Timer->KeTimer);
|
||||
|
||||
/* Handle Wake Timers */
|
||||
DPRINT("Doing Wake Semantics\n");
|
||||
KeAcquireSpinLockAtDpcLevel(&ExpWakeListLock);
|
||||
if (WakeTimer && !Timer->WakeTimer)
|
||||
if ((WakeTimer) && !(Timer->WakeTimerListEntry.Flink))
|
||||
{
|
||||
/* Insert it into the list */
|
||||
Timer->WakeTimer = TRUE;
|
||||
InsertTailList(&ExpWakeList, &Timer->WakeTimerListEntry);
|
||||
}
|
||||
else if (!WakeTimer && Timer->WakeTimer)
|
||||
else if (!(WakeTimer) && (Timer->WakeTimerListEntry.Flink))
|
||||
{
|
||||
/* Remove it from the list */
|
||||
RemoveEntryList(&Timer->WakeTimerListEntry);
|
||||
Timer->WakeTimer = FALSE;
|
||||
Timer->WakeTimerListEntry.Flink = NULL;
|
||||
}
|
||||
KeReleaseSpinLockFromDpcLevel(&ExpWakeListLock);
|
||||
|
||||
/* Set up the APC Routine if specified */
|
||||
Timer->Period = Period;
|
||||
if (TimerApcRoutine)
|
||||
{
|
||||
/* Initialize the APC */
|
||||
DPRINT("Initializing APC: 0x%p\n", Timer->TimerApc);
|
||||
KeInitializeApc(&Timer->TimerApc,
|
||||
&CurrentThread->Tcb,
|
||||
&Thread->Tcb,
|
||||
CurrentApcEnvironment,
|
||||
&ExpTimerApcKernelRoutine,
|
||||
(PKRUNDOWN_ROUTINE)NULL,
|
||||
|
@ -746,31 +679,30 @@ NtSetTimer(IN HANDLE TimerHandle,
|
|||
TimerContext);
|
||||
|
||||
/* Lock the Thread's Active List and Insert */
|
||||
KeAcquireSpinLockAtDpcLevel(&CurrentThread->ActiveTimerListLock);
|
||||
InsertTailList(&CurrentThread->ActiveTimerListHead,
|
||||
KeAcquireSpinLockAtDpcLevel(&Thread->ActiveTimerListLock);
|
||||
InsertTailList(&Thread->ActiveTimerListHead,
|
||||
&Timer->ActiveTimerListEntry);
|
||||
KeReleaseSpinLockFromDpcLevel(&CurrentThread->ActiveTimerListLock);
|
||||
Timer->ApcAssociated = TRUE;
|
||||
KeReleaseSpinLockFromDpcLevel(&Thread->ActiveTimerListLock);
|
||||
|
||||
/* One less dereference to do */
|
||||
DerefsToDo--;
|
||||
}
|
||||
|
||||
/* Enable and Set the Timer */
|
||||
DPRINT("Setting Kernel Timer\n");
|
||||
KeSetTimerEx(&Timer->KeTimer,
|
||||
TimerDueTime,
|
||||
Period,
|
||||
TimerApcRoutine ? &Timer->TimerDpc : 0);
|
||||
Timer->ApcAssociated = TimerApcRoutine ? TRUE : FALSE;
|
||||
TimerApcRoutine ? &Timer->TimerDpc : NULL);
|
||||
|
||||
/* Unlock the Timer */
|
||||
KeReleaseSpinLock(&Timer->Lock, OldIrql);
|
||||
|
||||
/* Dereference if it was previously enabled */
|
||||
if (!TimerApcRoutine) ObDereferenceObject(Timer);
|
||||
if (KillTimer) ObDereferenceObject(Timer);
|
||||
DPRINT("Finished Setting the Timer\n");
|
||||
if (DerefsToDo) ObDereferenceObjectEx(Timer, DerefsToDo);
|
||||
|
||||
/* Make sure it's safe to write to the handle */
|
||||
if(PreviousState != NULL)
|
||||
if (PreviousState)
|
||||
{
|
||||
_SEH_TRY
|
||||
{
|
||||
|
|
|
@ -617,8 +617,8 @@ ExpInitializeWorkerThreads(VOID)
|
|||
*--*/
|
||||
VOID
|
||||
NTAPI
|
||||
ExQueueWorkItem(PWORK_QUEUE_ITEM WorkItem,
|
||||
WORK_QUEUE_TYPE QueueType)
|
||||
ExQueueWorkItem(IN PWORK_QUEUE_ITEM WorkItem,
|
||||
IN WORK_QUEUE_TYPE QueueType)
|
||||
{
|
||||
PEX_WORK_QUEUE WorkQueue = &ExWorkerQueue[QueueType];
|
||||
ASSERT(QueueType < MaximumWorkQueue);
|
||||
|
|
|
@ -21,6 +21,19 @@ ULONG ExpAnsiCodePageDataOffset, ExpOemCodePageDataOffset;
|
|||
ULONG ExpUnicodeCaseTableDataOffset;
|
||||
PVOID ExpNlsSectionPointer;
|
||||
|
||||
typedef struct _ETIMER
|
||||
{
|
||||
KTIMER KeTimer;
|
||||
KAPC TimerApc;
|
||||
KDPC TimerDpc;
|
||||
LIST_ENTRY ActiveTimerListEntry;
|
||||
KSPIN_LOCK Lock;
|
||||
LONG Period;
|
||||
BOOLEAN ApcAssociated;
|
||||
BOOLEAN WakeTimer;
|
||||
LIST_ENTRY WakeTimerListEntry;
|
||||
} ETIMER, *PETIMER;
|
||||
|
||||
#define MAX_FAST_REFS 7
|
||||
|
||||
#define EX_OBJ_TO_HDR(eob) ((POBJECT_HEADER)((ULONG_PTR)(eob) & \
|
||||
|
|
|
@ -180,7 +180,7 @@ LpcpDestroyPortQueue(IN PLPCP_PORT_OBJECT Port,
|
|||
/* Loop queued messages */
|
||||
ListHead = &Port->MsgQueue.ReceiveHead;
|
||||
NextEntry = ListHead->Flink;
|
||||
while (ListHead != NextEntry)
|
||||
while ((NextEntry) && (ListHead != NextEntry))
|
||||
{
|
||||
/* Get the message */
|
||||
Message = CONTAINING_RECORD(NextEntry, LPCP_MESSAGE, Entry);
|
||||
|
|
|
@ -1969,10 +1969,7 @@ ObKillProcess(IN PEPROCESS Process)
|
|||
ExSweepHandleTable(HandleTable,
|
||||
ObpCloseHandleCallback,
|
||||
&Context);
|
||||
if (HandleTable->HandleCount != 0)
|
||||
{
|
||||
DPRINT1("FIXME: %d handles remain!\n", HandleTable->HandleCount);
|
||||
}
|
||||
ASSERT(HandleTable->HandleCount == 0);
|
||||
|
||||
/* Leave the critical region */
|
||||
KeLeaveCriticalRegion();
|
||||
|
|
|
@ -225,9 +225,12 @@ ClientConnectionThread(HANDLE ServerPort)
|
|||
/* If the connection was closed, handle that */
|
||||
if (Request->Header.u2.s2.Type == LPC_PORT_CLOSED)
|
||||
{
|
||||
DPRINT1("Port died, oh well\n");
|
||||
DPRINT("Port died, oh well\n");
|
||||
CsrFreeProcessData( Request->Header.ClientId.UniqueProcess );
|
||||
break;
|
||||
//NtClose()
|
||||
Reply = NULL;
|
||||
continue;
|
||||
//break;
|
||||
}
|
||||
|
||||
if (Request->Header.u2.s2.Type == LPC_CONNECTION_REQUEST)
|
||||
|
@ -239,7 +242,7 @@ ClientConnectionThread(HANDLE ServerPort)
|
|||
|
||||
if (Request->Header.u2.s2.Type == LPC_CLIENT_DIED)
|
||||
{
|
||||
DPRINT1("Clietn died, oh well\n");
|
||||
DPRINT("Clietn died, oh well\n");
|
||||
Reply = NULL;
|
||||
continue;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue