diff --git a/reactos/ntoskrnl/include/internal/ke.h b/reactos/ntoskrnl/include/internal/ke.h index b40f2a06e9d..fcd0d265d89 100644 --- a/reactos/ntoskrnl/include/internal/ke.h +++ b/reactos/ntoskrnl/include/internal/ke.h @@ -103,6 +103,8 @@ VOID KeContextToTrapFrame(PCONTEXT Context, PKTRAP_FRAME TrapFrame); VOID KeReleaseDispatcherDatabaseLockAtDpcLevel(BOOLEAN Wait); +BOOLEAN STDCALL KeRemoveQueueApc (PKAPC Apc); + /* INITIALIZATION FUNCTIONS *************************************************/ VOID KeInitExceptions(VOID); diff --git a/reactos/ntoskrnl/include/internal/nt.h b/reactos/ntoskrnl/include/internal/nt.h index 227fb096d9c..5cc1cd9d901 100644 --- a/reactos/ntoskrnl/include/internal/nt.h +++ b/reactos/ntoskrnl/include/internal/nt.h @@ -1,4 +1,6 @@ VOID NtInitializeEventImplementation(VOID); VOID NtInitializeEventPairImplementation(VOID); VOID NtInitializeSemaphoreImplementation(VOID); +VOID NtInitializeMutantImplementation(VOID); +VOID NtInitializeTimerImplementation(VOID); NTSTATUS NiInitPort(VOID); diff --git a/reactos/ntoskrnl/ke/apc.c b/reactos/ntoskrnl/ke/apc.c index ba96f6922d7..c7e8b31e064 100644 --- a/reactos/ntoskrnl/ke/apc.c +++ b/reactos/ntoskrnl/ke/apc.c @@ -220,7 +220,7 @@ VOID STDCALL KiDeliverApc(ULONG Unknown1, KeReleaseSpinLock(&PiApcLock, oldlvl); } -VOID STDCALL +VOID STDCALL KeInsertQueueApc (PKAPC Apc, PVOID SystemArgument1, PVOID SystemArgument2, @@ -296,6 +296,45 @@ KeInsertQueueApc (PKAPC Apc, KeReleaseSpinLock(&PiApcLock, oldlvl); } +BOOLEAN STDCALL +KeRemoveQueueApc (PKAPC Apc) +/* + * FUNCTION: Removes APC object from the apc queue + * ARGUMENTS: + * Apc = APC to remove + * RETURNS: TRUE if the APC was in the queue + * FALSE otherwise + * NOTE: This function is not exported. + */ +{ + KIRQL oldIrql; + PKTHREAD TargetThread; + + KeAcquireSpinLockAtDpcLevel(&PiApcLock); + KeRaiseIrql(HIGH_LEVEL, &oldIrql); + if (Apc->Inserted == FALSE) + { + KeReleaseSpinLock(&PiApcLock, oldIrql); + return(FALSE); + } + + TargetThread = Apc->Thread; + RemoveEntryList(&Apc->ApcListEntry); + if (Apc->ApcMode == KernelMode) + { + TargetThread->ApcState.KernelApcPending--; + } + else + { + TargetThread->ApcState.UserApcPending--; + } + Apc->Inserted = FALSE; + + KeReleaseSpinLock(&PiApcLock, oldIrql); + return(TRUE); +} + + VOID STDCALL KeInitializeApc (PKAPC Apc, PKTHREAD Thread, diff --git a/reactos/ntoskrnl/nt/nt.c b/reactos/ntoskrnl/nt/nt.c index 85c14e8fae9..be24c11c454 100644 --- a/reactos/ntoskrnl/nt/nt.c +++ b/reactos/ntoskrnl/nt/nt.c @@ -1,4 +1,5 @@ -/* +/* $Id: nt.c,v 1.6 2001/02/04 17:28:13 ekohl Exp $ + * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * FILE: ntoskrnl/nt/nt.c @@ -22,5 +23,8 @@ VOID NtInit(VOID) NtInitializeEventImplementation(); NtInitializeEventPairImplementation(); NtInitializeSemaphoreImplementation(); + NtInitializeTimerImplementation(); NiInitPort(); } + +/* EOF */ diff --git a/reactos/ntoskrnl/nt/nttimer.c b/reactos/ntoskrnl/nt/nttimer.c index 9dde8b747ae..4169d6a57ab 100644 --- a/reactos/ntoskrnl/nt/nttimer.c +++ b/reactos/ntoskrnl/nt/nttimer.c @@ -1,4 +1,5 @@ -/* +/* $Id: nttimer.c,v 1.7 2001/02/04 17:28:13 ekohl Exp $ + * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * FILE: ntoskrnl/nt/nttimer.c @@ -11,84 +12,289 @@ /* INCLUDES *****************************************************************/ #include +#include +#include +#include +#include + #include +/* TYPES ********************************************************************/ + +typedef struct _NTTIMER +{ + KTIMER Timer; + KDPC Dpc; + KAPC Apc; + BOOLEAN Running; +} NTTIMER, *PNTTIMER; + + /* GLOBALS ******************************************************************/ -#if 0 +POBJECT_TYPE ExTimerType = NULL; + static GENERIC_MAPPING ExpTimerMapping = { STANDARD_RIGHTS_READ | TIMER_QUERY_STATE, STANDARD_RIGHTS_WRITE | TIMER_MODIFY_STATE, STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE, TIMER_ALL_ACCESS}; -#endif /* FUNCTIONS *****************************************************************/ NTSTATUS -STDCALL -NtCancelTimer ( - IN HANDLE TimerHandle, - OUT PBOOLEAN CurrentState OPTIONAL - ) +NtpCreateTimer(PVOID ObjectBody, + PVOID Parent, + PWSTR RemainingPath, + POBJECT_ATTRIBUTES ObjectAttributes) +{ + DPRINT("NtpCreateTimer(ObjectBody %x, Parent %x, RemainingPath %S)\n", + ObjectBody, Parent, RemainingPath); + + if (RemainingPath != NULL && wcschr(RemainingPath+1, '\\') != NULL) + { + return(STATUS_UNSUCCESSFUL); + } + + if (Parent != NULL && RemainingPath != NULL) + { + ObAddEntryDirectory(Parent, ObjectBody, RemainingPath+1); + } + return(STATUS_SUCCESS); +} + + +VOID +NtpTimerDpcRoutine(PKDPC Dpc, + PVOID DeferredContext, + PVOID SystemArgument1, + PVOID SystemArgument2) +{ + PNTTIMER Timer; + KIRQL OldIrql; + + DPRINT("NtpTimerDpcRoutine()\n"); + + Timer = (PNTTIMER)DeferredContext; + + OldIrql = KeRaiseIrqlToDpcLevel(); + + if (Timer->Running == TRUE) + { + KeInsertQueueApc(&Timer->Apc, + SystemArgument1, + SystemArgument2, + KernelMode); + } + + KeLowerIrql(OldIrql); +} + + +VOID +NtpTimerApcKernelRoutine(PKAPC Apc, + PKNORMAL_ROUTINE* NormalRoutine, + PVOID* NormalContext, + PVOID* SystemArgument1, + PVOID* SystemArguemnt2) +{ + DPRINT("NtpTimerApcKernelRoutine()\n"); + +} + + +VOID NtInitializeTimerImplementation(VOID) +{ + ExTimerType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE)); + + RtlCreateUnicodeString(&ExTimerType->TypeName, L"Timer"); + + ExTimerType->MaxObjects = ULONG_MAX; + ExTimerType->MaxHandles = ULONG_MAX; + ExTimerType->TotalObjects = 0; + ExTimerType->TotalHandles = 0; + ExTimerType->PagedPoolCharge = 0; + ExTimerType->NonpagedPoolCharge = sizeof(NTTIMER); + ExTimerType->Mapping = &ExpTimerMapping; + ExTimerType->Dump = NULL; + ExTimerType->Open = NULL; + ExTimerType->Close = NULL; + ExTimerType->Delete = NULL; + ExTimerType->Parse = NULL; + ExTimerType->Security = NULL; + ExTimerType->QueryName = NULL; + ExTimerType->OkayToClose = NULL; + ExTimerType->Create = NtpCreateTimer; +} + + +NTSTATUS STDCALL +NtCancelTimer(IN HANDLE TimerHandle, + OUT PBOOLEAN CurrentState OPTIONAL) +{ + PNTTIMER Timer; + NTSTATUS Status; + BOOLEAN State; + KIRQL OldIrql; + + DPRINT("NtCancelTimer()\n"); + Status = ObReferenceObjectByHandle(TimerHandle, + TIMER_ALL_ACCESS, + ExTimerType, + UserMode, + (PVOID*)&Timer, + NULL); + if (!NT_SUCCESS(Status)) + return Status; + + OldIrql = KeRaiseIrqlToDpcLevel(); + + State = KeCancelTimer(&Timer->Timer); + KeRemoveQueueDpc(&Timer->Dpc); + KeRemoveQueueApc(&Timer->Apc); + Timer->Running = FALSE; + + KeLowerIrql(OldIrql); + ObDereferenceObject(Timer); + + if (CurrentState != NULL) + { + *CurrentState = State; + } + + return STATUS_SUCCESS; +} + + +NTSTATUS STDCALL +NtCreateTimer(OUT PHANDLE TimerHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN TIMER_TYPE TimerType) +{ + PNTTIMER Timer; + + DPRINT("NtCreateTimer()\n"); + Timer = ObCreateObject(TimerHandle, + DesiredAccess, + ObjectAttributes, + ExTimerType); + + KeInitializeTimerEx(&Timer->Timer, + TimerType); + + KeInitializeDpc (&Timer->Dpc, + (PKDEFERRED_ROUTINE)NtpTimerDpcRoutine, + (PVOID)Timer); + + Timer->Running = FALSE; + + ObDereferenceObject(Timer); + + return(STATUS_SUCCESS); +} + + +NTSTATUS STDCALL +NtOpenTimer(OUT PHANDLE TimerHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes) +{ + NTSTATUS Status; + + Status = ObOpenObjectByName(ObjectAttributes, + ExTimerType, + NULL, + UserMode, + DesiredAccess, + NULL, + TimerHandle); + return Status; +} + + +NTSTATUS STDCALL +NtQueryTimer(IN HANDLE TimerHandle, + IN CINT TimerInformationClass, + OUT PVOID TimerInformation, + IN ULONG Length, + OUT PULONG ResultLength) { UNIMPLEMENTED; } -NTSTATUS -STDCALL -NtCreateTimer ( - OUT PHANDLE TimerHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, - IN TIMER_TYPE TimerType - ) +NTSTATUS STDCALL +NtSetTimer(IN HANDLE TimerHandle, + IN PLARGE_INTEGER DueTime, + IN PTIMERAPCROUTINE TimerApcRoutine, + IN PVOID TimerContext, + IN BOOL WakeTimer, + IN ULONG Period OPTIONAL, + OUT PBOOLEAN PreviousState OPTIONAL) { - UNIMPLEMENTED; + PNTTIMER Timer; + NTSTATUS Status; + BOOLEAN Result; + KIRQL OldIrql; + BOOLEAN State; + + DPRINT("NtSetTimer()\n"); + + Status = ObReferenceObjectByHandle(TimerHandle, + TIMER_ALL_ACCESS, + ExTimerType, + KeGetPreviousMode(), + (PVOID*)&Timer, + NULL); + if (!NT_SUCCESS(Status)) + return Status; + + State = KeReadStateTimer(&Timer->Timer); + + if (Timer->Running == TRUE) + { + /* cancel running timer */ + OldIrql = KeRaiseIrqlToDpcLevel(); + KeCancelTimer(&Timer->Timer); + KeRemoveQueueDpc(&Timer->Dpc); + KeRemoveQueueApc(&Timer->Apc); + Timer->Running = FALSE; + KeLowerIrql(OldIrql); + } + + KeInitializeApc(&Timer->Apc, + KeGetCurrentThread(), + 0, + (PKKERNEL_ROUTINE)NtpTimerApcKernelRoutine, + (PKRUNDOWN_ROUTINE)NULL, + (PKNORMAL_ROUTINE)TimerApcRoutine, + KeGetPreviousMode(), + TimerContext); + + Result = KeSetTimerEx (&Timer->Timer, + *DueTime, + Period, + &Timer->Dpc); + if (Result == FALSE) + { + ObDereferenceObject(Timer); + return STATUS_UNSUCCESSFUL; + } + + Timer->Running = TRUE; + + ObDereferenceObject(Timer); + + if (PreviousState != NULL) + { + *PreviousState = State; + } + + return STATUS_SUCCESS; } - -NTSTATUS -STDCALL -NtOpenTimer ( - OUT PHANDLE TimerHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes - ) -{ - UNIMPLEMENTED; -} - - -NTSTATUS -STDCALL -NtQueryTimer ( - IN HANDLE TimerHandle, - IN CINT TimerInformationClass, - OUT PVOID TimerInformation, - IN ULONG Length, - OUT PULONG ResultLength - ) -{ - UNIMPLEMENTED; -} - - -NTSTATUS -STDCALL -NtSetTimer ( - IN HANDLE TimerHandle, - IN PLARGE_INTEGER DueTime, - IN PTIMERAPCROUTINE TimerApcRoutine, - IN PVOID TimerContext, - IN BOOL WakeTimer, - IN ULONG Period OPTIONAL, - OUT PBOOLEAN PreviousState OPTIONAL - ) -{ - UNIMPLEMENTED; -} +/* EOF */