- 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
break;
case LPC_PORT_CLOSED:
Reply = NULL;
break;
case LPC_PORT_CLOSED:
Reply = NULL;
default:
if ((Request.SmHeader.ApiIndex) &&
(Request.SmHeader.ApiIndex < (sizeof SmApi / sizeof SmApi[0])))
default:
if ((Request.SmHeader.ApiIndex) &&
(Request.SmHeader.ApiIndex < (sizeof SmApi / sizeof SmApi[0])))
+VOID
+NTAPI
+KeFlushQueuedDpcs(
+ VOID
+);
+
BOOLEAN
NTAPI
KiIpiServiceRoutine(
BOOLEAN
NTAPI
KiIpiServiceRoutine(
// Failure to respect this will *ACHIEVE NOTHING*.
//
// Ex:
// Failure to respect this will *ACHIEVE NOTHING*.
//
// Ex:
-// - Fixup existing code that talks to Ke.
// - Implement Generic Callback mechanism.
// - Use pushlocks for handle implementation.
//
// - 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.
//
// 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.
//
// 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.
// Ke2:
// - New optimized table-based tick-hashed timer implementation.
// - New Thread Scheduler based on 2003.
DPRINT("DestroyHandleByEntry HT:0x%p Entry:0x%p\n", HandleTable, Entry);
DPRINT("DestroyHandleByEntry HT:0x%p Entry:0x%p\n", HandleTable, Entry);
- if (!(HandleTable->Flags & EX_HANDLE_TABLE_CLOSING))
- {
KeEnterCriticalRegion();
ExAcquireHandleLockExclusive(HandleTable);
KeEnterCriticalRegion();
ExAcquireHandleLockExclusive(HandleTable);
ExReleaseHandleLock(HandleTable);
KeLeaveCriticalRegion();
ExReleaseHandleLock(HandleTable);
KeLeaveCriticalRegion();
- * 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
* 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 <ntoskrnl.h>
#define NDEBUG
-#include <internal/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;
/* Timer Object Type */
POBJECT_TYPE ExTimerType = NULL;
static const INFORMATION_CLASS_INFO ExTimerInfoClass[] =
{
/* TimerBasicInformation */
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 *********************************************************/
ExTimerRundown(VOID)
{
PETHREAD Thread = PsGetCurrentThread();
KIRQL OldIrql;
PLIST_ENTRY CurrentEntry;
PETIMER Timer;
ExTimerRundown(VOID)
{
PETHREAD Thread = PsGetCurrentThread();
KIRQL OldIrql;
PLIST_ENTRY CurrentEntry;
PETIMER Timer;
- /* Lock the Thread's Active Timer List*/
+ /* Lock the Thread's Active Timer List and loop it */
KeAcquireSpinLock(&Thread->ActiveTimerListLock, &OldIrql);
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 */
Timer = CONTAINING_RECORD(CurrentEntry, ETIMER, ActiveTimerListEntry);
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;
- KeReleaseSpinLockFromDpcLevel(&Thread->ActiveTimerListLock);
+ KeReleaseSpinLock(&Thread->ActiveTimerListLock, OldIrql);
- KeAcquireSpinLockAtDpcLevel(&Timer->Lock);
+ KeAcquireSpinLock(&Timer->Lock, &OldIrql);
+
+ /* Lock the list again */
+ KeAcquireSpinLockAtDpcLevel(&Thread->ActiveTimerListLock);
- /* Cancel the timer and remove its DPC and APC */
- ASSERT(&Thread->Tcb == Timer->TimerApc.Thread);
- KeCancelTimer(&Timer->KeTimer);
- KeRemoveQueueDpc(&Timer->TimerDpc);
- KeRemoveQueueApc(&Timer->TimerApc);
+ /* 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);
/* Unlock the Timer */
KeReleaseSpinLock(&Timer->Lock, OldIrql);
/* Dereference it */
/* Unlock the Timer */
KeReleaseSpinLock(&Timer->Lock, OldIrql);
/* Dereference it */
- ObDereferenceObject(Timer);
+ ObDereferenceObjectEx(Timer, DerefsToDo);
/* Loop again */
KeAcquireSpinLock(&Thread->ActiveTimerListLock, &OldIrql);
/* Loop again */
KeAcquireSpinLock(&Thread->ActiveTimerListLock, &OldIrql);
+ CurrentEntry = Thread->ActiveTimerListHead.Flink;
}
/* Release lock and return */
}
/* Release lock and return */
-STDCALL
-ExpDeleteTimer(PVOID ObjectBody)
+NTAPI
+ExpDeleteTimer(IN PVOID ObjectBody)
{
KIRQL OldIrql;
PETIMER Timer = ObjectBody;
{
KIRQL OldIrql;
PETIMER Timer = ObjectBody;
- DPRINT("ExpDeleteTimer(Timer: 0x%p)\n", Timer);
/* Check if it has a Wait List */
/* Check if it has a Wait List */
+ if (Timer->WakeTimerListEntry.Flink)
{
/* Lock the Wake List */
KeAcquireSpinLock(&ExpWakeListLock, &OldIrql);
/* Check again, since it might've changed before we locked */
{
/* Lock the Wake List */
KeAcquireSpinLock(&ExpWakeListLock, &OldIrql);
/* Check again, since it might've changed before we locked */
+ if (Timer->WakeTimerListEntry.Flink)
{
/* Remove it from the Wait List */
{
/* Remove it from the Wait List */
- DPRINT("Removing wake list\n");
RemoveEntryList(&Timer->WakeTimerListEntry);
RemoveEntryList(&Timer->WakeTimerListEntry);
- Timer->WakeTimer = FALSE;
+ Timer->WakeTimerListEntry.Flink = NULL;
}
/* Release the Wake List */
KeReleaseSpinLock(&ExpWakeListLock, OldIrql);
}
}
/* 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);
KeCancelTimer(&Timer->KeTimer);
-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;
- 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 */
}
/* Release the Timer */
- KeReleaseSpinLock(&Timer->Lock, OldIrql);
- return;
-}
+ KeReleaseSpinLockFromDpcLevel(&Timer->Lock);
+ /* Dereference it if we couldn't queue the APC */
+ if (!Inserted) ObDereferenceObject(Timer);
+}
-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;
{
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);
/* 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*/
/* 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);
-
- /* Disable it */
- Timer->ApcAssociated = FALSE;
-
- /* Release spinlocks */
- KeReleaseSpinLockFromDpcLevel(&CurrentThread->ActiveTimerListLock);
- KeReleaseSpinLock(&Timer->Lock, OldIrql);
+ /* Check if it's not periodic */
+ if (!Timer->Period)
+ {
+ /* Remove it from the Active Timers List */
+ RemoveEntryList(&Timer->ActiveTimerListEntry);
- /* 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);
KeReleaseSpinLock(&Timer->Lock, OldIrql);
+
+ /* Dereference as needed */
+ ObDereferenceObjectEx(Timer, DerefsToDo);
ExpInitializeTimerImplementation(VOID)
{
OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
UNICODE_STRING Name;
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);
RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
RtlInitUnicodeString(&Name, L"Timer");
ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
InitializeListHead(&ExpWakeList);
}
InitializeListHead(&ExpWakeList);
}
+/* PUBLIC FUNCTIONS **********************************************************/
+
NtCancelTimer(IN HANDLE TimerHandle,
OUT PBOOLEAN CurrentState OPTIONAL)
{
NtCancelTimer(IN HANDLE TimerHandle,
OUT PBOOLEAN CurrentState OPTIONAL)
{
BOOLEAN State;
KIRQL OldIrql;
PETHREAD TimerThread;
BOOLEAN State;
KIRQL OldIrql;
PETHREAD TimerThread;
- BOOLEAN KillTimer = FALSE;
NTSTATUS Status = STATUS_SUCCESS;
PAGED_CODE();
NTSTATUS Status = STATUS_SUCCESS;
PAGED_CODE();
- DPRINT("NtCancelTimer(0x%p, 0x%x)\n", TimerHandle, CurrentState);
/* Check Parameter Validity */
/* Check Parameter Validity */
- if(CurrentState && PreviousMode != KernelMode)
+ if ((CurrentState) && (PreviousMode != KernelMode))
Status = _SEH_GetExceptionCode();
}
_SEH_END;
Status = _SEH_GetExceptionCode();
}
_SEH_END;
if(!NT_SUCCESS(Status)) return Status;
}
if(!NT_SUCCESS(Status)) return Status;
}
PreviousMode,
(PVOID*)&Timer,
NULL);
PreviousMode,
(PVOID*)&Timer,
NULL);
-
- /* Check for success */
- DPRINT("Timer Referenced: 0x%p\n", Timer);
-
/* Lock the Timer */
KeAcquireSpinLock(&Timer->Lock, &OldIrql);
/* Check if it's enabled */
if (Timer->ApcAssociated)
{
/* 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.
- */
TimerThread = CONTAINING_RECORD(Timer->TimerApc.Thread, ETHREAD, Tcb);
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);
/* Lock its active list */
KeAcquireSpinLockAtDpcLevel(&TimerThread->ActiveTimerListLock);
/* Remove it */
RemoveEntryList(&TimerThread->ActiveTimerListHead);
+ Timer->ApcAssociated = FALSE;
/* Unlock the list */
KeReleaseSpinLockFromDpcLevel(&TimerThread->ActiveTimerListLock);
/* Unlock the list */
KeReleaseSpinLockFromDpcLevel(&TimerThread->ActiveTimerListLock);
/* Cancel the Timer */
KeCancelTimer(&Timer->KeTimer);
KeRemoveQueueDpc(&Timer->TimerDpc);
/* 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 */
}
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 */
KeCancelTimer(&Timer->KeTimer);
}
/* Handle a Wake Timer */
+ if (Timer->WakeTimerListEntry.Flink)
{
/* Lock the Wake List */
KeAcquireSpinLockAtDpcLevel(&ExpWakeListLock);
/* Check again, since it might've changed before we locked */
{
/* Lock the Wake List */
KeAcquireSpinLockAtDpcLevel(&ExpWakeListLock);
/* Check again, since it might've changed before we locked */
+ if (Timer->WakeTimerListEntry.Flink)
{
/* Remove it from the Wait List */
{
/* Remove it from the Wait List */
- DPRINT("Removing wake list\n");
RemoveEntryList(&Timer->WakeTimerListEntry);
RemoveEntryList(&Timer->WakeTimerListEntry);
- Timer->WakeTimer = FALSE;
+ Timer->WakeTimerListEntry.Flink = NULL;
}
/* Release the Wake List */
}
/* Release the Wake List */
State = KeReadStateTimer(&Timer->KeTimer);
/* Dereference the Object */
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 */
/* Make sure it's safe to write to the handle */
NtCreateTimer(OUT PHANDLE TimerHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
NtCreateTimer(OUT PHANDLE TimerHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
NTSTATUS Status = STATUS_SUCCESS;
PAGED_CODE();
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)
/* Check Parameter Validity */
if (PreviousMode != KernelMode)
Status = _SEH_GetExceptionCode();
}
_SEH_END;
Status = _SEH_GetExceptionCode();
}
_SEH_END;
if(!NT_SUCCESS(Status)) return Status;
}
/* Check for correct timer type */
if ((TimerType != NotificationTimer) && (TimerType != SynchronizationTimer))
{
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;
}
return STATUS_INVALID_PARAMETER_4;
}
-
- /* Check for Success */
+ /* Initialize the DPC */
+ KeInitializeDpc(&Timer->TimerDpc, ExpTimerDpcRoutine, Timer);
+
/* Initialize the Kernel Timer */
/* Initialize the Kernel Timer */
- DPRINT("Initializing Timer: 0x%p\n", Timer);
KeInitializeTimerEx(&Timer->KeTimer, TimerType);
KeInitializeTimerEx(&Timer->KeTimer, TimerType);
- /* Initialize the Timer Lock */
+ /* Initialize the timer fields */
KeInitializeSpinLock(&Timer->Lock);
KeInitializeSpinLock(&Timer->Lock);
-
- /* Initialize the DPC */
- KeInitializeDpc(&Timer->TimerDpc, ExpTimerDpcRoutine, Timer);
-
- /* Set Initial State */
Timer->ApcAssociated = FALSE;
Timer->WakeTimer = FALSE;
Timer->ApcAssociated = FALSE;
Timer->WakeTimer = FALSE;
+ Timer->WakeTimerListEntry.Flink = NULL;
/* Insert the Timer */
Status = ObInsertObject((PVOID)Timer,
/* Insert the Timer */
Status = ObInsertObject((PVOID)Timer,
- DPRINT("Timer Inserted\n");
/* Make sure it's safe to write to the handle */
_SEH_TRY
/* Make sure it's safe to write to the handle */
_SEH_TRY
NtOpenTimer(OUT PHANDLE TimerHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes)
NtOpenTimer(OUT PHANDLE TimerHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes)
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
NTSTATUS Status = STATUS_SUCCESS;
PAGED_CODE();
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
NTSTATUS Status = STATUS_SUCCESS;
PAGED_CODE();
- DPRINT("NtOpenTimer(TimerHandle: 0x%p)\n", TimerHandle);
/* Check Parameter Validity */
if (PreviousMode != KernelMode)
/* Check Parameter Validity */
if (PreviousMode != KernelMode)
Status = _SEH_GetExceptionCode();
}
_SEH_END;
Status = _SEH_GetExceptionCode();
}
_SEH_END;
if(!NT_SUCCESS(Status)) return Status;
}
if(!NT_SUCCESS(Status)) return Status;
}
DesiredAccess,
NULL,
&hTimer);
DesiredAccess,
NULL,
&hTimer);
-
- /* Check for success */
if(NT_SUCCESS(Status))
{
/* Make sure it's safe to write to the handle */
if(NT_SUCCESS(Status))
{
/* Make sure it's safe to write to the handle */
NtQueryTimer(IN HANDLE TimerHandle,
IN TIMER_INFORMATION_CLASS TimerInformationClass,
OUT PVOID TimerInformation,
IN ULONG TimerInformationLength,
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();
{
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;
- DPRINT("NtQueryTimer(TimerHandle: 0x%p, Class: %d)\n", TimerHandle, TimerInformationClass);
/* Check Validity */
Status = DefaultQueryInfoBufferCheck(TimerInformationClass,
ExTimerInfoClass,
/* Check Validity */
Status = DefaultQueryInfoBufferCheck(TimerInformationClass,
ExTimerInfoClass,
- sizeof(ExTimerInfoClass) / sizeof(ExTimerInfoClass[0]),
+ sizeof(ExTimerInfoClass) /
+ sizeof(ExTimerInfoClass[0]),
TimerInformation,
TimerInformationLength,
ReturnLength,
PreviousMode);
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,
/* Get the Timer Object */
Status = ObReferenceObjectByHandle(TimerHandle,
PreviousMode,
(PVOID*)&Timer,
NULL);
PreviousMode,
(PVOID*)&Timer,
NULL);
-
- /* Check for Success */
if(NT_SUCCESS(Status))
{
/* Return the Basic Information */
if(NT_SUCCESS(Status))
{
/* Return the Basic Information */
BasicInfo->SignalState = KeReadStateTimer(&Timer->KeTimer);
/* Return the buffer length if requested */
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)
{
}
_SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
{
NtSetTimer(IN HANDLE TimerHandle,
IN PLARGE_INTEGER DueTime,
IN PTIMER_APC_ROUTINE TimerApcRoutine OPTIONAL,
NtSetTimer(IN HANDLE TimerHandle,
IN PLARGE_INTEGER DueTime,
IN PTIMER_APC_ROUTINE TimerApcRoutine OPTIONAL,
KIRQL OldIrql;
BOOLEAN State;
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
KIRQL OldIrql;
BOOLEAN State;
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
- PETHREAD CurrentThread = PsGetCurrentThread();
+ PETHREAD Thread = PsGetCurrentThread();
LARGE_INTEGER TimerDueTime;
PETHREAD TimerThread;
LARGE_INTEGER TimerDueTime;
PETHREAD TimerThread;
- BOOLEAN KillTimer = FALSE;
NTSTATUS Status = STATUS_SUCCESS;
PAGED_CODE();
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)
/* Check Parameter Validity */
if (PreviousMode != KernelMode)
_SEH_TRY
{
TimerDueTime = ProbeForReadLargeInteger(DueTime);
_SEH_TRY
{
TimerDueTime = ProbeForReadLargeInteger(DueTime);
-
- if(PreviousState)
- {
- ProbeForWriteBoolean(PreviousState);
- }
+ if(PreviousState) ProbeForWriteBoolean(PreviousState);
}
_SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
{
Status = _SEH_GetExceptionCode();
}
_SEH_END;
}
_SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
{
Status = _SEH_GetExceptionCode();
}
_SEH_END;
if(!NT_SUCCESS(Status)) return Status;
}
/* Check for a valid Period */
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,
/* Get the Timer Object */
Status = ObReferenceObjectByHandle(TimerHandle,
/*
* Tell the user we don't support Wake Timers...
* when we have the ability to use/detect the Power Management
/*
* 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;
* on the actual PM capabilities
*/
if (WakeTimer) Status = STATUS_TIMER_RESUME_IGNORED;
if (NT_SUCCESS(Status))
{
/* Lock the Timer */
if (NT_SUCCESS(Status))
{
/* Lock the Timer */
- DPRINT("Timer Referencced: 0x%p\n", Timer);
KeAcquireSpinLock(&Timer->Lock, &OldIrql);
/* Cancel Running Timer */
if (Timer->ApcAssociated)
{
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);
/* Lock its active list */
KeAcquireSpinLockAtDpcLevel(&TimerThread->ActiveTimerListLock);
/* Remove it */
RemoveEntryList(&TimerThread->ActiveTimerListHead);
+ Timer->ApcAssociated = FALSE;
/* Unlock the list */
KeReleaseSpinLockFromDpcLevel(&TimerThread->ActiveTimerListLock);
/* Unlock the list */
KeReleaseSpinLockFromDpcLevel(&TimerThread->ActiveTimerListLock);
/* Cancel the Timer */
KeCancelTimer(&Timer->KeTimer);
KeRemoveQueueDpc(&Timer->TimerDpc);
/* 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 */
/* If timer was disabled, we still need to cancel it */
- DPRINT("No APCs. Simply cancelling\n");
KeCancelTimer(&Timer->KeTimer);
}
KeCancelTimer(&Timer->KeTimer);
}
State = KeReadStateTimer(&Timer->KeTimer);
/* Handle Wake Timers */
State = KeReadStateTimer(&Timer->KeTimer);
/* Handle Wake Timers */
- DPRINT("Doing Wake Semantics\n");
KeAcquireSpinLockAtDpcLevel(&ExpWakeListLock);
KeAcquireSpinLockAtDpcLevel(&ExpWakeListLock);
- if (WakeTimer && !Timer->WakeTimer)
+ if ((WakeTimer) && !(Timer->WakeTimerListEntry.Flink))
{
/* Insert it into the list */
{
/* Insert it into the list */
- Timer->WakeTimer = TRUE;
InsertTailList(&ExpWakeList, &Timer->WakeTimerListEntry);
}
InsertTailList(&ExpWakeList, &Timer->WakeTimerListEntry);
}
- else if (!WakeTimer && Timer->WakeTimer)
+ else if (!(WakeTimer) && (Timer->WakeTimerListEntry.Flink))
{
/* Remove it from the list */
RemoveEntryList(&Timer->WakeTimerListEntry);
{
/* Remove it from the list */
RemoveEntryList(&Timer->WakeTimerListEntry);
- Timer->WakeTimer = FALSE;
+ Timer->WakeTimerListEntry.Flink = NULL;
}
KeReleaseSpinLockFromDpcLevel(&ExpWakeListLock);
/* Set up the APC Routine if specified */
}
KeReleaseSpinLockFromDpcLevel(&ExpWakeListLock);
/* Set up the APC Routine if specified */
+ Timer->Period = Period;
if (TimerApcRoutine)
{
/* Initialize the APC */
if (TimerApcRoutine)
{
/* Initialize the APC */
- DPRINT("Initializing APC: 0x%p\n", Timer->TimerApc);
KeInitializeApc(&Timer->TimerApc,
KeInitializeApc(&Timer->TimerApc,
CurrentApcEnvironment,
&ExpTimerApcKernelRoutine,
(PKRUNDOWN_ROUTINE)NULL,
CurrentApcEnvironment,
&ExpTimerApcKernelRoutine,
(PKRUNDOWN_ROUTINE)NULL,
TimerContext);
/* Lock the Thread's Active List and Insert */
TimerContext);
/* Lock the Thread's Active List and Insert */
- KeAcquireSpinLockAtDpcLevel(&CurrentThread->ActiveTimerListLock);
- InsertTailList(&CurrentThread->ActiveTimerListHead,
+ KeAcquireSpinLockAtDpcLevel(&Thread->ActiveTimerListLock);
+ InsertTailList(&Thread->ActiveTimerListHead,
&Timer->ActiveTimerListEntry);
&Timer->ActiveTimerListEntry);
- KeReleaseSpinLockFromDpcLevel(&CurrentThread->ActiveTimerListLock);
+ Timer->ApcAssociated = TRUE;
+ KeReleaseSpinLockFromDpcLevel(&Thread->ActiveTimerListLock);
+ /* One less dereference to do */
+ DerefsToDo--;
}
/* Enable and Set the Timer */
}
/* Enable and Set the Timer */
- DPRINT("Setting Kernel Timer\n");
KeSetTimerEx(&Timer->KeTimer,
TimerDueTime,
Period,
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 */
/* 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 */
/* Make sure it's safe to write to the handle */
- if(PreviousState != NULL)
-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);
{
PEX_WORK_QUEUE WorkQueue = &ExWorkerQueue[QueueType];
ASSERT(QueueType < MaximumWorkQueue);
ULONG ExpUnicodeCaseTableDataOffset;
PVOID ExpNlsSectionPointer;
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) & \
#define MAX_FAST_REFS 7
#define EX_OBJ_TO_HDR(eob) ((POBJECT_HEADER)((ULONG_PTR)(eob) & \
/* Loop queued messages */
ListHead = &Port->MsgQueue.ReceiveHead;
NextEntry = ListHead->Flink;
/* 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);
{
/* Get the message */
Message = CONTAINING_RECORD(NextEntry, LPCP_MESSAGE, Entry);
ExSweepHandleTable(HandleTable,
ObpCloseHandleCallback,
&Context);
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();
/* Leave the critical region */
KeLeaveCriticalRegion();
/* If the connection was closed, handle that */
if (Request->Header.u2.s2.Type == LPC_PORT_CLOSED)
{
/* 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 );
CsrFreeProcessData( Request->Header.ClientId.UniqueProcess );
+ //NtClose()
+ Reply = NULL;
+ continue;
+ //break;
}
if (Request->Header.u2.s2.Type == LPC_CONNECTION_REQUEST)
}
if (Request->Header.u2.s2.Type == LPC_CONNECTION_REQUEST)
if (Request->Header.u2.s2.Type == LPC_CLIENT_DIED)
{
if (Request->Header.u2.s2.Type == LPC_CLIENT_DIED)
{
- DPRINT1("Clietn died, oh well\n");
+ DPRINT("Clietn died, oh well\n");
Reply = NULL;
continue;
}
Reply = NULL;
continue;
}