From db4c78ea863ac23cb5c52de1f65da3f2126f00ac Mon Sep 17 00:00:00 2001 From: Alex Ionescu Date: Mon, 28 Feb 2005 17:40:15 +0000 Subject: [PATCH] Reverting to 13775. Sorry for the mess. This is dedicated to Jane! 19934415. svn path=/trunk/; revision=13777 --- reactos/config | 4 +- reactos/drivers/storage/floppy/floppy.c | 8 +- reactos/include/ddk/extypes.h | 21 - reactos/include/ddk/iotypes.h | 2 - reactos/include/ddk/ketypes.h | 45 +- reactos/include/ntos/zwtypes.h | 6 +- reactos/lib/ntdll/def/ntdll.def | 4 + reactos/ntoskrnl/Makefile | 7 +- reactos/ntoskrnl/cm/registry.c | 23 - reactos/ntoskrnl/ex/error.c | 163 -- reactos/ntoskrnl/ex/event.c | 830 +++++---- reactos/ntoskrnl/ex/evtpair.c | 850 +++++---- reactos/ntoskrnl/ex/init.c | 640 +------ reactos/ntoskrnl/ex/mutant.c | 586 +++--- reactos/ntoskrnl/ex/rundown.c | 5 +- reactos/ntoskrnl/ex/sem.c | 583 +++--- reactos/ntoskrnl/ex/sysinfo.c | 14 - reactos/ntoskrnl/ex/timer.c | 30 +- reactos/ntoskrnl/ex/work.c | 227 +-- reactos/ntoskrnl/include/internal/ex.h | 13 +- reactos/ntoskrnl/include/internal/id.h | 13 + reactos/ntoskrnl/include/internal/io.h | 2 +- reactos/ntoskrnl/include/internal/ke.h | 40 +- reactos/ntoskrnl/include/internal/nls.h | 1 - reactos/ntoskrnl/include/internal/ntoskrnl.h | 4 +- reactos/ntoskrnl/include/internal/ps.h | 9 +- reactos/ntoskrnl/io/bootlog.c | 5 +- reactos/ntoskrnl/io/create.c | 4 +- reactos/ntoskrnl/io/driver.c | 2 +- reactos/ntoskrnl/io/iocomp.c | 536 +++--- reactos/ntoskrnl/io/iomgr.c | 57 +- reactos/ntoskrnl/io/wmi.c | 14 - reactos/ntoskrnl/ke/alert.c | 150 ++ reactos/ntoskrnl/ke/apc.c | 1258 +++++-------- reactos/ntoskrnl/ke/bug.c | 25 - reactos/ntoskrnl/ke/catch.c | 423 +++-- reactos/ntoskrnl/ke/critical.c | 56 + reactos/ntoskrnl/ke/dpc.c | 653 ++++--- reactos/ntoskrnl/ke/error.c | 98 + reactos/ntoskrnl/ke/event.c | 300 +-- reactos/ntoskrnl/ke/i386/tskswitch.S | 2 +- reactos/ntoskrnl/ke/kthread.c | 936 ++++------ reactos/ntoskrnl/ke/main.c | 1159 ++++++++++-- reactos/ntoskrnl/ke/mutex.c | 307 ++-- reactos/ntoskrnl/ke/queue.c | 621 ++----- reactos/ntoskrnl/ke/sem.c | 114 +- reactos/ntoskrnl/ke/timer.c | 14 +- reactos/ntoskrnl/ke/wait.c | 1736 ++++++++++-------- reactos/ntoskrnl/ntoskrnl.def | 5 +- reactos/ntoskrnl/ntoskrnl.mc | 16 - reactos/ntoskrnl/ob/wait.c | 300 --- reactos/ntoskrnl/ps/kill.c | 4 +- reactos/ntoskrnl/ps/process.c | 4 +- reactos/ntoskrnl/ps/thread.c | 88 +- reactos/ntoskrnl/rtl/nls.c | 27 +- reactos/tools/nci/sysfuncs.lst | 2 + 56 files changed, 6221 insertions(+), 6825 deletions(-) delete mode 100644 reactos/ntoskrnl/ex/error.c create mode 100644 reactos/ntoskrnl/ke/alert.c create mode 100644 reactos/ntoskrnl/ke/critical.c create mode 100644 reactos/ntoskrnl/ke/error.c delete mode 100644 reactos/ntoskrnl/ob/wait.c diff --git a/reactos/config b/reactos/config index 9a6cdff4812..5a8c1f69da9 100644 --- a/reactos/config +++ b/reactos/config @@ -15,7 +15,7 @@ ARCH := i386 # be optimze for. # -OARCH := pentium2 +OARCH := i486 # # Whether to compile in the kernel debugger @@ -30,7 +30,7 @@ DBG := 0 # # Whether to compile with optimizations # -OPTIMIZED := 1 +OPTIMIZED := 0 # # Whether to compile a multiprocessor or single processor version diff --git a/reactos/drivers/storage/floppy/floppy.c b/reactos/drivers/storage/floppy/floppy.c index 344793009e6..987eb2ffeff 100644 --- a/reactos/drivers/storage/floppy/floppy.c +++ b/reactos/drivers/storage/floppy/floppy.c @@ -58,7 +58,7 @@ static ULONG gNumberOfControllers = 0; /* Queue thread management */ static KEVENT QueueThreadTerminate; -static PVOID QueueThreadObject; +static PVOID ThreadObject; static VOID NTAPI MotorStopDpcFunc(PKDPC UnusedDpc, @@ -378,8 +378,8 @@ static VOID NTAPI Unload(PDRIVER_OBJECT DriverObject) KdPrint(("floppy: unloading\n")); KeSetEvent(&QueueThreadTerminate, 0, FALSE); - KeWaitForSingleObject(QueueThreadObject, Executive, KernelMode, FALSE, 0); - ObDereferenceObject(QueueThreadObject); + KeWaitForSingleObject(ThreadObject, Executive, KernelMode, FALSE, 0); + ObDereferenceObject(ThreadObject); for(i = 0; i < gNumberOfControllers; i++) { @@ -1152,7 +1152,7 @@ NTSTATUS NTAPI DriverEntry(PDRIVER_OBJECT DriverObject, return STATUS_INSUFFICIENT_RESOURCES; } - if(ObReferenceObjectByHandle(ThreadHandle, STANDARD_RIGHTS_ALL, NULL, KernelMode, &QueueThreadObject, NULL) != STATUS_SUCCESS) + if(ObReferenceObjectByHandle(ThreadHandle, STANDARD_RIGHTS_ALL, NULL, KernelMode, &ThreadObject, NULL) != STATUS_SUCCESS) { KdPrint(("floppy: Unable to reference returned thread handle; failing init\n")); return STATUS_UNSUCCESSFUL; diff --git a/reactos/include/ddk/extypes.h b/reactos/include/ddk/extypes.h index 2c438f6329f..4db6f6dd11b 100644 --- a/reactos/include/ddk/extypes.h +++ b/reactos/include/ddk/extypes.h @@ -30,23 +30,6 @@ typedef enum _WORK_QUEUE_TYPE { MaximumWorkQueue } WORK_QUEUE_TYPE; -typedef struct _EX_QUEUE_WORKER_INFO { - UCHAR QueueDisabled:1; - UCHAR MakeThreadsAsNecessary:1; - UCHAR WaitMode:1; - ULONG WorkerCount:29; -} EX_QUEUE_WORKER_INFO, *PEX_QUEUE_WORKER_INFO; - -typedef struct _EX_WORK_QUEUE { - KQUEUE WorkerQueue; - ULONG DynamicThreadCount; - ULONG WorkItemsProcessed; - ULONG WorkItemsProcessedLastPass; - ULONG QueueDepthLastPass; - EX_QUEUE_WORKER_INFO Info; -} EX_WORK_QUEUE, *PEX_WORK_QUEUE; - - typedef ULONG_PTR ERESOURCE_THREAD, *PERESOURCE_THREAD; typedef struct _OWNER_ENTRY @@ -257,10 +240,6 @@ typedef VOID STDCALL_FUNC PVOID Argument1, PVOID Argument2); -extern struct _OBJECT_TYPE EXPORTED *ExMutantObjectType; -extern struct _OBJECT_TYPE EXPORTED *ExSemaphoreObjectType; -extern struct _OBJECT_TYPE EXPORTED *ExTimerType; - #endif /* __INCLUDE_DDK_EXTYPES_H */ /* EOF */ diff --git a/reactos/include/ddk/iotypes.h b/reactos/include/ddk/iotypes.h index 379cfc88a5a..bca07696b55 100644 --- a/reactos/include/ddk/iotypes.h +++ b/reactos/include/ddk/iotypes.h @@ -886,8 +886,6 @@ struct _FAST_IO_DISPATCH_TABLE #endif #define IO_TYPE_DRIVER 4L -#define IO_TYPE_FILE 0x0F5L - #define DRVO_UNLOAD_INVOKED 0x1L #define DRVO_LEGACY_DRIVER 0x2L #define DRVO_BUILTIN_DRIVER 0x4L diff --git a/reactos/include/ddk/ketypes.h b/reactos/include/ddk/ketypes.h index b938fc6c0b4..ce77b02599c 100644 --- a/reactos/include/ddk/ketypes.h +++ b/reactos/include/ddk/ketypes.h @@ -36,34 +36,23 @@ typedef VOID STDCALL_FUNC struct _DISPATCHER_HEADER; -typedef enum _KOBJECTS { - EventNotificationObject = 0, - EventSynchronizationObject = 1, - MutantObject = 2, - ProcessObject = 3, - QueueObject = 4, - SemaphoreObject = 5, - ThreadObject = 6, - GateObject = 7, - TimerNotificationObject = 8, - TimerSynchronizationObject = 9, - Spare2Object = 10, - Spare3Object = 11, - Spare4Object = 12, - Spare5Object = 13, - Spare6Object = 14, - Spare7Object = 15, - Spare8Object = 16, - Spare9Object = 17, - ApcObject = 18, - DpcObject = 19, - DeviceQueueObject = 20, - EventPairObject = 21, - InterruptObject = 22, - ProfileObject = 23, - ThreadedDpcObject = 24, - MaximumKernelObject = 25 -} KOBJECTS; +typedef enum _KERNEL_OBJECTS { + KNotificationEvent = 0, + KSynchronizationEvent = 1, + KMutant = 2, + KProcess = 3, + KQueue = 4, + KSemaphore = 5, + KThread = 6, + KNotificationTimer = 8, + KSynchronizationTimer = 9, + KApc = 18, + KDpc = 19, + KDeviceQueue = 20, + KEventPair = 21, + KInterrupt = 22, + KProfile = 23 +} KERNEL_OBJECTS; #include diff --git a/reactos/include/ntos/zwtypes.h b/reactos/include/ntos/zwtypes.h index 78f6d1eb26c..37ba0b14f6a 100755 --- a/reactos/include/ntos/zwtypes.h +++ b/reactos/include/ntos/zwtypes.h @@ -1262,9 +1262,9 @@ typedef enum _MUTANT_INFORMATION_CLASS typedef struct _MUTANT_BASIC_INFORMATION { - LONG CurrentCount; - BOOLEAN OwnedByCaller; - BOOLEAN AbandonedState; + LONG Count; + BOOLEAN Owned; + BOOLEAN Abandoned; } MUTANT_BASIC_INFORMATION, *PMUTANT_BASIC_INFORMATION; diff --git a/reactos/lib/ntdll/def/ntdll.def b/reactos/lib/ntdll/def/ntdll.def index 66e909cdb9a..f9101bae979 100644 --- a/reactos/lib/ntdll/def/ntdll.def +++ b/reactos/lib/ntdll/def/ntdll.def @@ -225,6 +225,7 @@ NtSetEaFile@16 NtSetEvent@8 NtSetHighEventPair@4 NtSetHighWaitLowEventPair@4 +NtSetHighWaitLowThread@0 NtSetInformationFile@20 NtSetInformationJobObject@16 NtSetInformationKey@16 @@ -237,6 +238,7 @@ NtSetIoCompletion@20 NtSetLdtEntries@24 NtSetLowEventPair@4 NtSetLowWaitHighEventPair@4 +NtSetLowWaitHighThread@0 NtSetSecurityObject@12 NtSetSystemEnvironmentValue@8 NtSetSystemInformation@12 @@ -847,6 +849,7 @@ ZwSetEaFile@16 ZwSetEvent@8 ZwSetHighEventPair@4 ZwSetHighWaitLowEventPair@4 +ZwSetHighWaitLowThread@0 ZwSetInformationFile@20 ZwSetInformationKey@16 ZwSetInformationObject@16 @@ -858,6 +861,7 @@ ZwSetIoCompletion@20 ZwSetLdtEntries@24 ZwSetLowEventPair@4 ZwSetLowWaitHighEventPair@4 +ZwSetLowWaitHighThread@0 ZwSetSecurityObject@12 ZwSetSystemEnvironmentValue@8 ZwSetSystemInformation@12 diff --git a/reactos/ntoskrnl/Makefile b/reactos/ntoskrnl/Makefile index ca482379398..9dc41bf8ef9 100644 --- a/reactos/ntoskrnl/Makefile +++ b/reactos/ntoskrnl/Makefile @@ -101,8 +101,10 @@ OBJECTS_KE = \ ke/bug.o \ ke/catch.o \ ke/clock.o \ + ke/critical.o \ ke/dpc.o \ ke/device.o \ + ke/error.o \ ke/event.o \ ke/kqueue.o \ ke/kthread.o \ @@ -116,6 +118,7 @@ OBJECTS_KE = \ ke/spinlock.o \ ke/timer.o \ ke/wait.o \ + ke/alert.o # Memory Manager (Mm) OBJECTS_MM = \ @@ -216,8 +219,7 @@ OBJECTS_OB = \ ob/object.o \ ob/sdcache.o \ ob/security.o \ - ob/symlink.o \ - ob/wait.o + ob/symlink.o # Process Manager (Ps) OBJECTS_PS = \ @@ -240,7 +242,6 @@ OBJECTS_PS = \ OBJECTS_EX = \ ex/btree.o \ ex/callback.o \ - ex/error.o \ ex/event.o \ ex/evtpair.o \ ex/fmutex.o \ diff --git a/reactos/ntoskrnl/cm/registry.c b/reactos/ntoskrnl/cm/registry.c index 919c3077164..304192c8e7d 100644 --- a/reactos/ntoskrnl/cm/registry.c +++ b/reactos/ntoskrnl/cm/registry.c @@ -241,29 +241,6 @@ CmiCheckRegistry(BOOLEAN Verbose) CmiCheckByName(Verbose, L"User"); } -VOID -INIT_FUNCTION -STDCALL -CmInitHives(BOOLEAN SetupBoot) -{ - PCHAR BaseAddress; - - /* Load Registry Hives */ - BaseAddress = (PCHAR)CachedModules[SystemRegistry]->ModStart; - CmImportSystemHive(BaseAddress, - CachedModules[SystemRegistry]->ModEnd - (ULONG_PTR)BaseAddress); - - BaseAddress = (PCHAR)CachedModules[HardwareRegistry]->ModStart; - CmImportHardwareHive(BaseAddress, - CachedModules[HardwareRegistry]->ModEnd - (ULONG_PTR)BaseAddress); - - - /* Create dummy keys if no hardware hive was found */ - CmImportHardwareHive (NULL, 0); - - /* Initialize volatile registry settings */ - if (SetupBoot == FALSE) CmInit2((PCHAR)KeLoaderBlock.CommandLine); -} VOID INIT_FUNCTION CmInitializeRegistry(VOID) diff --git a/reactos/ntoskrnl/ex/error.c b/reactos/ntoskrnl/ex/error.c deleted file mode 100644 index d1d99a57751..00000000000 --- a/reactos/ntoskrnl/ex/error.c +++ /dev/null @@ -1,163 +0,0 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS kernel - * FILE: ntoskrnl/ex/error.c - * PURPOSE: Error Functions and Status/Exception Dispatching/Raising - * - * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) - Created File - */ - -/* INCLUDES *****************************************************************/ - -#include -#define NDEBUG -#include - -/* GLOBALS ****************************************************************/ - -BOOLEAN ExReadyForErrors = FALSE; -PEPORT ExpDefaultErrorPort = NULL; -PEPROCESS ExpDefaultErrorPortProcess = NULL; - -/* FUNCTIONS ****************************************************************/ - -/* - * @implemented - */ -VOID -STDCALL -ExRaiseAccessViolation(VOID) -{ - /* Raise the Right Status */ - ExRaiseStatus (STATUS_ACCESS_VIOLATION); -} - -/* - * @implemented - */ -VOID -STDCALL -ExRaiseDatatypeMisalignment (VOID) -{ - /* Raise the Right Status */ - ExRaiseStatus (STATUS_DATATYPE_MISALIGNMENT); -} - -/* - * @implemented - */ -VOID -STDCALL -ExRaiseStatus(IN NTSTATUS Status) -{ - EXCEPTION_RECORD ExceptionRecord; - - DPRINT("ExRaiseStatus(%x)\n", Status); - - /* Set up an Exception Record */ - ExceptionRecord.ExceptionRecord = NULL; - ExceptionRecord.NumberParameters = 0; - ExceptionRecord.ExceptionCode = Status; - ExceptionRecord.ExceptionFlags = 0; - - /* Call the Rtl Function */ - RtlRaiseException(&ExceptionRecord); -} - -/* - * @implemented - */ -VOID -STDCALL -ExRaiseException (PEXCEPTION_RECORD ExceptionRecord) -{ - /* Call the Rtl function */ - RtlRaiseException(ExceptionRecord); -} - -/* - * @implemented - */ -BOOLEAN -STDCALL -ExSystemExceptionFilter(VOID) -{ - return KeGetPreviousMode() != KernelMode ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH; -} - -/* - * @unimplemented - */ -VOID -STDCALL -ExRaiseHardError(IN NTSTATUS ErrorStatus, - IN ULONG NumberOfParameters, - IN PUNICODE_STRING UnicodeStringParameterMask OPTIONAL, - IN PVOID *Parameters, - IN HARDERROR_RESPONSE_OPTION ResponseOption, - OUT PHARDERROR_RESPONSE Response) -{ - UNIMPLEMENTED; -} - -NTSTATUS -STDCALL -NtRaiseHardError(IN NTSTATUS ErrorStatus, - IN ULONG NumberOfParameters, - IN PUNICODE_STRING UnicodeStringParameterMask OPTIONAL, - IN PVOID *Parameters, - IN HARDERROR_RESPONSE_OPTION ResponseOption, - OUT PHARDERROR_RESPONSE Response) -{ - DPRINT1("Hard error %x\n", ErrorStatus); - - /* Call the Executive Function (WE SHOULD PUT SEH HERE/CAPTURE!) */ - ExRaiseHardError(ErrorStatus, - NumberOfParameters, - UnicodeStringParameterMask, - Parameters, - ResponseOption, - Response); - - /* Return Success */ - return STATUS_SUCCESS; -} - -NTSTATUS -STDCALL -NtSetDefaultHardErrorPort(IN HANDLE PortHandle) -{ - - KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); - NTSTATUS Status = STATUS_UNSUCCESSFUL; - - /* Check if we have the Privilege */ - if(!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode)) { - - DPRINT1("NtSetDefaultHardErrorPort: Caller requires the SeTcbPrivilege privilege!\n"); - return STATUS_PRIVILEGE_NOT_HELD; - } - - /* Only called once during bootup, make sure we weren't called yet */ - if(!ExReadyForErrors) { - - Status = ObReferenceObjectByHandle(PortHandle, - 0, - LpcPortObjectType, - PreviousMode, - (PVOID*)&ExpDefaultErrorPort, - NULL); - - /* Check for Success */ - if(NT_SUCCESS(Status)) { - - /* Save the data */ - ExpDefaultErrorPortProcess = PsGetCurrentProcess(); - ExReadyForErrors = TRUE; - } - } - - return Status; -} - -/* EOF */ diff --git a/reactos/ntoskrnl/ex/event.c b/reactos/ntoskrnl/ex/event.c index c05fedb56a6..4db20f50ba5 100644 --- a/reactos/ntoskrnl/ex/event.c +++ b/reactos/ntoskrnl/ex/event.c @@ -19,286 +19,300 @@ POBJECT_TYPE EXPORTED ExEventObjectType = NULL; static GENERIC_MAPPING ExpEventMapping = { - STANDARD_RIGHTS_READ | SYNCHRONIZE | EVENT_QUERY_STATE, - STANDARD_RIGHTS_WRITE | SYNCHRONIZE | EVENT_MODIFY_STATE, - STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE | EVENT_QUERY_STATE, - EVENT_ALL_ACCESS}; - -static const INFORMATION_CLASS_INFO ExEventInfoClass[] = { - - /* EventBasicInformation */ - ICI_SQ_SAME( sizeof(EVENT_BASIC_INFORMATION), sizeof(ULONG), ICIF_QUERY), + STANDARD_RIGHTS_READ | SYNCHRONIZE | EVENT_QUERY_STATE, + STANDARD_RIGHTS_WRITE | SYNCHRONIZE | EVENT_MODIFY_STATE, + STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE | EVENT_QUERY_STATE, + EVENT_ALL_ACCESS}; + +static const INFORMATION_CLASS_INFO ExEventInfoClass[] = +{ + ICI_SQ_SAME( sizeof(EVENT_BASIC_INFORMATION), sizeof(ULONG), ICIF_QUERY ), /* EventBasicInformation */ }; /* FUNCTIONS *****************************************************************/ -VOID -INIT_FUNCTION +NTSTATUS STDCALL +NtpCreateEvent(PVOID ObjectBody, + PVOID Parent, + PWSTR RemainingPath, + POBJECT_ATTRIBUTES ObjectAttributes) +{ + DPRINT("NtpCreateEvent(ObjectBody %x, Parent %x, RemainingPath %S)\n", + ObjectBody, Parent, RemainingPath); + + if (RemainingPath != NULL && wcschr(RemainingPath+1, '\\') != NULL) + { + return(STATUS_UNSUCCESSFUL); + } + + return(STATUS_SUCCESS); +} + + +VOID INIT_FUNCTION ExpInitializeEventImplementation(VOID) { - /* Create the Event Object Type */ - ExEventObjectType = ExAllocatePool(NonPagedPool,sizeof(OBJECT_TYPE)); - RtlpCreateUnicodeString(&ExEventObjectType->TypeName, L"Event", NonPagedPool); - ExEventObjectType->Tag = TAG('E', 'V', 'T', 'T'); - ExEventObjectType->PeakObjects = 0; - ExEventObjectType->PeakHandles = 0; - ExEventObjectType->TotalObjects = 0; - ExEventObjectType->TotalHandles = 0; - ExEventObjectType->PagedPoolCharge = 0; - ExEventObjectType->NonpagedPoolCharge = sizeof(KEVENT); - ExEventObjectType->Mapping = &ExpEventMapping; - ExEventObjectType->Dump = NULL; - ExEventObjectType->Open = NULL; - ExEventObjectType->Close = NULL; - ExEventObjectType->Delete = NULL; - ExEventObjectType->Parse = NULL; - ExEventObjectType->Security = NULL; - ExEventObjectType->QueryName = NULL; - ExEventObjectType->OkayToClose = NULL; - ExEventObjectType->Create = NULL; - ExEventObjectType->DuplicationNotify = NULL; - ObpCreateTypeObject(ExEventObjectType); + ExEventObjectType = ExAllocatePool(NonPagedPool,sizeof(OBJECT_TYPE)); + + RtlpCreateUnicodeString(&ExEventObjectType->TypeName, L"Event", NonPagedPool); + + ExEventObjectType->Tag = TAG('E', 'V', 'T', 'T'); + ExEventObjectType->PeakObjects = 0; + ExEventObjectType->PeakHandles = 0; + ExEventObjectType->TotalObjects = 0; + ExEventObjectType->TotalHandles = 0; + ExEventObjectType->PagedPoolCharge = 0; + ExEventObjectType->NonpagedPoolCharge = sizeof(KEVENT); + ExEventObjectType->Mapping = &ExpEventMapping; + ExEventObjectType->Dump = NULL; + ExEventObjectType->Open = NULL; + ExEventObjectType->Close = NULL; + ExEventObjectType->Delete = NULL; + ExEventObjectType->Parse = NULL; + ExEventObjectType->Security = NULL; + ExEventObjectType->QueryName = NULL; + ExEventObjectType->OkayToClose = NULL; + ExEventObjectType->Create = NtpCreateEvent; + ExEventObjectType->DuplicationNotify = NULL; + + ObpCreateTypeObject(ExEventObjectType); } + /* * @implemented */ -NTSTATUS -STDCALL +NTSTATUS STDCALL NtClearEvent(IN HANDLE EventHandle) { - PKEVENT Event; - NTSTATUS Status; - - PAGED_CODE(); + PKEVENT Event; + NTSTATUS Status; - /* Reference the Object */ - Status = ObReferenceObjectByHandle(EventHandle, - EVENT_MODIFY_STATE, - ExEventObjectType, - ExGetPreviousMode(), - (PVOID*)&Event, - NULL); + PAGED_CODE(); - /* Check for Success */ - if(NT_SUCCESS(Status)) { - - /* Clear the Event and Dereference */ - KeClearEvent(Event); - ObDereferenceObject(Event); - } + Status = ObReferenceObjectByHandle(EventHandle, + EVENT_MODIFY_STATE, + ExEventObjectType, + ExGetPreviousMode(), + (PVOID*)&Event, + NULL); + if(NT_SUCCESS(Status)) + { + KeClearEvent(Event); + ObDereferenceObject(Event); + } - /* Return Status */ - return Status; + return Status; } /* * @implemented */ -NTSTATUS -STDCALL +NTSTATUS STDCALL NtCreateEvent(OUT PHANDLE EventHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, - IN EVENT_TYPE EventType, - IN BOOLEAN InitialState) + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN EVENT_TYPE EventType, + IN BOOLEAN InitialState) { - KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); - PKEVENT Event; - HANDLE hEvent; - NTSTATUS Status = STATUS_SUCCESS; + KPROCESSOR_MODE PreviousMode; + PKEVENT Event; + HANDLE hEvent; + NTSTATUS Status = STATUS_SUCCESS; - PAGED_CODE(); + PAGED_CODE(); - /* Check Output Safety */ - if(PreviousMode == UserMode) { - - _SEH_TRY { - - ProbeForWrite(EventHandle, - sizeof(HANDLE), - sizeof(ULONG)); - } _SEH_HANDLE { - - Status = _SEH_GetExceptionCode(); - - } _SEH_END; + PreviousMode = ExGetPreviousMode(); + + if(PreviousMode == UserMode) + { + _SEH_TRY + { + ProbeForWrite(EventHandle, + sizeof(HANDLE), + sizeof(ULONG)); + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; - if(!NT_SUCCESS(Status)) return Status; - } - - /* Create the Object */ - Status = ObCreateObject(PreviousMode, - ExEventObjectType, - ObjectAttributes, - PreviousMode, - NULL, - sizeof(KEVENT), - 0, - 0, - (PVOID*)&Event); - - /* Check for Success */ - if(NT_SUCCESS(Status)) { - - /* Initalize the Event */ - KeInitializeEvent(Event, - EventType, - InitialState); - - /* Insert it */ - Status = ObInsertObject((PVOID)Event, - NULL, - DesiredAccess, - 0, - NULL, - &hEvent); - ObDereferenceObject(Event); + if(!NT_SUCCESS(Status)) + { + return Status; + } + } - /* Check for success and return handle */ - if(NT_SUCCESS(Status)) { - - _SEH_TRY { - - *EventHandle = hEvent; - - } _SEH_HANDLE { - - Status = _SEH_GetExceptionCode(); - - } _SEH_END; - } - } - - /* Return Status */ - return Status; + Status = ObCreateObject(PreviousMode, + ExEventObjectType, + ObjectAttributes, + PreviousMode, + NULL, + sizeof(KEVENT), + 0, + 0, + (PVOID*)&Event); + if(NT_SUCCESS(Status)) + { + KeInitializeEvent(Event, + EventType, + InitialState); + + + Status = ObInsertObject((PVOID)Event, + NULL, + DesiredAccess, + 0, + NULL, + &hEvent); + ObDereferenceObject(Event); + + if(NT_SUCCESS(Status)) + { + _SEH_TRY + { + *EventHandle = hEvent; + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + } + } + + return Status; } + /* * @implemented */ -NTSTATUS -STDCALL +NTSTATUS STDCALL NtOpenEvent(OUT PHANDLE EventHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes) + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes) { - HANDLE hEvent; - KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); - NTSTATUS Status = STATUS_SUCCESS; + HANDLE hEvent; + KPROCESSOR_MODE PreviousMode; + NTSTATUS Status = STATUS_SUCCESS; - PAGED_CODE(); - DPRINT("NtOpenEvent(0x%x, 0x%x, 0x%x)\n", EventHandle, DesiredAccess, ObjectAttributes); - - /* Check Output Safety */ - if(PreviousMode == UserMode) { - - _SEH_TRY { - - ProbeForWrite(EventHandle, - sizeof(HANDLE), - sizeof(ULONG)); - } _SEH_HANDLE { - - Status = _SEH_GetExceptionCode(); - - } _SEH_END; + PAGED_CODE(); + + DPRINT("NtOpenEvent(0x%x, 0x%x, 0x%x)\n", EventHandle, DesiredAccess, ObjectAttributes); + + PreviousMode = ExGetPreviousMode(); + + if(PreviousMode == UserMode) + { + _SEH_TRY + { + ProbeForWrite(EventHandle, + sizeof(HANDLE), + sizeof(ULONG)); + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; - if(!NT_SUCCESS(Status)) return Status; - } - - /* Open the Object */ - Status = ObOpenObjectByName(ObjectAttributes, - ExEventObjectType, - NULL, - PreviousMode, - DesiredAccess, - NULL, - &hEvent); + if(!NT_SUCCESS(Status)) + { + return Status; + } + } + + Status = ObOpenObjectByName(ObjectAttributes, + ExEventObjectType, + NULL, + PreviousMode, + DesiredAccess, + NULL, + &hEvent); - /* Check for success and return handle */ - if(NT_SUCCESS(Status)) { - - _SEH_TRY { - - *EventHandle = hEvent; - - } _SEH_HANDLE { - - Status = _SEH_GetExceptionCode(); - - } _SEH_END; - } + if(NT_SUCCESS(Status)) + { + _SEH_TRY + { + *EventHandle = hEvent; + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + } - /* Return status */ - return Status; + return Status; } + /* * @implemented */ -NTSTATUS -STDCALL +NTSTATUS STDCALL NtPulseEvent(IN HANDLE EventHandle, - OUT PLONG PreviousState OPTIONAL) + OUT PLONG PreviousState OPTIONAL) { - PKEVENT Event; - KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); - NTSTATUS Status = STATUS_SUCCESS; + PKEVENT Event; + KPROCESSOR_MODE PreviousMode; + NTSTATUS Status = STATUS_SUCCESS; - PAGED_CODE(); - DPRINT("NtPulseEvent(EventHandle 0%x PreviousState 0%x)\n", - EventHandle, PreviousState); - - /* Check buffer validity */ - if(PreviousState && PreviousMode == UserMode) { - - _SEH_TRY { - - ProbeForWrite(PreviousState, - sizeof(LONG), - sizeof(ULONG)); - } _SEH_HANDLE { - - Status = _SEH_GetExceptionCode(); - - } _SEH_END; + PAGED_CODE(); - if(!NT_SUCCESS(Status)) return Status; - } - - /* Open the Object */ - Status = ObReferenceObjectByHandle(EventHandle, - EVENT_MODIFY_STATE, - ExEventObjectType, - PreviousMode, - (PVOID*)&Event, - NULL); - - /* Check for success */ - if(NT_SUCCESS(Status)) { - - /* Pulse the Event */ - LONG Prev = KePulseEvent(Event, EVENT_INCREMENT, FALSE); - ObDereferenceObject(Event); + DPRINT("NtPulseEvent(EventHandle 0%x PreviousState 0%x)\n", + EventHandle, PreviousState); + + PreviousMode = ExGetPreviousMode(); + + if(PreviousState != NULL && PreviousMode == UserMode) + { + _SEH_TRY + { + ProbeForWrite(PreviousState, + sizeof(LONG), + sizeof(ULONG)); + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; - /* Return it */ - if(PreviousState) { - - _SEH_TRY { - - *PreviousState = Prev; - - } _SEH_HANDLE { - - Status = _SEH_GetExceptionCode(); - - } _SEH_END; - } + if(!NT_SUCCESS(Status)) + { + return Status; + } + } + + Status = ObReferenceObjectByHandle(EventHandle, + EVENT_MODIFY_STATE, + ExEventObjectType, + PreviousMode, + (PVOID*)&Event, + NULL); + if(NT_SUCCESS(Status)) + { + LONG Prev = KePulseEvent(Event, EVENT_INCREMENT, FALSE); + ObDereferenceObject(Event); + + if(PreviousState != NULL) + { + _SEH_TRY + { + *PreviousState = Prev; + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + } } - /* Return Status */ return Status; } @@ -306,202 +320,230 @@ NtPulseEvent(IN HANDLE EventHandle, /* * @implemented */ -NTSTATUS -STDCALL +NTSTATUS STDCALL NtQueryEvent(IN HANDLE EventHandle, - IN EVENT_INFORMATION_CLASS EventInformationClass, - OUT PVOID EventInformation, - IN ULONG EventInformationLength, - OUT PULONG ReturnLength OPTIONAL) + IN EVENT_INFORMATION_CLASS EventInformationClass, + OUT PVOID EventInformation, + IN ULONG EventInformationLength, + OUT PULONG ReturnLength OPTIONAL) { - PKEVENT Event; - KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); - NTSTATUS Status = STATUS_SUCCESS; - PEVENT_BASIC_INFORMATION BasicInfo = (PEVENT_BASIC_INFORMATION)EventInformation; - - /* Check buffers and class validity */ - DefaultQueryInfoBufferCheck(EventInformationClass, - ExEventInfoClass, - EventInformation, - EventInformationLength, - ReturnLength, - PreviousMode, - &Status); - if(!NT_SUCCESS(Status)) { - - /* Invalid buffers */ - DPRINT("NtQuerySemaphore() failed, Status: 0x%x\n", Status); - return Status; - } + PKEVENT Event; + KPROCESSOR_MODE PreviousMode; + NTSTATUS Status = STATUS_SUCCESS; - /* Get the Object */ - Status = ObReferenceObjectByHandle(EventHandle, - EVENT_QUERY_STATE, - ExEventObjectType, - PreviousMode, - (PVOID*)&Event, - NULL); - - /* Check for success */ - if(NT_SUCCESS(Status)) { - - _SEH_TRY { - - /* Return Event Type and State */ - BasicInfo->EventType = Event->Header.Type; - BasicInfo->EventState = KeReadStateEvent(Event); - - /* Return length */ - if(ReturnLength) *ReturnLength = sizeof(EVENT_BASIC_INFORMATION); - - } _SEH_HANDLE { - - Status = _SEH_GetExceptionCode(); - - } _SEH_END; - - /* Dereference the Object */ - ObDereferenceObject(Event); + PAGED_CODE(); + + PreviousMode = ExGetPreviousMode(); + + DefaultQueryInfoBufferCheck(EventInformationClass, + ExEventInfoClass, + EventInformation, + EventInformationLength, + ReturnLength, + PreviousMode, + &Status); + if(!NT_SUCCESS(Status)) + { + DPRINT1("NtQueryEvent() failed, Status: 0x%x\n", Status); + return Status; + } + + Status = ObReferenceObjectByHandle(EventHandle, + EVENT_QUERY_STATE, + ExEventObjectType, + PreviousMode, + (PVOID*)&Event, + NULL); + if(NT_SUCCESS(Status)) + { + switch(EventInformationClass) + { + case EventBasicInformation: + { + PEVENT_BASIC_INFORMATION BasicInfo = (PEVENT_BASIC_INFORMATION)EventInformation; + + _SEH_TRY + { + if (Event->Header.Type == InternalNotificationEvent) + BasicInfo->EventType = NotificationEvent; + else + BasicInfo->EventType = SynchronizationEvent; + BasicInfo->EventState = KeReadStateEvent(Event); + + if(ReturnLength != NULL) + { + *ReturnLength = sizeof(EVENT_BASIC_INFORMATION); + } + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + break; + } + + default: + Status = STATUS_NOT_IMPLEMENTED; + break; + } + + ObDereferenceObject(Event); } - /* Return status */ return Status; } + /* * @implemented */ -NTSTATUS -STDCALL +NTSTATUS STDCALL NtResetEvent(IN HANDLE EventHandle, - OUT PLONG PreviousState OPTIONAL) + OUT PLONG PreviousState OPTIONAL) { - PKEVENT Event; - KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); - NTSTATUS Status = STATUS_SUCCESS; + PKEVENT Event; + KPROCESSOR_MODE PreviousMode; + NTSTATUS Status = STATUS_SUCCESS; - PAGED_CODE(); - - DPRINT("NtResetEvent(EventHandle 0%x PreviousState 0%x)\n", - EventHandle, PreviousState); - - /* Check buffer validity */ - if(PreviousState && PreviousMode == UserMode) { - - _SEH_TRY { - - ProbeForWrite(PreviousState, - sizeof(LONG), - sizeof(ULONG)); - } _SEH_HANDLE { - - Status = _SEH_GetExceptionCode(); - - } _SEH_END; - - if(!NT_SUCCESS(Status)) return Status; - } + PAGED_CODE(); + + DPRINT("NtResetEvent(EventHandle 0%x PreviousState 0%x)\n", + EventHandle, PreviousState); + + PreviousMode = ExGetPreviousMode(); + + if(PreviousState != NULL && PreviousMode == UserMode) + { + _SEH_TRY + { + ProbeForWrite(PreviousState, + sizeof(LONG), + sizeof(ULONG)); + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + + if(!NT_SUCCESS(Status)) + { + return Status; + } + } - /* Open the Object */ - Status = ObReferenceObjectByHandle(EventHandle, - EVENT_MODIFY_STATE, - ExEventObjectType, - PreviousMode, - (PVOID*)&Event, - NULL); - - /* Check for success */ - if(NT_SUCCESS(Status)) { - - /* Reset the Event */ - LONG Prev = KeResetEvent(Event); - ObDereferenceObject(Event); + Status = ObReferenceObjectByHandle(EventHandle, + EVENT_MODIFY_STATE, + ExEventObjectType, + PreviousMode, + (PVOID*)&Event, + NULL); + if(NT_SUCCESS(Status)) + { + LONG Prev = KeResetEvent(Event); + ObDereferenceObject(Event); - /* Return it */ - if(PreviousState) { - - _SEH_TRY { - - *PreviousState = Prev; - - } _SEH_HANDLE { - - Status = _SEH_GetExceptionCode(); - - } _SEH_END; - } + if(PreviousState != NULL) + { + _SEH_TRY + { + *PreviousState = Prev; + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + } } - /* Return Status */ return Status; } + /* * @implemented */ -NTSTATUS -STDCALL +NTSTATUS STDCALL NtSetEvent(IN HANDLE EventHandle, - OUT PLONG PreviousState OPTIONAL) + OUT PLONG PreviousState OPTIONAL) { - PKEVENT Event; - KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); - NTSTATUS Status = STATUS_SUCCESS; + PKEVENT Event; + KPROCESSOR_MODE PreviousMode; + NTSTATUS Status = STATUS_SUCCESS; - PAGED_CODE(); - - DPRINT1("NtSetEvent(EventHandle 0%x PreviousState 0%x)\n", - EventHandle, PreviousState); - - /* Check buffer validity */ - if(PreviousState != NULL && PreviousMode == UserMode) { - - _SEH_TRY { - - ProbeForWrite(PreviousState, - sizeof(LONG), - sizeof(ULONG)); - } _SEH_HANDLE { - - Status = _SEH_GetExceptionCode(); - - } _SEH_END; - - if(!NT_SUCCESS(Status)) return Status; - } + PAGED_CODE(); + + DPRINT("NtSetEvent(EventHandle 0%x PreviousState 0%x)\n", + EventHandle, PreviousState); + + PreviousMode = ExGetPreviousMode(); + + if(PreviousState != NULL && PreviousMode == UserMode) + { + _SEH_TRY + { + ProbeForWrite(PreviousState, + sizeof(LONG), + sizeof(ULONG)); + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + + if(!NT_SUCCESS(Status)) + { + return Status; + } + } - /* Open the Object */ - Status = ObReferenceObjectByHandle(EventHandle, - EVENT_MODIFY_STATE, - ExEventObjectType, - PreviousMode, - (PVOID*)&Event, - NULL); - - /* Check for success */ - if(NT_SUCCESS(Status)) { - - /* Set the Event */ - LONG Prev = KeSetEvent(Event, EVENT_INCREMENT, FALSE); - ObDereferenceObject(Event); - - /* Return it */ - if(PreviousState) { - - _SEH_TRY { - - *PreviousState = Prev; - - } _SEH_HANDLE { - - Status = _SEH_GetExceptionCode(); - - } _SEH_END; - } + Status = ObReferenceObjectByHandle(EventHandle, + EVENT_MODIFY_STATE, + ExEventObjectType, + PreviousMode, + (PVOID*)&Event, + NULL); + if(NT_SUCCESS(Status)) + { + LONG Prev = KeSetEvent(Event, EVENT_INCREMENT, FALSE); + ObDereferenceObject(Event); + + if(PreviousState != NULL) + { + _SEH_TRY + { + *PreviousState = Prev; + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + } } - /* Return Status */ return Status; } + +/* + * @unimplemented + */ +NTSTATUS +STDCALL +NtTraceEvent( + IN ULONG TraceHandle, + IN ULONG Flags, + IN ULONG TraceHeaderLength, + IN struct _EVENT_TRACE_HEADER* TraceHeader + ) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + + /* EOF */ diff --git a/reactos/ntoskrnl/ex/evtpair.c b/reactos/ntoskrnl/ex/evtpair.c index 05876a7f731..15b05e6bbc3 100644 --- a/reactos/ntoskrnl/ex/evtpair.c +++ b/reactos/ntoskrnl/ex/evtpair.c @@ -1,11 +1,11 @@ -/* +/* $Id: evtpair.c 12779 2005-01-04 04:45:00Z gdalsnes $ + * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * FILE: ntoskrnl/ex/evtpair.c * PURPOSE: Support for event pairs * - * PROGRAMMERS: Alex Ionescu (Commented, reorganized, removed Thread Pair, used KeInitializeEventPair, added SEH) - * David Welch (welch@mcmail.com) + * PROGRAMMERS: David Welch (welch@mcmail.com) * Skywing (skywing@valhallalegends.com) */ @@ -15,394 +15,588 @@ #define NDEBUG #include +#ifndef NTSYSAPI +#define NTSYSAPI +#endif + +#ifndef NTAPI +#define NTAPI STDCALL +#endif + + /* GLOBALS *******************************************************************/ POBJECT_TYPE EXPORTED ExEventPairObjectType = NULL; static GENERIC_MAPPING ExEventPairMapping = { - STANDARD_RIGHTS_READ, - STANDARD_RIGHTS_WRITE, - STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE, - EVENT_PAIR_ALL_ACCESS}; + STANDARD_RIGHTS_READ, + STANDARD_RIGHTS_WRITE, + STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE, + EVENT_PAIR_ALL_ACCESS}; +static KSPIN_LOCK ExThreadEventPairSpinLock; /* FUNCTIONS *****************************************************************/ -VOID -INIT_FUNCTION +NTSTATUS STDCALL +ExpCreateEventPair(PVOID ObjectBody, + PVOID Parent, + PWSTR RemainingPath, + POBJECT_ATTRIBUTES ObjectAttributes) +{ + DPRINT("ExpCreateEventPair(ObjectBody %x, Parent %x, RemainingPath %S)\n", + ObjectBody, Parent, RemainingPath); + + if (RemainingPath != NULL && wcschr(RemainingPath+1, '\\') != NULL) + { + return(STATUS_UNSUCCESSFUL); + } + + return(STATUS_SUCCESS); +} + +VOID INIT_FUNCTION ExpInitializeEventPairImplementation(VOID) { - /* Create the Event Pair Object Type */ - ExEventPairObjectType = ExAllocatePool(NonPagedPool,sizeof(OBJECT_TYPE)); - RtlpCreateUnicodeString(&ExEventPairObjectType->TypeName, L"EventPair", NonPagedPool); - ExEventPairObjectType->Tag = TAG('E', 'v', 'P', 'a'); - ExEventPairObjectType->PeakObjects = 0; - ExEventPairObjectType->PeakHandles = 0; - ExEventPairObjectType->TotalObjects = 0; - ExEventPairObjectType->TotalHandles = 0; - ExEventPairObjectType->PagedPoolCharge = 0; - ExEventPairObjectType->NonpagedPoolCharge = sizeof(KEVENT_PAIR); - ExEventPairObjectType->Mapping = &ExEventPairMapping; - ExEventPairObjectType->Dump = NULL; - ExEventPairObjectType->Open = NULL; - ExEventPairObjectType->Close = NULL; - ExEventPairObjectType->Delete = NULL; - ExEventPairObjectType->Parse = NULL; - ExEventPairObjectType->Security = NULL; - ExEventPairObjectType->QueryName = NULL; - ExEventPairObjectType->OkayToClose = NULL; - ExEventPairObjectType->Create = NULL; - ExEventPairObjectType->DuplicationNotify = NULL; - ObpCreateTypeObject(ExEventPairObjectType); + ExEventPairObjectType = ExAllocatePool(NonPagedPool,sizeof(OBJECT_TYPE)); + + RtlpCreateUnicodeString(&ExEventPairObjectType->TypeName, L"EventPair", NonPagedPool); + ExEventPairObjectType->Tag = TAG('E', 'v', 'P', 'a'); + ExEventPairObjectType->PeakObjects = 0; + ExEventPairObjectType->PeakHandles = 0; + ExEventPairObjectType->TotalObjects = 0; + ExEventPairObjectType->TotalHandles = 0; + ExEventPairObjectType->PagedPoolCharge = 0; + ExEventPairObjectType->NonpagedPoolCharge = sizeof(KEVENT_PAIR); + ExEventPairObjectType->Mapping = &ExEventPairMapping; + ExEventPairObjectType->Dump = NULL; + ExEventPairObjectType->Open = NULL; + ExEventPairObjectType->Close = NULL; + ExEventPairObjectType->Delete = NULL; + ExEventPairObjectType->Parse = NULL; + ExEventPairObjectType->Security = NULL; + ExEventPairObjectType->QueryName = NULL; + ExEventPairObjectType->OkayToClose = NULL; + ExEventPairObjectType->Create = ExpCreateEventPair; + ExEventPairObjectType->DuplicationNotify = NULL; + + KeInitializeSpinLock(&ExThreadEventPairSpinLock); + ObpCreateTypeObject(ExEventPairObjectType); } -NTSTATUS -STDCALL + +NTSTATUS STDCALL NtCreateEventPair(OUT PHANDLE EventPairHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes) + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes) { - PKEVENT_PAIR EventPair; - HANDLE hEventPair; - KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); - NTSTATUS Status = STATUS_SUCCESS; - - DPRINT1("NtCreateEventPair: %x\n", EventPairHandle); + PKEVENT_PAIR EventPair; + HANDLE hEventPair; + KPROCESSOR_MODE PreviousMode; + NTSTATUS Status = STATUS_SUCCESS; + + PAGED_CODE(); - /* Check Output Safety */ - if(PreviousMode == UserMode) { - - _SEH_TRY { - - ProbeForWrite(EventPairHandle, - sizeof(HANDLE), - sizeof(ULONG)); - } _SEH_HANDLE { - - Status = _SEH_GetExceptionCode(); - - } _SEH_END; + PreviousMode = ExGetPreviousMode(); + + if(PreviousMode == UserMode) + { + _SEH_TRY + { + ProbeForWrite(EventPairHandle, + sizeof(HANDLE), + sizeof(ULONG)); + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; - if(!NT_SUCCESS(Status)) return Status; - } - - /* Create the Object */ - DPRINT1("Creating EventPair\n"); - Status = ObCreateObject(PreviousMode, - ExEventPairObjectType, - ObjectAttributes, - PreviousMode, - NULL, - sizeof(KEVENT_PAIR), - 0, - 0, - (PVOID*)&EventPair); - - /* Check for Success */ - if(NT_SUCCESS(Status)) { - - /* Initalize the Event */ - DPRINT1("Initializing EventPair\n"); - KeInitializeEventPair(EventPair); - - /* Insert it */ - Status = ObInsertObject((PVOID)EventPair, - NULL, - DesiredAccess, - 0, - NULL, - &hEventPair); - ObDereferenceObject(EventPair); - - /* Check for success and return handle */ - if(NT_SUCCESS(Status)) { - - _SEH_TRY { - - *EventPairHandle = hEventPair; - - } _SEH_HANDLE { - - Status = _SEH_GetExceptionCode(); - - } _SEH_END; - } - } - - /* Return Status */ - return Status; + if(!NT_SUCCESS(Status)) + { + return Status; + } + } + + Status = ObCreateObject(PreviousMode, + ExEventPairObjectType, + ObjectAttributes, + PreviousMode, + NULL, + sizeof(KEVENT_PAIR), + 0, + 0, + (PVOID*)&EventPair); + if(NT_SUCCESS(Status)) + { + KeInitializeEvent(&EventPair->LowEvent, + SynchronizationEvent, + FALSE); + KeInitializeEvent(&EventPair->HighEvent, + SynchronizationEvent, + FALSE); + + Status = ObInsertObject ((PVOID)EventPair, + NULL, + DesiredAccess, + 0, + NULL, + &hEventPair); + ObDereferenceObject(EventPair); + + if(NT_SUCCESS(Status)) + { + _SEH_TRY + { + *EventPairHandle = hEventPair; + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + } + } + return Status; } -NTSTATUS -STDCALL +NTSTATUS STDCALL NtOpenEventPair(OUT PHANDLE EventPairHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes) + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes) { - HANDLE hEventPair; - KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); - NTSTATUS Status = STATUS_SUCCESS; + HANDLE hEventPair; + KPROCESSOR_MODE PreviousMode; + NTSTATUS Status = STATUS_SUCCESS; - /* Check Output Safety */ - if(PreviousMode == UserMode) { - - _SEH_TRY { - - ProbeForWrite(EventPairHandle, - sizeof(HANDLE), - sizeof(ULONG)); - } _SEH_HANDLE { - - Status = _SEH_GetExceptionCode(); - - } _SEH_END; + PAGED_CODE(); + + PreviousMode = ExGetPreviousMode(); + + if(PreviousMode == UserMode) + { + _SEH_TRY + { + ProbeForWrite(EventPairHandle, + sizeof(HANDLE), + sizeof(ULONG)); + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; - if(!NT_SUCCESS(Status)) return Status; - } - - /* Open the Object */ - Status = ObOpenObjectByName(ObjectAttributes, - ExEventPairObjectType, - NULL, - PreviousMode, - DesiredAccess, - NULL, - &hEventPair); - - /* Check for success and return handle */ - if(NT_SUCCESS(Status)) { - - _SEH_TRY { - - *EventPairHandle = hEventPair; - - } _SEH_HANDLE { - - Status = _SEH_GetExceptionCode(); - - } _SEH_END; - } + if(!NT_SUCCESS(Status)) + { + return Status; + } + } + + Status = ObOpenObjectByName(ObjectAttributes, + ExEventPairObjectType, + NULL, + PreviousMode, + DesiredAccess, + NULL, + &hEventPair); + if(NT_SUCCESS(Status)) + { + _SEH_TRY + { + *EventPairHandle = hEventPair; + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + } - /* Return status */ - return Status; + return Status; } -NTSTATUS -STDCALL +NTSTATUS STDCALL NtSetHighEventPair(IN HANDLE EventPairHandle) { - PKEVENT_PAIR EventPair; - KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); - NTSTATUS Status; + PKEVENT_PAIR EventPair; + KPROCESSOR_MODE PreviousMode; + NTSTATUS Status; + + PAGED_CODE(); + + DPRINT("NtSetHighEventPair(EventPairHandle %x)\n", + EventPairHandle); - DPRINT1("NtSetHighEventPair(EventPairHandle %x)\n", EventPairHandle); + PreviousMode = ExGetPreviousMode(); - /* Open the Object */ - Status = ObReferenceObjectByHandle(EventPairHandle, - SYNCHRONIZE, - ExEventPairObjectType, - PreviousMode, - (PVOID*)&EventPair, - NULL); - - /* Check for Success */ - if(NT_SUCCESS(Status)) { - - /* Set the Event */ - KeSetEvent(&EventPair->HighEvent, EVENT_INCREMENT, FALSE); - - /* Dereference Object */ - ObDereferenceObject(EventPair); - } + Status = ObReferenceObjectByHandle(EventPairHandle, + SYNCHRONIZE, + ExEventPairObjectType, + PreviousMode, + (PVOID*)&EventPair, + NULL); + if(NT_SUCCESS(Status)) + { + KeSetEvent(&EventPair->HighEvent, + EVENT_INCREMENT, + FALSE); + + ObDereferenceObject(EventPair); + } - /* Return status */ - return Status; + return Status; } -NTSTATUS -STDCALL +NTSTATUS STDCALL NtSetHighWaitLowEventPair(IN HANDLE EventPairHandle) { - PKEVENT_PAIR EventPair; - KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); - NTSTATUS Status; - - DPRINT1("NtSetHighWaitLowEventPair(EventPairHandle %x)\n", EventPairHandle); - - /* Open the Object */ - Status = ObReferenceObjectByHandle(EventPairHandle, - SYNCHRONIZE, - ExEventPairObjectType, - PreviousMode, - (PVOID*)&EventPair, - NULL); - - /* Check for Success */ - if(NT_SUCCESS(Status)) { - - /* Set the Event */ - KeSetEvent(&EventPair->HighEvent, EVENT_INCREMENT, FALSE); - - /* Wait for the Other one */ - KeWaitForSingleObject(&EventPair->LowEvent, - WrEventPair, - PreviousMode, - FALSE, - NULL); - - /* Dereference Object */ - ObDereferenceObject(EventPair); - } + PKEVENT_PAIR EventPair; + KPROCESSOR_MODE PreviousMode; + NTSTATUS Status; - /* Return status */ - return Status; + PAGED_CODE(); + + DPRINT("NtSetHighWaitLowEventPair(EventPairHandle %x)\n", + EventPairHandle); + + PreviousMode = ExGetPreviousMode(); + + Status = ObReferenceObjectByHandle(EventPairHandle, + SYNCHRONIZE, + ExEventPairObjectType, + PreviousMode, + (PVOID*)&EventPair, + NULL); + if(NT_SUCCESS(Status)) + { + KeSetEvent(&EventPair->HighEvent, + EVENT_INCREMENT, + TRUE); + + KeWaitForSingleObject(&EventPair->LowEvent, + WrEventPair, + PreviousMode, + FALSE, + NULL); + + ObDereferenceObject(EventPair); + } + + return Status; } -NTSTATUS -STDCALL + +NTSTATUS STDCALL NtSetLowEventPair(IN HANDLE EventPairHandle) { - PKEVENT_PAIR EventPair; - KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); - NTSTATUS Status; + PKEVENT_PAIR EventPair; + KPROCESSOR_MODE PreviousMode; + NTSTATUS Status; + + PAGED_CODE(); - DPRINT1("NtSetHighEventPair(EventPairHandle %x)\n", EventPairHandle); + DPRINT("NtSetLowEventPair(EventPairHandle %x)\n", + EventPairHandle); + + PreviousMode = ExGetPreviousMode(); - /* Open the Object */ - Status = ObReferenceObjectByHandle(EventPairHandle, - SYNCHRONIZE, - ExEventPairObjectType, - PreviousMode, - (PVOID*)&EventPair, - NULL); - - /* Check for Success */ - if(NT_SUCCESS(Status)) { - - /* Set the Event */ - KeSetEvent(&EventPair->LowEvent, EVENT_INCREMENT, FALSE); - - /* Dereference Object */ - ObDereferenceObject(EventPair); - } - - /* Return status */ - return Status; + Status = ObReferenceObjectByHandle(EventPairHandle, + SYNCHRONIZE, + ExEventPairObjectType, + PreviousMode, + (PVOID*)&EventPair, + NULL); + if(NT_SUCCESS(Status)) + { + KeSetEvent(&EventPair->LowEvent, + EVENT_INCREMENT, + FALSE); + + ObDereferenceObject(EventPair); + } + + return Status; } NTSTATUS STDCALL NtSetLowWaitHighEventPair(IN HANDLE EventPairHandle) { - PKEVENT_PAIR EventPair; - KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); - NTSTATUS Status; - - DPRINT1("NtSetHighWaitLowEventPair(EventPairHandle %x)\n", EventPairHandle); - - /* Open the Object */ - Status = ObReferenceObjectByHandle(EventPairHandle, - SYNCHRONIZE, - ExEventPairObjectType, - PreviousMode, - (PVOID*)&EventPair, - NULL); - - /* Check for Success */ - if(NT_SUCCESS(Status)) { - - /* Set the Event */ - KeSetEvent(&EventPair->LowEvent, EVENT_INCREMENT, FALSE); - - /* Wait for the Other one */ - KeWaitForSingleObject(&EventPair->HighEvent, - WrEventPair, - PreviousMode, - FALSE, - NULL); - - /* Dereference Object */ - ObDereferenceObject(EventPair); - } + PKEVENT_PAIR EventPair; + KPROCESSOR_MODE PreviousMode; + NTSTATUS Status; + + PAGED_CODE(); + + DPRINT("NtSetLowWaitHighEventPair(EventPairHandle %x)\n", + EventPairHandle); + + PreviousMode = ExGetPreviousMode(); - /* Return status */ - return Status; + Status = ObReferenceObjectByHandle(EventPairHandle, + SYNCHRONIZE, + ExEventPairObjectType, + PreviousMode, + (PVOID*)&EventPair, + NULL); + if(NT_SUCCESS(Status)) + { + KeSetEvent(&EventPair->LowEvent, + EVENT_INCREMENT, + TRUE); + + KeWaitForSingleObject(&EventPair->HighEvent, + WrEventPair, + PreviousMode, + FALSE, + NULL); + + ObDereferenceObject(EventPair); + } + + return Status; } -NTSTATUS -STDCALL +NTSTATUS STDCALL NtWaitLowEventPair(IN HANDLE EventPairHandle) { - PKEVENT_PAIR EventPair; - KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); - NTSTATUS Status; - - DPRINT1("NtSetHighWaitLowEventPair(EventPairHandle %x)\n", EventPairHandle); - - /* Open the Object */ - Status = ObReferenceObjectByHandle(EventPairHandle, - SYNCHRONIZE, - ExEventPairObjectType, - PreviousMode, - (PVOID*)&EventPair, - NULL); - - /* Check for Success */ - if(NT_SUCCESS(Status)) { - - /* Wait for the Event */ - KeWaitForSingleObject(&EventPair->LowEvent, - WrEventPair, - PreviousMode, - FALSE, - NULL); - - /* Dereference Object */ - ObDereferenceObject(EventPair); - } + PKEVENT_PAIR EventPair; + KPROCESSOR_MODE PreviousMode; + NTSTATUS Status; + + PAGED_CODE(); + + DPRINT("NtWaitLowEventPair(EventPairHandle %x)\n", + EventPairHandle); + + PreviousMode = ExGetPreviousMode(); - /* Return status */ - return Status; + Status = ObReferenceObjectByHandle(EventPairHandle, + SYNCHRONIZE, + ExEventPairObjectType, + PreviousMode, + (PVOID*)&EventPair, + NULL); + if(NT_SUCCESS(Status)) + { + KeWaitForSingleObject(&EventPair->LowEvent, + WrEventPair, + PreviousMode, + FALSE, + NULL); + + ObDereferenceObject(EventPair); + } + + return Status; } -NTSTATUS -STDCALL + +NTSTATUS STDCALL NtWaitHighEventPair(IN HANDLE EventPairHandle) { - PKEVENT_PAIR EventPair; - KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); - NTSTATUS Status; - - DPRINT1("NtSetHighWaitLowEventPair(EventPairHandle %x)\n", EventPairHandle); - - /* Open the Object */ - Status = ObReferenceObjectByHandle(EventPairHandle, - SYNCHRONIZE, - ExEventPairObjectType, - PreviousMode, - (PVOID*)&EventPair, - NULL); - - /* Check for Success */ - if(NT_SUCCESS(Status)) { - - /* Wait for the Event */ - KeWaitForSingleObject(&EventPair->HighEvent, - WrEventPair, - PreviousMode, - FALSE, - NULL); - - /* Dereference Object */ - ObDereferenceObject(EventPair); - } + PKEVENT_PAIR EventPair; + KPROCESSOR_MODE PreviousMode; + NTSTATUS Status; + + PAGED_CODE(); + + DPRINT("NtWaitHighEventPair(EventPairHandle %x)\n", + EventPairHandle); + + PreviousMode = ExGetPreviousMode(); - /* Return status */ - return Status; + Status = ObReferenceObjectByHandle(EventPairHandle, + SYNCHRONIZE, + ExEventPairObjectType, + PreviousMode, + (PVOID*)&EventPair, + NULL); + if(NT_SUCCESS(Status)) + { + KeWaitForSingleObject(&EventPair->HighEvent, + WrEventPair, + PreviousMode, + FALSE, + NULL); + + ObDereferenceObject(EventPair); + } + + return Status; +} + +#ifdef _ENABLE_THRDEVTPAIR + +/* + * Author: Skywing (skywing@valhallalegends.com), 09/08/2003 + * Note that the eventpair spinlock must be acquired when setting the thread + * eventpair via NtSetInformationThread. + * @implemented + */ +NTSTATUS +NTSYSAPI +NTAPI +NtSetLowWaitHighThread( + VOID + ) +{ + PETHREAD Thread; + PKEVENT_PAIR EventPair; + NTSTATUS Status; + KIRQL Irql; + + PAGED_CODE(); + + PreviousMode = ExGetPreviousMode(); + + if(!Thread->EventPair) + return STATUS_NO_EVENT_PAIR; + + KeAcquireSpinLock(&ExThreadEventPairSpinLock, &Irql); + + EventPair = Thread->EventPair; + + if(EventPair) + ObReferenceObjectByPointer(EventPair, + EVENT_PAIR_ALL_ACCESS, + ExEventPairObjectType, + UserMode); + + KeReleaseSpinLock(&ExThreadEventPairSpinLock, Irql); + + if(EventPair == NULL) + return STATUS_NO_EVENT_PAIR; + + KeSetEvent(&EventPair->LowEvent, + EVENT_INCREMENT, + TRUE); + + Status = KeWaitForSingleObject(&EventPair->HighEvent, + WrEventPair, + UserMode, + FALSE, + NULL); + + ObDereferenceObject(EventPair); + + return Status; } + +/* + * Author: Skywing (skywing@valhallalegends.com), 09/08/2003 + * Note that the eventpair spinlock must be acquired when setting the thread + * eventpair via NtSetInformationThread. + * @implemented + */ +NTSTATUS +NTSYSAPI +NTAPI +NtSetHighWaitLowThread( + VOID + ) +{ + PETHREAD Thread; + PKEVENT_PAIR EventPair; + NTSTATUS Status; + KIRQL Irql; + + PAGED_CODE(); + + Thread = PsGetCurrentThread(); + + if(!Thread->EventPair) + return STATUS_NO_EVENT_PAIR; + + KeAcquireSpinLock(&ExThreadEventPairSpinLock, &Irql); + + EventPair = PsGetCurrentThread()->EventPair; + + if(EventPair) + ObReferenceObjectByPointer(EventPair, + EVENT_PAIR_ALL_ACCESS, + ExEventPairObjectType, + UserMode); + + KeReleaseSpinLock(&ExThreadEventPairSpinLock, Irql); + + if(EventPair == NULL) + return STATUS_NO_EVENT_PAIR; + + KeSetEvent(&EventPair->HighEvent, + EVENT_INCREMENT, + TRUE); + + Status = KeWaitForSingleObject(&EventPair->LowEvent, + WrEventPair, + UserMode, + FALSE, + NULL); + + ObDereferenceObject(EventPair); + + return Status; +} + +/* + * Author: Skywing (skywing@valhallalegends.com), 09/08/2003 + * Note that the eventpair spinlock must be acquired when waiting on the + * eventpair via NtSetLow/HighWaitHigh/LowThread. Additionally, when + * deleting a thread object, NtpSwapThreadEventPair(Thread, NULL) should + * be called to release any preexisting eventpair object associated with + * the thread. The Microsoft name for this function is not known. + */ +VOID +ExpSwapThreadEventPair( + IN PETHREAD Thread, + IN PKEVENT_PAIR EventPair + ) +{ + PKEVENT_PAIR OriginalEventPair; + KIRQL Irql; + + KeAcquireSpinLock(&ExThreadEventPairSpinLock, &Irql); + + OriginalEventPair = Thread->EventPair; + Thread->EventPair = EventPair; + + if(OriginalEventPair) + ObDereferenceObject(OriginalEventPair); + + KeReleaseSpinLock(&ExThreadEventPairSpinLock, Irql); +} + +#else /* !_ENABLE_THRDEVTPAIR */ + +NTSTATUS +NTSYSAPI +NTAPI +NtSetLowWaitHighThread( + VOID + ) +{ + DPRINT1("NtSetLowWaitHighThread() not supported anymore (NT4 only)!\n"); + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTSYSAPI +NTAPI +NtSetHighWaitLowThread( + VOID + ) +{ + DPRINT1("NtSetHighWaitLowThread() not supported anymore (NT4 only)!\n"); + return STATUS_NOT_IMPLEMENTED; +} + +#endif /* _ENABLE_THRDEVTPAIR */ + /* EOF */ diff --git a/reactos/ntoskrnl/ex/init.c b/reactos/ntoskrnl/ex/init.c index 878be047b4f..03951a885d7 100644 --- a/reactos/ntoskrnl/ex/init.c +++ b/reactos/ntoskrnl/ex/init.c @@ -1,630 +1,21 @@ -/* +/* $Id$ + * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * FILE: ntoskrnl/ex/init.c * PURPOSE: Executive initalization * - * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) - Added ExpInitializeExecutive - * and optimized/cleaned it. - * Eric Kohl (ekohl@abo.rhein-zeitung.de) + * PROGRAMMERS: Eric Kohl (ekohl@abo.rhein-zeitung.de) */ #include -#include #define NDEBUG #include /* DATA **********************************************************************/ -extern ULONG MmCoreDumpType; -extern CHAR KiTimerSystemAuditing; -extern PVOID Ki386InitialStackArray[MAXIMUM_PROCESSORS]; -extern ADDRESS_RANGE KeMemoryMap[64]; -extern ULONG KeMemoryMapRangeCount; -extern ULONG_PTR FirstKrnlPhysAddr; -extern ULONG_PTR LastKrnlPhysAddr; -extern ULONG_PTR LastKernelAddress; -extern LOADER_MODULE KeLoaderModules[64]; - /* FUNCTIONS ****************************************************************/ -static -VOID -INIT_FUNCTION -InitSystemSharedUserPage (PCSZ ParameterLine) -{ - UNICODE_STRING ArcDeviceName; - UNICODE_STRING ArcName; - UNICODE_STRING BootPath; - UNICODE_STRING DriveDeviceName; - UNICODE_STRING DriveName; - WCHAR DriveNameBuffer[20]; - PCHAR ParamBuffer; - PWCHAR ArcNameBuffer; - PCHAR p; - NTSTATUS Status; - ULONG Length; - OBJECT_ATTRIBUTES ObjectAttributes; - HANDLE Handle; - ULONG i; - BOOLEAN BootDriveFound = FALSE; - - /* - * NOTE: - * The shared user page has been zeroed-out right after creation. - * There is NO need to do this again. - */ - Ki386SetProcessorFeatures(); - - /* Set the Version Data */ - SharedUserData->NtProductType = NtProductWinNt; - SharedUserData->ProductTypeIsValid = TRUE; - SharedUserData->NtMajorVersion = 5; - SharedUserData->NtMinorVersion = 0; - - /* - * Retrieve the current dos system path - * (e.g.: C:\reactos) from the given arc path - * (e.g.: multi(0)disk(0)rdisk(0)partititon(1)\reactos) - * Format: "\ [options...]" - */ - - /* Create local parameter line copy */ - ParamBuffer = ExAllocatePool(PagedPool, 256); - strcpy (ParamBuffer, (char *)ParameterLine); - DPRINT("%s\n", ParamBuffer); - - /* Cut options off */ - p = strchr (ParamBuffer, ' '); - if (p) *p = 0; - DPRINT("%s\n", ParamBuffer); - - /* Extract path */ - p = strchr (ParamBuffer, '\\'); - if (p) { - - DPRINT("Boot path: %s\n", p); - RtlCreateUnicodeStringFromAsciiz (&BootPath, p); - *p = 0; - - } else { - - DPRINT("Boot path: %s\n", "\\"); - RtlCreateUnicodeStringFromAsciiz (&BootPath, "\\"); - } - DPRINT("Arc name: %s\n", ParamBuffer); - - /* Only ARC Name left - Build full ARC Name */ - ArcNameBuffer = ExAllocatePool (PagedPool, 256 * sizeof(WCHAR)); - swprintf (ArcNameBuffer, L"\\ArcName\\%S", ParamBuffer); - RtlInitUnicodeString (&ArcName, ArcNameBuffer); - DPRINT("Arc name: %wZ\n", &ArcName); - - /* Free ParamBuffer */ - ExFreePool (ParamBuffer); - - /* Allocate ARC Device Name string */ - ArcDeviceName.Length = 0; - ArcDeviceName.MaximumLength = 256 * sizeof(WCHAR); - ArcDeviceName.Buffer = ExAllocatePool (PagedPool, 256 * sizeof(WCHAR)); - - /* Open the Symbolic Link */ - InitializeObjectAttributes(&ObjectAttributes, - &ArcName, - OBJ_OPENLINK, - NULL, - NULL); - Status = NtOpenSymbolicLinkObject(&Handle, - SYMBOLIC_LINK_ALL_ACCESS, - &ObjectAttributes); - - /* Free the String */ - RtlFreeUnicodeString (&ArcName); - - /* Check for Success */ - if (!NT_SUCCESS(Status)) { - - /* Free the Strings */ - RtlFreeUnicodeString(&BootPath); - RtlFreeUnicodeString(&ArcDeviceName); - CPRINT("NtOpenSymbolicLinkObject() failed (Status %x)\n", Status); - KEBUGCHECK(0); - } - - /* Query the Link */ - Status = NtQuerySymbolicLinkObject(Handle, - &ArcDeviceName, - &Length); - NtClose (Handle); - - /* Check for Success */ - if (!NT_SUCCESS(Status)) { - - /* Free the Strings */ - RtlFreeUnicodeString(&BootPath); - RtlFreeUnicodeString(&ArcDeviceName); - CPRINT("NtQuerySymbolicLinkObject() failed (Status %x)\n", Status); - KEBUGCHECK(0); - } - DPRINT("Length: %lu ArcDeviceName: %wZ\n", Length, &ArcDeviceName); - - /* Allocate Device Name string */ - DriveDeviceName.Length = 0; - DriveDeviceName.MaximumLength = 256 * sizeof(WCHAR); - DriveDeviceName.Buffer = ExAllocatePool (PagedPool, 256 * sizeof(WCHAR)); - - /* Loop Drives */ - for (i = 0; i < 26; i++) { - - /* Setup the String */ - swprintf (DriveNameBuffer, L"\\??\\%C:", 'A' + i); - RtlInitUnicodeString(&DriveName, - DriveNameBuffer); - - /* Open the Symbolic Link */ - InitializeObjectAttributes(&ObjectAttributes, - &DriveName, - OBJ_OPENLINK, - NULL, - NULL); - Status = NtOpenSymbolicLinkObject(&Handle, - SYMBOLIC_LINK_ALL_ACCESS, - &ObjectAttributes); - - /* If it failed, skip to the next drive */ - if (!NT_SUCCESS(Status)) { - DPRINT("Failed to open link %wZ\n", &DriveName); - continue; - } - - /* Query it */ - Status = NtQuerySymbolicLinkObject(Handle, - &DriveDeviceName, - &Length); - - /* If it failed, skip to the next drive */ - if (!NT_SUCCESS(Status)) { - DPRINT("Failed to query link %wZ\n", &DriveName); - continue; - } - DPRINT("Opened link: %wZ ==> %wZ\n", &DriveName, &DriveDeviceName); - - /* See if we've found the boot drive */ - if (!RtlCompareUnicodeString (&ArcDeviceName, &DriveDeviceName, FALSE)) { - - DPRINT("DOS Boot path: %c:%wZ\n", 'A' + i, &BootPath); - swprintf(SharedUserData->NtSystemRoot, L"%C:%wZ", 'A' + i, &BootPath); - BootDriveFound = TRUE; - } - - /* Close this Link */ - NtClose (Handle); - } - - /* Free all the Strings we have in memory */ - RtlFreeUnicodeString (&BootPath); - RtlFreeUnicodeString (&DriveDeviceName); - RtlFreeUnicodeString (&ArcDeviceName); - - /* Make sure we found the Boot Drive */ - if (BootDriveFound == FALSE) { - - DbgPrint("No system drive found!\n"); - KEBUGCHECK (NO_BOOT_DEVICE); - } -} - -inline -VOID -STDCALL -ExecuteRuntimeAsserts(VOID) -{ - /* - * Fail at runtime if someone has changed various structures without - * updating the offsets used for the assembler code. - */ - ASSERT(FIELD_OFFSET(KTHREAD, InitialStack) == KTHREAD_INITIAL_STACK); - ASSERT(FIELD_OFFSET(KTHREAD, Teb) == KTHREAD_TEB); - ASSERT(FIELD_OFFSET(KTHREAD, KernelStack) == KTHREAD_KERNEL_STACK); - ASSERT(FIELD_OFFSET(KTHREAD, NpxState) == KTHREAD_NPX_STATE); - ASSERT(FIELD_OFFSET(KTHREAD, ServiceTable) == KTHREAD_SERVICE_TABLE); - ASSERT(FIELD_OFFSET(KTHREAD, PreviousMode) == KTHREAD_PREVIOUS_MODE); - ASSERT(FIELD_OFFSET(KTHREAD, TrapFrame) == KTHREAD_TRAP_FRAME); - ASSERT(FIELD_OFFSET(KTHREAD, CallbackStack) == KTHREAD_CALLBACK_STACK); - ASSERT(FIELD_OFFSET(KTHREAD, ApcState.Process) == KTHREAD_APCSTATE_PROCESS); - ASSERT(FIELD_OFFSET(KPROCESS, DirectoryTableBase) == KPROCESS_DIRECTORY_TABLE_BASE); - ASSERT(FIELD_OFFSET(KPROCESS, IopmOffset) == KPROCESS_IOPM_OFFSET); - ASSERT(FIELD_OFFSET(KPROCESS, LdtDescriptor) == KPROCESS_LDT_DESCRIPTOR0); - ASSERT(FIELD_OFFSET(KTRAP_FRAME, Reserved9) == KTRAP_FRAME_RESERVED9); - ASSERT(FIELD_OFFSET(KV86M_TRAP_FRAME, SavedExceptionStack) == TF_SAVED_EXCEPTION_STACK); - ASSERT(FIELD_OFFSET(KV86M_TRAP_FRAME, regs) == TF_REGS); - ASSERT(FIELD_OFFSET(KV86M_TRAP_FRAME, orig_ebp) == TF_ORIG_EBP); - ASSERT(FIELD_OFFSET(KPCR, Tib.ExceptionList) == KPCR_EXCEPTION_LIST); - ASSERT(FIELD_OFFSET(KPCR, Self) == KPCR_SELF); - ASSERT(FIELD_OFFSET(KPCR, PrcbData) + FIELD_OFFSET(KPRCB, CurrentThread) == KPCR_CURRENT_THREAD); - ASSERT(FIELD_OFFSET(KPCR, PrcbData) + FIELD_OFFSET(KPRCB, NpxThread) == KPCR_NPX_THREAD); - ASSERT(FIELD_OFFSET(KTSS, Esp0) == KTSS_ESP0); - ASSERT(FIELD_OFFSET(KTSS, Eflags) == KTSS_EFLAGS); - ASSERT(FIELD_OFFSET(KTSS, IoMapBase) == KTSS_IOMAPBASE); - ASSERT(sizeof(FX_SAVE_AREA) == SIZEOF_FX_SAVE_AREA); -} - -inline -VOID -STDCALL -ParseAndCacheLoadedModules(PBOOLEAN SetupBoot) -{ - ULONG i; - PCHAR Name; - - /* Loop the Module List and get the modules we want */ - for (i = 1; i < KeLoaderBlock.ModsCount; i++) { - - /* Get the Name of this Module */ - if (!(Name = strrchr((PCHAR)KeLoaderModules[i].String, '\\'))) { - - /* Save the name */ - Name = (PCHAR)KeLoaderModules[i].String; - - } else { - - /* No name, skip */ - Name++; - } - - /* Now check for any of the modules we will need later */ - if (!_stricmp(Name, "ansi.nls")) { - - CachedModules[AnsiCodepage] = &KeLoaderModules[i]; - - } else if (!_stricmp(Name, "oem.nls")) { - - CachedModules[OemCodepage] = &KeLoaderModules[i]; - - } else if (!_stricmp(Name, "casemap.nls")) { - - CachedModules[UnicodeCasemap] = &KeLoaderModules[i]; - - } else if (!_stricmp(Name, "system") || !_stricmp(Name, "system.hiv")) { - - CachedModules[SystemRegistry] = &KeLoaderModules[i]; - *SetupBoot = FALSE; - - } else if (!_stricmp(Name, "hardware") || !_stricmp(Name, "hardware.hiv")) { - - CachedModules[HardwareRegistry] = &KeLoaderModules[i]; - } - } -} - -inline -VOID -STDCALL -ParseCommandLine(PULONG MaxMem, PBOOLEAN NoGuiBoot, PBOOLEAN BootLog) -{ - PCHAR p1, p2; - - p1 = (PCHAR)KeLoaderBlock.CommandLine; - while(*p1 && (p2 = strchr(p1, '/'))) { - - p2++; - if (!_strnicmp(p2, "MAXMEM", 6)) { - - p2 += 6; - while (isspace(*p2)) p2++; - - if (*p2 == '=') { - - p2++; - - while(isspace(*p2)) p2++; - - if (isdigit(*p2)) { - while (isdigit(*p2)) { - *MaxMem = *MaxMem * 10 + *p2 - '0'; - p2++; - } - break; - } - } - } else if (!_strnicmp(p2, "NOGUIBOOT", 9)) { - - p2 += 9; - *NoGuiBoot = TRUE; - - } else if (!_strnicmp(p2, "CRASHDUMP", 9)) { - - p2 += 9; - if (*p2 == ':') { - - p2++; - if (!_strnicmp(p2, "FULL", 4)) { - - MmCoreDumpType = MM_CORE_DUMP_TYPE_FULL; - - } else { - - MmCoreDumpType = MM_CORE_DUMP_TYPE_NONE; - } - } - } else if (!_strnicmp(p2, "BOOTLOG", 7)) { - - p2 += 7; - *BootLog = TRUE; - } - - p1 = p2; - } -} - -VOID -INIT_FUNCTION -STDCALL -ExpInitializeExecutive(VOID) -{ - CHAR str[50]; - UNICODE_STRING EventName; - HANDLE InitDoneEventHandle; - OBJECT_ATTRIBUTES ObjectAttributes; - BOOLEAN NoGuiBoot = FALSE; - BOOLEAN BootLog = FALSE; - ULONG MaxMem = 0; - BOOLEAN SetupBoot = TRUE; - LARGE_INTEGER Timeout; - HANDLE ProcessHandle; - HANDLE ThreadHandle; - NTSTATUS Status; - - /* Check if the structures match the ASM offset constants */ - ExecuteRuntimeAsserts(); - - /* Sets up the Text Sections of the Kernel and HAL for debugging */ - LdrInit1(); - - /* Lower the IRQL to Dispatch Level */ - KeLowerIrql(DISPATCH_LEVEL); - - /* Sets up the VDM Data */ - NtEarlyInitVdm(); - - /* Parse Command Line Settings */ - ParseCommandLine(&MaxMem, &NoGuiBoot, &BootLog); - - /* Initialize Kernel Memory Address Space */ - MmInit1(FirstKrnlPhysAddr, - LastKrnlPhysAddr, - LastKernelAddress, - (PADDRESS_RANGE)&KeMemoryMap, - KeMemoryMapRangeCount, - MaxMem > 8 ? MaxMem : 4096); - - /* Parse the Loaded Modules (by FreeLoader) and cache the ones we'll need */ - ParseAndCacheLoadedModules(&SetupBoot); - - /* Initialize the kernel debugger */ - KdInitSystem (1, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock); - - /* Initialize the Dispatcher, Clock and Bug Check Mechanisms. */ - KeInit2(); - - /* Bring back the IRQL to Passive */ - KeLowerIrql(PASSIVE_LEVEL); - - /* Load basic Security for other Managers */ - if (!SeInit1()) KEBUGCHECK(SECURITY_INITIALIZATION_FAILED); - - /* Create the Basic Object Manager Types to allow new Object Types */ - ObInit(); - - /* Initialize Lookaside Lists */ - ExInit2(); - - /* Set up Region Maps, Sections and the Paging File */ - MmInit2(); - - /* Initialize Tokens now that the Object Manager is ready */ - if (!SeInit2()) KEBUGCHECK(SECURITY1_INITIALIZATION_FAILED); - - /* Set 1 CPU for now, we'll increment this later */ - KeNumberProcessors = 1; - - /* Initalize the Process Manager */ - PiInitProcessManager(); - - /* Break into the Debugger if requested */ - if (KdPollBreakIn()) DbgBreakPointWithStatus (DBG_STATUS_CONTROL_C); - - /* Initialize all processors */ - while (!HalAllProcessorsStarted()) { - - PVOID ProcessorStack; - - /* Set up the Kernel and Process Manager for this CPU */ - KePrepareForApplicationProcessorInit(KeNumberProcessors); - PsPrepareForApplicationProcessorInit(KeNumberProcessors); - - /* Allocate a stack for use when booting the processor */ - ProcessorStack = Ki386InitialStackArray[((int)KeNumberProcessors)] + MM_STACK_SIZE; - - /* Tell HAL a new CPU is being started */ - HalStartNextProcessor(0, (ULONG)ProcessorStack - 2*sizeof(FX_SAVE_AREA)); - KeNumberProcessors++; - } - - /* Do Phase 1 HAL Initalization */ - HalInitSystem(1, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock); - - /* Initialize Basic System Objects and Worker Threads */ - ExInit3(); - - /* Initialize the GDB Stub and break */ - KdInit1(); - - /* Initialize I/O Objects, Filesystems, Error Logging and Shutdown */ - IoInit(); - - /* TBD */ - PoInit(); - - /* Initialize the Registry (Hives are NOT yet loaded!) */ - CmInitializeRegistry(); - - /* Unmap Low memory, initialize the Page Zeroing and the Balancer Thread */ - MmInit3(); - - /* Initialize Cache Views */ - CcInit(); - - /* Hook System Interrupt for the Debugger */ - KdInit2(); - - /* Initialize File Locking */ - FsRtlpInitFileLockingImplementation(); - - /* Report all resources used by hal */ - HalReportResourceUsage(); - - /* Clear the screen to blue */ - HalInitSystem(2, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock); - - /* Display version number and copyright/warranty message */ - HalDisplayString("Starting ReactOS "KERNEL_VERSION_STR" (Build " - KERNEL_VERSION_BUILD_STR")\n"); - HalDisplayString(RES_STR_LEGAL_COPYRIGHT); - HalDisplayString("\n\nReactOS is free software, covered by the GNU General " - "Public License, and you\n"); - HalDisplayString("are welcome to change it and/or distribute copies of it " - "under certain\n"); - HalDisplayString("conditions. There is absolutely no warranty for " - "ReactOS.\n\n"); - - /* Display number of Processors */ - sprintf(str, - "Found %d system processor(s). [%lu MB Memory]\n", - KeNumberProcessors, - (KeLoaderBlock.MemHigher + 1088)/ 1024); - HalDisplayString(str); - - /* Print which Debugger is being used */ - KdInit3(); - - /* Import and create NLS Data and Sections */ - RtlpInitNls(); - - /* Import and Load Registry Hives */ - CmInitHives(SetupBoot); - - /* Initialize the time zone information from the registry */ - ExpInitTimeZoneInfo(); - - /* Enter the kernel debugger before starting up the boot drivers */ -#ifdef KDBG - KdbEnter(); -#endif /* KDBG */ - - /* Setup Drivers and Root Device Node */ - IoInit2(BootLog); - - /* Display the boot screen image if not disabled */ - if (!NoGuiBoot) InbvEnableBootDriver(TRUE); - - /* Create ARC Names, SystemRoot SymLink, Load Drivers and Assign Letters */ - IoInit3(); - - /* Initialize the Default Locale */ - PiInitDefaultLocale(); - - /* Initialize shared user page. Set dos system path, dos device map, etc. */ - InitSystemSharedUserPage ((PCHAR)KeLoaderBlock.CommandLine); - - /* Create 'ReactOSInitDone' event */ - RtlInitUnicodeString(&EventName, L"\\ReactOSInitDone"); - InitializeObjectAttributes(&ObjectAttributes, - &EventName, - 0, - NULL, - NULL); - Status = ZwCreateEvent(&InitDoneEventHandle, - EVENT_ALL_ACCESS, - &ObjectAttributes, - SynchronizationEvent, - FALSE); - - /* Check for Success */ - if (!NT_SUCCESS(Status)) { - - DPRINT1("Failed to create 'ReactOSInitDone' event (Status 0x%x)\n", Status); - InitDoneEventHandle = INVALID_HANDLE_VALUE; - } - - /* Launch initial process */ - Status = LdrLoadInitialProcess(&ProcessHandle, - &ThreadHandle); - - /* Check for success, Bugcheck if we failed */ - if (!NT_SUCCESS(Status)) { - - KEBUGCHECKEX(SESSION4_INITIALIZATION_FAILED, Status, 0, 0, 0); - } - - /* Wait on the Completion Event */ - if (InitDoneEventHandle != INVALID_HANDLE_VALUE) { - - HANDLE Handles[2]; /* Init event, Initial process */ - - /* Setup the Handles to wait on */ - Handles[0] = InitDoneEventHandle; - Handles[1] = ProcessHandle; - - /* Wait for the system to be initialized */ - Timeout.QuadPart = (LONGLONG)-1200000000; /* 120 second timeout */ - Status = ZwWaitForMultipleObjects(2, - Handles, - WaitAny, - FALSE, - &Timeout); - if (!NT_SUCCESS(Status)) { - - DPRINT1("NtWaitForMultipleObjects failed with status 0x%x!\n", Status); - - } else if (Status == STATUS_TIMEOUT) { - - DPRINT1("WARNING: System not initialized after 120 seconds.\n"); - - } else if (Status == STATUS_WAIT_0 + 1) { - - /* Crash the system if the initial process was terminated. */ - KEBUGCHECKEX(SESSION5_INITIALIZATION_FAILED, Status, 0, 0, 0); - } - - /* Disable the Boot Logo */ - if (!NoGuiBoot) InbvEnableBootDriver(FALSE); - - /* Signal the Event and close the handle */ - ZwSetEvent(InitDoneEventHandle, NULL); - ZwClose(InitDoneEventHandle); - - } else { - - /* On failure to create 'ReactOSInitDone' event, go to text mode ASAP */ - if (!NoGuiBoot) InbvEnableBootDriver(FALSE); - - /* Crash the system if the initial process terminates within 5 seconds. */ - Timeout.QuadPart = (LONGLONG)-50000000; /* 5 second timeout */ - Status = ZwWaitForSingleObject(ProcessHandle, - FALSE, - &Timeout); - - /* Check for timeout, crash if the initial process didn't initalize */ - if (Status != STATUS_TIMEOUT) KEBUGCHECKEX(SESSION5_INITIALIZATION_FAILED, Status, 1, 0, 0); - } - - /* Enable the Clock, close remaining handles */ - KiTimerSystemAuditing = 1; - ZwClose(ThreadHandle); - ZwClose(ProcessHandle); -} - VOID INIT_FUNCTION ExInit2(VOID) { @@ -634,7 +25,7 @@ ExInit2(VOID) VOID INIT_FUNCTION ExInit3 (VOID) { - ExpInitializeWorkerThreads(); + ExInitializeWorkerThreads(); ExpInitializeEventImplementation(); ExpInitializeEventPairImplementation(); ExpInitializeMutantImplementation(); @@ -644,7 +35,28 @@ ExInit3 (VOID) ExpInitializeProfileImplementation(); ExpWin32kInit(); ExpInitUuids(); - ExpInitializeCallbacks(); +} + + +/* + * @implemented + */ +BOOLEAN STDCALL +ExIsProcessorFeaturePresent(IN ULONG ProcessorFeature) +{ + if (ProcessorFeature >= PROCESSOR_FEATURE_MAX) + return(FALSE); + + return(SharedUserData->ProcessorFeatures[ProcessorFeature]); +} + + +VOID STDCALL +ExPostSystemEvent (ULONG Unknown1, + ULONG Unknown2, + ULONG Unknown3) +{ + /* doesn't do anything */ } /* EOF */ diff --git a/reactos/ntoskrnl/ex/mutant.c b/reactos/ntoskrnl/ex/mutant.c index 8c125e236b2..f6a2d4b36c7 100644 --- a/reactos/ntoskrnl/ex/mutant.c +++ b/reactos/ntoskrnl/ex/mutant.c @@ -1,13 +1,11 @@ -/* +/* $Id:$ + * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * FILE: ntoskrnl/ex/mutant.c - * PURPOSE: Executive Management of Mutants + * PURPOSE: Synchronization primitives * - * PROGRAMMERS: - * Alex Ionescu - Fix tab/space mismatching, tiny fixes to query function and - * add more debug output. - * David Welch (welch@cwcom.net) + * PROGRAMMERS: David Welch (welch@cwcom.net) */ /* INCLUDES *****************************************************************/ @@ -19,342 +17,360 @@ POBJECT_TYPE ExMutantObjectType = NULL; static GENERIC_MAPPING ExpMutantMapping = { - STANDARD_RIGHTS_READ | SYNCHRONIZE | MUTANT_QUERY_STATE, - STANDARD_RIGHTS_WRITE | SYNCHRONIZE, - STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE | MUTANT_QUERY_STATE, - MUTANT_ALL_ACCESS}; + STANDARD_RIGHTS_READ | SYNCHRONIZE | MUTANT_QUERY_STATE, + STANDARD_RIGHTS_WRITE | SYNCHRONIZE, + STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE | MUTANT_QUERY_STATE, + MUTANT_ALL_ACCESS}; -static const INFORMATION_CLASS_INFO ExMutantInfoClass[] = { - - /* MutantBasicInformation */ - ICI_SQ_SAME( sizeof(MUTANT_BASIC_INFORMATION), sizeof(ULONG), ICIF_QUERY ), +static const INFORMATION_CLASS_INFO ExMutantInfoClass[] = +{ + ICI_SQ_SAME( sizeof(MUTANT_BASIC_INFORMATION), sizeof(ULONG), ICIF_QUERY ), /* MutantBasicInformation */ }; /* FUNCTIONS *****************************************************************/ -VOID -STDCALL -ExpDeleteMutant(PVOID ObjectBody) + +NTSTATUS STDCALL +ExpCreateMutant(PVOID ObjectBody, + PVOID Parent, + PWSTR RemainingPath, + POBJECT_ATTRIBUTES ObjectAttributes) { + DPRINT("NtpCreateMutant(ObjectBody %x, Parent %x, RemainingPath %S)\n", + ObjectBody, Parent, RemainingPath); - DPRINT("ExpDeleteMutant(ObjectBody %x)\n", ObjectBody); + if (RemainingPath != NULL && wcschr(RemainingPath+1, '\\') != NULL) + { + return(STATUS_UNSUCCESSFUL); + } - /* Make sure to release the Mutant */ - KeReleaseMutant((PKMUTANT)ObjectBody, - MUTANT_INCREMENT, - TRUE, - FALSE); + return(STATUS_SUCCESS); } -VOID -INIT_FUNCTION -ExpInitializeMutantImplementation(VOID) + +VOID STDCALL +ExpDeleteMutant(PVOID ObjectBody) { + DPRINT("NtpDeleteMutant(ObjectBody %x)\n", ObjectBody); - /* Allocate the Object Type */ - ExMutantObjectType = ExAllocatePoolWithTag(NonPagedPool, sizeof(OBJECT_TYPE), TAG('M', 't', 'n', 't')); - - /* Create the Object Type */ - RtlpCreateUnicodeString(&ExMutantObjectType->TypeName, L"Mutant", NonPagedPool); - ExMutantObjectType->Tag = TAG('M', 't', 'n', 't'); - ExMutantObjectType->PeakObjects = 0; - ExMutantObjectType->PeakHandles = 0; - ExMutantObjectType->TotalObjects = 0; - ExMutantObjectType->TotalHandles = 0; - ExMutantObjectType->PagedPoolCharge = 0; - ExMutantObjectType->NonpagedPoolCharge = sizeof(KMUTANT); - ExMutantObjectType->Mapping = &ExpMutantMapping; - ExMutantObjectType->Dump = NULL; - ExMutantObjectType->Open = NULL; - ExMutantObjectType->Close = NULL; - ExMutantObjectType->Delete = ExpDeleteMutant; - ExMutantObjectType->Parse = NULL; - ExMutantObjectType->Security = NULL; - ExMutantObjectType->QueryName = NULL; - ExMutantObjectType->OkayToClose = NULL; - ExMutantObjectType->Create = NULL; - ExMutantObjectType->DuplicationNotify = NULL; - ObpCreateTypeObject(ExMutantObjectType); + KeReleaseMutant((PKMUTANT)ObjectBody, + MUTANT_INCREMENT, + TRUE, + FALSE); } + +VOID INIT_FUNCTION +ExpInitializeMutantImplementation(VOID) +{ + ExMutantObjectType = ExAllocatePool(NonPagedPool,sizeof(OBJECT_TYPE)); + + RtlpCreateUnicodeString(&ExMutantObjectType->TypeName, L"Mutant", NonPagedPool); + + ExMutantObjectType->Tag = TAG('M', 'T', 'N', 'T'); + ExMutantObjectType->PeakObjects = 0; + ExMutantObjectType->PeakHandles = 0; + ExMutantObjectType->TotalObjects = 0; + ExMutantObjectType->TotalHandles = 0; + ExMutantObjectType->PagedPoolCharge = 0; + ExMutantObjectType->NonpagedPoolCharge = sizeof(KMUTANT); + ExMutantObjectType->Mapping = &ExpMutantMapping; + ExMutantObjectType->Dump = NULL; + ExMutantObjectType->Open = NULL; + ExMutantObjectType->Close = NULL; + ExMutantObjectType->Delete = ExpDeleteMutant; + ExMutantObjectType->Parse = NULL; + ExMutantObjectType->Security = NULL; + ExMutantObjectType->QueryName = NULL; + ExMutantObjectType->OkayToClose = NULL; + ExMutantObjectType->Create = ExpCreateMutant; + ExMutantObjectType->DuplicationNotify = NULL; + + ObpCreateTypeObject(ExMutantObjectType); +} + + /* * @implemented */ -NTSTATUS -STDCALL +NTSTATUS STDCALL NtCreateMutant(OUT PHANDLE MutantHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, - IN BOOLEAN InitialOwner) + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN BOOLEAN InitialOwner) { - KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); - HANDLE hMutant; - PKMUTANT Mutant; - NTSTATUS Status = STATUS_SUCCESS; - - DPRINT("NtCreateMutant(0x%x, 0x%x, 0x%x)\n", MutantHandle, DesiredAccess, ObjectAttributes); + KPROCESSOR_MODE PreviousMode; + HANDLE hMutant; + PKMUTEX Mutant; + NTSTATUS Status = STATUS_SUCCESS; - /* Check Output Safety */ - if(PreviousMode == UserMode) { - - _SEH_TRY { - - ProbeForWrite(MutantHandle, - sizeof(HANDLE), - sizeof(ULONG)); - } _SEH_HANDLE { - - Status = _SEH_GetExceptionCode(); - - } _SEH_END; - - if(!NT_SUCCESS(Status)) return Status; + PAGED_CODE(); + + PreviousMode = ExGetPreviousMode(); + + if(PreviousMode == UserMode) + { + _SEH_TRY + { + ProbeForWrite(MutantHandle, + sizeof(HANDLE), + sizeof(ULONG)); } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + + if(!NT_SUCCESS(Status)) + { + return Status; + } + } + + Status = ObCreateObject(PreviousMode, + ExMutantObjectType, + ObjectAttributes, + PreviousMode, + NULL, + sizeof(KMUTANT), + 0, + 0, + (PVOID*)&Mutant); + if(NT_SUCCESS(Status)) + { + KeInitializeMutant(Mutant, + InitialOwner); + + Status = ObInsertObject((PVOID)Mutant, + NULL, + DesiredAccess, + 0, + NULL, + &hMutant); + ObDereferenceObject(Mutant); - /* Create the Mutant Object*/ - Status = ObCreateObject(PreviousMode, - ExMutantObjectType, - ObjectAttributes, - PreviousMode, - NULL, - sizeof(KMUTANT), - 0, - 0, - (PVOID*)&Mutant); - - /* Check for success */ - if(NT_SUCCESS(Status)) { - - /* Initalize the Kernel Mutant */ - DPRINT("Initializing the Mutant\n"); - KeInitializeMutant(Mutant, InitialOwner); - - /* Insert the Object */ - Status = ObInsertObject((PVOID)Mutant, - NULL, - DesiredAccess, - 0, - NULL, - &hMutant); - ObDereferenceObject(Mutant); - - /* Check for success and return handle */ - if(NT_SUCCESS(Status)) { - - _SEH_TRY { - - *MutantHandle = hMutant; - - } _SEH_HANDLE { - - Status = _SEH_GetExceptionCode(); - - } _SEH_END; - } + if(NT_SUCCESS(Status)) + { + _SEH_TRY + { + *MutantHandle = hMutant; + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; } + } - /* Return Status */ - return Status; + return Status; } /* * @implemented */ -NTSTATUS -STDCALL +NTSTATUS STDCALL NtOpenMutant(OUT PHANDLE MutantHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes) + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes) { - HANDLE hMutant; - KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); - NTSTATUS Status = STATUS_SUCCESS; + HANDLE hMutant; + KPROCESSOR_MODE PreviousMode; + NTSTATUS Status = STATUS_SUCCESS; - PAGED_CODE(); + PAGED_CODE(); - DPRINT("NtOpenMutant(0x%x, 0x%x, 0x%x)\n", MutantHandle, DesiredAccess, ObjectAttributes); - - /* Check Output Safety */ - if(PreviousMode == UserMode) { - - _SEH_TRY { - - ProbeForWrite(MutantHandle, - sizeof(HANDLE), - sizeof(ULONG)); - } _SEH_HANDLE { - - Status = _SEH_GetExceptionCode(); - - } _SEH_END; - - if(!NT_SUCCESS(Status)) return Status; + DPRINT("NtOpenMutant(0x%x, 0x%x, 0x%x)\n", MutantHandle, DesiredAccess, ObjectAttributes); + + PreviousMode = ExGetPreviousMode(); + + if(PreviousMode == UserMode) + { + _SEH_TRY + { + ProbeForWrite(MutantHandle, + sizeof(HANDLE), + sizeof(ULONG)); } - - /* Open the Object */ - Status = ObOpenObjectByName(ObjectAttributes, - ExMutantObjectType, - NULL, - PreviousMode, - DesiredAccess, - NULL, - &hMutant); - - /* Check for success and return handle */ - if(NT_SUCCESS(Status)) { - - _SEH_TRY { - - *MutantHandle = hMutant; - - } _SEH_HANDLE { - - Status = _SEH_GetExceptionCode(); - - } _SEH_END; + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + + if(!NT_SUCCESS(Status)) + { + return Status; + } + } + + Status = ObOpenObjectByName(ObjectAttributes, + ExMutantObjectType, + NULL, + PreviousMode, + DesiredAccess, + NULL, + &hMutant); + + if(NT_SUCCESS(Status)) + { + _SEH_TRY + { + *MutantHandle = hMutant; + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); } + _SEH_END; + } - /* Return Status */ - return Status; + return Status; } + /* * @implemented */ -NTSTATUS -STDCALL +NTSTATUS STDCALL NtQueryMutant(IN HANDLE MutantHandle, - IN MUTANT_INFORMATION_CLASS MutantInformationClass, - OUT PVOID MutantInformation, - IN ULONG MutantInformationLength, - OUT PULONG ResultLength OPTIONAL) + IN MUTANT_INFORMATION_CLASS MutantInformationClass, + OUT PVOID MutantInformation, + IN ULONG MutantInformationLength, + OUT PULONG ResultLength OPTIONAL) { - PKMUTANT Mutant; - KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); - NTSTATUS Status = STATUS_SUCCESS; - PMUTANT_BASIC_INFORMATION BasicInfo = (PMUTANT_BASIC_INFORMATION)MutantInformation; - - /* Check buffers and parameters */ - DefaultQueryInfoBufferCheck(MutantInformationClass, - ExMutantInfoClass, - MutantInformation, - MutantInformationLength, - ResultLength, - PreviousMode, - &Status); - if(!NT_SUCCESS(Status)) { - - DPRINT1("NtQueryMutant() failed, Status: 0x%x\n", Status); - return Status; - } + PKMUTANT Mutant; + KPROCESSOR_MODE PreviousMode; + NTSTATUS Status = STATUS_SUCCESS; PAGED_CODE(); - /* Open the Object */ - Status = ObReferenceObjectByHandle(MutantHandle, - MUTANT_QUERY_STATE, - ExMutantObjectType, - PreviousMode, - (PVOID*)&Mutant, - NULL); - /* Check for Status */ - if(NT_SUCCESS(Status)) { - - _SEH_TRY { - - /* Fill out the Basic Information Requested */ - DPRINT1("Returning Mutant Information\n"); - BasicInfo->CurrentCount = KeReadStateMutant(Mutant); - BasicInfo->OwnedByCaller = (Mutant->OwnerThread == KeGetCurrentThread()); - BasicInfo->AbandonedState = Mutant->Abandoned; - - /* Return the Result Length if requested */ - if(ResultLength) *ResultLength = sizeof(MUTANT_BASIC_INFORMATION); - - } _SEH_HANDLE { - - Status = _SEH_GetExceptionCode(); - - } _SEH_END; - - /* Release the Object */ - ObDereferenceObject(Mutant); - } - - /* Return Status */ - return Status; + PreviousMode = ExGetPreviousMode(); + + DefaultQueryInfoBufferCheck(MutantInformationClass, + ExMutantInfoClass, + MutantInformation, + MutantInformationLength, + ResultLength, + PreviousMode, + &Status); + if(!NT_SUCCESS(Status)) + { + DPRINT1("NtQueryMutant() failed, Status: 0x%x\n", Status); + return Status; + } + + Status = ObReferenceObjectByHandle(MutantHandle, + MUTANT_QUERY_STATE, + ExMutantObjectType, + PreviousMode, + (PVOID*)&Mutant, + NULL); + if(NT_SUCCESS(Status)) + { + switch(MutantInformationClass) + { + case MutantBasicInformation: + { + PMUTANT_BASIC_INFORMATION BasicInfo = (PMUTANT_BASIC_INFORMATION)MutantInformation; + + _SEH_TRY + { + BasicInfo->Count = KeReadStateMutant(Mutant); + BasicInfo->Owned = (Mutant->OwnerThread != NULL); + BasicInfo->Abandoned = Mutant->Abandoned; + + if(ResultLength != NULL) + { + *ResultLength = sizeof(MUTANT_BASIC_INFORMATION); + } + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + break; + } + + default: + Status = STATUS_NOT_IMPLEMENTED; + break; + } + + ObDereferenceObject(Mutant); + } + + return Status; } /* * @implemented */ -NTSTATUS -STDCALL +NTSTATUS STDCALL NtReleaseMutant(IN HANDLE MutantHandle, - IN PLONG PreviousCount OPTIONAL) + IN PLONG PreviousCount OPTIONAL) { - PKMUTANT Mutant; - KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); - NTSTATUS Status = STATUS_SUCCESS; + PKMUTANT Mutant; + KPROCESSOR_MODE PreviousMode; + NTSTATUS Status = STATUS_SUCCESS; - PAGED_CODE(); - - DPRINT("NtReleaseMutant(MutantHandle 0%x PreviousCount 0%x)\n", - MutantHandle, - PreviousCount); - - /* Check Output Safety */ - if(PreviousMode == UserMode && PreviousCount) { - - _SEH_TRY { - - ProbeForWrite(PreviousCount, - sizeof(LONG), - sizeof(ULONG)); - } _SEH_HANDLE { - - Status = _SEH_GetExceptionCode(); - - } _SEH_END; - - if(!NT_SUCCESS(Status)) return Status; - } - - /* Open the Object */ - Status = ObReferenceObjectByHandle(MutantHandle, - MUTANT_QUERY_STATE, - ExMutantObjectType, - PreviousMode, - (PVOID*)&Mutant, - NULL); - - /* Check for Success and release if such */ - if(NT_SUCCESS(Status)) { - - /* Save the Old State */ - DPRINT1("Releasing Mutant\n"); - LONG Prev = KeReleaseMutant(Mutant, MUTANT_INCREMENT, FALSE, FALSE); - ObDereferenceObject(Mutant); - - /* Return it */ - if(PreviousCount) { - - _SEH_TRY { - - *PreviousCount = Prev; - - } _SEH_HANDLE { - - Status = _SEH_GetExceptionCode(); - - } _SEH_END; - } - } + PAGED_CODE(); - /* Return Status */ - return Status; + DPRINT("NtReleaseMutant(MutantHandle 0%x PreviousCount 0%x)\n", + MutantHandle, PreviousCount); + + PreviousMode = ExGetPreviousMode(); + + if(PreviousCount != NULL && PreviousMode == UserMode) + { + _SEH_TRY + { + ProbeForWrite(PreviousCount, + sizeof(LONG), + sizeof(ULONG)); + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + + if(!NT_SUCCESS(Status)) + { + return Status; + } + } + + Status = ObReferenceObjectByHandle(MutantHandle, + MUTANT_QUERY_STATE, + ExMutantObjectType, + PreviousMode, + (PVOID*)&Mutant, + NULL); + if(NT_SUCCESS(Status)) + { + LONG Prev = KeReleaseMutant(Mutant, MUTANT_INCREMENT, 0, FALSE); + ObDereferenceObject(Mutant); + + if(PreviousCount != NULL) + { + _SEH_TRY + { + *PreviousCount = Prev; + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + } + } + + return Status; } /* EOF */ diff --git a/reactos/ntoskrnl/ex/rundown.c b/reactos/ntoskrnl/ex/rundown.c index 580d9bb4e4e..baf8a38248b 100644 --- a/reactos/ntoskrnl/ex/rundown.c +++ b/reactos/ntoskrnl/ex/rundown.c @@ -1,10 +1,11 @@ -/* +/* $Id$ + * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * FILE: ntoskrnl/ex/rundown.c * PURPOSE: Rundown Protection Functions * - * PROGRAMMERS: Alex Ionescu & Thomas Weidenmueller - Implementation + * PROGRAMMERS: No programmer listed. */ /* INCLUDES *****************************************************************/ diff --git a/reactos/ntoskrnl/ex/sem.c b/reactos/ntoskrnl/ex/sem.c index ef9a41c5cef..274ce8aed1d 100644 --- a/reactos/ntoskrnl/ex/sem.c +++ b/reactos/ntoskrnl/ex/sem.c @@ -1,11 +1,11 @@ -/* +/* $Id: ntsem.c 12779 2005-01-04 04:45:00Z gdalsnes $ + * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * FILE: ntoskrnl/ex/sem.c * PURPOSE: Synchronization primitives * - * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)- Reformatting, bug fixes. - * David Welch (welch@mcmail.com) + * PROGRAMMERS: David Welch (welch@mcmail.com) */ /* INCLUDES *****************************************************************/ @@ -19,336 +19,345 @@ POBJECT_TYPE ExSemaphoreObjectType; static GENERIC_MAPPING ExSemaphoreMapping = { - STANDARD_RIGHTS_READ | SEMAPHORE_QUERY_STATE, - STANDARD_RIGHTS_WRITE | SEMAPHORE_MODIFY_STATE, - STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE | SEMAPHORE_QUERY_STATE, - SEMAPHORE_ALL_ACCESS}; - -static const INFORMATION_CLASS_INFO ExSemaphoreInfoClass[] = { - - /* SemaphoreBasicInformation */ - ICI_SQ_SAME( sizeof(SEMAPHORE_BASIC_INFORMATION), sizeof(ULONG), ICIF_QUERY ), + STANDARD_RIGHTS_READ | SEMAPHORE_QUERY_STATE, + STANDARD_RIGHTS_WRITE | SEMAPHORE_MODIFY_STATE, + STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE | SEMAPHORE_QUERY_STATE, + SEMAPHORE_ALL_ACCESS}; + +static const INFORMATION_CLASS_INFO ExSemaphoreInfoClass[] = +{ + ICI_SQ_SAME( sizeof(SEMAPHORE_BASIC_INFORMATION), sizeof(ULONG), ICIF_QUERY ), /* SemaphoreBasicInformation */ }; -VOID -INIT_FUNCTION +/* FUNCTIONS *****************************************************************/ + +NTSTATUS STDCALL +ExpCreateSemaphore(PVOID ObjectBody, + PVOID Parent, + PWSTR RemainingPath, + POBJECT_ATTRIBUTES ObjectAttributes) +{ + DPRINT("NtpCreateSemaphore(ObjectBody %x, Parent %x, RemainingPath %S)\n", + ObjectBody, Parent, RemainingPath); + + if (RemainingPath != NULL && wcschr(RemainingPath+1, '\\') != NULL) + { + return(STATUS_UNSUCCESSFUL); + } + + return(STATUS_SUCCESS); +} + +VOID INIT_FUNCTION ExpInitializeSemaphoreImplementation(VOID) { - - /* Create the Semaphore Object */ - ExSemaphoreObjectType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE)); - RtlpCreateUnicodeString(&ExSemaphoreObjectType->TypeName, L"Semaphore", NonPagedPool); - ExSemaphoreObjectType->Tag = TAG('S', 'E', 'M', 'T'); - ExSemaphoreObjectType->PeakObjects = 0; - ExSemaphoreObjectType->PeakHandles = 0; - ExSemaphoreObjectType->TotalObjects = 0; - ExSemaphoreObjectType->TotalHandles = 0; - ExSemaphoreObjectType->PagedPoolCharge = 0; - ExSemaphoreObjectType->NonpagedPoolCharge = sizeof(KSEMAPHORE); - ExSemaphoreObjectType->Mapping = &ExSemaphoreMapping; - ExSemaphoreObjectType->Dump = NULL; - ExSemaphoreObjectType->Open = NULL; - ExSemaphoreObjectType->Close = NULL; - ExSemaphoreObjectType->Delete = NULL; - ExSemaphoreObjectType->Parse = NULL; - ExSemaphoreObjectType->Security = NULL; - ExSemaphoreObjectType->QueryName = NULL; - ExSemaphoreObjectType->OkayToClose = NULL; - ExSemaphoreObjectType->Create = NULL; - ExSemaphoreObjectType->DuplicationNotify = NULL; - ObpCreateTypeObject(ExSemaphoreObjectType); + ExSemaphoreObjectType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE)); + + RtlpCreateUnicodeString(&ExSemaphoreObjectType->TypeName, L"Semaphore", NonPagedPool); + + ExSemaphoreObjectType->Tag = TAG('S', 'E', 'M', 'T'); + ExSemaphoreObjectType->PeakObjects = 0; + ExSemaphoreObjectType->PeakHandles = 0; + ExSemaphoreObjectType->TotalObjects = 0; + ExSemaphoreObjectType->TotalHandles = 0; + ExSemaphoreObjectType->PagedPoolCharge = 0; + ExSemaphoreObjectType->NonpagedPoolCharge = sizeof(KSEMAPHORE); + ExSemaphoreObjectType->Mapping = &ExSemaphoreMapping; + ExSemaphoreObjectType->Dump = NULL; + ExSemaphoreObjectType->Open = NULL; + ExSemaphoreObjectType->Close = NULL; + ExSemaphoreObjectType->Delete = NULL; + ExSemaphoreObjectType->Parse = NULL; + ExSemaphoreObjectType->Security = NULL; + ExSemaphoreObjectType->QueryName = NULL; + ExSemaphoreObjectType->OkayToClose = NULL; + ExSemaphoreObjectType->Create = ExpCreateSemaphore; + ExSemaphoreObjectType->DuplicationNotify = NULL; + + ObpCreateTypeObject(ExSemaphoreObjectType); } /* * @implemented */ -NTSTATUS -STDCALL +NTSTATUS STDCALL NtCreateSemaphore(OUT PHANDLE SemaphoreHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, - IN LONG InitialCount, - IN LONG MaximumCount) + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN LONG InitialCount, + IN LONG MaximumCount) { - PKSEMAPHORE Semaphore; - HANDLE hSemaphore; - KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); - NTSTATUS Status = STATUS_SUCCESS; + PKSEMAPHORE Semaphore; + HANDLE hSemaphore; + KPROCESSOR_MODE PreviousMode; + NTSTATUS Status = STATUS_SUCCESS; - PAGED_CODE(); - - /* Check Output Safety */ - if(PreviousMode == UserMode) { - - _SEH_TRY { - - ProbeForWrite(SemaphoreHandle, - sizeof(HANDLE), - sizeof(ULONG)); - } _SEH_HANDLE { - - Status = _SEH_GetExceptionCode(); - - } _SEH_END; - - if(!NT_SUCCESS(Status)) return Status; - } - - /* Make sure the counts make sense */ - if (!MaximumCount || !InitialCount || InitialCount > MaximumCount) { - - DPRINT("Invalid Count Data!\n"); - return STATUS_INVALID_PARAMETER; - } + PAGED_CODE(); - /* Create the Semaphore Object */ - Status = ObCreateObject(PreviousMode, - ExSemaphoreObjectType, - ObjectAttributes, - PreviousMode, - NULL, - sizeof(KSEMAPHORE), - 0, - 0, - (PVOID*)&Semaphore); - - /* Check for Success */ - if (NT_SUCCESS(Status)) { - - /* Initialize it */ - KeInitializeSemaphore(Semaphore, - InitialCount, - MaximumCount); - - /* Insert it into the Object Tree */ - Status = ObInsertObject((PVOID)Semaphore, - NULL, - DesiredAccess, - 0, - NULL, - &hSemaphore); - ObDereferenceObject(Semaphore); - - /* Check for success and return handle */ - if(NT_SUCCESS(Status)) { - - _SEH_TRY { - - *SemaphoreHandle = hSemaphore; - - } _SEH_HANDLE { - - Status = _SEH_GetExceptionCode(); - - } _SEH_END; - } - } + PreviousMode = ExGetPreviousMode(); + + if(PreviousMode == UserMode) + { + _SEH_TRY + { + ProbeForWrite(SemaphoreHandle, + sizeof(HANDLE), + sizeof(ULONG)); + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + + if(!NT_SUCCESS(Status)) + { + return Status; + } + } + + Status = ObCreateObject(PreviousMode, + ExSemaphoreObjectType, + ObjectAttributes, + PreviousMode, + NULL, + sizeof(KSEMAPHORE), + 0, + 0, + (PVOID*)&Semaphore); + if (NT_SUCCESS(Status)) + { + KeInitializeSemaphore(Semaphore, + InitialCount, + MaximumCount); + + Status = ObInsertObject ((PVOID)Semaphore, + NULL, + DesiredAccess, + 0, + NULL, + &hSemaphore); - /* Return Status */ - return Status; + ObDereferenceObject(Semaphore); + + if(NT_SUCCESS(Status)) + { + _SEH_TRY + { + *SemaphoreHandle = hSemaphore; + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + } + } + + return Status; } /* * @implemented */ -NTSTATUS -STDCALL +NTSTATUS STDCALL NtOpenSemaphore(OUT PHANDLE SemaphoreHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes) + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes) { - HANDLE hSemaphore; - KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); - NTSTATUS Status = STATUS_SUCCESS; + HANDLE hSemaphore; + KPROCESSOR_MODE PreviousMode; + NTSTATUS Status = STATUS_SUCCESS; - PAGED_CODE(); - - /* Check Output Safety */ - if(PreviousMode == UserMode) { - - _SEH_TRY { - - ProbeForWrite(SemaphoreHandle, - sizeof(HANDLE), - sizeof(ULONG)); - } _SEH_HANDLE { - - Status = _SEH_GetExceptionCode(); - - } _SEH_END; - - if(!NT_SUCCESS(Status)) return Status; - } - - /* Open the Object */ - Status = ObOpenObjectByName(ObjectAttributes, - ExSemaphoreObjectType, - NULL, - PreviousMode, - DesiredAccess, - NULL, - &hSemaphore); - - /* Check for success and return handle */ - if(NT_SUCCESS(Status)) { - - _SEH_TRY { - - *SemaphoreHandle = hSemaphore; - - } _SEH_HANDLE { - - Status = _SEH_GetExceptionCode(); - - } _SEH_END; - } + PAGED_CODE(); - /* Return Status */ - return Status; + PreviousMode = ExGetPreviousMode(); + + if(PreviousMode == UserMode) + { + _SEH_TRY + { + ProbeForWrite(SemaphoreHandle, + sizeof(HANDLE), + sizeof(ULONG)); + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + + if(!NT_SUCCESS(Status)) + { + return Status; + } + } + + Status = ObOpenObjectByName(ObjectAttributes, + ExSemaphoreObjectType, + NULL, + PreviousMode, + DesiredAccess, + NULL, + &hSemaphore); + if(NT_SUCCESS(Status)) + { + _SEH_TRY + { + *SemaphoreHandle = hSemaphore; + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + } + + return Status; } + /* * @implemented */ -NTSTATUS -STDCALL +NTSTATUS STDCALL NtQuerySemaphore(IN HANDLE SemaphoreHandle, - IN SEMAPHORE_INFORMATION_CLASS SemaphoreInformationClass, - OUT PVOID SemaphoreInformation, - IN ULONG SemaphoreInformationLength, - OUT PULONG ReturnLength OPTIONAL) + IN SEMAPHORE_INFORMATION_CLASS SemaphoreInformationClass, + OUT PVOID SemaphoreInformation, + IN ULONG SemaphoreInformationLength, + OUT PULONG ReturnLength OPTIONAL) { - PKSEMAPHORE Semaphore; - KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); - PSEMAPHORE_BASIC_INFORMATION BasicInfo = (PSEMAPHORE_BASIC_INFORMATION)SemaphoreInformation; - NTSTATUS Status = STATUS_SUCCESS; - - PAGED_CODE(); - - /* Check buffers and class validity */ - DefaultQueryInfoBufferCheck(SemaphoreInformationClass, - ExSemaphoreInfoClass, - SemaphoreInformation, - SemaphoreInformationLength, - ReturnLength, - PreviousMode, - &Status); - if(!NT_SUCCESS(Status)) { - - /* Invalid buffers */ - DPRINT("NtQuerySemaphore() failed, Status: 0x%x\n", Status); - return Status; - } - - /* Get the Object */ - Status = ObReferenceObjectByHandle(SemaphoreHandle, - SEMAPHORE_QUERY_STATE, - ExSemaphoreObjectType, - PreviousMode, - (PVOID*)&Semaphore, - NULL); - - /* Check for success */ - if(NT_SUCCESS(Status)) { + PKSEMAPHORE Semaphore; + KPROCESSOR_MODE PreviousMode; + NTSTATUS Status = STATUS_SUCCESS; - _SEH_TRY { - - /* Return the basic information */ - BasicInfo->CurrentCount = KeReadStateSemaphore(Semaphore); - BasicInfo->MaximumCount = Semaphore->Limit; - - /* Return length */ - if(ReturnLength) *ReturnLength = sizeof(SEMAPHORE_BASIC_INFORMATION); - - } _SEH_HANDLE { - - Status = _SEH_GetExceptionCode(); - - } _SEH_END; - - /* Dereference the Object */ - ObDereferenceObject(Semaphore); + PAGED_CODE(); + + PreviousMode = ExGetPreviousMode(); + + DefaultQueryInfoBufferCheck(SemaphoreInformationClass, + ExSemaphoreInfoClass, + SemaphoreInformation, + SemaphoreInformationLength, + ReturnLength, + PreviousMode, + &Status); + if(!NT_SUCCESS(Status)) + { + DPRINT1("NtQuerySemaphore() failed, Status: 0x%x\n", Status); + return Status; + } + + Status = ObReferenceObjectByHandle(SemaphoreHandle, + SEMAPHORE_QUERY_STATE, + ExSemaphoreObjectType, + PreviousMode, + (PVOID*)&Semaphore, + NULL); + if(NT_SUCCESS(Status)) + { + switch(SemaphoreInformationClass) + { + case SemaphoreBasicInformation: + { + PSEMAPHORE_BASIC_INFORMATION BasicInfo = (PSEMAPHORE_BASIC_INFORMATION)SemaphoreInformation; + + _SEH_TRY + { + BasicInfo->CurrentCount = KeReadStateSemaphore(Semaphore); + BasicInfo->MaximumCount = Semaphore->Limit; + + if(ReturnLength != NULL) + { + *ReturnLength = sizeof(SEMAPHORE_BASIC_INFORMATION); + } + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + break; + } + + default: + Status = STATUS_NOT_IMPLEMENTED; + break; + } + + ObDereferenceObject(Semaphore); } - /* Return status */ return Status; } + /* * @implemented */ -NTSTATUS -STDCALL +NTSTATUS STDCALL NtReleaseSemaphore(IN HANDLE SemaphoreHandle, - IN LONG ReleaseCount, - OUT PLONG PreviousCount OPTIONAL) + IN LONG ReleaseCount, + OUT PLONG PreviousCount OPTIONAL) { - KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();; - PKSEMAPHORE Semaphore; - NTSTATUS Status = STATUS_SUCCESS; + KPROCESSOR_MODE PreviousMode; + PKSEMAPHORE Semaphore; + NTSTATUS Status = STATUS_SUCCESS; - PAGED_CODE(); - - /* Check buffer validity */ - if(PreviousCount != NULL && PreviousMode == UserMode) { - - _SEH_TRY { - - ProbeForWrite(PreviousCount, - sizeof(LONG), - sizeof(ULONG)); - } _SEH_HANDLE { - - Status = _SEH_GetExceptionCode(); - - } _SEH_END; - - if(!NT_SUCCESS(Status)) return Status; - } - - /* Make sure count makes sense */ - if (!ReleaseCount) { - - DPRINT("Invalid Release Count\n"); - return STATUS_INVALID_PARAMETER; - } + PAGED_CODE(); - /* Get the Object */ - Status = ObReferenceObjectByHandle(SemaphoreHandle, - SEMAPHORE_MODIFY_STATE, - ExSemaphoreObjectType, - PreviousMode, - (PVOID*)&Semaphore, - NULL); - - /* Check for success */ - if (NT_SUCCESS(Status)) { - - /* Release the semaphore */ - LONG PrevCount = KeReleaseSemaphore(Semaphore, - IO_NO_INCREMENT, - ReleaseCount, - FALSE); - ObDereferenceObject(Semaphore); + PreviousMode = ExGetPreviousMode(); + + if(PreviousCount != NULL && PreviousMode == UserMode) + { + _SEH_TRY + { + ProbeForWrite(PreviousCount, + sizeof(LONG), + sizeof(ULONG)); + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + + if(!NT_SUCCESS(Status)) + { + return Status; + } + } + + Status = ObReferenceObjectByHandle(SemaphoreHandle, + SEMAPHORE_MODIFY_STATE, + ExSemaphoreObjectType, + PreviousMode, + (PVOID*)&Semaphore, + NULL); + if (NT_SUCCESS(Status)) + { + LONG PrevCount = KeReleaseSemaphore(Semaphore, + IO_NO_INCREMENT, + ReleaseCount, + FALSE); + ObDereferenceObject(Semaphore); - /* Return it */ - if(PreviousCount) { - - _SEH_TRY { - - *PreviousCount = PrevCount; - - } _SEH_HANDLE { - - Status = _SEH_GetExceptionCode(); - - } _SEH_END; - } - } + if(PreviousCount != NULL) + { + _SEH_TRY + { + *PreviousCount = PrevCount; + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + } + } - /* Return Status */ - return Status; + return Status; } /* EOF */ diff --git a/reactos/ntoskrnl/ex/sysinfo.c b/reactos/ntoskrnl/ex/sysinfo.c index 352e3a84971..2efe7292c20 100644 --- a/reactos/ntoskrnl/ex/sysinfo.c +++ b/reactos/ntoskrnl/ex/sysinfo.c @@ -86,20 +86,6 @@ ExGetCurrentProcessorCounts ( ProcessorNumber = &ProcNumber; } -/* - * @implemented - */ -BOOLEAN -STDCALL -ExIsProcessorFeaturePresent(IN ULONG ProcessorFeature) -{ - /* Quick check to see if it exists at all */ - if (ProcessorFeature >= PROCESSOR_FEATURE_MAX) return(FALSE); - - /* Return our support for it */ - return(SharedUserData->ProcessorFeatures[ProcessorFeature]); -} - NTSTATUS STDCALL NtQuerySystemEnvironmentValue (IN PUNICODE_STRING VariableName, OUT PWCHAR ValueBuffer, diff --git a/reactos/ntoskrnl/ex/timer.c b/reactos/ntoskrnl/ex/timer.c index c2ecdd59c6b..fa0a2540d3d 100644 --- a/reactos/ntoskrnl/ex/timer.c +++ b/reactos/ntoskrnl/ex/timer.c @@ -473,7 +473,7 @@ NtQueryTimer(IN HANDLE TimerHandle, PreviousMode = ExGetPreviousMode(); DPRINT("NtQueryTimer(TimerHandle: %x, Class: %d)\n", TimerHandle, TimerInformationClass); - + /* Check Validity */ DefaultQueryInfoBufferCheck(TimerInformationClass, ExTimerInfoClass, @@ -498,23 +498,27 @@ NtQueryTimer(IN HANDLE TimerHandle, /* Check for Success */ if(NT_SUCCESS(Status)) { + + switch(TimerInformationClass) { + case TimerBasicInformation: { + /* Return the Basic Information */ + _SEH_TRY { - /* Return the Basic Information */ - _SEH_TRY { - - /* FIXME: Interrupt correction based on Interrupt Time */ - DPRINT("Returning Information for Timer: %x. Time Remaining: %d\n", Timer, Timer->KeTimer.DueTime.QuadPart); - BasicInfo->TimeRemaining.QuadPart = Timer->KeTimer.DueTime.QuadPart; - BasicInfo->SignalState = KeReadStateTimer(&Timer->KeTimer); + /* FIXME: Interrupt correction based on Interrupt Time */ + DPRINT("Returning Information for Timer: %x. Time Remaining: %d\n", Timer, Timer->KeTimer.DueTime.QuadPart); + BasicInfo->TimeRemaining.QuadPart = Timer->KeTimer.DueTime.QuadPart; + BasicInfo->SignalState = KeReadStateTimer(&Timer->KeTimer); - if(ReturnLength != NULL) *ReturnLength = sizeof(TIMER_BASIC_INFORMATION); + if(ReturnLength != NULL) { + *ReturnLength = sizeof(TIMER_BASIC_INFORMATION); + } - } _SEH_HANDLE { - + } _SEH_HANDLE { Status = _SEH_GetExceptionCode(); - } _SEH_END; + } _SEH_END; + } + } - /* Dereference Object */ ObDereferenceObject(Timer); } diff --git a/reactos/ntoskrnl/ex/work.c b/reactos/ntoskrnl/ex/work.c index 0a5f82f1588..8d7bac152fa 100644 --- a/reactos/ntoskrnl/ex/work.c +++ b/reactos/ntoskrnl/ex/work.c @@ -1,11 +1,11 @@ -/* +/* $Id$ + * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * FILE: ntoskrnl/ex/work.c * PURPOSE: Manage system work queues * - * PROGRAMMERS: Alex Ionescu - Used correct work queue array and added some fixes and checks. - * Gunnar Dalsnes - Implemented + * PROGRAMMERS: David Welch (welch@mcmail.com) */ /* INCLUDES ******************************************************************/ @@ -25,10 +25,17 @@ /* * PURPOSE: Queue of items waiting to be processed at normal priority */ -EX_WORK_QUEUE ExWorkerQueue[MaximumWorkQueue]; +KQUEUE EiNormalWorkQueue; + +KQUEUE EiCriticalWorkQueue; + +KQUEUE EiHyperCriticalWorkQueue; /* FUNCTIONS ****************************************************************/ +//static NTSTATUS STDCALL +static VOID STDCALL +ExWorkerThreadEntryPoint(IN PVOID context) /* * FUNCTION: Entry point for a worker thread * ARGUMENTS: @@ -37,138 +44,138 @@ EX_WORK_QUEUE ExWorkerQueue[MaximumWorkQueue]; * NOTE: To kill a worker thread you must queue an item whose callback * calls PsTerminateSystemThread */ -static -VOID -STDCALL -ExpWorkerThreadEntryPoint(IN PVOID Context) { - PWORK_QUEUE_ITEM WorkItem; - PLIST_ENTRY QueueEntry; - WORK_QUEUE_TYPE WorkQueueType; - PEX_WORK_QUEUE WorkQueue; + + PWORK_QUEUE_ITEM item; + PLIST_ENTRY current; - /* Get Queue Type and Worker Queue */ - WorkQueueType = (WORK_QUEUE_TYPE)Context; - WorkQueue = &ExWorkerQueue[WorkQueueType]; - - /* Loop forever */ - while (TRUE) { - - /* Wait for Something to Happen on the Queue */ - QueueEntry = KeRemoveQueue(&WorkQueue->WorkerQueue, KernelMode, NULL); + while (TRUE) + { + current = KeRemoveQueue( (PKQUEUE)context, KernelMode, NULL ); - /* Can't happen since we do a KernelMode wait (and we're a system thread) */ - ASSERT((NTSTATUS)QueueEntry != STATUS_USER_APC); + /* can't happend since we do a KernelMode wait (and we're a system thread) */ + ASSERT((NTSTATUS)current != STATUS_USER_APC); - /* this should never happen either, since we wait with NULL timeout, - * but there's a slight possibility that STATUS_TIMEOUT is returned - * at queue rundown in NT (unlikely) -Gunnar - */ - ASSERT((NTSTATUS)QueueEntry != STATUS_TIMEOUT); - - /* Increment Processed Work Items */ - InterlockedIncrement(&WorkQueue->WorkItemsProcessed); - - /* Get the Work Item */ - WorkItem = CONTAINING_RECORD(QueueEntry, WORK_QUEUE_ITEM, List); - - /* Call the Worker Routine */ - WorkItem->WorkerRoutine(WorkItem->Parameter); - - /* Make sure it returned at right IRQL */ - if (KeGetCurrentIrql() != PASSIVE_LEVEL) { - - /* FIXME: Make this an Ex */ - KEBUGCHECK(WORKER_THREAD_RETURNED_AT_BAD_IRQL); - } - - /* Make sure it returned with Impersionation Disabled */ - if (PsGetCurrentThread()->ActiveImpersonationInfo) { - - /* FIXME: Make this an Ex */ - KEBUGCHECK(IMPERSONATING_WORKER_THREAD); - } - } + /* this should never happend either, since we wait with NULL timeout, + * but there's a slight possibility that STATUS_TIMEOUT is returned + * at queue rundown in NT (unlikely) -Gunnar + */ + ASSERT((NTSTATUS)current != STATUS_TIMEOUT); + + /* based on INVALID_WORK_QUEUE_ITEM bugcheck desc. */ + if (current->Flink == NULL || current->Blink == NULL) + { + KeBugCheck(INVALID_WORK_QUEUE_ITEM); + } + + /* "reinitialize" item (same as done in ExInitializeWorkItem) */ + current->Flink = NULL; + + item = CONTAINING_RECORD( current, WORK_QUEUE_ITEM, List); + item->WorkerRoutine(item->Parameter); + + if (KeGetCurrentIrql() != PASSIVE_LEVEL) + { + KeBugCheck(IRQL_NOT_LESS_OR_EQUAL); + } + } + } -static -VOID -STDCALL -ExpInitializeWorkQueue(WORK_QUEUE_TYPE WorkQueueType, - KPRIORITY Priority) +static VOID ExInitializeWorkQueue(PKQUEUE WorkQueue, + KPRIORITY Priority) { - ULONG i; - PETHREAD Thread; - HANDLE hThread; + ULONG i; + PETHREAD Thread; + HANDLE hThread; - /* Loop through how many threads we need to create */ - for (i = 0; i < NUMBER_OF_WORKER_THREADS; i++) { - - /* Create the System Thread */ - PsCreateSystemThread(&hThread, - THREAD_ALL_ACCESS, - NULL, - NULL, - NULL, - ExpWorkerThreadEntryPoint, - (PVOID)WorkQueueType); - - /* Get the Thread */ - ObReferenceObjectByHandle(hThread, - THREAD_SET_INFORMATION, - PsThreadType, - KernelMode, - (PVOID*)&Thread, - NULL); - - /* Set the Priority */ - KeSetPriorityThread(&Thread->Tcb, Priority); + + for (i=0; iTcb, + Priority); + ObDereferenceObject(Thread); + ZwClose(hThread); + } } -VOID -INIT_FUNCTION -ExpInitializeWorkerThreads(VOID) +VOID INIT_FUNCTION +ExInitializeWorkerThreads(VOID) { - ULONG WorkQueueType; - - /* Initialize the Array */ - for (WorkQueueType = 0; WorkQueueType < MaximumWorkQueue; WorkQueueType++) { - - RtlZeroMemory(&ExWorkerQueue[WorkQueueType], sizeof(EX_WORK_QUEUE)); - KeInitializeQueue(&ExWorkerQueue[WorkQueueType].WorkerQueue, 0); - } - - /* Create the built-in worker threads for each work queue */ - ExpInitializeWorkQueue(CriticalWorkQueue, LOW_REALTIME_PRIORITY); - ExpInitializeWorkQueue(DelayedWorkQueue, LOW_PRIORITY); - ExpInitializeWorkQueue(HyperCriticalWorkQueue, HIGH_PRIORITY); + KeInitializeQueue( &EiNormalWorkQueue, NUMBER_OF_WORKER_THREADS ); + KeInitializeQueue( &EiCriticalWorkQueue , NUMBER_OF_WORKER_THREADS ); + KeInitializeQueue( &EiHyperCriticalWorkQueue , NUMBER_OF_WORKER_THREADS ); + + ExInitializeWorkQueue(&EiNormalWorkQueue, + LOW_PRIORITY); + ExInitializeWorkQueue(&EiCriticalWorkQueue, + LOW_REALTIME_PRIORITY); + ExInitializeWorkQueue(&EiHyperCriticalWorkQueue, + HIGH_PRIORITY); } /* * @implemented - * + */ +VOID STDCALL +ExQueueWorkItem (PWORK_QUEUE_ITEM WorkItem, + WORK_QUEUE_TYPE QueueType) +/* * FUNCTION: Inserts a work item in a queue for one of the system worker * threads to process * ARGUMENTS: * WorkItem = Item to insert * QueueType = Queue to insert it in */ -VOID -STDCALL -ExQueueWorkItem(PWORK_QUEUE_ITEM WorkItem, - WORK_QUEUE_TYPE QueueType) { ASSERT(WorkItem!=NULL); ASSERT_IRQL(DISPATCH_LEVEL); ASSERT(WorkItem->List.Flink == NULL); - - /* Insert the Queue */ - KeInsertQueue(&ExWorkerQueue[QueueType].WorkerQueue, &WorkItem->List); + /* + * Insert the item in the appropiate queue and wake up any thread + * waiting for something to do + */ + switch(QueueType) + { + case DelayedWorkQueue: + KeInsertQueue ( + &EiNormalWorkQueue, + &WorkItem->List + ); + break; + + case CriticalWorkQueue: + KeInsertQueue ( + &EiCriticalWorkQueue, + &WorkItem->List + ); + break; + + case HyperCriticalWorkQueue: + KeInsertQueue ( + &EiHyperCriticalWorkQueue, + &WorkItem->List + ); + break; + + default: + break; + + } } /* EOF */ diff --git a/reactos/ntoskrnl/include/internal/ex.h b/reactos/ntoskrnl/include/internal/ex.h index d42decd8737..3596bfe2420 100644 --- a/reactos/ntoskrnl/include/internal/ex.h +++ b/reactos/ntoskrnl/include/internal/ex.h @@ -98,19 +98,24 @@ ExInit3(VOID); VOID ExpInitTimeZoneInfo(VOID); VOID -ExpInitializeWorkerThreads(VOID); +ExInitializeWorkerThreads(VOID); VOID ExpInitLookasideLists(VOID); VOID ExpInitializeCallbacks(VOID); VOID ExpInitUuids(VOID); -VOID -STDCALL -ExpInitializeExecutive(VOID); /* OTHER FUNCTIONS **********************************************************/ +#ifdef _ENABLE_THRDEVTPAIR +VOID +ExpSwapThreadEventPair( + IN struct _ETHREAD* Thread, + IN struct _KEVENT_PAIR* EventPair + ); +#endif /* _ENABLE_THRDEVTPAIR */ + LONGLONG FASTCALL ExfpInterlockedExchange64(LONGLONG volatile * Destination, diff --git a/reactos/ntoskrnl/include/internal/id.h b/reactos/ntoskrnl/include/internal/id.h index 5f86d9126f3..43a29588163 100644 --- a/reactos/ntoskrnl/include/internal/id.h +++ b/reactos/ntoskrnl/include/internal/id.h @@ -2,5 +2,18 @@ * Structure ids */ +#define InternalBaseType (0xcc) +#define InternalNotificationEvent (InternalBaseType + 1) +#define InternalSynchronizationEvent (InternalBaseType + 2) +#define InternalSemaphoreType (InternalBaseType + 3) +#define InternalProcessType (InternalBaseType + 4) +#define InternalThreadType (InternalBaseType + 5) +#define InternalFileType (InternalBaseType + 6) +#define InternalDriverType (InternalBaseType + 7) +#define InternalDeviceType (InternalBaseType + 8) +#define InternalMutexType (InternalBaseType + 9) +#define InternalNotificationTimer (InternalBaseType + 10) +#define InternalSynchronizationTimer (InternalBaseType + 11) +#define InternalQueueType (InternalBaseType + 12) diff --git a/reactos/ntoskrnl/include/internal/io.h b/reactos/ntoskrnl/include/internal/io.h index 95d129cbe6e..823c153c197 100644 --- a/reactos/ntoskrnl/include/internal/io.h +++ b/reactos/ntoskrnl/include/internal/io.h @@ -412,7 +412,7 @@ IoDestroyDriverList(VOID); /* bootlog.c */ VOID -IopInitBootLog(BOOLEAN StartBootLog); +IopInitBootLog(VOID); VOID IopStartBootLog(VOID); diff --git a/reactos/ntoskrnl/include/internal/ke.h b/reactos/ntoskrnl/include/internal/ke.h index c4f48eadd91..e9e78f6d9ef 100644 --- a/reactos/ntoskrnl/include/internal/ke.h +++ b/reactos/ntoskrnl/include/internal/ke.h @@ -115,17 +115,6 @@ typedef struct _KPROFILE struct _EPROCESS *Process; } KPROFILE, *PKPROFILE; -/* Cached modules from the loader block */ -typedef enum _CACHED_MODULE_TYPE { - AnsiCodepage, - OemCodepage, - UnicodeCasemap, - SystemRegistry, - HardwareRegistry, - MaximumCachedModuleType, -} CACHED_MODULE_TYPE, *PCACHED_MODULE_TYPE; -extern PLOADER_MODULE CachedModules[MaximumCachedModuleType]; - VOID STDCALL DbgBreakPointNoBugCheck(VOID); @@ -155,42 +144,30 @@ VOID STDCALL KeUpdateRunTime(PKTRAP_FRAME TrapFrame, KIRQL Irql); VOID STDCALL KiExpireTimers(PKDPC Dpc, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2); -KIRQL inline FASTCALL KeAcquireDispatcherDatabaseLock(VOID); -VOID inline FASTCALL KeAcquireDispatcherDatabaseLockAtDpcLevel(VOID); -VOID inline FASTCALL KeReleaseDispatcherDatabaseLock(KIRQL Irql); -VOID inline FASTCALL KeReleaseDispatcherDatabaseLockFromDpcLevel(VOID); +KIRQL KeAcquireDispatcherDatabaseLock(VOID); +VOID KeAcquireDispatcherDatabaseLockAtDpcLevel(VOID); +VOID KeReleaseDispatcherDatabaseLock(KIRQL Irql); +VOID KeReleaseDispatcherDatabaseLockFromDpcLevel(VOID); BOOLEAN KiDispatcherObjectWake(DISPATCHER_HEADER* hdr, KPRIORITY increment); VOID STDCALL KeExpireTimers(PKDPC Apc, PVOID Arg1, PVOID Arg2, PVOID Arg3); -VOID inline FASTCALL KeInitializeDispatcherHeader(DISPATCHER_HEADER* Header, ULONG Type, +VOID KeInitializeDispatcherHeader(DISPATCHER_HEADER* Header, ULONG Type, ULONG Size, ULONG SignalState); VOID KeDumpStackFrames(PULONG Frame); BOOLEAN KiTestAlert(VOID); -VOID FASTCALL KiAbortWaitThread(struct _KTHREAD* Thread, NTSTATUS WaitStatus); - -BOOLEAN STDCALL KiInsertTimer(PKTIMER Timer, LARGE_INTEGER DueTime); - -VOID inline FASTCALL KiSatisfyObjectWait(PDISPATCHER_HEADER Object, PKTHREAD Thread); - -BOOLEAN inline FASTCALL KiIsObjectSignaled(PDISPATCHER_HEADER Object, PKTHREAD Thread); - -VOID inline FASTCALL KiSatisifyMultipleObjectWaits(PKWAIT_BLOCK WaitBlock); - -VOID FASTCALL KiWaitTest(PDISPATCHER_HEADER Object, KPRIORITY Increment); +BOOLEAN KiAbortWaitThread(struct _KTHREAD* Thread, NTSTATUS WaitStatus); PULONG KeGetStackTopThread(struct _ETHREAD* Thread); VOID KeContextToTrapFrame(PCONTEXT Context, PKTRAP_FRAME TrapFrame); VOID STDCALL KiDeliverApc(KPROCESSOR_MODE PreviousMode, PVOID Reserved, PKTRAP_FRAME TrapFrame); - -VOID STDCALL KeInitializeEventPair(PKEVENT_PAIR EventPair); -VOID STDCALL KiInitializeUserApc(IN PVOID Reserved, +VOID KiInitializeUserApc(IN PVOID Reserved, IN PKTRAP_FRAME TrapFrame, IN PKNORMAL_ROUTINE NormalRoutine, IN PVOID NormalContext, @@ -206,7 +183,6 @@ STDCALL KeTestAlertThread(IN KPROCESSOR_MODE AlertMode); BOOLEAN STDCALL KeRemoveQueueApc (PKAPC Apc); -VOID FASTCALL KiWakeQueue(IN PKQUEUE Queue); PLIST_ENTRY STDCALL KeRundownQueue(IN PKQUEUE Queue); extern LARGE_INTEGER SystemBootTime; @@ -218,7 +194,7 @@ VOID KeInitInterrupts(VOID); VOID KeInitTimer(VOID); VOID KeInitDpc(struct _KPCR* Pcr); VOID KeInitDispatcher(VOID); -VOID inline FASTCALL KeInitializeDispatcher(VOID); +VOID KeInitializeDispatcher(VOID); VOID KiInitializeSystemClock(VOID); VOID KeInitializeBugCheck(VOID); VOID Phase1Initialization(PVOID Context); diff --git a/reactos/ntoskrnl/include/internal/nls.h b/reactos/ntoskrnl/include/internal/nls.h index 84787cba712..46906e37767 100644 --- a/reactos/ntoskrnl/include/internal/nls.h +++ b/reactos/ntoskrnl/include/internal/nls.h @@ -29,7 +29,6 @@ extern ULONG NlsUnicodeTableOffset; extern PUSHORT NlsUnicodeUpcaseTable; extern PUSHORT NlsUnicodeLowercaseTable; -VOID STDCALL RtlpInitNls(VOID); VOID RtlpImportAnsiCodePage(PUSHORT TableBase, ULONG Size); VOID RtlpImportOemCodePage(PUSHORT TableBase, ULONG Size); VOID RtlpImportUnicodeCasemap(PUSHORT TableBase, ULONG Size); diff --git a/reactos/ntoskrnl/include/internal/ntoskrnl.h b/reactos/ntoskrnl/include/internal/ntoskrnl.h index 972b42a09e8..a98537fe3c0 100644 --- a/reactos/ntoskrnl/include/internal/ntoskrnl.h +++ b/reactos/ntoskrnl/include/internal/ntoskrnl.h @@ -49,12 +49,10 @@ VOID ExpInitializeProfileImplementation(VOID); */ VOID MmInitSystem(ULONG Phase, PLOADER_PARAMETER_BLOCK LoaderBlock, ULONG LastKernelAddress); VOID IoInit(VOID); -VOID IoInit2(BOOLEAN BootLog); -VOID STDCALL IoInit3(VOID); +VOID IoInit2(VOID); VOID ObInit(VOID); VOID PsInit(VOID); VOID CmInitializeRegistry(VOID); -VOID STDCALL CmInitHives(BOOLEAN SetupBoot); VOID CmInit2(PCHAR CommandLine); VOID CmShutdownRegistry(VOID); BOOLEAN CmImportSystemHive(PCHAR ChunkBase, ULONG ChunkSize); diff --git a/reactos/ntoskrnl/include/internal/ps.h b/reactos/ntoskrnl/include/internal/ps.h index c954fb7adc1..1be0eeefe19 100644 --- a/reactos/ntoskrnl/include/internal/ps.h +++ b/reactos/ntoskrnl/include/internal/ps.h @@ -498,9 +498,7 @@ VOID STDCALL PsExitSpecialApc(PKAPC Apc, VOID -STDCALL KeInitializeThread(PKPROCESS Process, PKTHREAD Thread, BOOLEAN First); - NTSTATUS KeReleaseThread(PKTHREAD Thread); VOID @@ -527,11 +525,8 @@ VOID PsUnfreezeProcessThreads(PEPROCESS Process); ULONG PsEnumThreadsByProcess(PEPROCESS Process); PEPROCESS PsGetNextProcess(PEPROCESS OldProcess); VOID -STDCALL -PsBlockThread(PNTSTATUS Status, - UCHAR Alertable, - ULONG WaitMode, - UCHAR WaitReason); +PsBlockThread(PNTSTATUS Status, UCHAR Alertable, ULONG WaitMode, + BOOLEAN DispatcherLock, KIRQL WaitIrql, UCHAR WaitReason); VOID PsUnblockThread(PETHREAD Thread, PNTSTATUS WaitStatus, KPRIORITY Increment); VOID diff --git a/reactos/ntoskrnl/io/bootlog.c b/reactos/ntoskrnl/io/bootlog.c index 9324dd9f6de..71dc17b194a 100644 --- a/reactos/ntoskrnl/io/bootlog.c +++ b/reactos/ntoskrnl/io/bootlog.c @@ -27,14 +27,13 @@ static ERESOURCE IopBootLogResource; /* FUNCTIONS ****************************************************************/ VOID INIT_FUNCTION -IopInitBootLog(BOOLEAN StartBootLog) +IopInitBootLog(VOID) { ExInitializeResourceLite(&IopBootLogResource); - if (StartBootLog) IopStartBootLog(); } -VOID INIT_FUNCTION +VOID IopStartBootLog(VOID) { IopBootLogCreate = TRUE; diff --git a/reactos/ntoskrnl/io/create.c b/reactos/ntoskrnl/io/create.c index 6a2919e630e..b507fc51f93 100644 --- a/reactos/ntoskrnl/io/create.c +++ b/reactos/ntoskrnl/io/create.c @@ -176,7 +176,7 @@ IopCreateFile(PVOID ObjectBody, FileObject, DeviceObject); FileObject->Vpb = DeviceObject->Vpb; - FileObject->Type = IO_TYPE_FILE; + FileObject->Type = InternalFileType; return(STATUS_SUCCESS); } @@ -240,7 +240,7 @@ IoCreateStreamFileObject(PFILE_OBJECT FileObject, CreatedFileObject->DeviceObject = DeviceObject->Vpb->DeviceObject; CreatedFileObject->Vpb = DeviceObject->Vpb; - CreatedFileObject->Type = IO_TYPE_FILE; + CreatedFileObject->Type = InternalFileType; CreatedFileObject->Flags |= FO_DIRECT_DEVICE_OPEN; // shouldn't we initialize the lock event, and several other things here too? diff --git a/reactos/ntoskrnl/io/driver.c b/reactos/ntoskrnl/io/driver.c index 9e29e1cbef3..7cab4e63911 100644 --- a/reactos/ntoskrnl/io/driver.c +++ b/reactos/ntoskrnl/io/driver.c @@ -160,7 +160,7 @@ IopCreateDriver( RtlZeroMemory(Object->DriverExtension, sizeof(DRIVER_EXTENSION)); - Object->Type = IO_TYPE_DRIVER; + Object->Type = InternalDriverType; for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) Object->MajorFunction[i] = IopInvalidDeviceRequest; diff --git a/reactos/ntoskrnl/io/iocomp.c b/reactos/ntoskrnl/io/iocomp.c index d52fcc4f79f..de412e59036 100644 --- a/reactos/ntoskrnl/io/iocomp.c +++ b/reactos/ntoskrnl/io/iocomp.c @@ -1,4 +1,5 @@ -/* +/* $Id$ + * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * FILE: ntoskrnl/io/iocomp.c @@ -17,327 +18,372 @@ POBJECT_TYPE ExIoCompletionType; -NPAGED_LOOKASIDE_LIST IoCompletionPacketLookaside; +NPAGED_LOOKASIDE_LIST IoCompletionPacketLookaside; static GENERIC_MAPPING ExIoCompletionMapping = { - STANDARD_RIGHTS_READ | IO_COMPLETION_QUERY_STATE, - STANDARD_RIGHTS_WRITE | IO_COMPLETION_MODIFY_STATE, - STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE | IO_COMPLETION_QUERY_STATE, - IO_COMPLETION_ALL_ACCESS + STANDARD_RIGHTS_READ | IO_COMPLETION_QUERY_STATE, + STANDARD_RIGHTS_WRITE | IO_COMPLETION_MODIFY_STATE, + STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE | IO_COMPLETION_QUERY_STATE, + IO_COMPLETION_ALL_ACCESS }; /* FUNCTIONS *****************************************************************/ -VOID +NTSTATUS STDCALL +IopCreateIoCompletion( + PVOID ObjectBody, + PVOID Parent, + PWSTR RemainingPath, + POBJECT_ATTRIBUTES ObjectAttributes + ) +{ + DPRINT("IopCreateIoCompletion(ObjectBody %x, Parent %x, RemainingPath %S)\n", + ObjectBody, Parent, RemainingPath); + + if (RemainingPath != NULL && wcschr(RemainingPath+1, '\\') != NULL) + { + return STATUS_UNSUCCESSFUL; + } + + return STATUS_SUCCESS; +} + +VOID STDCALL IopDeleteIoCompletion(PVOID ObjectBody) { - PKQUEUE Queue = ObjectBody; - PLIST_ENTRY FirstEntry; - PLIST_ENTRY CurrentEntry; - PIO_COMPLETION_PACKET Packet; - - DPRINT("IopDeleteIoCompletion()\n"); - - /* Rundown the Queue */ - FirstEntry = KeRundownQueue(Queue); - - /* Clean up the IRPs */ - if (FirstEntry) { - - CurrentEntry = FirstEntry; - do { - - /* Get the Packet */ - Packet = CONTAINING_RECORD(CurrentEntry, IO_COMPLETION_PACKET, ListEntry); - - /* Go to next Entry */ - CurrentEntry = CurrentEntry->Flink; - - /* Free it */ - ExFreeToNPagedLookasideList(&IoCompletionPacketLookaside, Packet); - } while (FirstEntry != CurrentEntry); - } + PKQUEUE Queue = ObjectBody; + + DPRINT("IopDeleteIoCompletion()\n"); + + KeRundownQueue(Queue); } + /* - * @implemented + * @unimplemented */ NTSTATUS STDCALL -IoSetIoCompletion(IN PVOID IoCompletion, - IN PVOID KeyContext, - IN PVOID ApcContext, - IN NTSTATUS IoStatus, - IN ULONG_PTR IoStatusInformation, - IN BOOLEAN Quota) +IoSetCompletionRoutineEx( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PIO_COMPLETION_ROUTINE CompletionRoutine, + IN PVOID Context, + IN BOOLEAN InvokeOnSuccess, + IN BOOLEAN InvokeOnError, + IN BOOLEAN InvokeOnCancel + ) { - PKQUEUE Queue = (PKQUEUE)IoCompletion; - PIO_COMPLETION_PACKET Packet; - - /* Allocate the Packet */ - Packet = ExAllocateFromNPagedLookasideList(&IoCompletionPacketLookaside); - if (NULL == Packet) return STATUS_NO_MEMORY; - - /* Set up the Packet */ - Packet->Key = KeyContext; - Packet->Context = ApcContext; - Packet->IoStatus.Status = IoStatus; - Packet->IoStatus.Information = IoStatusInformation; - - /* Insert the Queue */ - KeInsertQueue(Queue, &Packet->ListEntry); - - /* Return Success */ - return STATUS_SUCCESS; + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; } /* - * @unimplemented + * @implemented */ NTSTATUS STDCALL -IoSetCompletionRoutineEx(IN PDEVICE_OBJECT DeviceObject, - IN PIRP Irp, - IN PIO_COMPLETION_ROUTINE CompletionRoutine, - IN PVOID Context, - IN BOOLEAN InvokeOnSuccess, - IN BOOLEAN InvokeOnError, - IN BOOLEAN InvokeOnCancel) +IoSetIoCompletion ( + IN PVOID IoCompletion, + IN PVOID KeyContext, + IN PVOID ApcContext, + IN NTSTATUS IoStatus, + IN ULONG_PTR IoStatusInformation, + IN BOOLEAN Quota + ) { - UNIMPLEMENTED; - return STATUS_NOT_IMPLEMENTED; + PKQUEUE Queue = (PKQUEUE) IoCompletion; + PIO_COMPLETION_PACKET Packet; + + Packet = ExAllocateFromNPagedLookasideList(&IoCompletionPacketLookaside); + if (NULL == Packet) + { + return STATUS_NO_MEMORY; + } + + Packet->Key = KeyContext; + Packet->Context = ApcContext; + Packet->IoStatus.Status = IoStatus; + Packet->IoStatus.Information = IoStatusInformation; + + KeInsertQueue(Queue, &Packet->ListEntry); + + return STATUS_SUCCESS; } VOID FASTCALL IopInitIoCompletionImplementation(VOID) { - /* Create the IO Completion Type */ - ExIoCompletionType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE)); - RtlpCreateUnicodeString(&ExIoCompletionType->TypeName, L"IoCompletion", NonPagedPool); - ExIoCompletionType->Tag = IOC_TAG; - ExIoCompletionType->PeakObjects = 0; - ExIoCompletionType->PeakHandles = 0; - ExIoCompletionType->TotalObjects = 0; - ExIoCompletionType->TotalHandles = 0; - ExIoCompletionType->PagedPoolCharge = 0; - ExIoCompletionType->NonpagedPoolCharge = sizeof(KQUEUE); - ExIoCompletionType->Mapping = &ExIoCompletionMapping; - ExIoCompletionType->Dump = NULL; - ExIoCompletionType->Open = NULL; - ExIoCompletionType->Close = NULL; - ExIoCompletionType->Delete = IopDeleteIoCompletion; - ExIoCompletionType->Parse = NULL; - ExIoCompletionType->Security = NULL; - ExIoCompletionType->QueryName = NULL; - ExIoCompletionType->OkayToClose = NULL; - ExIoCompletionType->Create = NULL; - ExIoCompletionType->DuplicationNotify = NULL; - - /* Initialize the Lookaside List we'll use for packets */ - ExInitializeNPagedLookasideList(&IoCompletionPacketLookaside, - NULL, - NULL, - 0, - sizeof(IO_COMPLETION_PACKET), - IOC_TAG, - 0); + ExIoCompletionType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE)); + + RtlpCreateUnicodeString(&ExIoCompletionType->TypeName, L"IoCompletion", NonPagedPool); + + ExIoCompletionType->Tag = IOC_TAG; + ExIoCompletionType->PeakObjects = 0; + ExIoCompletionType->PeakHandles = 0; + ExIoCompletionType->TotalObjects = 0; + ExIoCompletionType->TotalHandles = 0; + ExIoCompletionType->PagedPoolCharge = 0; + ExIoCompletionType->NonpagedPoolCharge = sizeof(KQUEUE); + ExIoCompletionType->Mapping = &ExIoCompletionMapping; + ExIoCompletionType->Dump = NULL; + ExIoCompletionType->Open = NULL; + ExIoCompletionType->Close = NULL; + ExIoCompletionType->Delete = IopDeleteIoCompletion; + ExIoCompletionType->Parse = NULL; + ExIoCompletionType->Security = NULL; + ExIoCompletionType->QueryName = NULL; + ExIoCompletionType->OkayToClose = NULL; + ExIoCompletionType->Create = IopCreateIoCompletion; + ExIoCompletionType->DuplicationNotify = NULL; + + ExInitializeNPagedLookasideList(&IoCompletionPacketLookaside, + NULL, + NULL, + 0, + sizeof(IO_COMPLETION_PACKET), + IOC_TAG, + 0); } + NTSTATUS STDCALL -NtCreateIoCompletion(OUT PHANDLE IoCompletionHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes, - IN ULONG NumberOfConcurrentThreads) +NtCreateIoCompletion( + OUT PHANDLE IoCompletionHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN ULONG NumberOfConcurrentThreads + ) { - PKQUEUE Queue; - NTSTATUS Status; - KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); - - /* Create the Object */ - Status = ObCreateObject(PreviousMode, - ExIoCompletionType, - ObjectAttributes, - PreviousMode, - NULL, - sizeof(KQUEUE), - 0, - 0, - (PVOID*)&Queue); - - /* Check for success */ - if (!NT_SUCCESS(Status)) { - - /* Initialize the Queue */ - KeInitializeQueue(Queue, NumberOfConcurrentThreads); - - /* Insert it */ - Status = ObInsertObject(Queue, - NULL, - DesiredAccess, - 0, - NULL, - IoCompletionHandle); - ObDereferenceObject(Queue); + PKQUEUE Queue; + NTSTATUS Status; + + Status = ObCreateObject(ExGetPreviousMode(), + ExIoCompletionType, + ObjectAttributes, + ExGetPreviousMode(), + NULL, + sizeof(KQUEUE), + 0, + 0, + (PVOID*)&Queue); + if (!NT_SUCCESS(Status)) + { + return Status; } - - /* Return Status */ + + Status = ObInsertObject ((PVOID)Queue, + NULL, + DesiredAccess, + 0, + NULL, + IoCompletionHandle); + if (!NT_SUCCESS(Status)) + { + ObDereferenceObject(Queue); + return Status; + } + + KeInitializeQueue(Queue, NumberOfConcurrentThreads); + ObDereferenceObject(Queue); + return STATUS_SUCCESS; + /* + + CompletionPort = NULL OR ExistingCompletionPort + + */ + + } +/* +DesiredAccess: +ZERO +IO_COMPLETION_QUERY_STATE Query access +IO_COMPLETION_MODIFY_STATE Modify access +IO_COMPLETION_ALL_ACCESS All of the preceding + STANDARD_RIGHTS_ALL + +ObjectAttributes +OBJ_OPENLINK and OBJ_PERMANENT are not valid attributes + +Return Value +STATUS_SUCCESS or an error status, such as STATUS_ACCESS_DENIED or +STATUS_OBJECT_NAME_NOT_FOUND. +*/ NTSTATUS STDCALL -NtOpenIoCompletion(OUT PHANDLE IoCompletionHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes) +NtOpenIoCompletion( + OUT PHANDLE IoCompletionHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes + ) { - NTSTATUS Status; - KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); - - /* Open the Object */ - Status = ObOpenObjectByName(ObjectAttributes, - ExIoCompletionType, - NULL, - PreviousMode, - DesiredAccess, - NULL, - IoCompletionHandle); - - /* Return Status */ - return Status; + NTSTATUS Status; + + Status = ObOpenObjectByName(ObjectAttributes, + ExIoCompletionType, + NULL, + UserMode, + DesiredAccess, + NULL, + IoCompletionHandle); //<- ??? + + return Status; } + NTSTATUS STDCALL -NtQueryIoCompletion(IN HANDLE IoCompletionHandle, - IN IO_COMPLETION_INFORMATION_CLASS IoCompletionInformationClass, - OUT PVOID IoCompletionInformation, - IN ULONG IoCompletionInformationLength, - OUT PULONG ResultLength OPTIONAL) +NtQueryIoCompletion( + IN HANDLE IoCompletionHandle, + IN IO_COMPLETION_INFORMATION_CLASS IoCompletionInformationClass, + OUT PVOID IoCompletionInformation, + IN ULONG IoCompletionInformationLength, + OUT PULONG ResultLength OPTIONAL + ) { - PKQUEUE Queue; - NTSTATUS Status; - KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); + PKQUEUE Queue; + NTSTATUS Status; - /* Get the Object */ - Status = ObReferenceObjectByHandle(IoCompletionHandle, + if (IoCompletionInformationClass != IoCompletionBasicInformation) + { + return STATUS_INVALID_INFO_CLASS; + } + if (IoCompletionInformationLength < sizeof(IO_COMPLETION_BASIC_INFORMATION)) + { + return STATUS_INFO_LENGTH_MISMATCH; + } + + Status = ObReferenceObjectByHandle( IoCompletionHandle, IO_COMPLETION_QUERY_STATE, ExIoCompletionType, - PreviousMode, + UserMode, (PVOID*)&Queue, NULL); - - /* Check for Success */ - if (NT_SUCCESS(Status)) { - - /* Return Info */ - ((PIO_COMPLETION_BASIC_INFORMATION)IoCompletionInformation)->Depth = KeReadStateQueue(Queue); - ObDereferenceObject(Queue); + if (NT_SUCCESS(Status)) + { + ((PIO_COMPLETION_BASIC_INFORMATION)IoCompletionInformation)->Depth = + Queue->Header.SignalState; - /* Return Result Length if needed */ - if (ResultLength) *ResultLength = sizeof(IO_COMPLETION_BASIC_INFORMATION); - } + ObDereferenceObject(Queue); - /* Return Status */ - return Status; + if (ResultLength) *ResultLength = sizeof(IO_COMPLETION_BASIC_INFORMATION); + } + + return Status; } + /* * Dequeues an I/O completion message from an I/O completion object */ NTSTATUS STDCALL -NtRemoveIoCompletion(IN HANDLE IoCompletionHandle, - OUT PVOID *CompletionKey, - OUT PVOID *CompletionContext, - OUT PIO_STATUS_BLOCK IoStatusBlock, - IN PLARGE_INTEGER Timeout OPTIONAL) +NtRemoveIoCompletion( + IN HANDLE IoCompletionHandle, + OUT PVOID *CompletionKey, + OUT PVOID *CompletionContext, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN PLARGE_INTEGER Timeout OPTIONAL + ) { - PKQUEUE Queue; - NTSTATUS Status; - PIO_COMPLETION_PACKET Packet; - PLIST_ENTRY ListEntry; - KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); - - /* Open the Object */ - Status = ObReferenceObjectByHandle(IoCompletionHandle, + PKQUEUE Queue; + NTSTATUS Status; + PIO_COMPLETION_PACKET Packet; + PLIST_ENTRY ListEntry; + + Status = ObReferenceObjectByHandle( IoCompletionHandle, IO_COMPLETION_MODIFY_STATE, ExIoCompletionType, - PreviousMode, + UserMode, (PVOID*)&Queue, NULL); - - /* Check for success */ - if (NT_SUCCESS(Status)) { - - /* Remove queue */ - ListEntry = KeRemoveQueue(Queue, PreviousMode, Timeout); - - /* If we got a timeout or user_apc back, return the status */ - if ((NTSTATUS)ListEntry == STATUS_TIMEOUT || (NTSTATUS)ListEntry == STATUS_USER_APC) { - - Status = (NTSTATUS)ListEntry; - - } else { - - /* Get the Packet Data */ - Packet = CONTAINING_RECORD(ListEntry, IO_COMPLETION_PACKET, ListEntry); - - /* Return it */ - if (CompletionKey) *CompletionKey = Packet->Key; - if (CompletionContext) *CompletionContext = Packet->Context; - if (IoStatusBlock) *IoStatusBlock = Packet->IoStatus; - - /* Free packet */ - ExFreeToNPagedLookasideList(&IoCompletionPacketLookaside, Packet); - } + if (!NT_SUCCESS(Status)) + { + return Status; + } + + /* + Try 2 remove packet from queue. Wait (optionaly) if + no packet in queue or max num of threads allready running. + */ + + do { + + ListEntry = KeRemoveQueue(Queue, UserMode, Timeout ); + + /* Nebbets book says nothing about NtRemoveIoCompletion returning STATUS_USER_APC, + and the umode equivalent GetQueuedCompletionStatus says nothing about this either, + so my guess it we should restart the operation. Need further investigation. -Gunnar + */ + + } while((NTSTATUS)ListEntry == STATUS_USER_APC); + + ObDereferenceObject(Queue); + + if ((NTSTATUS)ListEntry == STATUS_TIMEOUT) + { + return STATUS_TIMEOUT; + } + + ASSERT(ListEntry); - /* Dereference the Object */ - ObDereferenceObject(Queue); - } - - /* Return status */ - return Status; + Packet = CONTAINING_RECORD(ListEntry, IO_COMPLETION_PACKET, ListEntry); + + if (CompletionKey) *CompletionKey = Packet->Key; + if (CompletionContext) *CompletionContext = Packet->Context; + if (IoStatusBlock) *IoStatusBlock = Packet->IoStatus; + + ExFreeToNPagedLookasideList(&IoCompletionPacketLookaside, Packet); + + return STATUS_SUCCESS; } + +/* +ASSOSIERT MED FOB's IoCompletionContext + +typedef struct _IO_COMPLETION_CONTEXT { + PVOID Port; + ULONG Key; +} IO_COMPLETION_CONTEXT, *PIO_COMPLETION_CONTEXT; + +*/ + + /* * Queues an I/O completion message to an I/O completion object */ NTSTATUS STDCALL -NtSetIoCompletion(IN HANDLE IoCompletionPortHandle, - IN PVOID CompletionKey, - IN PVOID CompletionContext, - IN NTSTATUS CompletionStatus, - IN ULONG CompletionInformation) +NtSetIoCompletion( + IN HANDLE IoCompletionPortHandle, + IN PVOID CompletionKey, + IN PVOID CompletionContext, + IN NTSTATUS CompletionStatus, + IN ULONG CompletionInformation + ) { - NTSTATUS Status; - PKQUEUE Queue; - - /* Get the Object */ - Status = ObReferenceObjectByHandle(IoCompletionPortHandle, + NTSTATUS Status; + PKQUEUE Queue; + + Status = ObReferenceObjectByHandle( IoCompletionPortHandle, IO_COMPLETION_MODIFY_STATE, ExIoCompletionType, - ExGetPreviousMode(), + UserMode, (PVOID*)&Queue, NULL); - - /* Check for Success */ - if (NT_SUCCESS(Status)) { - - /* Set the Completion */ - Status = IoSetIoCompletion(Queue, - CompletionKey, - CompletionContext, - CompletionStatus, - CompletionInformation, - TRUE); - ObDereferenceObject(Queue); - } - - /* Return status */ - return Status; + if (NT_SUCCESS(Status)) + { + Status = IoSetIoCompletion(Queue, CompletionKey, CompletionContext, + CompletionStatus, CompletionInformation, TRUE); + ObDereferenceObject(Queue); + } + + return Status; } diff --git a/reactos/ntoskrnl/io/iomgr.c b/reactos/ntoskrnl/io/iomgr.c index 4cc4d60acfa..81852d21362 100644 --- a/reactos/ntoskrnl/io/iomgr.c +++ b/reactos/ntoskrnl/io/iomgr.c @@ -553,17 +553,14 @@ IoInit (VOID) } -VOID -INIT_FUNCTION -IoInit2(BOOLEAN BootLog) +VOID INIT_FUNCTION +IoInit2(VOID) { PDEVICE_NODE DeviceNode; PDRIVER_OBJECT DriverObject; MODULE_OBJECT ModuleObject; NTSTATUS Status; - IoCreateDriverList(); - KeInitializeSpinLock (&IoStatisticsLock); /* Initialize raw filesystem driver */ @@ -608,56 +605,6 @@ IoInit2(BOOLEAN BootLog) IopInvalidateDeviceRelations( IopRootDeviceNode, BusRelations); - - /* Start boot logging */ - IopInitBootLog(BootLog); - - /* Load boot start drivers */ - IopInitializeBootDrivers(); -} - -VOID -STDCALL -INIT_FUNCTION -IoInit3(VOID) -{ - NTSTATUS Status; - - /* Create ARC names for boot devices */ - IoCreateArcNames(); - - /* Create the SystemRoot symbolic link */ - CPRINT("CommandLine: %s\n", (PCHAR)KeLoaderBlock.CommandLine); - Status = IoCreateSystemRootLink((PCHAR)KeLoaderBlock.CommandLine); - if (!NT_SUCCESS(Status)) { - DbgPrint("IoCreateSystemRootLink FAILED: (0x%x) - ", Status); - DbgPrintErrorMessage (Status); - KEBUGCHECK(INACCESSIBLE_BOOT_DEVICE); - } - - /* Start Profiling on a Debug Build */ -#if defined(KDBG) || defined(DBG) - KdbInitProfiling2(); -#endif /* KDBG */ - - /* I/O is now setup for disk access, so start the debugging logger thread. */ - if ((KdDebuggerEnabled == TRUE) && (KdDebugState & KD_DEBUG_BOOTLOG)) DebugLogInit2(); - - /* Load services for devices found by PnP manager */ - IopInitializePnpServices(IopRootDeviceNode, FALSE); - - /* Load system start drivers */ - IopInitializeSystemDrivers(); - IoDestroyDriverList(); - - /* Stop boot logging */ - IopStopBootLog(); - - /* Assign drive letters */ - IoAssignDriveLetters((PLOADER_PARAMETER_BLOCK)&KeLoaderBlock, - NULL, - NULL, - NULL); } /* diff --git a/reactos/ntoskrnl/io/wmi.c b/reactos/ntoskrnl/io/wmi.c index 9d01c6b1f55..8b9088270f5 100644 --- a/reactos/ntoskrnl/io/wmi.c +++ b/reactos/ntoskrnl/io/wmi.c @@ -249,18 +249,4 @@ IoWMIDeviceObjectToInstanceName( return STATUS_NOT_IMPLEMENTED; } -/* - * @unimplemented - */ -NTSTATUS -STDCALL -NtTraceEvent(IN ULONG TraceHandle, - IN ULONG Flags, - IN ULONG TraceHeaderLength, - IN struct _EVENT_TRACE_HEADER* TraceHeader) -{ - UNIMPLEMENTED; - return STATUS_NOT_IMPLEMENTED; -} - /*Eof*/ diff --git a/reactos/ntoskrnl/ke/alert.c b/reactos/ntoskrnl/ke/alert.c new file mode 100644 index 00000000000..99084a862e4 --- /dev/null +++ b/reactos/ntoskrnl/ke/alert.c @@ -0,0 +1,150 @@ +/* $Id:$ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: ntoskrnl/ke/alert.c + * PURPOSE: Alerts + * + * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) + */ + +/* INCLUDES *****************************************************************/ + +#include +#define NDEBUG +#include + +/* GLOBALS *******************************************************************/ + + +/* FUNCTIONS *****************************************************************/ + + +BOOLEAN +STDCALL +KeTestAlertThread(IN KPROCESSOR_MODE AlertMode) +/* + * FUNCTION: Tests whether there are any pending APCs for the current thread + * and if so the APCs will be delivered on exit from kernel mode + */ +{ + KIRQL OldIrql; + PKTHREAD Thread = KeGetCurrentThread(); + BOOLEAN OldState; + + ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); + + OldIrql = KeAcquireDispatcherDatabaseLock(); + KiAcquireSpinLock(&Thread->ApcQueueLock); + + OldState = Thread->Alerted[AlertMode]; + + /* If the Thread is Alerted, Clear it */ + if (OldState) { + Thread->Alerted[AlertMode] = FALSE; + } else if ((AlertMode == UserMode) && (!IsListEmpty(&Thread->ApcState.ApcListHead[UserMode]))) { + /* If the mode is User and the Queue isn't empty, set Pending */ + Thread->ApcState.UserApcPending = TRUE; + } + + KiReleaseSpinLock(&Thread->ApcQueueLock); + KeReleaseDispatcherDatabaseLock(OldIrql); + return OldState; +} + + +VOID +KeAlertThread(PKTHREAD Thread, KPROCESSOR_MODE AlertMode) +{ + KIRQL oldIrql; + + + oldIrql = KeAcquireDispatcherDatabaseLock(); + + + /* Return if thread is already alerted. */ + if (Thread->Alerted[AlertMode] == FALSE) + { + if (Thread->State == THREAD_STATE_BLOCKED && + (AlertMode == KernelMode || Thread->WaitMode == AlertMode) && + Thread->Alertable) + { + KiAbortWaitThread(Thread, STATUS_ALERTED); + } + else + { + Thread->Alerted[AlertMode] = TRUE; + } + } + + KeReleaseDispatcherDatabaseLock(oldIrql); + +} + + +/* + * + * NOT EXPORTED + */ +NTSTATUS STDCALL +NtAlertResumeThread(IN HANDLE ThreadHandle, + OUT PULONG SuspendCount) +{ + UNIMPLEMENTED; + return(STATUS_NOT_IMPLEMENTED); + +} + +/* + * @implemented + * + * EXPORTED + */ +NTSTATUS STDCALL +NtAlertThread (IN HANDLE ThreadHandle) +{ + KPROCESSOR_MODE PreviousMode; + PETHREAD Thread; + NTSTATUS Status; + + PreviousMode = ExGetPreviousMode(); + + Status = ObReferenceObjectByHandle(ThreadHandle, + THREAD_SUSPEND_RESUME, + PsThreadType, + PreviousMode, + (PVOID*)&Thread, + NULL); + if (!NT_SUCCESS(Status)) + { + return(Status); + } + + /* do an alert depending on the processor mode. If some kmode code wants to + enforce a umode alert it should call KeAlertThread() directly. If kmode + code wants to do a kmode alert it's sufficient to call it with Zw or just + use KeAlertThread() directly */ + + KeAlertThread(&Thread->Tcb, PreviousMode); + + ObDereferenceObject(Thread); + return(STATUS_SUCCESS); +} + + +/* + * NOT EXPORTED + */ +NTSTATUS +STDCALL +NtTestAlert(VOID) +{ + KPROCESSOR_MODE PreviousMode; + + PreviousMode = ExGetPreviousMode(); + + /* Check and Alert Thread if needed */ + + return KeTestAlertThread(PreviousMode) ? STATUS_ALERTED : STATUS_SUCCESS; +} + diff --git a/reactos/ntoskrnl/ke/apc.c b/reactos/ntoskrnl/ke/apc.c index 04d9786b5fb..5b47908713f 100644 --- a/reactos/ntoskrnl/ke/apc.c +++ b/reactos/ntoskrnl/ke/apc.c @@ -1,4 +1,5 @@ -/* +/* $Id$ + * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * FILE: ntoskrnl/ke/apc.c @@ -18,820 +19,581 @@ VOID PsTerminateCurrentThread(NTSTATUS ExitStatus); -/* FUNCTIONS *****************************************************************/ +#define TAG_KAPC TAG('K', 'A', 'P', 'C') -/*++ - * KeEnterCriticalRegion - * @implemented NT4 - * - * The KeEnterCriticalRegion routine temporarily disables the delivery of - * normal kernel APCs; special kernel-mode APCs are still delivered. - * - * Params: - * None. - * - * Returns: - * None. - * - * Remarks: - * Highest-level drivers can call this routine while running in the context - * of the thread that requested the current I/O operation. Any caller of - * this routine should call KeLeaveCriticalRegion as quickly as possible. - * - * Callers of KeEnterCriticalRegion must be running at IRQL <= APC_LEVEL. - * - *--*/ -VOID -STDCALL -KeEnterCriticalRegion(VOID) -{ - /* Disable Kernel APCs */ - PKTHREAD Thread = KeGetCurrentThread(); - if (Thread) Thread->KernelApcDisable--; -} +/* FUNCTIONS *****************************************************************/ -/*++ - * KeInitializeApc - * @implemented NT4 - * - * The The KeInitializeApc routine initializes an APC object, and registers - * the Kernel, Rundown and Normal routines for that object. - * - * Params: - * Apc - Pointer to a KAPC structure that represents the APC object to - * initialize. The caller must allocate storage for the structure - * from resident memory. - * - * Thread - Thread to which to deliver the APC. - * - * TargetEnvironment - APC Environment to be used. - * - * KernelRoutine - Points to the KernelRoutine to associate with the APC. - * This routine is executed for all APCs. - * - * RundownRoutine - Points to the RundownRoutine to associate with the APC. - * This routine is executed when the Thread exists with - * the APC executing. - * - * NormalRoutine - Points to the NormalRoutine to associate with the APC. - * This routine is executed at PASSIVE_LEVEL. If this is - * not specifed, the APC becomes a Special APC and the - * Mode and Context parameters are ignored. - * - * Mode - Specifies the processor mode at which to run the Normal Routine. - * - * Context - Specifices the value to pass as Context parameter to the - * registered routines. - * - * Returns: - * None. - * - * Remarks: - * The caller can queue an initialized APC with KeInsertQueueApc. - * - * Storage for the APC object must be resident, such as nonpaged pool - * allocated by the caller. - * - * Callers of this routine must be running at IRQL = PASSIVE_LEVEL. - * - *--*/ +/* + * @implemented + */ VOID STDCALL -KeInitializeApc(IN PKAPC Apc, - IN PKTHREAD Thread, - IN KAPC_ENVIRONMENT TargetEnvironment, - IN PKKERNEL_ROUTINE KernelRoutine, - IN PKRUNDOWN_ROUTINE RundownRoutine OPTIONAL, - IN PKNORMAL_ROUTINE NormalRoutine, - IN KPROCESSOR_MODE Mode, - IN PVOID Context) +KeInitializeApc( + IN PKAPC Apc, + IN PKTHREAD Thread, + IN KAPC_ENVIRONMENT TargetEnvironment, + IN PKKERNEL_ROUTINE KernelRoutine, + IN PKRUNDOWN_ROUTINE RundownRoutine OPTIONAL, + IN PKNORMAL_ROUTINE NormalRoutine, + IN KPROCESSOR_MODE Mode, + IN PVOID Context) +/* + * FUNCTION: Initialize an APC object + * ARGUMENTS: + * Apc = Pointer to the APC object to initialized + * Thread = Thread the APC is to be delivered to + * TargetEnvironment = APC environment to use + * KernelRoutine = Routine to be called for a kernel-mode APC + * RundownRoutine = Routine to be called if the thread has exited with + * the APC being executed + * NormalRoutine = Routine to be called for a user-mode APC + * Mode = APC mode + * Context = Parameter to be passed to the APC routine + */ { - DPRINT("KeInitializeApc(Apc %x, Thread %x, Environment %d, " - "KernelRoutine %x, RundownRoutine %x, NormalRoutine %x, Mode %d, " - "Context %x)\n",Apc,Thread,TargetEnvironment,KernelRoutine,RundownRoutine, - NormalRoutine,Mode,Context); - - /* Set up the basic APC Structure Data */ - RtlZeroMemory(Apc, sizeof(KAPC)); - Apc->Type = ApcObject; - Apc->Size = sizeof(KAPC); - - /* Set the Environment */ - if (TargetEnvironment == CurrentApcEnvironment) { - - Apc->ApcStateIndex = Thread->ApcStateIndex; - - } else { - - Apc->ApcStateIndex = TargetEnvironment; - } - - /* Set the Thread and Routines */ - Apc->Thread = Thread; - Apc->KernelRoutine = KernelRoutine; - Apc->RundownRoutine = RundownRoutine; - Apc->NormalRoutine = NormalRoutine; + DPRINT ("KeInitializeApc(Apc %x, Thread %x, Environment %d, " + "KernelRoutine %x, RundownRoutine %x, NormalRoutine %x, Mode %d, " + "Context %x)\n",Apc,Thread,TargetEnvironment,KernelRoutine,RundownRoutine, + NormalRoutine,Mode,Context); + + /* Set up the basic APC Structure Data */ + RtlZeroMemory(Apc, sizeof(KAPC)); + Apc->Type = KApc; + Apc->Size = sizeof(KAPC); + + /* Set the Environment */ + if (TargetEnvironment == CurrentApcEnvironment) { + Apc->ApcStateIndex = Thread->ApcStateIndex; + } else { + Apc->ApcStateIndex = TargetEnvironment; + } + + /* Set the Thread and Routines */ + Apc->Thread = Thread; + Apc->KernelRoutine = KernelRoutine; + Apc->RundownRoutine = RundownRoutine; + Apc->NormalRoutine = NormalRoutine; - /* Check if this is a Special APC, in which case we use KernelMode and no Context */ - if (ARGUMENT_PRESENT(NormalRoutine)) { - - Apc->ApcMode = Mode; - Apc->NormalContext = Context; - - } else { - - Apc->ApcMode = KernelMode; - } + /* Check if this is a Special APC, in which case we use KernelMode and no Context */ + if (ARGUMENT_PRESENT(NormalRoutine)) { + Apc->ApcMode = Mode; + Apc->NormalContext = Context; + } else { + Apc->ApcMode = KernelMode; + } } -/*++ - * KeInsertQueueApc - * @implemented NT4 - * - * The KeInsertQueueApc routine queues a APC for execution when the right - * scheduler environment exists. - * - * Params: - * Apc - Pointer to an initialized control object of type DPC for which the - * caller provides the storage. - * - * SystemArgument[1,2] - Pointer to a set of two parameters that contain - * untyped data. - * - * PriorityBoost - Priority Boost to apply to the Thread. - * - * Returns: - * If the APC is already inserted or APC queueing is disabled, FALSE. - * Otherwise, TRUE. - * - * Remarks: - * The APC will execute at APC_LEVEL for the KernelRoutine registered, and - * at PASSIVE_LEVEL for the NormalRoutine registered. - * - * Callers of this routine must be running at IRQL = PASSIVE_LEVEL. - * - *--*/ +/* + * @implemented + */ BOOLEAN STDCALL -KeInsertQueueApc(PKAPC Apc, - PVOID SystemArgument1, - PVOID SystemArgument2, - KPRIORITY PriorityBoost) - +KeInsertQueueApc (PKAPC Apc, + PVOID SystemArgument1, + PVOID SystemArgument2, + KPRIORITY PriorityBoost) +/* + * FUNCTION: Queues an APC for execution + * ARGUMENTS: + * Apc = APC to be queued + * SystemArgument[1-2] = Arguments we ignore and simply pass on. + * PriorityBoost = Priority Boost to give to the Thread + */ { - KIRQL OldIrql; - PKTHREAD Thread; - PLIST_ENTRY ApcListEntry; - PKAPC QueuedApc; + KIRQL OldIrql; + PKTHREAD Thread; + PLIST_ENTRY ApcListEntry; + PKAPC QueuedApc; - ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); - DPRINT("KeInsertQueueApc(Apc %x, SystemArgument1 %x, " - "SystemArgument2 %x)\n",Apc,SystemArgument1, - SystemArgument2); - - /* Lock the Dispatcher Database */ - OldIrql = KeAcquireDispatcherDatabaseLock(); - - /* Get the Thread specified in the APC */ - Thread = Apc->Thread; - - /* Make sure the thread allows APC Queues. + ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); + DPRINT ("KeInsertQueueApc(Apc %x, SystemArgument1 %x, " + "SystemArgument2 %x)\n",Apc,SystemArgument1, + SystemArgument2); + + OldIrql = KeAcquireDispatcherDatabaseLock(); + + /* Get the Thread specified in the APC */ + Thread = Apc->Thread; + + /* Make sure the thread allows APC Queues. * The thread is not apc queueable, for instance, when it's (about to be) terminated. */ - if (Thread->ApcQueueable == FALSE) { - DPRINT("Thread doesn't allow APC Queues\n"); - KeReleaseDispatcherDatabaseLock(OldIrql); - return FALSE; - } - - /* Set the System Arguments */ - Apc->SystemArgument1 = SystemArgument1; - Apc->SystemArgument2 = SystemArgument2; - - /* Don't do anything if the APC is already inserted */ - if (Apc->Inserted) { - - KeReleaseDispatcherDatabaseLock(OldIrql); - return FALSE; - } - - /* Three scenarios: - 1) Kernel APC with Normal Routine or User APC = Put it at the end of the List - 2) User APC which is PsExitSpecialApc = Put it at the front of the List - 3) Kernel APC without Normal Routine = Put it at the end of the No-Normal Routine Kernel APC list - */ - if ((Apc->ApcMode != KernelMode) && (Apc->KernelRoutine == (PKKERNEL_ROUTINE)PsExitSpecialApc)) { - - DPRINT ("Inserting the Process Exit APC into the Queue\n"); - Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->UserApcPending = TRUE; - InsertHeadList(&Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode], - &Apc->ApcListEntry); - - } else if (Apc->NormalRoutine == NULL) { - - DPRINT ("Inserting Special APC %x into the Queue\n", Apc); - - for (ApcListEntry = Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode].Flink; - ApcListEntry != &Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode]; - ApcListEntry = ApcListEntry->Flink) { - - QueuedApc = CONTAINING_RECORD(ApcListEntry, KAPC, ApcListEntry); - if (Apc->NormalRoutine != NULL) break; - } - - /* We found the first "Normal" APC, so write right before it */ - ApcListEntry = ApcListEntry->Blink; - InsertHeadList(ApcListEntry, &Apc->ApcListEntry); - - } else { - - DPRINT ("Inserting Normal APC %x into the %x Queue\n", Apc, Apc->ApcMode); - InsertTailList(&Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode], - &Apc->ApcListEntry); - } - - /* Confirm Insertion */ - Apc->Inserted = TRUE; - - /* - * Three possibilites here again: - * 1) Kernel APC, The thread is Running: Request an Interrupt - * 2) Kernel APC, The Thread is Waiting at PASSIVE_LEVEL and APCs are enabled and not in progress: Unwait the Thread - * 3) User APC, Unwait the Thread if it is alertable - */ - if (Apc->ApcMode == KernelMode) { - - /* Set Kernel APC pending */ - Thread->ApcState.KernelApcPending = TRUE; - - /* Check the Thread State */ - if (Thread->State == THREAD_STATE_RUNNING) { - - /* FIXME: Use IPI */ - DPRINT ("Requesting APC Interrupt for Running Thread \n"); - HalRequestSoftwareInterrupt(APC_LEVEL); - - } else if ((Thread->State == THREAD_STATE_BLOCKED) && + if (Thread->ApcQueueable == FALSE) { + DPRINT("Thread doesn't allow APC Queues\n"); + KeReleaseDispatcherDatabaseLock(OldIrql); + return FALSE; + } + + /* Set the System Arguments */ + Apc->SystemArgument1 = SystemArgument1; + Apc->SystemArgument2 = SystemArgument2; + + /* Don't do anything if the APC is already inserted */ + if (Apc->Inserted) { + KeReleaseDispatcherDatabaseLock(OldIrql); + return FALSE; + } + + /* Three scenarios: + 1) Kernel APC with Normal Routine or User APC = Put it at the end of the List + 2) User APC which is PsExitSpecialApc = Put it at the front of the List + 3) Kernel APC without Normal Routine = Put it at the end of the No-Normal Routine Kernel APC list + */ + if ((Apc->ApcMode != KernelMode) && (Apc->KernelRoutine == (PKKERNEL_ROUTINE)PsExitSpecialApc)) { + DPRINT ("Inserting the Process Exit APC into the Queue\n"); + Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->UserApcPending = TRUE; + InsertHeadList(&Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode], + &Apc->ApcListEntry); + } else if (Apc->NormalRoutine == NULL) { + DPRINT ("Inserting Special APC %x into the Queue\n", Apc); + for (ApcListEntry = Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode].Flink; + ApcListEntry != &Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode]; + ApcListEntry = ApcListEntry->Flink) { + + QueuedApc = CONTAINING_RECORD(ApcListEntry, KAPC, ApcListEntry); + if (Apc->NormalRoutine != NULL) break; + } + + /* We found the first "Normal" APC, so write right before it */ + ApcListEntry = ApcListEntry->Blink; + InsertHeadList(ApcListEntry, &Apc->ApcListEntry); + } else { + DPRINT ("Inserting Normal APC %x into the %x Queue\n", Apc, Apc->ApcMode); + InsertTailList(&Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode], + &Apc->ApcListEntry); + } + + /* Confirm Insertion */ + Apc->Inserted = TRUE; + + /* Three possibilites here again: + 1) Kernel APC, The thread is Running: Request an Interrupt + 2) Kernel APC, The Thread is Waiting at PASSIVE_LEVEL and APCs are enabled and not in progress: Unwait the Thread + 3) User APC, Unwait the Thread if it is alertable + */ + if (Apc->ApcMode == KernelMode) { + Thread->ApcState.KernelApcPending = TRUE; + if (Thread->State == THREAD_STATE_RUNNING) { + /* FIXME: Use IPI */ + DPRINT ("Requesting APC Interrupt for Running Thread \n"); + HalRequestSoftwareInterrupt(APC_LEVEL); + } else if ((Thread->State == THREAD_STATE_BLOCKED) && (Thread->WaitIrql < APC_LEVEL) && - (Apc->NormalRoutine == NULL)) { - - DPRINT("Waking up Thread for Kernel-Mode APC Delivery \n"); - KiAbortWaitThread(Thread, STATUS_KERNEL_APC); - } - + (Apc->NormalRoutine == NULL)) + { + DPRINT ("Waking up Thread for Kernel-Mode APC Delivery \n"); + KiAbortWaitThread(Thread, STATUS_KERNEL_APC); + } } else if ((Thread->State == THREAD_STATE_BLOCKED) && (Thread->WaitMode == UserMode) && - (Thread->Alertable)) { - - DPRINT("Waking up Thread for User-Mode APC Delivery \n"); - Thread->ApcState.UserApcPending = TRUE; - KiAbortWaitThread(Thread, STATUS_USER_APC); - } - - /* Return Sucess if we are here */ - KeReleaseDispatcherDatabaseLock(OldIrql); - return TRUE; + (Thread->Alertable)) + { + DPRINT ("Waking up Thread for User-Mode APC Delivery \n"); + Thread->ApcState.UserApcPending = TRUE; + KiAbortWaitThread(Thread, STATUS_USER_APC); + } + + /* Return Sucess if we are here */ + KeReleaseDispatcherDatabaseLock(OldIrql); + return TRUE; } -/*++ - * KeLeaveCriticalRegion - * @implemented NT4 - * - * The KeLeaveCriticalRegion routine reenables the delivery of normal - * kernel-mode APCs that were disabled by a call to KeEnterCriticalRegion. - * - * Params: - * None. - * - * Returns: - * None. - * - * Remarks: - * Highest-level drivers can call this routine while running in the context - * of the thread that requested the current I/O operation. - * - * Callers of KeLeaveCriticalRegion must be running at IRQL <= DISPATCH_LEVEL. - * - *--*/ -VOID -STDCALL -KeLeaveCriticalRegion (VOID) +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. + */ { - PKTHREAD Thread = KeGetCurrentThread(); - - /* Check if Kernel APCs are now enabled */ - if((Thread) && (++Thread->KernelApcDisable == 0)) { - - /* Check if we need to request an APC Delivery */ - if (!IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode])) { - - /* Set APC Pending */ - Thread->ApcState.KernelApcPending = TRUE; - HalRequestSoftwareInterrupt(APC_LEVEL); - } - } + KIRQL OldIrql; + PKTHREAD Thread = Apc->Thread; + + ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); + DPRINT("KeRemoveQueueApc called for APC: %x \n", Apc); + + OldIrql = KeAcquireDispatcherDatabaseLock(); + KeAcquireSpinLock(&Thread->ApcQueueLock, &OldIrql); + + /* Remove it from the Queue if it's inserted */ + if (!Apc->Inserted == FALSE) { + RemoveEntryList(&Apc->ApcListEntry); + Apc->Inserted = FALSE; + + /* If the Queue is completely empty, then no more APCs are pending */ + if (IsListEmpty(&Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode])) { + if (Apc->ApcMode == KernelMode) { + Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->KernelApcPending = FALSE; + } else { + Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->UserApcPending = FALSE; + } + } + } else { + KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql); + KeReleaseDispatcherDatabaseLock(OldIrql); + return(FALSE); + } + + /* Restore IRQL and Return */ + KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql); + KeReleaseDispatcherDatabaseLock(OldIrql); + return(TRUE); } -/*++ - * KeRemoveQueueApc - * - * The KeRemoveQueueApc routine removes a given APC object from the system - * APC queue. - * - * Params: - * APC - Pointer to an initialized APC object that was queued by calling - * KeInsertQueueApc. - * - * Returns: - * TRUE if the APC Object is in the APC Queue. If it isn't, no operation is - * performed and FALSE is returned. - * - * Remarks: - * If the given APC Object is currently queued, it is removed from the queue - * and any calls to the registered routines are cancelled. - * - * Callers of KeLeaveCriticalRegion can be running at any IRQL. - * - *--*/ -BOOLEAN -STDCALL -KeRemoveQueueApc(PKAPC Apc) -{ - KIRQL OldIrql; - PKTHREAD Thread = Apc->Thread; - - ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); - DPRINT("KeRemoveQueueApc called for APC: %x \n", Apc); - - OldIrql = KeAcquireDispatcherDatabaseLock(); - KeAcquireSpinLock(&Thread->ApcQueueLock, &OldIrql); - - /* Check if it's inserted */ - if (Apc->Inserted) { - - /* Remove it from the Queue*/ - RemoveEntryList(&Apc->ApcListEntry); - Apc->Inserted = FALSE; - - /* If the Queue is completely empty, then no more APCs are pending */ - if (IsListEmpty(&Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode])) { - - /* Set the correct State based on the Apc Mode */ - if (Apc->ApcMode == KernelMode) { - - Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->KernelApcPending = FALSE; - - } else { - - Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->UserApcPending = FALSE; - } - } - - } else { - - /* It's not inserted, fail */ - KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql); - KeReleaseDispatcherDatabaseLock(OldIrql); - return(FALSE); - } - - /* Restore IRQL and Return */ - KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql); - KeReleaseDispatcherDatabaseLock(OldIrql); - return(TRUE); -} -/*++ - * KiDeliverApc - * @implemented @NT4 - * - * The KiDeliverApc routine is called from IRQL switching code if the - * thread is returning from an IRQL >= APC_LEVEL and Kernel-Mode APCs are - * pending. - * - * Params: - * DeliveryMode - Specifies the current processor mode. - * - * Reserved - Pointer to the Exception Frame on non-i386 builds. - * - * TrapFrame - Pointer to the Trap Frame. - * - * Returns: - * None. - * - * Remarks: - * First, Special APCs are delivered, followed by Kernel-Mode APCs and - * User-Mode APCs. Note that the TrapFrame is only valid if the previous - * mode is User. - * - * Upon entry, this routine executes at APC_LEVEL. - * - *--*/ +/* + * @implemented + */ VOID STDCALL KiDeliverApc(KPROCESSOR_MODE DeliveryMode, PVOID Reserved, PKTRAP_FRAME TrapFrame) +/* + * FUNCTION: Deliver an APC to the current thread. + * NOTES: This is called from the IRQL switching code if the current thread + * is returning from an IRQL greater than or equal to APC_LEVEL to + * PASSIVE_LEVEL and there are kernel-mode APCs pending. This means any + * pending APCs will be delivered after a thread gets a new quantum and + * after it wakes from a wait. Note that the TrapFrame is only valid if + * the previous mode is User. + */ { - PKTHREAD Thread = KeGetCurrentThread(); - PLIST_ENTRY ApcListEntry; - PKAPC Apc; - KIRQL OldIrql; - PKKERNEL_ROUTINE KernelRoutine; - PVOID NormalContext; - PKNORMAL_ROUTINE NormalRoutine; - PVOID SystemArgument1; - PVOID SystemArgument2; + PKTHREAD Thread = KeGetCurrentThread(); + PLIST_ENTRY ApcListEntry; + PKAPC Apc; + KIRQL OldIrql; + PKKERNEL_ROUTINE KernelRoutine; + PVOID NormalContext; + PKNORMAL_ROUTINE NormalRoutine; + PVOID SystemArgument1; + PVOID SystemArgument2; - ASSERT_IRQL_EQUAL(APC_LEVEL); - - /* Lock the APC Queue and Raise IRQL to Synch */ - KeAcquireSpinLock(&Thread->ApcQueueLock, &OldIrql); - - /* Clear APC Pending */ - Thread->ApcState.KernelApcPending = FALSE; - - /* Do the Kernel APCs first */ - while (!IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode])) { - - /* Get the next Entry */ - ApcListEntry = Thread->ApcState.ApcListHead[KernelMode].Flink; - Apc = CONTAINING_RECORD(ApcListEntry, KAPC, ApcListEntry); - - /* Save Parameters so that it's safe to free the Object in Kernel Routine*/ - NormalRoutine = Apc->NormalRoutine; - KernelRoutine = Apc->KernelRoutine; - NormalContext = Apc->NormalContext; - SystemArgument1 = Apc->SystemArgument1; - SystemArgument2 = Apc->SystemArgument2; + ASSERT_IRQL_EQUAL(APC_LEVEL); + + /* Lock the APC Queue and Raise IRQL to Synch */ + KeAcquireSpinLock(&Thread->ApcQueueLock, &OldIrql); + + /* Clear APC Pending */ + Thread->ApcState.KernelApcPending = FALSE; + + /* Do the Kernel APCs first */ + while (!IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode])) { + + /* Get the next Entry */ + ApcListEntry = Thread->ApcState.ApcListHead[KernelMode].Flink; + Apc = CONTAINING_RECORD(ApcListEntry, KAPC, ApcListEntry); + + /* Save Parameters so that it's safe to free the Object in Kernel Routine*/ + NormalRoutine = Apc->NormalRoutine; + KernelRoutine = Apc->KernelRoutine; + NormalContext = Apc->NormalContext; + SystemArgument1 = Apc->SystemArgument1; + SystemArgument2 = Apc->SystemArgument2; - /* Special APC */ - if (NormalRoutine == NULL) { - - /* Remove the APC from the list */ - Apc->Inserted = FALSE; - RemoveEntryList(ApcListEntry); - - /* Go back to APC_LEVEL */ - KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql); - - /* Call the Special APC */ - DPRINT("Delivering a Special APC: %x\n", Apc); - KernelRoutine(Apc, - &NormalRoutine, - &NormalContext, - &SystemArgument1, - &SystemArgument2); - - /* Raise IRQL and Lock again */ - KeAcquireSpinLock(&Thread->ApcQueueLock, &OldIrql); + /* Special APC */ + if (NormalRoutine == NULL) { + /* Remove the APC from the list */ + Apc->Inserted = FALSE; + RemoveEntryList(ApcListEntry); + + /* Go back to APC_LEVEL */ + KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql); + + /* Call the Special APC */ + DPRINT("Delivering a Special APC: %x\n", Apc); + KernelRoutine(Apc, + &NormalRoutine, + &NormalContext, + &SystemArgument1, + &SystemArgument2); + + /* Raise IRQL and Lock again */ + KeAcquireSpinLock(&Thread->ApcQueueLock, &OldIrql); + } else { + /* Normal Kernel APC */ + if (Thread->ApcState.KernelApcInProgress || Thread->KernelApcDisable) { - } else { - - /* Normal Kernel APC */ - if (Thread->ApcState.KernelApcInProgress || Thread->KernelApcDisable) { - - /* - * DeliveryMode must be KernelMode in this case, since one may not - * return to umode while being inside a critical section or while - * a regular kmode apc is running (the latter should be impossible btw). - * -Gunnar - */ - ASSERT(DeliveryMode == KernelMode); - - KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql); - return; - } - - /* Dequeue the APC */ - RemoveEntryList(ApcListEntry); - Apc->Inserted = FALSE; - - /* Go back to APC_LEVEL */ - KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql); - - /* Call the Kernel APC */ - DPRINT("Delivering a Normal APC: %x\n", Apc); - KernelRoutine(Apc, - &NormalRoutine, - &NormalContext, - &SystemArgument1, - &SystemArgument2); - - /* If There still is a Normal Routine, then we need to call this at PASSIVE_LEVEL */ - if (NormalRoutine != NULL) { - - /* At Passive Level, this APC can be prempted by a Special APC */ - Thread->ApcState.KernelApcInProgress = TRUE; - KeLowerIrql(PASSIVE_LEVEL); - - /* Call and Raise IRQ back to APC_LEVEL */ - DPRINT("Calling the Normal Routine for a Normal APC: %x\n", Apc); - NormalRoutine(&NormalContext, &SystemArgument1, &SystemArgument2); - KeRaiseIrql(APC_LEVEL, &OldIrql); - } - - /* Raise IRQL and Lock again */ - KeAcquireSpinLock(&Thread->ApcQueueLock, &OldIrql); - Thread->ApcState.KernelApcInProgress = FALSE; - } - } - - /* Now we do the User APCs */ - if ((!IsListEmpty(&Thread->ApcState.ApcListHead[UserMode])) && - (DeliveryMode == UserMode) && (Thread->ApcState.UserApcPending == TRUE)) { - - /* It's not pending anymore */ - Thread->ApcState.UserApcPending = FALSE; - - /* Get the APC Object */ - ApcListEntry = Thread->ApcState.ApcListHead[UserMode].Flink; - Apc = CONTAINING_RECORD(ApcListEntry, KAPC, ApcListEntry); - - /* Save Parameters so that it's safe to free the Object in Kernel Routine*/ - NormalRoutine = Apc->NormalRoutine; - KernelRoutine = Apc->KernelRoutine; - NormalContext = Apc->NormalContext; - SystemArgument1 = Apc->SystemArgument1; - SystemArgument2 = Apc->SystemArgument2; - - /* Remove the APC from Queue, restore IRQL and call the APC */ - RemoveEntryList(ApcListEntry); - Apc->Inserted = FALSE; + /* + * DeliveryMode must be KernelMode in this case, since one may not + * return to umode while being inside a critical section or while + * a regular kmode apc is running (the latter should be impossible btw). + * -Gunnar + */ + ASSERT(DeliveryMode == KernelMode); + + KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql); + return; + } + + /* Dequeue the APC */ + RemoveEntryList(ApcListEntry); + Apc->Inserted = FALSE; + + /* Go back to APC_LEVEL */ + KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql); + + /* Call the Kernel APC */ + DPRINT("Delivering a Normal APC: %x\n", Apc); + KernelRoutine(Apc, + &NormalRoutine, + &NormalContext, + &SystemArgument1, + &SystemArgument2); + + /* If There still is a Normal Routine, then we need to call this at PASSIVE_LEVEL */ + if (NormalRoutine != NULL) { + /* At Passive Level, this APC can be prempted by a Special APC */ + Thread->ApcState.KernelApcInProgress = TRUE; + KeLowerIrql(PASSIVE_LEVEL); + + /* Call and Raise IRQ back to APC_LEVEL */ + DPRINT("Calling the Normal Routine for a Normal APC: %x\n", Apc); + NormalRoutine(&NormalContext, &SystemArgument1, &SystemArgument2); + KeRaiseIrql(APC_LEVEL, &OldIrql); + } + + /* Raise IRQL and Lock again */ + KeAcquireSpinLock(&Thread->ApcQueueLock, &OldIrql); + Thread->ApcState.KernelApcInProgress = FALSE; + } + } + + /* Now we do the User APCs */ + if ((!IsListEmpty(&Thread->ApcState.ApcListHead[UserMode])) && + (DeliveryMode == UserMode) && + (Thread->ApcState.UserApcPending == TRUE)) { + + /* It's not pending anymore */ + Thread->ApcState.UserApcPending = FALSE; + + /* Get the APC Object */ + ApcListEntry = Thread->ApcState.ApcListHead[UserMode].Flink; + Apc = CONTAINING_RECORD(ApcListEntry, KAPC, ApcListEntry); + + /* Save Parameters so that it's safe to free the Object in Kernel Routine*/ + NormalRoutine = Apc->NormalRoutine; + KernelRoutine = Apc->KernelRoutine; + NormalContext = Apc->NormalContext; + SystemArgument1 = Apc->SystemArgument1; + SystemArgument2 = Apc->SystemArgument2; + + /* Remove the APC from Queue, restore IRQL and call the APC */ + RemoveEntryList(ApcListEntry); + Apc->Inserted = FALSE; - KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql); - DPRINT("Calling the Kernel Routine for for a User APC: %x\n", Apc); - KernelRoutine(Apc, - &NormalRoutine, - &NormalContext, - &SystemArgument1, - &SystemArgument2); - - if (NormalRoutine == NULL) { - - /* Check if more User APCs are Pending */ - KeTestAlertThread(UserMode); - - } else { - - /* Set up the Trap Frame and prepare for Execution in NTDLL.DLL */ - DPRINT("Delivering a User APC: %x\n", Apc); - KiInitializeUserApc(Reserved, - TrapFrame, - NormalRoutine, - NormalContext, - SystemArgument1, - SystemArgument2); - } - - } else { - - /* Go back to APC_LEVEL */ - KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql); - } + KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql); + DPRINT("Calling the Kernel Routine for for a User APC: %x\n", Apc); + KernelRoutine(Apc, + &NormalRoutine, + &NormalContext, + &SystemArgument1, + &SystemArgument2); + + if (NormalRoutine == NULL) { + /* Check if more User APCs are Pending */ + KeTestAlertThread(UserMode); + } else { + /* Set up the Trap Frame and prepare for Execution in NTDLL.DLL */ + DPRINT("Delivering a User APC: %x\n", Apc); + KiInitializeUserApc(Reserved, + TrapFrame, + NormalRoutine, + NormalContext, + SystemArgument1, + SystemArgument2); + } + } else { + /* Go back to APC_LEVEL */ + KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql); + } } VOID STDCALL KiFreeApcRoutine(PKAPC Apc, - PKNORMAL_ROUTINE* NormalRoutine, - PVOID* NormalContext, - PVOID* SystemArgument1, - PVOID* SystemArgument2) + PKNORMAL_ROUTINE* NormalRoutine, + PVOID* NormalContext, + PVOID* SystemArgument1, + PVOID* SystemArgument2) { - /* Free the APC and do nothing else */ - ExFreePool(Apc); + /* Free the APC and do nothing else */ + ExFreePool(Apc); } -/*++ - * KiInitializeUserApc - * - * Prepares the Context for a User-Mode APC called through NTDLL.DLL - * - * Params: - * Reserved - Pointer to the Exception Frame on non-i386 builds. - * - * TrapFrame - Pointer to the Trap Frame. - * - * NormalRoutine - Pointer to the NormalRoutine to call. - * - * NormalContext - Pointer to the context to send to the Normal Routine. - * - * SystemArgument[1-2] - Pointer to a set of two parameters that contain - * untyped data. - * - * Returns: - * None. - * - * Remarks: - * None. - * - *--*/ -VOID -STDCALL +VOID KiInitializeUserApc(IN PVOID Reserved, - IN PKTRAP_FRAME TrapFrame, - IN PKNORMAL_ROUTINE NormalRoutine, - IN PVOID NormalContext, - IN PVOID SystemArgument1, - IN PVOID SystemArgument2) + IN PKTRAP_FRAME TrapFrame, + IN PKNORMAL_ROUTINE NormalRoutine, + IN PVOID NormalContext, + IN PVOID SystemArgument1, + IN PVOID SystemArgument2) +/* + * FUNCTION: Prepares the Context for a user mode APC through ntdll.dll + */ { - PCONTEXT Context; - PULONG Esp; + PCONTEXT Context; + PULONG Esp; - DPRINT("KiInitializeUserApc(TrapFrame %x/%x)\n", TrapFrame, KeGetCurrentThread()->TrapFrame); + DPRINT("KiInitializeUserApc(TrapFrame %x/%x)\n", TrapFrame, KeGetCurrentThread()->TrapFrame); - /* - * Save the thread's current context (in other words the registers - * that will be restored when it returns to user mode) so the - * APC dispatcher can restore them later - */ - Context = (PCONTEXT)(((PUCHAR)TrapFrame->Esp) - sizeof(CONTEXT)); - RtlZeroMemory(Context, sizeof(CONTEXT)); - Context->ContextFlags = CONTEXT_FULL; - Context->SegGs = TrapFrame->Gs; - Context->SegFs = TrapFrame->Fs; - Context->SegEs = TrapFrame->Es; - Context->SegDs = TrapFrame->Ds; - Context->Edi = TrapFrame->Edi; - Context->Esi = TrapFrame->Esi; - Context->Ebx = TrapFrame->Ebx; - Context->Edx = TrapFrame->Edx; - Context->Ecx = TrapFrame->Ecx; - Context->Eax = TrapFrame->Eax; - Context->Ebp = TrapFrame->Ebp; - Context->Eip = TrapFrame->Eip; - Context->SegCs = TrapFrame->Cs; - Context->EFlags = TrapFrame->Eflags; - Context->Esp = TrapFrame->Esp; - Context->SegSs = TrapFrame->Ss; + /* + * Save the thread's current context (in other words the registers + * that will be restored when it returns to user mode) so the + * APC dispatcher can restore them later + */ + Context = (PCONTEXT)(((PUCHAR)TrapFrame->Esp) - sizeof(CONTEXT)); + RtlZeroMemory(Context, sizeof(CONTEXT)); + Context->ContextFlags = CONTEXT_FULL; + Context->SegGs = TrapFrame->Gs; + Context->SegFs = TrapFrame->Fs; + Context->SegEs = TrapFrame->Es; + Context->SegDs = TrapFrame->Ds; + Context->Edi = TrapFrame->Edi; + Context->Esi = TrapFrame->Esi; + Context->Ebx = TrapFrame->Ebx; + Context->Edx = TrapFrame->Edx; + Context->Ecx = TrapFrame->Ecx; + Context->Eax = TrapFrame->Eax; + Context->Ebp = TrapFrame->Ebp; + Context->Eip = TrapFrame->Eip; + Context->SegCs = TrapFrame->Cs; + Context->EFlags = TrapFrame->Eflags; + Context->Esp = TrapFrame->Esp; + Context->SegSs = TrapFrame->Ss; - /* - * Setup the trap frame so the thread will start executing at the - * APC Dispatcher when it returns to user-mode - */ - Esp = (PULONG)(((PUCHAR)TrapFrame->Esp) - (sizeof(CONTEXT) + (6 * sizeof(ULONG)))); - Esp[0] = 0xdeadbeef; - Esp[1] = (ULONG)NormalRoutine; - Esp[2] = (ULONG)NormalContext; - Esp[3] = (ULONG)SystemArgument1; - Esp[4] = (ULONG)SystemArgument2; - Esp[5] = (ULONG)Context; - TrapFrame->Eip = (ULONG)LdrpGetSystemDllApcDispatcher(); - TrapFrame->Esp = (ULONG)Esp; + /* + * Setup the trap frame so the thread will start executing at the + * APC Dispatcher when it returns to user-mode + */ + Esp = (PULONG)(((PUCHAR)TrapFrame->Esp) - (sizeof(CONTEXT) + (6 * sizeof(ULONG)))); + Esp[0] = 0xdeadbeef; + Esp[1] = (ULONG)NormalRoutine; + Esp[2] = (ULONG)NormalContext; + Esp[3] = (ULONG)SystemArgument1; + Esp[4] = (ULONG)SystemArgument2; + Esp[5] = (ULONG)Context; + TrapFrame->Eip = (ULONG)LdrpGetSystemDllApcDispatcher(); + TrapFrame->Esp = (ULONG)Esp; } -/*++ - * KeAreApcsDisabled - * @implemented NT4 - * - * Prepares the Context for a User-Mode APC called through NTDLL.DLL - * - * Params: - * None. - * - * Returns: - * KeAreApcsDisabled returns TRUE if the thread is within a critical region - * or a guarded region, and FALSE otherwise. - * - * Remarks: - * A thread running at IRQL = PASSIVE_LEVEL can use KeAreApcsDisabled to - * determine if normal kernel APCs are disabled. A thread that is inside a - * critical region has both user APCs and normal kernel APCs disabled, but - * not special kernel APCs. A thread that is inside a guarded region has - * all APCs disabled, including special kernel APCs. - * - * Callers of this routine must be running at IRQL <= APC_LEVEL. - * - *--*/ +/* + * @implemented + */ BOOLEAN STDCALL -KeAreApcsDisabled(VOID) +KeAreApcsDisabled( + VOID + ) { - /* Return the Kernel APC State */ - return KeGetCurrentThread()->KernelApcDisable ? TRUE : FALSE; + return KeGetCurrentThread()->KernelApcDisable ? TRUE : FALSE; } -/*++ - * NtQueueApcThread - * NT4 - * - * This routine is used to queue an APC from user-mode for the specified - * thread. - * - * Params: - * Thread Handle - Handle to the Thread. This handle must have THREAD_SET_CONTEXT privileges. - * - * ApcRoutine - Pointer to the APC Routine to call when the APC executes. - * - * NormalContext - Pointer to the context to send to the Normal Routine. - * - * SystemArgument[1-2] - Pointer to a set of two parameters that contain - * untyped data. - * - * Returns: - * STATUS_SUCCESS or failure cute from associated calls. - * - * Remarks: - * The thread must enter an alertable wait before the APC will be - * delivered. - * - *--*/ NTSTATUS STDCALL -NtQueueApcThread(HANDLE ThreadHandle, - PKNORMAL_ROUTINE ApcRoutine, - PVOID NormalContext, - PVOID SystemArgument1, - PVOID SystemArgument2) +NtQueueApcThread(HANDLE ThreadHandle, + PKNORMAL_ROUTINE ApcRoutine, + PVOID NormalContext, + PVOID SystemArgument1, + PVOID SystemArgument2) +/* + * FUNCTION: + * This function is used to queue an APC from user-mode for the specified thread. + * The thread must enter an alertable wait before the APC will be delivered. + * + * ARGUMENTS: + * Thread Handle - Handle to the Thread. This handle must have THREAD_SET_CONTEXT privileges. + * ApcRoutine - Pointer to the APC Routine to call when the APC executes. + * NormalContext - User-defined value to pass to the APC Routine + * SystemArgument1 - User-defined value to pass to the APC Routine + * SystemArgument2 - User-defined value to pass to the APC Routine + * + * RETURNS: NTSTATUS SUCCESS or Failure Code from included calls. + */ { - PKAPC Apc; - PETHREAD Thread; - KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); - NTSTATUS Status; - - /* Get ETHREAD from Handle */ - Status = ObReferenceObjectByHandle(ThreadHandle, - THREAD_SET_CONTEXT, - PsThreadType, - PreviousMode, - (PVOID)&Thread, - NULL); - - /* Fail if the Handle is invalid for some reason */ - if (!NT_SUCCESS(Status)) { - - return(Status); - } - - /* If this is a Kernel or System Thread, then fail */ - if (Thread->Tcb.Teb == NULL) { - - ObDereferenceObject(Thread); - return STATUS_INVALID_HANDLE; - } + + PKAPC Apc; + PETHREAD Thread; + KPROCESSOR_MODE PreviousMode; + NTSTATUS Status; + + PreviousMode = ExGetPreviousMode(); + + /* Get ETHREAD from Handle */ + Status = ObReferenceObjectByHandle(ThreadHandle, + THREAD_SET_CONTEXT, + PsThreadType, + PreviousMode, + (PVOID)&Thread, + NULL); + + /* Fail if the Handle is invalid for some reason */ + if (!NT_SUCCESS(Status)) { + return(Status); + } + + /* If this is a Kernel or System Thread, then fail */ + if (Thread->Tcb.Teb == NULL) { + ObDereferenceObject(Thread); + return STATUS_INVALID_HANDLE; + } - /* Allocate an APC */ - Apc = ExAllocatePoolWithTag(NonPagedPool, sizeof(KAPC), TAG('P', 's', 'a', 'p')); - if (Apc == NULL) { - - ObDereferenceObject(Thread); - return(STATUS_NO_MEMORY); - } + /* Allocate an APC */ + Apc = ExAllocatePoolWithTag(NonPagedPool, sizeof(KAPC), TAG_KAPC); + if (Apc == NULL) { + ObDereferenceObject(Thread); + return(STATUS_NO_MEMORY); + } - /* Initialize and Queue a user mode apc (always!) */ - KeInitializeApc(Apc, - &Thread->Tcb, - OriginalApcEnvironment, - KiFreeApcRoutine, - NULL, - ApcRoutine, - UserMode, - NormalContext); - - if (!KeInsertQueueApc(Apc, SystemArgument1, SystemArgument2, IO_NO_INCREMENT)) { - - Status = STATUS_UNSUCCESSFUL; - - } else { - - Status = STATUS_SUCCESS; - } + /* Initialize and Queue a user mode apc (always!) */ + KeInitializeApc(Apc, + &Thread->Tcb, + OriginalApcEnvironment, + KiFreeApcRoutine, + NULL, + ApcRoutine, + UserMode, + NormalContext); + if (!KeInsertQueueApc(Apc, SystemArgument1, SystemArgument2, IO_NO_INCREMENT)) { + Status = STATUS_UNSUCCESSFUL; + } else { + Status = STATUS_SUCCESS; + } - /* Dereference Thread and Return */ - ObDereferenceObject(Thread); - return Status; + /* Dereference Thread and Return */ + ObDereferenceObject(Thread); + return Status; } -static inline -VOID RepairList(PLIST_ENTRY Original, - PLIST_ENTRY Copy, - KPROCESSOR_MODE Mode) + +static inline VOID RepairList(PLIST_ENTRY Original, + PLIST_ENTRY Copy, + KPROCESSOR_MODE Mode) { - /* Copy Source to Desination */ - if (IsListEmpty(&Original[(int)Mode])) { - - InitializeListHead(&Copy[(int)Mode]); - - } else { - - Copy[(int)Mode].Flink = Original[(int)Mode].Flink; - Copy[(int)Mode].Blink = Original[(int)Mode].Blink; - Original[(int)Mode].Flink->Blink = &Copy[(int)Mode]; - Original[(int)Mode].Blink->Flink = &Copy[(int)Mode]; - } + /* Copy Source to Desination */ + if (IsListEmpty(&Original[(int)Mode])) { + InitializeListHead(&Copy[(int)Mode]); + } else { + Copy[(int)Mode].Flink = Original[(int)Mode].Flink; + Copy[(int)Mode].Blink = Original[(int)Mode].Blink; + Original[(int)Mode].Flink->Blink = &Copy[(int)Mode]; + Original[(int)Mode].Blink->Flink = &Copy[(int)Mode]; + } } VOID STDCALL -KiMoveApcState(PKAPC_STATE OldState, - PKAPC_STATE NewState) +KiMoveApcState (PKAPC_STATE OldState, + PKAPC_STATE NewState) { - /* Restore backup of Original Environment */ - *NewState = *OldState; + /* Restore backup of Original Environment */ + *NewState = *OldState; - /* Repair Lists */ - RepairList(NewState->ApcListHead, OldState->ApcListHead, KernelMode); - RepairList(NewState->ApcListHead, OldState->ApcListHead, UserMode); + /* Repair Lists */ + RepairList(NewState->ApcListHead, OldState->ApcListHead, KernelMode); + RepairList(NewState->ApcListHead, OldState->ApcListHead, UserMode); } diff --git a/reactos/ntoskrnl/ke/bug.c b/reactos/ntoskrnl/ke/bug.c index fd2f58c96e7..2af3e26b721 100644 --- a/reactos/ntoskrnl/ke/bug.c +++ b/reactos/ntoskrnl/ke/bug.c @@ -47,17 +47,6 @@ KeDeregisterBugCheckCallback(PKBUGCHECK_CALLBACK_RECORD CallbackRecord) return FALSE; } -/* - * @unimplemented - */ -BOOLEAN -STDCALL -KeDeregisterBugCheckReasonCallback(IN PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord) -{ - UNIMPLEMENTED; - return FALSE; -} - /* * @implemented */ @@ -85,20 +74,6 @@ KeRegisterBugCheckCallback(PKBUGCHECK_CALLBACK_RECORD CallbackRecord, return(FALSE); } -/* - * @unimplemented - */ -BOOLEAN -STDCALL -KeRegisterBugCheckReasonCallback(IN PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord, - IN PKBUGCHECK_REASON_CALLBACK_ROUTINE CallbackRoutine, - IN KBUGCHECK_CALLBACK_REASON Reason, - IN PUCHAR Component) -{ - UNIMPLEMENTED; - return FALSE; -} - VOID STDCALL KeBugCheckWithTf(ULONG BugCheckCode, ULONG BugCheckParameter1, diff --git a/reactos/ntoskrnl/ke/catch.c b/reactos/ntoskrnl/ke/catch.c index 1657b5f592d..1d4ca92a486 100644 --- a/reactos/ntoskrnl/ke/catch.c +++ b/reactos/ntoskrnl/ke/catch.c @@ -1,4 +1,5 @@ -/* +/* $Id$ + * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * FILE: ntoskrnl/ke/catch.c @@ -20,206 +21,282 @@ ULONG RtlpDispatchException(IN PEXCEPTION_RECORD ExceptionRecord, IN PCONTEXT Context); -/* - * @unimplemented - */ VOID -STDCALL -KiCoprocessorError(VOID) +KiDispatchException(PEXCEPTION_RECORD ExceptionRecord, + PCONTEXT Context, + PKTRAP_FRAME Tf, + KPROCESSOR_MODE PreviousMode, + BOOLEAN SearchFrames) { - UNIMPLEMENTED; -} + EXCEPTION_DISPOSITION Value; + CONTEXT TContext; + KD_CONTINUE_TYPE Action = kdHandleException; -/* - * @unimplemented - */ -VOID -STDCALL -KiUnexpectedInterrupt(VOID) -{ - UNIMPLEMENTED; -} + DPRINT("KiDispatchException() called\n"); -VOID -KiDispatchException(PEXCEPTION_RECORD ExceptionRecord, - PCONTEXT Context, - PKTRAP_FRAME Tf, - KPROCESSOR_MODE PreviousMode, - BOOLEAN SearchFrames) -{ - EXCEPTION_DISPOSITION Value; - CONTEXT TContext; - KD_CONTINUE_TYPE Action = kdHandleException; - - DPRINT("KiDispatchException() called\n"); - - /* Increase number of Exception Dispatches */ - KeGetCurrentKPCR()->PrcbData.KeExceptionDispatchCount++; - - if (!Context) { - - /* Assume Full context */ - TContext.ContextFlags = CONTEXT_FULL; - - /* Check the mode */ - if (PreviousMode == UserMode) { - - /* Add Debugger Registers if this is User Mode */ - TContext.ContextFlags = TContext.ContextFlags | CONTEXT_DEBUGGER; - } + + /* PCR->KeExceptionDispatchCount++; */ + + if (Context == NULL) + { + TContext.ContextFlags = CONTEXT_FULL; + if (PreviousMode == UserMode) + { + TContext.ContextFlags = TContext.ContextFlags | CONTEXT_DEBUGGER; + } - /* Convert the Trapframe into a Context */ - KeTrapFrameToContext(Tf, &TContext); + KeTrapFrameToContext(Tf, &TContext); - /* Use local stack context */ - Context = &TContext; + Context = &TContext; } -#if 0 /* FIXME: Isn't this right? With a break after? */ - if (ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) { - Context->Eip--; +#if 0 + if (ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) + { + Context->Eip--; } #endif + + if (KdDebuggerEnabled && KdDebugState & KD_DEBUG_GDB) + { + Action = KdEnterDebuggerException (ExceptionRecord, Context, Tf); + } - /* Check if a Debugger is enabled */ - if (KdDebuggerEnabled && KdDebugState & KD_DEBUG_GDB) { - - /* Break into it */ - Action = KdEnterDebuggerException (ExceptionRecord, Context, Tf); + if (Action == kdContinue) + { + return; } - - /* If the debugger said continue, then continue */ - if (Action == kdContinue) return; - - /* If the Debugger couldn't handle it... */ - if (Action != kdDoNotHandleException) { - - /* See what kind of Exception this is */ - if (PreviousMode == UserMode) { - - /* User mode exception, search the frames if we have to */ - if (SearchFrames) { - - PULONG Stack; - ULONG CDest; - char temp_space[12 + sizeof(EXCEPTION_RECORD) + sizeof(CONTEXT)]; /* FIXME: HACKHACK */ - PULONG pNewUserStack = (PULONG)(Tf->Esp - (12 + sizeof(EXCEPTION_RECORD) + sizeof(CONTEXT))); - NTSTATUS StatusOfCopy; + + if (Action != kdDoNotHandleException) + { + if (PreviousMode == UserMode) + { + if (SearchFrames) + { + PULONG Stack; + ULONG CDest; + char temp_space[12 + sizeof(EXCEPTION_RECORD) + sizeof(CONTEXT)]; /* FIXME: HACKHACK */ + PULONG pNewUserStack = (PULONG)(Tf->Esp - (12 + sizeof(EXCEPTION_RECORD) + sizeof(CONTEXT))); + NTSTATUS StatusOfCopy; #ifdef KDBG - /* Enter KDB if available */ - Action = KdbEnterDebuggerException(ExceptionRecord, - PreviousMode, - Context, - Tf, - FALSE); - - /* Exit if we're continuing */ - if (Action == kdContinue) return; + Action = KdbEnterDebuggerException (ExceptionRecord, PreviousMode, + Context, Tf, FALSE); + if (Action == kdContinue) + { + return; + } #endif - /* FIXME: Forward exception to user mode debugger */ - - /* FIXME: Check user mode stack for enough space */ - - /* Let usermode try and handle the exception. Setup Stack */ - Stack = (PULONG)temp_space; - CDest = 3 + (ROUND_UP(sizeof(EXCEPTION_RECORD), 4) / 4); - /* Return Address */ - Stack[0] = 0; - /* Pointer to EXCEPTION_RECORD structure */ - Stack[1] = (ULONG)&pNewUserStack[3]; - /* Pointer to CONTEXT structure */ - Stack[2] = (ULONG)&pNewUserStack[CDest]; - memcpy(&Stack[3], ExceptionRecord, sizeof(EXCEPTION_RECORD)); - memcpy(&Stack[CDest], Context, sizeof(CONTEXT)); - - /* Copy Stack */ - StatusOfCopy = MmCopyToCaller(pNewUserStack, - temp_space, - (12 + sizeof(EXCEPTION_RECORD) + sizeof(CONTEXT))); - - /* Check for success */ - if (NT_SUCCESS(StatusOfCopy)) { - - /* Set new Stack Pointer */ - Tf->Esp = (ULONG)pNewUserStack; - - } else { - - /* - * Now it really hit the ventilation device. Sorry, - * can do nothing but kill the sucker. - */ - ZwTerminateThread(NtCurrentThread(), ExceptionRecord->ExceptionCode); - DPRINT1("User-mode stack was invalid. Terminating target thread\n"); - } - - /* Set EIP to the User-mode Dispathcer */ - Tf->Eip = (ULONG)LdrpGetSystemDllExceptionDispatcher(); - return; - } + /* FIXME: Forward exception to user mode debugger */ + + /* FIXME: Check user mode stack for enough space */ + + /* + * Let usermode try and handle the exception + */ + Stack = (PULONG)temp_space; + CDest = 3 + (ROUND_UP(sizeof(EXCEPTION_RECORD), 4) / 4); + /* Return address */ + Stack[0] = 0; + /* Pointer to EXCEPTION_RECORD structure */ + Stack[1] = (ULONG)&pNewUserStack[3]; + /* Pointer to CONTEXT structure */ + Stack[2] = (ULONG)&pNewUserStack[CDest]; + memcpy(&Stack[3], ExceptionRecord, sizeof(EXCEPTION_RECORD)); + memcpy(&Stack[CDest], Context, sizeof(CONTEXT)); - /* FIXME: Forward the exception to the debugger */ + StatusOfCopy = MmCopyToCaller(pNewUserStack, + temp_space, + (12 + sizeof(EXCEPTION_RECORD) + sizeof(CONTEXT))); + if (NT_SUCCESS(StatusOfCopy)) + { + Tf->Esp = (ULONG)pNewUserStack; + } + else + { + /* Now it really hit the ventilation device. Sorry, + * can do nothing but kill the sucker. + */ + ZwTerminateThread(NtCurrentThread(), ExceptionRecord->ExceptionCode); + DPRINT1("User-mode stack was invalid. Terminating target thread\n"); + } + Tf->Eip = (ULONG)LdrpGetSystemDllExceptionDispatcher(); + return; + } - /* FIXME: Forward the exception to the process exception port */ + /* FIXME: Forward the exception to the debugger */ + + /* FIXME: Forward the exception to the process exception port */ - #ifdef KDBG - /* Enter KDB if available */ - Action = KdbEnterDebuggerException(ExceptionRecord, - PreviousMode, - Context, - Tf, - TRUE); - - /* Exit if we're continuing */ - if (Action == kdContinue) return; + Action = KdbEnterDebuggerException (ExceptionRecord, PreviousMode, + Context, Tf, TRUE); + if (Action == kdContinue) + { + return; + } #endif - /* Terminate the offending thread */ - DPRINT1("Unhandled UserMode exception, terminating thread\n"); - ZwTerminateThread(NtCurrentThread(), ExceptionRecord->ExceptionCode); - - } else { - - /* This is Kernel Mode */ + /* Terminate the offending thread */ + DPRINT1("Unhandled UserMode exception, terminating thread\n"); + ZwTerminateThread(NtCurrentThread(), ExceptionRecord->ExceptionCode); + } + else + { + /* PreviousMode == KernelMode */ #ifdef KDBG - /* Enter KDB if available */ - Action = KdbEnterDebuggerException(ExceptionRecord, - PreviousMode, - Context, - Tf, - FALSE); - - /* Exit if we're continuing */ - if (Action == kdContinue) return; + Action = KdbEnterDebuggerException (ExceptionRecord, PreviousMode, + Context, Tf, FALSE); + if (Action == kdContinue) + { + return; + } #endif - /* Dispatch the Exception */ - Value = RtlpDispatchException (ExceptionRecord, Context); - DPRINT("RtlpDispatchException() returned with 0x%X\n", Value); - - /* If RtlpDispatchException() did not handle the exception then bugcheck */ - if (Value != ExceptionContinueExecution || - 0 != (ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE)) { - - DPRINT("ExceptionRecord->ExceptionAddress = 0x%x\n", ExceptionRecord->ExceptionAddress); + Value = RtlpDispatchException (ExceptionRecord, Context); + + DPRINT("RtlpDispatchException() returned with 0x%X\n", Value); + /* + * If RtlpDispatchException() does not handle the exception then + * bugcheck + */ + if (Value != ExceptionContinueExecution || + 0 != (ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE)) + { + DPRINT("ExceptionRecord->ExceptionAddress = 0x%x\n", + ExceptionRecord->ExceptionAddress ); #ifdef KDBG - /* Enter KDB if available */ - Action = KdbEnterDebuggerException(ExceptionRecord, - PreviousMode, - Context, - Tf, - TRUE); - - /* Exit if we're continuing */ - if (Action == kdContinue) return; + Action = KdbEnterDebuggerException (ExceptionRecord, PreviousMode, + Context, Tf, TRUE); + if (Action == kdContinue) + { + return; + } #endif - KEBUGCHECKWITHTF(KMODE_EXCEPTION_NOT_HANDLED, 0, 0, 0, 0, Tf); - } - } + KEBUGCHECKWITHTF(KMODE_EXCEPTION_NOT_HANDLED, 0, 0, 0, 0, Tf); + } + } } } +/* + * @implemented + */ +VOID STDCALL +ExRaiseAccessViolation (VOID) +{ + ExRaiseStatus (STATUS_ACCESS_VIOLATION); +} + +/* + * @implemented + */ +VOID STDCALL +ExRaiseDatatypeMisalignment (VOID) +{ + ExRaiseStatus (STATUS_DATATYPE_MISALIGNMENT); +} + +/* + * @implemented + */ +VOID STDCALL +ExRaiseStatus (IN NTSTATUS Status) +{ + EXCEPTION_RECORD ExceptionRecord; + + DPRINT("ExRaiseStatus(%x)\n", Status); + + ExceptionRecord.ExceptionRecord = NULL; + ExceptionRecord.NumberParameters = 0; + ExceptionRecord.ExceptionCode = Status; + ExceptionRecord.ExceptionFlags = 0; + + RtlRaiseException(&ExceptionRecord); +} + + + +/* + * @implemented + */ +VOID +STDCALL +ExRaiseException ( + PEXCEPTION_RECORD ExceptionRecord + ) +{ + RtlRaiseException(ExceptionRecord); +} + +/* + * @implemented + */ +BOOLEAN +STDCALL +ExSystemExceptionFilter(VOID) +{ + return KeGetPreviousMode() != KernelMode ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH; +} + +/* + * @unimplemented + */ +VOID +STDCALL +ExRaiseHardError ( + IN NTSTATUS ErrorStatus, + IN ULONG NumberOfParameters, + IN PUNICODE_STRING UnicodeStringParameterMask OPTIONAL, + IN PVOID *Parameters, + IN HARDERROR_RESPONSE_OPTION ResponseOption, + OUT PHARDERROR_RESPONSE Response + ) +{ + UNIMPLEMENTED; +} + +/* + * @unimplemented + */ +BOOLEAN +STDCALL +KeDeregisterBugCheckReasonCallback( + IN PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord + ) +{ + UNIMPLEMENTED; + return FALSE; +} + +/* + * @unimplemented + */ +ULONG +STDCALL +KeGetRecommendedSharedDataAlignment( + VOID + ) +{ + UNIMPLEMENTED; + return 0; +} + +/* + * @unimplemented + */ +BOOLEAN +STDCALL +KeRegisterBugCheckReasonCallback( + IN PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord, + IN PKBUGCHECK_REASON_CALLBACK_ROUTINE CallbackRoutine, + IN KBUGCHECK_CALLBACK_REASON Reason, + IN PUCHAR Component + ) +{ + UNIMPLEMENTED; + return FALSE; +} + /* EOF */ diff --git a/reactos/ntoskrnl/ke/critical.c b/reactos/ntoskrnl/ke/critical.c new file mode 100644 index 00000000000..e2428549b45 --- /dev/null +++ b/reactos/ntoskrnl/ke/critical.c @@ -0,0 +1,56 @@ +/* $Id$ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: ntoskrnl/ke/critical.c + * PURPOSE: Implement critical regions + * + * PROGRAMMERS: David Welch (welch@mcmail.com) + */ + +/* INCLUDES *****************************************************************/ + +#include +#define NDEBUG +#include + +/* FUNCTIONS *****************************************************************/ + +/* + * @implemented + */ +VOID STDCALL KeEnterCriticalRegion (VOID) +{ + PKTHREAD Thread = KeGetCurrentThread(); + + DPRINT("KeEnterCriticalRegion()\n"); + + if (!Thread) return; /* <-Early in the boot process the current thread is obseved to be NULL */ + + Thread->KernelApcDisable--; +} + +/* + * @implemented + */ +VOID STDCALL KeLeaveCriticalRegion (VOID) +{ + PKTHREAD Thread = KeGetCurrentThread(); + + DPRINT("KeLeaveCriticalRegion()\n"); + + if (!Thread) return; /* <-Early in the boot process the current thread is obseved to be NULL */ + + /* Reference: http://www.ntfsd.org/archive/ntfsd0104/msg0203.html */ + if(++Thread->KernelApcDisable == 0) + { + if (!IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode])) + { + Thread->ApcState.KernelApcPending = TRUE; + HalRequestSoftwareInterrupt(APC_LEVEL); + } + } + +} + +/* EOF */ diff --git a/reactos/ntoskrnl/ke/dpc.c b/reactos/ntoskrnl/ke/dpc.c index 0d68ce65182..2aee866c39d 100644 --- a/reactos/ntoskrnl/ke/dpc.c +++ b/reactos/ntoskrnl/ke/dpc.c @@ -24,15 +24,15 @@ /* TYPES *******************************************************************/ #define MAX_QUANTUM 0x7F +/* GLOBALS ******************************************************************/ /* FUNCTIONS ****************************************************************/ +VOID INIT_FUNCTION +KeInitDpc(PKPCR Pcr) /* * FUNCTION: Initialize DPC handling */ -VOID -INIT_FUNCTION -KeInitDpc(PKPCR Pcr) { InitializeListHead(&Pcr->PrcbData.DpcData[0].DpcListHead); KeInitializeEvent(Pcr->PrcbData.DpcEvent, 0, 0); @@ -47,9 +47,9 @@ KeInitDpc(PKPCR Pcr) */ VOID STDCALL -KeInitializeThreadedDpc(PKDPC Dpc, - PKDEFERRED_ROUTINE DeferredRoutine, - PVOID DeferredContext) +KeInitializeThreadedDpc(PKDPC Dpc, + PKDEFERRED_ROUTINE DeferredRoutine, + PVOID DeferredContext) /* * FUNCTION: * Initalizes a Threaded DPC and registers the DeferredRoutine for it. @@ -60,18 +60,24 @@ KeInitializeThreadedDpc(PKDPC Dpc, * NOTE: Callers can be running at any IRQL. */ { - DPRINT("Threaded DPC Initializing: %x with Routine: %x\n", Dpc, DeferredRoutine); - Dpc->Type = ThreadedDpcObject; - Dpc->Number= 0; - Dpc->Importance= MediumImportance; - Dpc->DeferredRoutine = DeferredRoutine; - Dpc->DeferredContext = DeferredContext; - Dpc->DpcData = NULL; + DPRINT("Threaded DPC Initializing: %x with Routine: %x\n", Dpc, DeferredRoutine); + //Dpc->Type = KThreadedDpc; + Dpc->Number= 0; + Dpc->Importance= MediumImportance; + Dpc->DeferredRoutine = DeferredRoutine; + Dpc->DeferredContext = DeferredContext; + Dpc->DpcData = NULL; } /* * @implemented - * + */ +VOID +STDCALL +KeInitializeDpc (PKDPC Dpc, + PKDEFERRED_ROUTINE DeferredRoutine, + PVOID DeferredContext) +/* * FUNCTION: * Initalizes a DPC and registers the DeferredRoutine for it. * ARGUMENTS: @@ -80,24 +86,24 @@ KeInitializeThreadedDpc(PKDPC Dpc, * DeferredContext = Parameter to be passed to the callback routine. * NOTE: Callers can be running at any IRQL. */ -VOID -STDCALL -KeInitializeDpc(PKDPC Dpc, - PKDEFERRED_ROUTINE DeferredRoutine, - PVOID DeferredContext) { - DPRINT("DPC Initializing: %x with Routine: %x\n", Dpc, DeferredRoutine); - Dpc->Type = DpcObject; - Dpc->Number= 0; - Dpc->Importance= MediumImportance; - Dpc->DeferredRoutine = DeferredRoutine; - Dpc->DeferredContext = DeferredContext; - Dpc->DpcData = NULL; + DPRINT("DPC Initializing: %x with Routine: %x\n", Dpc, DeferredRoutine); + Dpc->Type = KDpc; + Dpc->Number= 0; + Dpc->Importance= MediumImportance; + Dpc->DeferredRoutine = DeferredRoutine; + Dpc->DeferredContext = DeferredContext; + Dpc->DpcData = NULL; } /* * @implemented - * + */ +BOOLEAN STDCALL +KeInsertQueueDpc (PKDPC Dpc, + PVOID SystemArgument1, + PVOID SystemArgument2) +/* * FUNCTION: * Queues a DPC for execution when the IRQL of a processor * drops below DISPATCH_LEVEL @@ -149,141 +155,124 @@ KeInitializeDpc(PKDPC Dpc, * is greater that the target depth or the minimum DPC rate is less than the * target rate. */ -BOOLEAN -STDCALL -KeInsertQueueDpc(PKDPC Dpc, - PVOID SystemArgument1, - PVOID SystemArgument2) { - KIRQL OldIrql; - PKPCR Pcr; - - DPRINT("KeInsertQueueDpc(DPC %x, SystemArgument1 %x, SystemArgument2 %x)\n", - Dpc, SystemArgument1, SystemArgument2); - - /* Check IRQL and Raise it to HIGH_LEVEL */ - ASSERT(KeGetCurrentIrql()>=DISPATCH_LEVEL); - KeRaiseIrql(HIGH_LEVEL, &OldIrql); - - /* Check if this is a Thread DPC, which we don't support (yet) */ - if (Dpc->Type == ThreadedDpcObject) { - return FALSE; - KeLowerIrql(OldIrql); - } + KIRQL OldIrql; + PKPCR Pcr; + + DPRINT("KeInsertQueueDpc(DPC %x, SystemArgument1 %x, SystemArgument2 %x)\n", + Dpc, SystemArgument1, SystemArgument2); + + /* Check IRQL and Raise it to HIGH_LEVEL */ + ASSERT(KeGetCurrentIrql()>=DISPATCH_LEVEL); + KeRaiseIrql(HIGH_LEVEL, &OldIrql); + + /* Check if this is a Thread DPC, which we don't support (yet) */ + //if (Dpc->Type == KThreadedDpc) { + // return FALSE; + // KeLowerIrql(OldIrql); + //} #ifdef CONFIG_SMP - /* Get the right PCR for this CPU */ - if (Dpc->Number >= MAXIMUM_PROCESSORS) { - - ASSERT (Dpc->Number - MAXIMUM_PROCESSORS < KeNumberProcessors); - Pcr = (PKPCR)(KPCR_BASE + (Dpc->Number - MAXIMUM_PROCESSORS) * PAGE_SIZE); - - } else { - - ASSERT (Dpc->Number < KeNumberProcessors); - Pcr = KeGetCurrentKPCR(); - Dpc->Number = KeGetCurrentProcessorNumber(); - } - - KiAcquireSpinLock(&Pcr->PrcbData.DpcData[0].DpcLock); + /* Get the right PCR for this CPU */ + if (Dpc->Number >= MAXIMUM_PROCESSORS) { + ASSERT (Dpc->Number - MAXIMUM_PROCESSORS < KeNumberProcessors); + Pcr = (PKPCR)(KPCR_BASE + (Dpc->Number - MAXIMUM_PROCESSORS) * PAGE_SIZE); + } else { + ASSERT (Dpc->Number < KeNumberProcessors); + Pcr = KeGetCurrentKPCR(); + Dpc->Number = KeGetCurrentProcessorNumber(); + } + KiAcquireSpinLock(&Pcr->PrcbData.DpcData[0].DpcLock); #else - Pcr = (PKPCR)KPCR_BASE; + Pcr = (PKPCR)KPCR_BASE; #endif - /* Get the DPC Data */ - if (InterlockedCompareExchangeUL(&Dpc->DpcData, &Pcr->PrcbData.DpcData[0].DpcLock, 0)) { - - DPRINT("DPC Already Inserted"); + /* Get the DPC Data */ + if (InterlockedCompareExchangeUL(&Dpc->DpcData, &Pcr->PrcbData.DpcData[0].DpcLock, 0)) { + DPRINT("DPC Already Inserted"); #ifdef CONFIG_SMP - KiReleaseSpinLock(&Pcr->PrcbData.DpcData[0].DpcLock); + KiReleaseSpinLock(&Pcr->PrcbData.DpcData[0].DpcLock); #endif - KeLowerIrql(OldIrql); - return(FALSE); - } - - /* Make sure the lists are free if the Queue is 0 */ - if (Pcr->PrcbData.DpcData[0].DpcQueueDepth == 0) { - - ASSERT(IsListEmpty(&Pcr->PrcbData.DpcData[0].DpcListHead)); - } else { - - ASSERT(!IsListEmpty(&Pcr->PrcbData.DpcData[0].DpcListHead)); - } - - /* Now we can play with the DPC safely */ - Dpc->SystemArgument1=SystemArgument1; - Dpc->SystemArgument2=SystemArgument2; - Pcr->PrcbData.DpcData[0].DpcQueueDepth++; - Pcr->PrcbData.DpcData[0].DpcCount++; - - /* Insert the DPC into the list. HighImportance DPCs go at the beginning */ - if (Dpc->Importance == HighImportance) { - - InsertHeadList(&Pcr->PrcbData.DpcData[0].DpcListHead, &Dpc->DpcListEntry); - } else { - - InsertTailList(&Pcr->PrcbData.DpcData[0].DpcListHead, &Dpc->DpcListEntry); - } - DPRINT("New DPC Added. Dpc->DpcListEntry.Flink %x\n", Dpc->DpcListEntry.Flink); + KeLowerIrql(OldIrql); + return(FALSE); + } + + /* Make sure the lists are free if the Queue is 0 */ + if (Pcr->PrcbData.DpcData[0].DpcQueueDepth == 0) { + ASSERT(IsListEmpty(&Pcr->PrcbData.DpcData[0].DpcListHead)); + } else { + ASSERT(!IsListEmpty(&Pcr->PrcbData.DpcData[0].DpcListHead)); + } + + /* Now we can play with the DPC safely */ + Dpc->SystemArgument1=SystemArgument1; + Dpc->SystemArgument2=SystemArgument2; + Pcr->PrcbData.DpcData[0].DpcQueueDepth++; + Pcr->PrcbData.DpcData[0].DpcCount++; + + /* Insert the DPC into the list. HighImportance DPCs go at the beginning */ + if (Dpc->Importance == HighImportance) { + InsertHeadList(&Pcr->PrcbData.DpcData[0].DpcListHead, &Dpc->DpcListEntry); + } else { + InsertTailList(&Pcr->PrcbData.DpcData[0].DpcListHead, &Dpc->DpcListEntry); + } + DPRINT("New DPC Added. Dpc->DpcListEntry.Flink %x\n", Dpc->DpcListEntry.Flink); - /* Make sure a DPC isn't executing already and respect rules outlined above. */ - if ((!Pcr->PrcbData.DpcRoutineActive) && (!Pcr->PrcbData.DpcInterruptRequested)) { - -#ifdef CONFIG_SMP - /* Check if this is the same CPU */ - if (Pcr != KeGetCurrentKPCR()) { - - /* Send IPI if High Importance */ - if ((Dpc->Importance == HighImportance) || - (Pcr->PrcbData.DpcData[0].DpcQueueDepth >= Pcr->PrcbData.MaximumDpcQueueDepth)) { - - if (Dpc->Number >= MAXIMUM_PROCESSORS) { - - KiIpiSendRequest(1 << (Dpc->Number - MAXIMUM_PROCESSORS), IPI_REQUEST_DPC); - } else { - - KiIpiSendRequest(1 << Dpc->Number, IPI_REQUEST_DPC); - } - - } - } else { - - /* Request an Interrupt only if the DPC isn't low priority */ - if ((Dpc->Importance != LowImportance) || - (Pcr->PrcbData.DpcData[0].DpcQueueDepth >= Pcr->PrcbData.MaximumDpcQueueDepth) || - (Pcr->PrcbData.DpcRequestRate < Pcr->PrcbData.MinimumDpcRate)) { - - /* Request Interrupt */ - HalRequestSoftwareInterrupt(DISPATCH_LEVEL); - Pcr->PrcbData.DpcInterruptRequested = TRUE; - } - } + /* Make sure a DPC isn't executing already and respect rules outlined above. */ + if ((!Pcr->PrcbData.DpcRoutineActive) && (!Pcr->PrcbData.DpcInterruptRequested)) { + +#ifdef CONFIG_SMP + /* Check if this is the same CPU */ + if (Pcr != KeGetCurrentKPCR()) { + /* Send IPI if High Importance */ + if ((Dpc->Importance == HighImportance) || + (Pcr->PrcbData.DpcData[0].DpcQueueDepth >= Pcr->PrcbData.MaximumDpcQueueDepth)) { + if (Dpc->Number >= MAXIMUM_PROCESSORS) { + KiIpiSendRequest(1 << (Dpc->Number - MAXIMUM_PROCESSORS), IPI_REQUEST_DPC); + } else { + KiIpiSendRequest(1 << Dpc->Number, IPI_REQUEST_DPC); + } + + } + } else { + /* Request an Interrupt only if the DPC isn't low priority */ + if ((Dpc->Importance != LowImportance) || + (Pcr->PrcbData.DpcData[0].DpcQueueDepth >= Pcr->PrcbData.MaximumDpcQueueDepth) || + (Pcr->PrcbData.DpcRequestRate < Pcr->PrcbData.MinimumDpcRate)) { + + /* Request Interrupt */ + HalRequestSoftwareInterrupt(DISPATCH_LEVEL); + Pcr->PrcbData.DpcInterruptRequested = TRUE; + } + } #else - DPRINT("Requesting Interrupt. Importance: %x. QueueDepth: %x. MaxQueue: %x . RequestRate: %x. MinRate:%x \n", Dpc->Importance, Pcr->PrcbData.DpcData[0].DpcQueueDepth, Pcr->PrcbData.MaximumDpcQueueDepth, Pcr->PrcbData.DpcRequestRate, Pcr->PrcbData.MinimumDpcRate); - - /* Request an Interrupt only if the DPC isn't low priority */ - if ((Dpc->Importance != LowImportance) || - (Pcr->PrcbData.DpcData[0].DpcQueueDepth >= Pcr->PrcbData.MaximumDpcQueueDepth) || - (Pcr->PrcbData.DpcRequestRate < Pcr->PrcbData.MinimumDpcRate)) { - - /* Request Interrupt */ - DPRINT("Requesting Interrupt\n"); - HalRequestSoftwareInterrupt(DISPATCH_LEVEL); - Pcr->PrcbData.DpcInterruptRequested = TRUE; - } + DPRINT("Requesting Interrupt. Importance: %x. QueueDepth: %x. MaxQueue: %x . RequestRate: %x. MinRate:%x \n", Dpc->Importance, Pcr->PrcbData.DpcData[0].DpcQueueDepth, Pcr->PrcbData.MaximumDpcQueueDepth, Pcr->PrcbData.DpcRequestRate, Pcr->PrcbData.MinimumDpcRate); + /* Request an Interrupt only if the DPC isn't low priority */ + if ((Dpc->Importance != LowImportance) || + (Pcr->PrcbData.DpcData[0].DpcQueueDepth >= Pcr->PrcbData.MaximumDpcQueueDepth) || + (Pcr->PrcbData.DpcRequestRate < Pcr->PrcbData.MinimumDpcRate)) { + + /* Request Interrupt */ + DPRINT("Requesting Interrupt\n"); + HalRequestSoftwareInterrupt(DISPATCH_LEVEL); + Pcr->PrcbData.DpcInterruptRequested = TRUE; + } #endif - } + } #ifdef CONFIG_SMP - KiReleaseSpinLock(&Pcr->PrcbData.DpcData[0].DpcLock); + KiReleaseSpinLock(&Pcr->PrcbData.DpcData[0].DpcLock); #endif - /* Lower IRQL */ - KeLowerIrql(OldIrql); - return(TRUE); + /* Lower IRQL */ + KeLowerIrql(OldIrql); + return(TRUE); } /* * @implemented - * + */ +BOOLEAN STDCALL +KeRemoveQueueDpc (PKDPC Dpc) +/* * FUNCTION: * Removes DPC object from the system dpc queue * ARGUMENTS: @@ -292,36 +281,33 @@ KeInsertQueueDpc(PKDPC Dpc, * TRUE if the DPC was in the queue * FALSE otherwise */ -BOOLEAN -STDCALL -KeRemoveQueueDpc(PKDPC Dpc) { - BOOLEAN WasInQueue; - KIRQL OldIrql; - - /* Raise IRQL */ - DPRINT("Removing DPC: %x\n", Dpc); - KeRaiseIrql(HIGH_LEVEL, &OldIrql); + BOOLEAN WasInQueue; + KIRQL OldIrql; + + /* Raise IRQL */ + DPRINT("Removing DPC: %x\n", Dpc); + KeRaiseIrql(HIGH_LEVEL, &OldIrql); #ifdef CONFIG_SMP - KiAcquireSpinLock(&((PKDPC_DATA)Dpc->DpcData)->DpcLock); + KiAcquireSpinLock(&((PKDPC_DATA)Dpc->DpcData)->DpcLock); #endif - - /* First make sure the DPC lock isn't being held */ - WasInQueue = Dpc->DpcData ? TRUE : FALSE; - if (Dpc->DpcData) { - - /* Remove the DPC */ - ((PKDPC_DATA)Dpc->DpcData)->DpcQueueDepth--; - RemoveEntryList(&Dpc->DpcListEntry); - - } + + /* First make sure the DPC lock isn't being held */ + WasInQueue = Dpc->DpcData ? TRUE : FALSE; + if (Dpc->DpcData) { + + /* Remove the DPC */ + ((PKDPC_DATA)Dpc->DpcData)->DpcQueueDepth--; + RemoveEntryList(&Dpc->DpcListEntry); + + } #ifdef CONFIG_SMP KiReleaseSpinLock(&((PKDPC_DATA)Dpc->DpcData)->DpcLock); #endif - /* Return if the DPC was in the queue or not */ - KeLowerIrql(OldIrql); - return WasInQueue; + /* Return if the DPC was in the queue or not */ + KeLowerIrql(OldIrql); + return WasInQueue; } /* @@ -337,8 +323,7 @@ KeFlushQueuedDpcs(VOID) * Called when deleting a Driver. */ { - /* Request an interrupt if needed */ - if (KeGetCurrentKPCR()->PrcbData.DpcData[0].DpcQueueDepth) HalRequestSoftwareInterrupt(DISPATCH_LEVEL); + if (KeGetCurrentKPCR()->PrcbData.DpcData[0].DpcQueueDepth) HalRequestSoftwareInterrupt(DISPATCH_LEVEL); } /* @@ -347,11 +332,10 @@ KeFlushQueuedDpcs(VOID) BOOLEAN STDCALL KeIsExecutingDpc( - VOID + VOID ) { - /* Return if the Dpc Routine is active */ - return KeGetCurrentKPCR()->PrcbData.DpcRoutineActive; + return KeGetCurrentKPCR()->PrcbData.DpcRoutineActive; } /* @@ -365,41 +349,39 @@ KeIsExecutingDpc( */ VOID STDCALL -KeSetImportanceDpc (IN PKDPC Dpc, - IN KDPC_IMPORTANCE Importance) +KeSetImportanceDpc (IN PKDPC Dpc, + IN KDPC_IMPORTANCE Importance) { - /* Set the DPC Importance */ - Dpc->Importance = Importance; + Dpc->Importance = Importance; } /* - * @implemented - * * FUNCTION: Specifies on which processor the DPC will run * ARGUMENTS: * Dpc = Initalizes DPC * Number = Processor number * RETURNS: None + * + * @implemented */ -VOID -STDCALL -KeSetTargetProcessorDpc(IN PKDPC Dpc, - IN CCHAR Number) +VOID STDCALL +KeSetTargetProcessorDpc (IN PKDPC Dpc, + IN CCHAR Number) { - /* Check how many CPUs are on the system */ - if (Number >= MAXIMUM_PROCESSORS) { - - /* No CPU Number */ - Dpc->Number = 0; - - } else { - - /* Set the Number Specified */ - ASSERT(Number < KeNumberProcessors); - Dpc->Number = Number + MAXIMUM_PROCESSORS; - } + if (Number >= MAXIMUM_PROCESSORS) + { + Dpc->Number = 0; + } + else + { + ASSERT(Number < KeNumberProcessors); + Dpc->Number = Number + MAXIMUM_PROCESSORS; + } } +VOID +STDCALL +KiQuantumEnd(VOID) /* * FUNCTION: * Called when a quantum end occurs to check if priority should be changed @@ -407,173 +389,152 @@ KeSetTargetProcessorDpc(IN PKDPC Dpc, * NOTES: * Called when deleting a Driver. */ -VOID -STDCALL -KiQuantumEnd(VOID) { - PKPRCB Prcb; - PKTHREAD CurrentThread; - KIRQL OldIrql; - PKPROCESS Process; - KPRIORITY OldPriority; - KPRIORITY NewPriority; - - /* Lock dispatcher, get current thread */ - Prcb = &KeGetCurrentKPCR()->PrcbData; - CurrentThread = KeGetCurrentThread(); - OldIrql = KeRaiseIrqlToSynchLevel(); - - /* Get the Thread's Process */ - Process = CurrentThread->ApcState.Process; - - /* Set DPC Event if requested */ - if (Prcb->DpcSetEventRequest) { - KeSetEvent(Prcb->DpcEvent, 0, 0); - } - - /* Check if Quantum expired */ - if (CurrentThread->Quantum <= 0) { - /* Set the new Quantum */ - CurrentThread->Quantum = Process->ThreadQuantum; - - /* Calculate new priority */ - OldPriority = CurrentThread->Priority; - if (OldPriority < LOW_REALTIME_PRIORITY) { - - /* Set the New Priority and add the Priority Decrement */ - NewPriority = OldPriority - CurrentThread->PriorityDecrement - 1; - - /* Don't go out of bounds */ - if (NewPriority < CurrentThread->BasePriority) NewPriority = CurrentThread->BasePriority; - - /* Reset the priority decrement */ - CurrentThread->PriorityDecrement = 0; - - /* Set a new priority if needed */ - if (OldPriority != NewPriority) { - - /* Set new Priority */ - CurrentThread->Priority = NewPriority; - - } else { - - /* Queue new thread if none is already */ - if (Prcb->NextThread == NULL) { - - /* FIXME: Schedule a New Thread, when ROS will have NT Scheduler */ - - } else { - - /* Make the current thread non-premeptive if a new thread is queued */ - CurrentThread->Preempted = FALSE; - } - } - - - } else { - /* Set the Quantum back to Maximum */ - //if (CurrentThread->DisableQuantum) { - // CurrentThread->Quantum = MAX_QUANTUM; - //} - } - } - - /* Dispatch the Thread */ - KeLowerIrql(DISPATCH_LEVEL); - PsDispatchThread(THREAD_STATE_READY); -} + PKPRCB Prcb; + PKTHREAD CurrentThread; + KIRQL OldIrql; + PKPROCESS Process; + KPRIORITY OldPriority; + KPRIORITY NewPriority; + + /* Lock dispatcher, get current thread */ + Prcb = &KeGetCurrentKPCR()->PrcbData; + CurrentThread = KeGetCurrentThread(); + OldIrql = KeRaiseIrqlToSynchLevel(); + + /* Get the Thread's Process */ + Process = CurrentThread->ApcState.Process; + + /* Set DPC Event if requested */ + if (Prcb->DpcSetEventRequest) { + KeSetEvent(Prcb->DpcEvent, 0, 0); + } + + /* Check if Quantum expired */ + if (CurrentThread->Quantum <= 0) { + /* Set the new Quantum */ + CurrentThread->Quantum = Process->ThreadQuantum; + + /* Calculate new priority */ + OldPriority = CurrentThread->Priority; + if (OldPriority < LOW_REALTIME_PRIORITY) { + NewPriority = OldPriority - CurrentThread->PriorityDecrement - 1; + if (NewPriority < CurrentThread->BasePriority) { + NewPriority = CurrentThread->BasePriority; + } + CurrentThread->PriorityDecrement = 0; + if (OldPriority != NewPriority) { + /* Set new Priority */ + CurrentThread->Priority = NewPriority; + } else { + /* Queue new thread if none is already */ + if (Prcb->NextThread == NULL) { + /* FIXME: Schedule a New Thread, when ROS will have NT Scheduler */ + } else { + /* Make the current thread non-premeptive if a new thread is queued */ + CurrentThread->Preempted = FALSE; + } + } + } else { + /* Set the Quantum back to Maximum */ + //if (CurrentThread->DisableQuantum) { + // CurrentThread->Quantum = MAX_QUANTUM; + //} + } + } + /* Dispatch the Thread */ + KeLowerIrql(DISPATCH_LEVEL); + PsDispatchThread(THREAD_STATE_READY); +} /* * @implemented - * - * FUNCTION: - * Called whenever a system interrupt is generated at DISPATCH_LEVEL. - * It delivers queued DPCs and dispatches a new thread if need be. */ VOID STDCALL KiDispatchInterrupt(VOID) +/* + * FUNCTION: + * Called whenever a system interrupt is generated at DISPATCH_LEVEL. + * It delivers queued DPCs and dispatches a new thread if need be. + */ { - PLIST_ENTRY DpcEntry; - PKDPC Dpc; - KIRQL OldIrql; - PKPCR Pcr; - - DPRINT("Dispatching Interrupts\n"); - ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); - - /* Set DPC Deliver to Active */ - Pcr = KeGetCurrentKPCR(); - - if (Pcr->PrcbData.DpcData[0].DpcQueueDepth > 0) { - /* Raise IRQL */ - KeRaiseIrql(HIGH_LEVEL, &OldIrql); -#ifdef CONFIG_SMP - KiAcquireSpinLock(&Pcr->PrcbData.DpcData[0].DpcLock); + PLIST_ENTRY DpcEntry; + PKDPC Dpc; + KIRQL OldIrql; + PKPCR Pcr; + + DPRINT("Dispatching Interrupts\n"); + ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); + + /* Set DPC Deliver to Active */ + Pcr = KeGetCurrentKPCR(); + + if (Pcr->PrcbData.DpcData[0].DpcQueueDepth > 0) { + /* Raise IRQL */ + KeRaiseIrql(HIGH_LEVEL, &OldIrql); +#ifdef CONFIG_SMP + KiAcquireSpinLock(&Pcr->PrcbData.DpcData[0].DpcLock); #endif - Pcr->PrcbData.DpcRoutineActive = TRUE; - - DPRINT("&Pcr->PrcbData.DpcData[0].DpcListHead: %x\n", &Pcr->PrcbData.DpcData[0].DpcListHead); - /* Loop while we have entries */ - while (!IsListEmpty(&Pcr->PrcbData.DpcData[0].DpcListHead)) { - - ASSERT(Pcr->PrcbData.DpcData[0].DpcQueueDepth > 0); - DPRINT("Queue Depth: %x\n", Pcr->PrcbData.DpcData[0].DpcQueueDepth); - - /* Get the DPC call it */ - DpcEntry = RemoveHeadList(&Pcr->PrcbData.DpcData[0].DpcListHead); - Dpc = CONTAINING_RECORD(DpcEntry, KDPC, DpcListEntry); - DPRINT("Dpc->DpcListEntry.Flink %x\n", Dpc->DpcListEntry.Flink); - Dpc->DpcData = NULL; - Pcr->PrcbData.DpcData[0].DpcQueueDepth--; + Pcr->PrcbData.DpcRoutineActive = TRUE; + + DPRINT("&Pcr->PrcbData.DpcData[0].DpcListHead: %x\n", &Pcr->PrcbData.DpcData[0].DpcListHead); + /* Loop while we have entries */ + while (!IsListEmpty(&Pcr->PrcbData.DpcData[0].DpcListHead)) { + ASSERT(Pcr->PrcbData.DpcData[0].DpcQueueDepth > 0); + DPRINT("Queue Depth: %x\n", Pcr->PrcbData.DpcData[0].DpcQueueDepth); + + /* Get the DPC call it */ + DpcEntry = RemoveHeadList(&Pcr->PrcbData.DpcData[0].DpcListHead); + Dpc = CONTAINING_RECORD(DpcEntry, KDPC, DpcListEntry); + DPRINT("Dpc->DpcListEntry.Flink %x\n", Dpc->DpcListEntry.Flink); + Dpc->DpcData = NULL; + Pcr->PrcbData.DpcData[0].DpcQueueDepth--; #ifdef CONFIG_SMP - KiReleaseSpinLock(&Pcr->PrcbData.DpcData[0].DpcLock); + KiReleaseSpinLock(&Pcr->PrcbData.DpcData[0].DpcLock); #endif - /* Disable/Enabled Interrupts and Call the DPC */ - KeLowerIrql(OldIrql); - DPRINT("Calling DPC: %x\n", Dpc); - Dpc->DeferredRoutine(Dpc, - Dpc->DeferredContext, - Dpc->SystemArgument1, - Dpc->SystemArgument2); - KeRaiseIrql(HIGH_LEVEL, &OldIrql); - + /* Disable/Enabled Interrupts and Call the DPC */ + KeLowerIrql(OldIrql); + DPRINT("Calling DPC: %x\n", Dpc); + Dpc->DeferredRoutine(Dpc, + Dpc->DeferredContext, + Dpc->SystemArgument1, + Dpc->SystemArgument2); + KeRaiseIrql(HIGH_LEVEL, &OldIrql); + #ifdef CONFIG_SMP - KiAcquireSpinLock(&Pcr->PrcbData.DpcData[0].DpcLock); - /* - * If the dpc routine drops the irql below DISPATCH_LEVEL, - * a thread switch can occur and after the next thread switch - * the execution may start on an other processor. - */ - if (Pcr != KeGetCurrentKPCR()) { - - Pcr->PrcbData.DpcRoutineActive = FALSE; - KiReleaseSpinLock(&Pcr->PrcbData.DpcData[0].DpcLock); - Pcr = KeGetCurrentKPCR(); - KiAcquireSpinLock(&Pcr->PrcbData.DpcData[0].DpcLock); - Pcr->PrcbData.DpcRoutineActive = TRUE; - } + KiAcquireSpinLock(&Pcr->PrcbData.DpcData[0].DpcLock); + /* + * If the dpc routine drops the irql below DISPATCH_LEVEL, + * a thread switch can occur and after the next thread switch + * the execution may start on an other processor. + */ + if (Pcr != KeGetCurrentKPCR()) { + Pcr->PrcbData.DpcRoutineActive = FALSE; + KiReleaseSpinLock(&Pcr->PrcbData.DpcData[0].DpcLock); + Pcr = KeGetCurrentKPCR(); + KiAcquireSpinLock(&Pcr->PrcbData.DpcData[0].DpcLock); + Pcr->PrcbData.DpcRoutineActive = TRUE; + } #endif - } - /* Clear DPC Flags */ - Pcr->PrcbData.DpcRoutineActive = FALSE; - Pcr->PrcbData.DpcInterruptRequested = FALSE; + } + /* Clear DPC Flags */ + Pcr->PrcbData.DpcRoutineActive = FALSE; + Pcr->PrcbData.DpcInterruptRequested = FALSE; #ifdef CONFIG_SMP - KiReleaseSpinLock(&Pcr->PrcbData.DpcData[0].DpcLock); + KiReleaseSpinLock(&Pcr->PrcbData.DpcData[0].DpcLock); #endif - - /* DPC Dispatching Ended, re-enable interrupts */ - KeLowerIrql(OldIrql); - } - - DPRINT("Checking for Quantum End\n"); - - /* If we have Quantum End, call the function */ - if (Pcr->PrcbData.QuantumEnd) { - - Pcr->PrcbData.QuantumEnd = FALSE; - KiQuantumEnd(); - } + + /* DPC Dispatching Ended, re-enable interrupts */ + KeLowerIrql(OldIrql); + } + + DPRINT("Checking for Quantum End\n"); + /* If we have Quantum End, call the function */ + if (Pcr->PrcbData.QuantumEnd) { + Pcr->PrcbData.QuantumEnd = FALSE; + KiQuantumEnd(); + } } /* EOF */ diff --git a/reactos/ntoskrnl/ke/error.c b/reactos/ntoskrnl/ke/error.c new file mode 100644 index 00000000000..d6172aa1687 --- /dev/null +++ b/reactos/ntoskrnl/ke/error.c @@ -0,0 +1,98 @@ +/* $Id$ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: ntoskrnl/ke/error.c + * PURPOSE: Error reason setting/getting + * + * PROGRAMMERS: David Welch + */ + +/* INCLUDE *****************************************************************/ + +#include +#include + +/* FUNCTIONS ***************************************************************/ + +BOOLEAN ExReadyForErrors = FALSE; +PEPORT ExpDefaultErrorPort = NULL; +PEPROCESS ExpDefaultErrorPortProcess = NULL; + +/* + * @unimplemented + */ +VOID +STDCALL +KiCoprocessorError( + VOID +) +{ + UNIMPLEMENTED; +} + +/* + * @unimplemented + */ +VOID +STDCALL +KiUnexpectedInterrupt( + VOID +) +{ + UNIMPLEMENTED; +} + +NTSTATUS STDCALL +NtRaiseHardError(IN NTSTATUS ErrorStatus, + IN ULONG NumberOfParameters, + IN PUNICODE_STRING UnicodeStringParameterMask OPTIONAL, + IN PVOID *Parameters, + IN HARDERROR_RESPONSE_OPTION ResponseOption, + OUT PHARDERROR_RESPONSE Response) +{ + DPRINT1("Hard error %x\n", ErrorStatus); + return(STATUS_SUCCESS); +} + +NTSTATUS STDCALL +NtSetDefaultHardErrorPort(IN HANDLE PortHandle) +{ + KPROCESSOR_MODE PreviousMode; + NTSTATUS Status; + + PreviousMode = ExGetPreviousMode(); + + if(!SeSinglePrivilegeCheck(SeTcbPrivilege, + PreviousMode)) + { + DPRINT1("NtSetDefaultHardErrorPort: Caller requires the SeTcbPrivilege privilege!\n"); + return STATUS_PRIVILEGE_NOT_HELD; + } + + /* serialization shouldn't be required here as it usually is just called once + during startup */ + + if(!ExReadyForErrors) + { + Status = ObReferenceObjectByHandle(PortHandle, + 0, + LpcPortObjectType, + PreviousMode, + (PVOID*)&ExpDefaultErrorPort, + NULL); + if(NT_SUCCESS(Status)) + { + ExpDefaultErrorPortProcess = PsGetCurrentProcess(); + ExReadyForErrors = TRUE; + } + } + else + { + Status = STATUS_UNSUCCESSFUL; + } + + return Status; +} + +/* EOF */ diff --git a/reactos/ntoskrnl/ke/event.c b/reactos/ntoskrnl/ke/event.c index 7683afa3b42..5ef0e626bf4 100644 --- a/reactos/ntoskrnl/ke/event.c +++ b/reactos/ntoskrnl/ke/event.c @@ -19,211 +19,121 @@ /* * @implemented */ -VOID -STDCALL -KeClearEvent(PKEVENT Event) +VOID STDCALL KeClearEvent (PKEVENT Event) { - DPRINT("KeClearEvent(Event %x)\n", Event); - - /* Reset Signal State */ - Event->Header.SignalState = FALSE; + DPRINT("KeClearEvent(Event %x)\n", Event); + 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) { - DPRINT("KeInitializeEvent(Event %x)\n", Event); - - /* Initialize the Dispatcher Header */ - KeInitializeDispatcherHeader(&Event->Header, - Type, - sizeof(Event) / sizeof(ULONG), - 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)); } /* * @implemented */ -VOID -STDCALL -KeInitializeEventPair(PKEVENT_PAIR EventPair) +LONG STDCALL KeReadStateEvent (PKEVENT Event) { - 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); + return(Event->Header.SignalState); } /* * @implemented */ -LONG STDCALL -KePulseEvent(IN PKEVENT Event, - IN KPRIORITY Increment, - IN BOOLEAN Wait) +LONG STDCALL KeResetEvent (PKEVENT Event) { - 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; + /* FIXME: must use interlocked func. everywhere! (wait.c) + * or use dispather lock instead + * -Gunnar */ + return(InterlockedExchange(&(Event->Header.SignalState),0)); } /* * @implemented */ -LONG -STDCALL -KeReadStateEvent(PKEVENT Event) +LONG STDCALL KeSetEvent (PKEVENT Event, + KPRIORITY Increment, + BOOLEAN Wait) { - /* Return the Signal State */ - return Event->Header.SignalState; -} + KIRQL OldIrql; + int ret; -/* - * @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; + DPRINT("KeSetEvent(Event %x, Wait %x)\n",Event,Wait); + + OldIrql = KeAcquireDispatcherDatabaseLock(); + + ret = InterlockedExchange(&Event->Header.SignalState,1); + + KiDispatcherObjectWake(&Event->Header, Increment); + + if (Wait == FALSE) + { + KeReleaseDispatcherDatabaseLock(OldIrql); + } + else + { + KTHREAD *Thread = KeGetCurrentThread(); + Thread->WaitNext = TRUE; + Thread->WaitIrql = OldIrql; + } + + return(ret); } /* * @implemented */ -LONG -STDCALL -KeSetEvent(PKEVENT Event, - KPRIORITY Increment, - BOOLEAN Wait) +LONG STDCALL +KePulseEvent (IN PKEVENT Event, + IN KPRIORITY Increment, + IN BOOLEAN Wait) { - KIRQL OldIrql; - LONG PreviousState; - PKWAIT_BLOCK WaitBlock; - - DPRINT("KeSetEvent(Event %x, Wait %x)\n",Event,Wait); - - /* 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); - } + KIRQL OldIrql; + LONG Ret; + + DPRINT("KePulseEvent(Event %x, Wait %x)\n",Event,Wait); + OldIrql = KeAcquireDispatcherDatabaseLock(); + Ret = InterlockedExchange(&Event->Header.SignalState,1); + KiDispatcherObjectWake(&Event->Header, Increment); + InterlockedExchange(&(Event->Header.SignalState),0); + + if (Wait == FALSE) + { + KeReleaseDispatcherDatabaseLock(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; + else + { + KTHREAD *Thread = KeGetCurrentThread(); + Thread->WaitNext = TRUE; + Thread->WaitIrql = OldIrql; } - /* Return the previous State */ - DPRINT("Done: %d\n", PreviousState); - return PreviousState; + return Ret; } /* @@ -231,39 +141,27 @@ KeSetEvent(PKEVENT Event, */ VOID STDCALL -KeSetEventBoostPriority(IN PKEVENT Event, - IN PKTHREAD *Thread OPTIONAL) +KeSetEventBoostPriority( + IN PKEVENT Event, + IN PKTHREAD *Thread OPTIONAL +) { - 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 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); - } + PKTHREAD WaitingThread; + KIRQL OldIrql; + + OldIrql = KeAcquireDispatcherDatabaseLock(); + + /* 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 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); - /* Release the Dispatcher Database Lock */ - KeReleaseDispatcherDatabaseLock(OldIrql); + KeReleaseDispatcherDatabaseLock(OldIrql); } /* EOF */ diff --git a/reactos/ntoskrnl/ke/i386/tskswitch.S b/reactos/ntoskrnl/ke/i386/tskswitch.S index 6d5038ae9bb..a97577fa5ee 100644 --- a/reactos/ntoskrnl/ke/i386/tskswitch.S +++ b/reactos/ntoskrnl/ke/i386/tskswitch.S @@ -200,7 +200,7 @@ _Ki386ContextSwitch: */ sti - call @KeReleaseDispatcherDatabaseLockFromDpcLevel@0 + call _KeReleaseDispatcherDatabaseLockFromDpcLevel cmpl $0, _PiNrThreadsAwaitingReaping je 5f diff --git a/reactos/ntoskrnl/ke/kthread.c b/reactos/ntoskrnl/ke/kthread.c index de1fd0bf367..40b352fb11a 100644 --- a/reactos/ntoskrnl/ke/kthread.c +++ b/reactos/ntoskrnl/ke/kthread.c @@ -1,11 +1,11 @@ -/* +/* $Id$ + * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * FILE: ntoskrnl/ke/kthread.c * PURPOSE: Microkernel thread support * - * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) - Commented, reorganized some stuff, fixed/implemented some functions. - * David Welch (welch@cwcom.net) + * PROGRAMMERS: David Welch (welch@cwcom.net) */ /* INCLUDES *****************************************************************/ @@ -16,93 +16,19 @@ /* FUNCTIONS *****************************************************************/ -ULONG -STDCALL -KeAlertResumeThread(IN PKTHREAD Thread) +VOID +KiServiceCheck (VOID) { - ULONG PreviousCount; - KIRQL OldIrql; - - ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); - - /* Lock the Dispatcher Database and the APC Queue */ - OldIrql = KeAcquireDispatcherDatabaseLock(); - KiAcquireSpinLock(&Thread->ApcQueueLock); - - /* Return if Thread is already alerted. */ - if (Thread->Alerted[KernelMode] == FALSE) { - - /* If it's Blocked, unblock if it we should */ - if (Thread->State == THREAD_STATE_BLOCKED && Thread->Alertable) { - - DPRINT("Aborting Wait\n"); - KiAbortWaitThread(Thread, STATUS_ALERTED); - - } else { - - /* If not, simply Alert it */ - Thread->Alerted[KernelMode] = TRUE; - } - } - - /* Save the old Suspend Count */ - PreviousCount = Thread->SuspendCount; - - /* If the thread is suspended, decrease one of the suspend counts */ - if (PreviousCount) { - - /* Decrease count. If we are now zero, unwait it completely */ - if (--Thread->SuspendCount) { - - /* Signal and satisfy */ - Thread->SuspendSemaphore.Header.SignalState++; - KiWaitTest(&Thread->SuspendSemaphore.Header, IO_NO_INCREMENT); - } - } + PETHREAD Thread; - /* Release Locks and return the Old State */ - KiReleaseSpinLock(&Thread->ApcQueueLock); - KeReleaseDispatcherDatabaseLock(OldIrql); - return PreviousCount; -} + Thread = PsGetCurrentThread(); -BOOLEAN -STDCALL -KeAlertThread(PKTHREAD Thread, - KPROCESSOR_MODE AlertMode) -{ - KIRQL OldIrql; - BOOLEAN PreviousState; + if (Thread->Tcb.ServiceTable != KeServiceDescriptorTableShadow) + { + PsInitWin32Thread (Thread); - /* Acquire the Dispatcher Database Lock */ - OldIrql = KeAcquireDispatcherDatabaseLock(); - - /* Save the Previous State */ - PreviousState = Thread->Alerted[AlertMode]; - - /* Return if Thread is already alerted. */ - if (PreviousState == FALSE) { - - /* If it's Blocked, unblock if it we should */ - if (Thread->State == THREAD_STATE_BLOCKED && - (AlertMode == KernelMode || Thread->WaitMode == AlertMode) && - Thread->Alertable) { - - DPRINT("Aborting Wait\n"); - KiAbortWaitThread(Thread, STATUS_ALERTED); - - } else { - - /* If not, simply Alert it */ - Thread->Alerted[AlertMode] = TRUE; - } + Thread->Tcb.ServiceTable = KeServiceDescriptorTableShadow; } - - /* Release the Dispatcher Lock */ - KeReleaseDispatcherDatabaseLock(OldIrql); - - /* Return the old state */ - return PreviousState; } /* @@ -110,231 +36,28 @@ KeAlertThread(PKTHREAD Thread, */ VOID STDCALL -KeCapturePersistentThreadState(IN PVOID CurrentThread, - IN ULONG Setting1, - IN ULONG Setting2, - IN ULONG Setting3, - IN ULONG Setting4, - IN ULONG Setting5, - IN PVOID ThreadState) +KeCapturePersistentThreadState( + IN PVOID CurrentThread, + IN ULONG Setting1, + IN ULONG Setting2, + IN ULONG Setting3, + IN ULONG Setting4, + IN ULONG Setting5, + IN PVOID ThreadState +) { - UNIMPLEMENTED; + UNIMPLEMENTED; } -/* - * FUNCTION: Initialize the microkernel state of the thread - */ VOID -STDCALL -KeInitializeThread(PKPROCESS Process, - PKTHREAD Thread, - BOOLEAN First) +KeFreeStackPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address, + PFN_TYPE Page, SWAPENTRY SwapEntry, BOOLEAN Dirty) { - PVOID KernelStack; - NTSTATUS Status; - extern unsigned int init_stack_top; - extern unsigned int init_stack; - PMEMORY_AREA StackArea; - ULONG i; - PHYSICAL_ADDRESS BoundaryAddressMultiple; - - /* Initialize the Boundary Address */ - BoundaryAddressMultiple.QuadPart = 0; - - /* Initalize the Dispatcher Header */ - KeInitializeDispatcherHeader(&Thread->DispatcherHeader, - ThreadObject, - sizeof(KTHREAD), - FALSE); - InitializeListHead(&Thread->MutantListHead); - - /* If this is isn't the first thread, allocate the Kernel Stack */ - if (!First) { - - PFN_TYPE Page[MM_STACK_SIZE / PAGE_SIZE]; - KernelStack = NULL; - - MmLockAddressSpace(MmGetKernelAddressSpace()); - Status = MmCreateMemoryArea(NULL, - MmGetKernelAddressSpace(), - MEMORY_AREA_KERNEL_STACK, - &KernelStack, - MM_STACK_SIZE, - 0, - &StackArea, - FALSE, - FALSE, - BoundaryAddressMultiple); - MmUnlockAddressSpace(MmGetKernelAddressSpace()); - - /* Check for Success */ - if (!NT_SUCCESS(Status)) { - - DPRINT1("Failed to create thread stack\n"); - KEBUGCHECK(0); - } - - /* Mark the Stack */ - for (i = 0; i < (MM_STACK_SIZE / PAGE_SIZE); i++) { - - Status = MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE, &Page[i]); - - /* Check for success */ - if (!NT_SUCCESS(Status)) { - - KEBUGCHECK(0); - } - } - - /* Create a Virtual Mapping for it */ - Status = MmCreateVirtualMapping(NULL, - KernelStack, - PAGE_READWRITE, - Page, - MM_STACK_SIZE / PAGE_SIZE); - - /* Check for success */ - if (!NT_SUCCESS(Status)) { - - KEBUGCHECK(0); - } - - /* Set the Kernel Stack */ - Thread->InitialStack = (PCHAR)KernelStack + MM_STACK_SIZE; - Thread->StackBase = (PCHAR)KernelStack + MM_STACK_SIZE; - Thread->StackLimit = (ULONG_PTR)KernelStack; - Thread->KernelStack = (PCHAR)KernelStack + MM_STACK_SIZE; - - } else { - - /* Use the Initial Stack */ - Thread->InitialStack = (PCHAR)init_stack_top; - Thread->StackBase = (PCHAR)init_stack_top; - Thread->StackLimit = (ULONG_PTR)init_stack; - Thread->KernelStack = (PCHAR)init_stack_top; + ASSERT(SwapEntry == 0); + if (Page != 0) + { + MmReleasePageMemoryConsumer(MC_NPPOOL, Page); } - - /* - * Establish the pde's for the new stack and the thread structure within the - * address space of the new process. They are accessed while taskswitching or - * while handling page faults. At this point it isn't possible to call the - * page fault handler for the missing pde's. - */ - MmUpdatePageDir((PEPROCESS)Process, (PVOID)Thread->StackLimit, MM_STACK_SIZE); - MmUpdatePageDir((PEPROCESS)Process, (PVOID)Thread, sizeof(ETHREAD)); - - /* Set the Thread to initalized */ - Thread->State = THREAD_STATE_INITIALIZED; - - /* The Native API function will initialize the TEB field later */ - Thread->Teb = NULL; - - /* Initialize stuff to zero */ - Thread->TlsArray = NULL; - Thread->DebugActive = 0; - Thread->Alerted[0] = 0; - Thread->Alerted[1] = 0; - Thread->Iopl = 0; - - /* FIXME: Think how this might work */ - Thread->NpxState = 0; - Thread->NpxIrql = 0; - - /* Setup APC Fields */ - InitializeListHead(&Thread->ApcState.ApcListHead[0]); - InitializeListHead(&Thread->ApcState.ApcListHead[1]); - Thread->ApcState.Process = Process; - Thread->ApcState.KernelApcInProgress = 0; - Thread->ApcState.KernelApcPending = 0; - Thread->ApcState.UserApcPending = 0; - Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->ApcState; - Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->SavedApcState; - Thread->ApcStateIndex = OriginalApcEnvironment; - Thread->ApcQueueable = TRUE; - memset(&Thread->SavedApcState, 0, sizeof(KAPC_STATE)); - KeInitializeSpinLock(&Thread->ApcQueueLock); - - /* Setup Wait Fields */ - Thread->WaitStatus = STATUS_SUCCESS; - Thread->WaitIrql = PASSIVE_LEVEL; - Thread->WaitMode = 0; - Thread->WaitNext = FALSE; - Thread->WaitListEntry.Flink = NULL; - Thread->WaitListEntry.Blink = NULL; - Thread->WaitTime = 0; - Thread->WaitBlockList = NULL; - memset(Thread->WaitBlock, 0, sizeof(KWAIT_BLOCK) * 4); - memset(&Thread->Timer, 0, sizeof(KTIMER)); - KeInitializeTimer(&Thread->Timer); - - /* Setup scheduler Fields */ - Thread->BasePriority = Process->BasePriority; - Thread->DecrementCount = 0; - Thread->PriorityDecrement = 0; - Thread->Quantum = Process->ThreadQuantum; - Thread->Saturation = 0; - Thread->Priority = Process->BasePriority; - Thread->UserAffinity = Process->Affinity; - Thread->SystemAffinityActive = 0; - Thread->Affinity = Process->Affinity; - Thread->Preempted = 0; - Thread->ProcessReadyQueue = 0; - Thread->KernelStackResident = 1; - Thread->NextProcessor = 0; - Thread->ContextSwitches = 0; - - /* Setup Queue Fields */ - Thread->Queue = NULL; - Thread->QueueListEntry.Flink = NULL; - Thread->QueueListEntry.Blink = NULL; - - /* Setup Misc Fields */ - Thread->LegoData = 0; - Thread->PowerState = 0; - Thread->ServiceTable = KeServiceDescriptorTable; - Thread->CallbackStack = NULL; - Thread->Win32Thread = NULL; - Thread->TrapFrame = NULL; - Thread->EnableStackSwap = 0; - Thread->LargeStack = 0; - Thread->ResourceIndex = 0; - Thread->PreviousMode = KernelMode; - Thread->KernelTime = 0; - Thread->UserTime = 0; - Thread->AutoAlignment = Process->AutoAlignment; - - /* FIXME OPTIMIZATION OF DOOM. DO NOT ENABLE FIXME */ -#if 0 - Thread->WaitBlock[3].Object = (PVOID)&Thread->Timer; - Thread->WaitBlock[3].Thread = Thread; - Thread->WaitBlock[3].WaitKey = STATUS_TIMEOUT; - Thread->WaitBlock[3].WaitType = WaitAny; - Thread->WaitBlock[3].NextWaitBlock = NULL; - InsertTailList(&Thread->Timer.Header.WaitListHead, - &Thread->WaitBlock[3].WaitListEntry); -#endif - - /* Initialize the Suspend APC */ - KeInitializeApc(&Thread->SuspendApc, - Thread, - OriginalApcEnvironment, - PiSuspendThreadKernelRoutine, - PiSuspendThreadRundownRoutine, - PiSuspendThreadNormalRoutine, - KernelMode, - NULL); - - /* Initialize the Suspend Semaphore */ - KeInitializeSemaphore(&Thread->SuspendSemaphore, 0, 128); - - /* Insert the Thread into the Process's Thread List */ - InsertTailList(&Process->ThreadListHead, &Thread->ThreadListEntry); - - /* Set up the Suspend Counts */ - Thread->FreezeCount = 0; - Thread->SuspendCount = 0; - - /* Do x86 specific part */ } /* @@ -342,9 +65,11 @@ KeInitializeThread(PKPROCESS Process, */ KPRIORITY STDCALL -KeQueryPriorityThread (IN PKTHREAD Thread) +KeQueryPriorityThread ( + IN PKTHREAD Thread + ) { - return Thread->Priority; + return Thread->Priority; } /* @@ -352,29 +77,19 @@ KeQueryPriorityThread (IN PKTHREAD Thread) */ ULONG STDCALL -KeQueryRuntimeThread(IN PKTHREAD Thread, - OUT PULONG UserTime) -{ - /* Return the User Time */ - *UserTime = Thread->UserTime; - - /* Return the Kernel Time */ - return Thread->KernelTime; -} - -VOID -KeFreeStackPage(PVOID Context, - MEMORY_AREA* MemoryArea, - PVOID Address, - PFN_TYPE Page, - SWAPENTRY SwapEntry, - BOOLEAN Dirty) +KeQueryRuntimeThread( + IN PKTHREAD Thread, + OUT PULONG UserTime + ) { - ASSERT(SwapEntry == 0); - if (Page) MmReleasePageMemoryConsumer(MC_NPPOOL, Page); + /* Return the User Time */ + *UserTime = Thread->UserTime; + + /* Return the Kernel Time */ + return Thread->KernelTime; } -NTSTATUS +NTSTATUS KeReleaseThread(PKTHREAD Thread) /* * FUNCTION: Releases the resource allocated for a thread by @@ -408,329 +123,344 @@ KeReleaseThread(PKTHREAD Thread) */ BOOLEAN STDCALL -KeSetKernelStackSwapEnable(IN BOOLEAN Enable) +KeSetKernelStackSwapEnable( + IN BOOLEAN Enable + ) { - PKTHREAD Thread = KeGetCurrentThread(); - BOOLEAN PreviousState; - KIRQL OldIrql; - - /* Lock the Dispatcher Database */ - OldIrql = KeAcquireDispatcherDatabaseLock(); - - /* Save Old State */ - PreviousState = Thread->EnableStackSwap; - - /* Set New State */ - Thread->EnableStackSwap = Enable; - - /* No, Release Lock */ - KeReleaseDispatcherDatabaseLock(OldIrql); - - /* Return Old State */ - return PreviousState; + PKTHREAD Thread; + BOOLEAN PreviousState; + + Thread = KeGetCurrentThread(); + + /* Save Old State */ + PreviousState = Thread->EnableStackSwap; + + /* Set New State */ + Thread->EnableStackSwap = Enable; + + /* Return Old State */ + return PreviousState; } +VOID +KeInitializeThread(PKPROCESS Process, PKTHREAD Thread, BOOLEAN First) /* - * @implemented + * FUNCTION: Initialize the microkernel state of the thread */ -VOID -STDCALL -KeRevertToUserAffinityThread(VOID) { - PKTHREAD CurrentThread = KeGetCurrentThread(); - KIRQL OldIrql; - - ASSERT(CurrentThread->SystemAffinityActive != FALSE); - - /* Lock the Dispatcher Database */ - OldIrql = KeAcquireDispatcherDatabaseLock(); - - /* Return to User Affinity */ - CurrentThread->Affinity = CurrentThread->UserAffinity; - - /* Disable System Affinity */ - CurrentThread->SystemAffinityActive = FALSE; - - /* Check if we need to Dispatch a New thread */ - if (CurrentThread->Affinity & (1 << KeGetCurrentProcessorNumber())) { - - /* No, just release */ - KeReleaseDispatcherDatabaseLock(OldIrql); - - } else { - - /* We need to dispatch a new thread */ - CurrentThread->WaitIrql = OldIrql; - PsDispatchThreadNoLock(THREAD_STATE_READY); - KeLowerIrql(OldIrql); + PVOID KernelStack; + NTSTATUS Status; + extern unsigned int init_stack_top; + extern unsigned int init_stack; + PMEMORY_AREA StackArea; + ULONG i; + PHYSICAL_ADDRESS BoundaryAddressMultiple; + + BoundaryAddressMultiple.QuadPart = 0; + + KeInitializeDispatcherHeader(&Thread->DispatcherHeader, + InternalThreadType, + sizeof(ETHREAD), + FALSE); + InitializeListHead(&Thread->MutantListHead); + if (!First) + { + PFN_TYPE Page[MM_STACK_SIZE / PAGE_SIZE]; + KernelStack = NULL; + + MmLockAddressSpace(MmGetKernelAddressSpace()); + Status = MmCreateMemoryArea(NULL, + MmGetKernelAddressSpace(), + MEMORY_AREA_KERNEL_STACK, + &KernelStack, + MM_STACK_SIZE, + 0, + &StackArea, + FALSE, + FALSE, + BoundaryAddressMultiple); + MmUnlockAddressSpace(MmGetKernelAddressSpace()); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to create thread stack\n"); + KEBUGCHECK(0); + } + for (i = 0; i < (MM_STACK_SIZE / PAGE_SIZE); i++) + { + Status = MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE, &Page[i]); + if (!NT_SUCCESS(Status)) + { + KEBUGCHECK(0); + } + } + Status = MmCreateVirtualMapping(NULL, + KernelStack, + PAGE_READWRITE, + Page, + MM_STACK_SIZE / PAGE_SIZE); + if (!NT_SUCCESS(Status)) + { + KEBUGCHECK(0); + } + Thread->InitialStack = (PCHAR)KernelStack + MM_STACK_SIZE; + Thread->StackBase = (PCHAR)KernelStack + MM_STACK_SIZE; + Thread->StackLimit = (ULONG_PTR)KernelStack; + Thread->KernelStack = (PCHAR)KernelStack + MM_STACK_SIZE; + } + else + { + Thread->InitialStack = (PCHAR)init_stack_top; + Thread->StackBase = (PCHAR)init_stack_top; + Thread->StackLimit = (ULONG_PTR)init_stack; + Thread->KernelStack = (PCHAR)init_stack_top; } + + /* + * Establish the pde's for the new stack and the thread structure within the + * address space of the new process. They are accessed while taskswitching or + * while handling page faults. At this point it isn't possible to call the + * page fault handler for the missing pde's. + */ + + MmUpdatePageDir((PEPROCESS)Process, (PVOID)Thread->StackLimit, MM_STACK_SIZE); + MmUpdatePageDir((PEPROCESS)Process, (PVOID)Thread, sizeof(ETHREAD)); + + /* + * The Native API function will initialize the TEB field later + */ + Thread->Teb = NULL; + Thread->TlsArray = NULL; + Thread->DebugActive = 0; + Thread->State = THREAD_STATE_INITIALIZED; + Thread->Alerted[0] = 0; + Thread->Alerted[1] = 0; + Thread->Iopl = 0; + /* + * FIXME: Think how this might work + */ + Thread->NpxState = 0; + + Thread->Saturation = 0; + Thread->Priority = Process->BasePriority; + InitializeListHead(&Thread->ApcState.ApcListHead[0]); + InitializeListHead(&Thread->ApcState.ApcListHead[1]); + Thread->ApcState.Process = Process; + Thread->ApcState.KernelApcInProgress = 0; + Thread->ApcState.KernelApcPending = 0; + Thread->ApcState.UserApcPending = 0; + Thread->ContextSwitches = 0; + Thread->WaitStatus = STATUS_SUCCESS; + Thread->WaitIrql = PASSIVE_LEVEL; + Thread->WaitMode = 0; + Thread->WaitNext = FALSE; + Thread->WaitBlockList = NULL; + Thread->WaitListEntry.Flink = NULL; + Thread->WaitListEntry.Blink = NULL; + Thread->WaitTime = 0; + Thread->BasePriority = Process->BasePriority; + Thread->DecrementCount = 0; + Thread->PriorityDecrement = 0; + Thread->Quantum = Process->ThreadQuantum; + memset(Thread->WaitBlock, 0, sizeof(KWAIT_BLOCK)*4); + Thread->LegoData = 0; + Thread->UserAffinity = Process->Affinity; + Thread->SystemAffinityActive = 0; + Thread->PowerState = 0; + Thread->NpxIrql = 0; + Thread->ServiceTable = KeServiceDescriptorTable; + Thread->Queue = NULL; + KeInitializeSpinLock(&Thread->ApcQueueLock); + memset(&Thread->Timer, 0, sizeof(KTIMER)); + KeInitializeTimer(&Thread->Timer); + Thread->QueueListEntry.Flink = NULL; + Thread->QueueListEntry.Blink = NULL; + Thread->Affinity = Process->Affinity; + Thread->Preempted = 0; + Thread->ProcessReadyQueue = 0; + Thread->KernelStackResident = 1; + Thread->NextProcessor = 0; + Thread->CallbackStack = NULL; + Thread->Win32Thread = NULL; + Thread->TrapFrame = NULL; + Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->ApcState; + Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->SavedApcState; + Thread->EnableStackSwap = 0; + Thread->LargeStack = 0; + Thread->ResourceIndex = 0; + Thread->PreviousMode = KernelMode; + Thread->KernelTime = 0; + Thread->UserTime = 0; + memset(&Thread->SavedApcState, 0, sizeof(KAPC_STATE)); + + Thread->ApcStateIndex = OriginalApcEnvironment; + Thread->ApcQueueable = TRUE; + Thread->AutoAlignment = Process->AutoAlignment; + + KeInitializeApc(&Thread->SuspendApc, + Thread, + OriginalApcEnvironment, + PiSuspendThreadKernelRoutine, + PiSuspendThreadRundownRoutine, + PiSuspendThreadNormalRoutine, + KernelMode, + NULL); + KeInitializeSemaphore(&Thread->SuspendSemaphore, 0, 128); + + InsertTailList(&Process->ThreadListHead, + &Thread->ThreadListEntry); + Thread->FreezeCount = 0; + Thread->SuspendCount = 0; + + /* + * Do x86 specific part + */ } /* * @implemented */ -CCHAR +VOID STDCALL -KeSetIdealProcessorThread(IN PKTHREAD Thread, - IN CCHAR Processor) +KeRevertToUserAffinityThread(VOID) { - CCHAR PreviousIdealProcessor; - KIRQL OldIrql; - - /* Lock the Dispatcher Database */ - OldIrql = KeAcquireDispatcherDatabaseLock(); - - /* Save Old Ideal Processor */ - PreviousIdealProcessor = Thread->IdealProcessor; - - /* Set New Ideal Processor */ - Thread->IdealProcessor = Processor; - - /* Release Lock */ - KeReleaseDispatcherDatabaseLock(OldIrql); - - /* Return Old Ideal Processor */ - return PreviousIdealProcessor; +#ifdef CONFIG_SMP + PKTHREAD CurrentThread; + KIRQL oldIrql; + + oldIrql = KeAcquireDispatcherDatabaseLock(); + + CurrentThread = KeGetCurrentThread(); + + ASSERT(CurrentThread->SystemAffinityActive != FALSE); + + /* Return to User Affinity */ + CurrentThread->Affinity = CurrentThread->UserAffinity; + + /* Disable System Affinity */ + CurrentThread->SystemAffinityActive = FALSE; + + if (CurrentThread->Affinity & (1 << KeGetCurrentProcessorNumber())) + { + KeReleaseDispatcherDatabaseLock(oldIrql); + } + else + { + CurrentThread->WaitIrql = oldIrql; + PsDispatchThreadNoLock(THREAD_STATE_READY); + KeLowerIrql(oldIrql); + } +#endif } /* * @implemented */ -VOID +CCHAR STDCALL -KeSetSystemAffinityThread(IN KAFFINITY Affinity) +KeSetIdealProcessorThread ( + IN PKTHREAD Thread, + IN CCHAR Processor) { - PKTHREAD CurrentThread = KeGetCurrentThread(); - KIRQL OldIrql; - - ASSERT(Affinity & ((1 << KeNumberProcessors) - 1)); - - /* Lock the Dispatcher Database */ - OldIrql = KeAcquireDispatcherDatabaseLock(); - - /* Set the System Affinity Specified */ - CurrentThread->Affinity = Affinity; - - /* Enable System Affinity */ - CurrentThread->SystemAffinityActive = TRUE; - - /* Check if we need to Dispatch a New thread */ - if (Affinity & (1 << KeGetCurrentProcessorNumber())) { - - /* No, just release */ - KeReleaseDispatcherDatabaseLock(OldIrql); - - } else { - - /* We need to dispatch a new thread */ - CurrentThread->WaitIrql = OldIrql; - PsDispatchThreadNoLock(THREAD_STATE_READY); - KeLowerIrql(OldIrql); - } + CCHAR PreviousIdealProcessor; + + /* Save Old Ideal Processor */ + PreviousIdealProcessor = Thread->IdealProcessor; + + /* Set New Ideal Processor */ + Thread->IdealProcessor = Processor; + + /* Return Old Ideal Processor */ + return PreviousIdealProcessor; } /* * @implemented */ - /* The Increment Argument seems to be ignored by NT and always 0 when called */ VOID STDCALL -KeTerminateThread(IN KPRIORITY Increment) +KeSetSystemAffinityThread(IN KAFFINITY Affinity) { - /* Call our own internal routine */ - PsTerminateCurrentThread(0); +#ifdef CONFIG_SMP + PKTHREAD CurrentThread; + KIRQL oldIrql; + + oldIrql = KeAcquireDispatcherDatabaseLock(); + + CurrentThread = KeGetCurrentThread(); + + ASSERT(Affinity & ((1 << KeNumberProcessors) - 1)); + + /* Set the System Affinity Specified */ + CurrentThread->Affinity = Affinity; + + /* Enable System Affinity */ + CurrentThread->SystemAffinityActive = TRUE; + + if (Affinity & (1 << KeGetCurrentProcessorNumber())) + { + KeReleaseDispatcherDatabaseLock(oldIrql); + } + else + { + CurrentThread->WaitIrql = oldIrql; + PsDispatchThreadNoLock(THREAD_STATE_READY); + KeLowerIrql(oldIrql); + } +#endif } /* - * FUNCTION: Tests whether there are any pending APCs for the current thread - * and if so the APCs will be delivered on exit from kernel mode + * @implemented */ -BOOLEAN -STDCALL -KeTestAlertThread(IN KPROCESSOR_MODE AlertMode) -{ - KIRQL OldIrql; - PKTHREAD Thread = KeGetCurrentThread(); - BOOLEAN OldState; - - ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); - - /* Lock the Dispatcher Database and the APC Queue */ - OldIrql = KeAcquireDispatcherDatabaseLock(); - KiAcquireSpinLock(&Thread->ApcQueueLock); - - /* Save the old State */ - OldState = Thread->Alerted[AlertMode]; - - /* If the Thread is Alerted, Clear it */ - if (OldState) { - - Thread->Alerted[AlertMode] = FALSE; - - } else if ((AlertMode == UserMode) && (!IsListEmpty(&Thread->ApcState.ApcListHead[UserMode]))) { - - /* If the mode is User and the Queue isn't empty, set Pending */ - Thread->ApcState.UserApcPending = TRUE; - } - - /* Release Locks and return the Old State */ - KiReleaseSpinLock(&Thread->ApcQueueLock); - KeReleaseDispatcherDatabaseLock(OldIrql); - return OldState; -} - VOID -KiServiceCheck (VOID) -{ - PKTHREAD Thread = KeGetCurrentThread(); - - /* Check if we need to inialize Win32 for this Thread */ - if (Thread->ServiceTable != KeServiceDescriptorTableShadow) { - - /* We do. Initialize it and save the new table */ - PsInitWin32Thread((PETHREAD)Thread); - Thread->ServiceTable = KeServiceDescriptorTableShadow; - } -} - -/* - * - * NOT EXPORTED - */ -NTSTATUS STDCALL -NtAlertResumeThread(IN HANDLE ThreadHandle, - OUT PULONG SuspendCount) +KeTerminateThread(IN KPRIORITY Increment) { - KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); - PETHREAD Thread; - NTSTATUS Status; - ULONG PreviousState; - - /* Check if parameters are valid */ - if(PreviousMode != KernelMode) { - - _SEH_TRY { - - ProbeForWrite(SuspendCount, - sizeof(HANDLE), - sizeof(ULONG)); - - } _SEH_HANDLE { - - Status = _SEH_GetExceptionCode(); - - } _SEH_END; - } - - /* Reference the Object */ - Status = ObReferenceObjectByHandle(ThreadHandle, - THREAD_SUSPEND_RESUME, - PsThreadType, - PreviousMode, - (PVOID*)&Thread, - NULL); - - /* Check for Success */ - if (NT_SUCCESS(Status)) { - - /* Call the Kernel Function */ - PreviousState = KeAlertResumeThread(&Thread->Tcb); - - /* Dereference Object */ - ObDereferenceObject(Thread); - - if (SuspendCount) { - - _SEH_TRY { - - *SuspendCount = PreviousState; - - } _SEH_HANDLE { - - Status = _SEH_GetExceptionCode(); - - } _SEH_END; - } - } - - /* Return status */ - return Status; + /* The Increment Argument seems to be ignored by NT and always 0 when called */ + + /* Call our own internal routine */ + PsTerminateCurrentThread(0); } -/* - * @implemented - * - * EXPORTED - */ -NTSTATUS -STDCALL -NtAlertThread (IN HANDLE ThreadHandle) -{ - KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); - PETHREAD Thread; - NTSTATUS Status; - - /* Reference the Object */ - Status = ObReferenceObjectByHandle(ThreadHandle, - THREAD_SUSPEND_RESUME, - PsThreadType, - PreviousMode, - (PVOID*)&Thread, - NULL); - - /* Check for Success */ - if (NT_SUCCESS(Status)) { - - /* - * Do an alert depending on the processor mode. If some kmode code wants to - * enforce a umode alert it should call KeAlertThread() directly. If kmode - * code wants to do a kmode alert it's sufficient to call it with Zw or just - * use KeAlertThread() directly - */ - KeAlertThread(&Thread->Tcb, PreviousMode); - - /* Dereference Object */ - ObDereferenceObject(Thread); - } - - /* Return status */ - return Status; -} NTSTATUS STDCALL NtDelayExecution(IN BOOLEAN Alertable, IN PLARGE_INTEGER DelayInterval) { - KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); - LARGE_INTEGER SafeInterval; - NTSTATUS Status; + KPROCESSOR_MODE PreviousMode; + LARGE_INTEGER SafeInterval; - /* Check if parameters are valid */ - if(PreviousMode != KernelMode) { + PreviousMode = ExGetPreviousMode(); + + if(PreviousMode != KernelMode) + { + NTSTATUS Status = STATUS_SUCCESS; + + _SEH_TRY + { + ProbeForRead(DelayInterval, + sizeof(LARGE_INTEGER), + sizeof(ULONG)); + /* make a copy on the kernel stack and let DelayInterval point to it so + we don't need to wrap KeDelayExecutionThread in SEH! */ + SafeInterval = *DelayInterval; + DelayInterval = &SafeInterval; + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; - _SEH_TRY { - - ProbeForRead(DelayInterval, - sizeof(LARGE_INTEGER), - sizeof(ULONG)); - - /* make a copy on the kernel stack and let DelayInterval point to it so - we don't need to wrap KeDelayExecutionThread in SEH! */ - SafeInterval = *DelayInterval; - - } _SEH_HANDLE { - - Status = _SEH_GetExceptionCode(); - } _SEH_END; + if(!NT_SUCCESS(Status)) + { + return Status; + } } - /* Call the Kernel Function */ - Status = KeDelayExecutionThread(PreviousMode, - Alertable, - &SafeInterval); - - /* Return Status */ - return Status; + return KeDelayExecutionThread(PreviousMode, + Alertable, + DelayInterval); } diff --git a/reactos/ntoskrnl/ke/main.c b/reactos/ntoskrnl/ke/main.c index 71021dae392..eef694b0bc7 100644 --- a/reactos/ntoskrnl/ke/main.c +++ b/reactos/ntoskrnl/ke/main.c @@ -1,24 +1,37 @@ -/* +/* $Id$ + * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * FILE: ntoskrnl/ke/main.c * PURPOSE: Initalizes the kernel * - * PROGRAMMERS: Alex Ionescu (cleaned up code, moved Executiv stuff to ex/init.c) - * David Welch (welch@cwcom.net) + * PROGRAMMERS: David Welch (welch@cwcom.net) */ /* INCLUDES *****************************************************************/ #include +#include "../dbg/kdb.h" +#include +#include + +#ifdef HALDBG +#include +#else +#if defined(_MSC_VER) && (_MSC_VER <= 1200) +#define ps +#else +#define ps(args...) +#endif /* HALDBG */ + +#endif + #define NDEBUG #include /* GLOBALS *******************************************************************/ #define BUILD_OSCSDVERSION(major, minor) (((major & 0xFF) << 8) | (minor & 0xFF)) - - ULONG NtMajorVersion = 4; ULONG NtMinorVersion = 0; ULONG NtOSCSDVersion = BUILD_OSCSDVERSION(6, 0); @@ -45,17 +58,19 @@ EXPORTED ULONG KiDmaIoCoherency = 0; /* RISC Architectures only */ EXPORTED ULONG InitSafeBootMode = 0; /* KB83764 */ #endif /* __GNUC__ */ -LOADER_MODULE KeLoaderModules[64]; +static LOADER_MODULE KeLoaderModules[64]; static CHAR KeLoaderModuleStrings[64][256]; static CHAR KeLoaderCommandLine[256]; -ADDRESS_RANGE KeMemoryMap[64]; -ULONG KeMemoryMapRangeCount; -ULONG_PTR FirstKrnlPhysAddr; -ULONG_PTR LastKrnlPhysAddr; -ULONG_PTR LastKernelAddress; +static ADDRESS_RANGE KeMemoryMap[64]; +static ULONG KeMemoryMapRangeCount; +static ULONG_PTR FirstKrnlPhysAddr; +static ULONG_PTR LastKrnlPhysAddr; +static ULONG_PTR LastKernelAddress; volatile BOOLEAN Initialized = FALSE; +extern ULONG MmCoreDumpType; +extern CHAR KiTimerSystemAuditing; -ULONG KeLargestCacheLine = 0x40; /* FIXME: Arch-specific */ +extern PVOID Ki386InitialStackArray[MAXIMUM_PROCESSORS]; /* We allocate 4 pages, but we only use 3. The 4th is to guarantee page alignment */ ULONG kernel_stack[4096]; @@ -67,59 +82,793 @@ ULONG init_stack_top; ULONG trap_stack; ULONG trap_stack_top; -/* Cached modules from the loader block */ -PLOADER_MODULE CachedModules[MaximumCachedModuleType]; - /* FUNCTIONS ****************************************************************/ +static VOID INIT_FUNCTION +InitSystemSharedUserPage (PCSZ ParameterLine) +{ + UNICODE_STRING ArcDeviceName; + UNICODE_STRING ArcName; + UNICODE_STRING BootPath; + UNICODE_STRING DriveDeviceName; + UNICODE_STRING DriveName; + WCHAR DriveNameBuffer[20]; + PCHAR ParamBuffer; + PWCHAR ArcNameBuffer; + PCHAR p; + NTSTATUS Status; + ULONG Length; + OBJECT_ATTRIBUTES ObjectAttributes; + HANDLE Handle; + ULONG i; + BOOLEAN BootDriveFound; + + /* + * NOTE: + * The shared user page has been zeroed-out right after creation. + * There is NO need to do this again. + */ + + Ki386SetProcessorFeatures(); + + SharedUserData->NtProductType = NtProductWinNt; + SharedUserData->ProductTypeIsValid = TRUE; + SharedUserData->NtMajorVersion = 5; + SharedUserData->NtMinorVersion = 0; + + BootDriveFound = FALSE; + + /* + * Retrieve the current dos system path + * (e.g.: C:\reactos) from the given arc path + * (e.g.: multi(0)disk(0)rdisk(0)partititon(1)\reactos) + * Format: "\ [options...]" + */ + + /* create local parameter line copy */ + ParamBuffer = ExAllocatePool (PagedPool, 256); + strcpy (ParamBuffer, (char *)ParameterLine); + DPRINT("%s\n", ParamBuffer); + + /* cut options off */ + p = strchr (ParamBuffer, ' '); + if (p) + { + *p = 0; + } + DPRINT("%s\n", ParamBuffer); + + /* extract path */ + p = strchr (ParamBuffer, '\\'); + if (p) + { + DPRINT("Boot path: %s\n", p); + RtlCreateUnicodeStringFromAsciiz (&BootPath, p); + *p = 0; + } + else + { + DPRINT("Boot path: %s\n", "\\"); + RtlCreateUnicodeStringFromAsciiz (&BootPath, "\\"); + } + DPRINT("Arc name: %s\n", ParamBuffer); + + /* Only arc name left - build full arc name */ + ArcNameBuffer = ExAllocatePool (PagedPool, 256 * sizeof(WCHAR)); + swprintf (ArcNameBuffer, L"\\ArcName\\%S", ParamBuffer); + RtlInitUnicodeString (&ArcName, ArcNameBuffer); + DPRINT("Arc name: %wZ\n", &ArcName); + + /* free ParamBuffer */ + ExFreePool (ParamBuffer); + + /* allocate arc device name string */ + ArcDeviceName.Length = 0; + ArcDeviceName.MaximumLength = 256 * sizeof(WCHAR); + ArcDeviceName.Buffer = ExAllocatePool (PagedPool, 256 * sizeof(WCHAR)); + + InitializeObjectAttributes (&ObjectAttributes, + &ArcName, + OBJ_OPENLINK, + NULL, + NULL); + + Status = NtOpenSymbolicLinkObject (&Handle, + SYMBOLIC_LINK_ALL_ACCESS, + &ObjectAttributes); + RtlFreeUnicodeString (&ArcName); + if (!NT_SUCCESS(Status)) + { + RtlFreeUnicodeString (&BootPath); + RtlFreeUnicodeString (&ArcDeviceName); + CPRINT("NtOpenSymbolicLinkObject() failed (Status %x)\n", + Status); + + KEBUGCHECK (0x0); + } + + Status = NtQuerySymbolicLinkObject (Handle, + &ArcDeviceName, + &Length); + NtClose (Handle); + if (!NT_SUCCESS(Status)) + { + RtlFreeUnicodeString (&BootPath); + RtlFreeUnicodeString (&ArcDeviceName); + CPRINT("NtQuerySymbolicObject() failed (Status %x)\n", + Status); + + KEBUGCHECK (0x0); + } + DPRINT("Length: %lu ArcDeviceName: %wZ\n", Length, &ArcDeviceName); + + + /* allocate device name string */ + DriveDeviceName.Length = 0; + DriveDeviceName.MaximumLength = 256 * sizeof(WCHAR); + DriveDeviceName.Buffer = ExAllocatePool (PagedPool, 256 * sizeof(WCHAR)); + + for (i = 0; i < 26; i++) + { + swprintf (DriveNameBuffer, L"\\??\\%C:", 'A' + i); + RtlInitUnicodeString (&DriveName, + DriveNameBuffer); + + InitializeObjectAttributes (&ObjectAttributes, + &DriveName, + OBJ_OPENLINK, + NULL, + NULL); + + Status = NtOpenSymbolicLinkObject (&Handle, + SYMBOLIC_LINK_ALL_ACCESS, + &ObjectAttributes); + if (!NT_SUCCESS(Status)) + { + DPRINT("Failed to open link %wZ\n", + &DriveName); + continue; + } + + Status = NtQuerySymbolicLinkObject (Handle, + &DriveDeviceName, + &Length); + if (!NT_SUCCESS(Status)) + { + DPRINT("Failed query open link %wZ\n", + &DriveName); + continue; + } + DPRINT("Opened link: %wZ ==> %wZ\n", + &DriveName, &DriveDeviceName); + + if (!RtlCompareUnicodeString (&ArcDeviceName, &DriveDeviceName, FALSE)) + { + DPRINT("DOS Boot path: %c:%wZ\n", 'A' + i, &BootPath); + swprintf(SharedUserData->NtSystemRoot, + L"%C:%wZ", 'A' + i, &BootPath); + + BootDriveFound = TRUE; + } + + NtClose (Handle); + } + + RtlFreeUnicodeString (&BootPath); + RtlFreeUnicodeString (&DriveDeviceName); + RtlFreeUnicodeString (&ArcDeviceName); + + if (BootDriveFound == FALSE) + { + DbgPrint("No system drive found!\n"); + KEBUGCHECK (NO_BOOT_DEVICE); + } +} + +VOID INIT_FUNCTION +ExpInitializeExecutive(VOID) +{ + LARGE_INTEGER Timeout; + HANDLE ProcessHandle; + HANDLE ThreadHandle; + ULONG i; + ULONG start; + ULONG length; + PCHAR name; + CHAR str[50]; + NTSTATUS Status; + BOOLEAN SetupBoot; + PCHAR p1, p2; + ULONG MaxMem; + BOOLEAN NoGuiBoot = FALSE; + UNICODE_STRING Name; + HANDLE InitDoneEventHandle; + OBJECT_ATTRIBUTES ObjectAttributes; + + /* + * Fail at runtime if someone has changed various structures without + * updating the offsets used for the assembler code. + */ + ASSERT(FIELD_OFFSET(KTHREAD, InitialStack) == KTHREAD_INITIAL_STACK); + ASSERT(FIELD_OFFSET(KTHREAD, Teb) == KTHREAD_TEB); + ASSERT(FIELD_OFFSET(KTHREAD, KernelStack) == KTHREAD_KERNEL_STACK); + ASSERT(FIELD_OFFSET(KTHREAD, NpxState) == KTHREAD_NPX_STATE); + ASSERT(FIELD_OFFSET(KTHREAD, ServiceTable) == KTHREAD_SERVICE_TABLE); + ASSERT(FIELD_OFFSET(KTHREAD, PreviousMode) == KTHREAD_PREVIOUS_MODE); + ASSERT(FIELD_OFFSET(KTHREAD, TrapFrame) == KTHREAD_TRAP_FRAME); + ASSERT(FIELD_OFFSET(KTHREAD, CallbackStack) == KTHREAD_CALLBACK_STACK); + ASSERT(FIELD_OFFSET(KTHREAD, ApcState.Process) == KTHREAD_APCSTATE_PROCESS); + ASSERT(FIELD_OFFSET(KPROCESS, DirectoryTableBase) == + KPROCESS_DIRECTORY_TABLE_BASE); + ASSERT(FIELD_OFFSET(KPROCESS, IopmOffset) == KPROCESS_IOPM_OFFSET); + ASSERT(FIELD_OFFSET(KPROCESS, LdtDescriptor) == KPROCESS_LDT_DESCRIPTOR0); + ASSERT(FIELD_OFFSET(KTRAP_FRAME, Reserved9) == KTRAP_FRAME_RESERVED9); + ASSERT(FIELD_OFFSET(KV86M_TRAP_FRAME, SavedExceptionStack) == TF_SAVED_EXCEPTION_STACK); + ASSERT(FIELD_OFFSET(KV86M_TRAP_FRAME, regs) == TF_REGS); + ASSERT(FIELD_OFFSET(KV86M_TRAP_FRAME, orig_ebp) == TF_ORIG_EBP); + + ASSERT(FIELD_OFFSET(KPCR, Tib.ExceptionList) == KPCR_EXCEPTION_LIST); + ASSERT(FIELD_OFFSET(KPCR, Self) == KPCR_SELF); + ASSERT(FIELD_OFFSET(KPCR, PrcbData) + FIELD_OFFSET(KPRCB, CurrentThread) == KPCR_CURRENT_THREAD); + ASSERT(FIELD_OFFSET(KPCR, PrcbData) + FIELD_OFFSET(KPRCB, NpxThread) == KPCR_NPX_THREAD); + + ASSERT(FIELD_OFFSET(KTSS, Esp0) == KTSS_ESP0); + ASSERT(FIELD_OFFSET(KTSS, Eflags) == KTSS_EFLAGS); + ASSERT(FIELD_OFFSET(KTSS, IoMapBase) == KTSS_IOMAPBASE); + + ASSERT(sizeof(FX_SAVE_AREA) == SIZEOF_FX_SAVE_AREA); + + LdrInit1(); + + KeLowerIrql(DISPATCH_LEVEL); + + NtEarlyInitVdm(); + + p1 = (PCHAR)KeLoaderBlock.CommandLine; + + MaxMem = 0; + while(*p1 && (p2 = strchr(p1, '/'))) + { + p2++; + if (!_strnicmp(p2, "MAXMEM", 6)) + { + p2 += 6; + while (isspace(*p2)) p2++; + if (*p2 == '=') + { + p2++; + while(isspace(*p2)) p2++; + if (isdigit(*p2)) + { + while (isdigit(*p2)) + { + MaxMem = MaxMem * 10 + *p2 - '0'; + p2++; + } + break; + } + } + } + else if (!_strnicmp(p2, "NOGUIBOOT", 9)) + { + p2 += 9; + NoGuiBoot = TRUE; + } + else if (!_strnicmp(p2, "CRASHDUMP", 9)) + { + p2 += 9; + if (*p2 == ':') + { + p2++; + if (!_strnicmp(p2, "FULL", 4)) + { + MmCoreDumpType = MM_CORE_DUMP_TYPE_FULL; + } + else + { + MmCoreDumpType = MM_CORE_DUMP_TYPE_NONE; + } + } + } + p1 = p2; + } + + MmInit1(FirstKrnlPhysAddr, + LastKrnlPhysAddr, + LastKernelAddress, + (PADDRESS_RANGE)&KeMemoryMap, + KeMemoryMapRangeCount, + MaxMem > 8 ? MaxMem : 4096); + + /* Import ANSI code page table */ + for (i = 1; i < KeLoaderBlock.ModsCount; i++) + { + start = KeLoaderModules[i].ModStart; + length = KeLoaderModules[i].ModEnd - start; + + name = strrchr((PCHAR)KeLoaderModules[i].String, '\\'); + if (name == NULL) + { + name = (PCHAR)KeLoaderModules[i].String; + } + else + { + name++; + } + + if (!_stricmp (name, "ansi.nls")) + { + RtlpImportAnsiCodePage((PUSHORT)start, length); + } + } + + /* Import OEM code page table */ + for (i = 1; i < KeLoaderBlock.ModsCount; i++) + { + start = KeLoaderModules[i].ModStart; + length = KeLoaderModules[i].ModEnd - start; + + name = strrchr((PCHAR)KeLoaderModules[i].String, '\\'); + if (name == NULL) + { + name = (PCHAR)KeLoaderModules[i].String; + } + else + { + name++; + } + + if (!_stricmp (name, "oem.nls")) + { + RtlpImportOemCodePage((PUSHORT)start, length); + } + } + + /* Import Unicode casemap table */ + for (i = 1; i < KeLoaderBlock.ModsCount; i++) + { + start = KeLoaderModules[i].ModStart; + length = KeLoaderModules[i].ModEnd - start; + + name = strrchr((PCHAR)KeLoaderModules[i].String, '\\'); + if (name == NULL) + { + name = (PCHAR)KeLoaderModules[i].String; + } + else + { + name++; + } + + if (!_stricmp (name, "casemap.nls")) + { + RtlpImportUnicodeCasemap((PUSHORT)start, length); + } + } + + /* Create initial NLS tables */ + RtlpCreateInitialNlsTables(); + + /* + * Initialize the kernel debugger + */ + KdInitSystem (1, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock); + + KeInit2(); + +#if 0 + if (KeMemoryMapRangeCount > 0) + { + DPRINT1("MemoryMap:\n"); + for (i = 0; i < KeMemoryMapRangeCount; i++) + { + switch(KeMemoryMap[i].Type) + { + case 1: + strcpy(str, "(usable)"); + break; + case 2: + strcpy(str, "(reserved)"); + break; + case 3: + strcpy(str, "(ACPI data)"); + break; + case 4: + strcpy(str, "(ACPI NVS)"); + break; + default: + sprintf(str, "type %lu", KeMemoryMap[i].Type); + } + DPRINT1("%08x - %08x %s\n", KeMemoryMap[i].BaseAddrLow, KeMemoryMap[i].BaseAddrLow + KeMemoryMap[i].LengthLow, str); + } + } +#endif + + KeLowerIrql(PASSIVE_LEVEL); + + if (!SeInit1()) + KEBUGCHECK(SECURITY_INITIALIZATION_FAILED); + + ObInit(); + ExInit2(); + MmInit2(); + + if (!SeInit2()) + KEBUGCHECK(SECURITY1_INITIALIZATION_FAILED); + + KeNumberProcessors = 1; + + PiInitProcessManager(); + + if (KdPollBreakIn ()) + { + DbgBreakPointWithStatus (DBG_STATUS_CONTROL_C); + } + + /* Initialize all processors */ + while (!HalAllProcessorsStarted()) + { + PVOID ProcessorStack; + + KePrepareForApplicationProcessorInit(KeNumberProcessors); + PsPrepareForApplicationProcessorInit(KeNumberProcessors); + + /* Allocate a stack for use when booting the processor */ + ProcessorStack = Ki386InitialStackArray[((int)KeNumberProcessors)] + MM_STACK_SIZE; + + HalStartNextProcessor(0, (ULONG)ProcessorStack - 2*sizeof(FX_SAVE_AREA)); + KeNumberProcessors++; + } + + /* + * Initialize various critical subsystems + */ + HalInitSystem(1, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock); + + ExInit3(); + KdInit1(); + IoInit(); + PoInit(); + CmInitializeRegistry(); + MmInit3(); + CcInit(); + KdInit2(); + FsRtlpInitFileLockingImplementation(); + + /* Report all resources used by hal */ + HalReportResourceUsage(); + + /* + * Clear the screen to blue + */ + HalInitSystem(2, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock); + + /* + * Display version number and copyright/warranty message + */ + HalDisplayString("Starting ReactOS "KERNEL_VERSION_STR" (Build " + KERNEL_VERSION_BUILD_STR")\n"); + HalDisplayString(RES_STR_LEGAL_COPYRIGHT); + HalDisplayString("\n\nReactOS is free software, covered by the GNU General " + "Public License, and you\n"); + HalDisplayString("are welcome to change it and/or distribute copies of it " + "under certain\n"); + HalDisplayString("conditions. There is absolutely no warranty for " + "ReactOS.\n\n"); + + if (KeNumberProcessors > 1) + { + sprintf(str, + "Found %d system processors. [%lu MB Memory]\n", + KeNumberProcessors, + (KeLoaderBlock.MemHigher + 1088)/ 1024); + } + else + { + sprintf(str, + "Found 1 system processor. [%lu MB Memory]\n", + (KeLoaderBlock.MemHigher + 1088)/ 1024); + } + HalDisplayString(str); + + KdInit3(); + + + /* Create the NLS section */ + RtlpCreateNlsSection(); + + /* + * Initalize services loaded at boot time + */ + DPRINT("%d files loaded\n",KeLoaderBlock.ModsCount); + for (i=0; i < KeLoaderBlock.ModsCount; i++) + { + CPRINT("Module: '%s' at %08lx, length 0x%08lx\n", + KeLoaderModules[i].String, + KeLoaderModules[i].ModStart, + KeLoaderModules[i].ModEnd - KeLoaderModules[i].ModStart); + } + + /* Pass 1: import system hive registry chunk */ + SetupBoot = TRUE; + for (i = 1; i < KeLoaderBlock.ModsCount; i++) + { + start = KeLoaderModules[i].ModStart; + length = KeLoaderModules[i].ModEnd - start; + + DPRINT("Module: '%s'\n", (PCHAR)KeLoaderModules[i].String); + name = strrchr((PCHAR)KeLoaderModules[i].String, '\\'); + if (name == NULL) + { + name = (PCHAR)KeLoaderModules[i].String; + } + else + { + name++; + } + + if (!_stricmp (name, "system") || + !_stricmp (name, "system.hiv")) + { + CPRINT("Process system hive registry chunk at %08lx\n", start); + SetupBoot = FALSE; + CmImportSystemHive((PCHAR)start, length); + } + } + + /* Pass 2: import hardware hive registry chunk */ + for (i = 1; i < KeLoaderBlock.ModsCount; i++) + { + start = KeLoaderModules[i].ModStart; + length = KeLoaderModules[i].ModEnd - start; + name = (PCHAR)KeLoaderModules[i].String; + if (!_stricmp (name, "hardware") || + !_stricmp (name, "hardware.hiv")) + { + CPRINT("Process hardware hive registry chunk at %08lx\n", start); + CmImportHardwareHive((PCHAR)start, length); + } + } + + /* Create dummy keys if no hardware hive was found */ + CmImportHardwareHive (NULL, 0); + + /* Initialize volatile registry settings */ + if (SetupBoot == FALSE) + { + CmInit2((PCHAR)KeLoaderBlock.CommandLine); + } + + /* Initialize the time zone information from the registry */ + ExpInitTimeZoneInfo(); + + /* + * Enter the kernel debugger before starting up the boot drivers + */ +#ifdef KDBG + KdbEnter(); +#endif /* KDBG */ + + IoCreateDriverList(); + + IoInit2(); + + /* Initialize Callbacks before drivers */ + ExpInitializeCallbacks(); + + /* Start boot logging */ + IopInitBootLog(); + p1 = (PCHAR)KeLoaderBlock.CommandLine; + while (*p1 && (p2 = strchr(p1, '/'))) + { + p2++; + if (!_strnicmp(p2, "BOOTLOG", 7)) + { + p2 += 7; + IopStartBootLog(); + } + + p1 = p2; + } + + /* + * Load boot start drivers + */ + IopInitializeBootDrivers(); + + /* Display the boot screen image if not disabled */ + if (!NoGuiBoot) + { + InbvEnableBootDriver(TRUE); + } + + /* Create ARC names for boot devices */ + IoCreateArcNames(); + + /* Create the SystemRoot symbolic link */ + CPRINT("CommandLine: %s\n", (PCHAR)KeLoaderBlock.CommandLine); + DPRINT1("MmSystemRangeStart: 0x%x PageDir: 0x%x\n", MmSystemRangeStart, KeLoaderBlock.PageDirectoryStart); + Status = IoCreateSystemRootLink((PCHAR)KeLoaderBlock.CommandLine); + if (!NT_SUCCESS(Status)) + { + DbgPrint ( "IoCreateSystemRootLink FAILED: (0x%x) - ", Status ); + DbgPrintErrorMessage ( Status ); + KEBUGCHECK(INACCESSIBLE_BOOT_DEVICE); + } + +#if defined(KDBG) || defined(DBG) + KdbInitProfiling2(); +#endif /* KDBG */ + + /* On the assumption that we can now access disks start up the debug + * logger thread */ + if ((KdDebuggerEnabled == TRUE) && (KdDebugState & KD_DEBUG_BOOTLOG)) + { + DebugLogInit2(); + } + + PiInitDefaultLocale(); + + /* + * Load services for devices found by PnP manager + */ + IopInitializePnpServices(IopRootDeviceNode, FALSE); + + /* + * Load system start drivers + */ + IopInitializeSystemDrivers(); + + IoDestroyDriverList(); + + /* Stop boot logging */ + IopStopBootLog(); + + /* + * Assign drive letters + */ + IoAssignDriveLetters ((PLOADER_PARAMETER_BLOCK)&KeLoaderBlock, + NULL, + NULL, + NULL); + + /* + * Initialize shared user page: + * - set dos system path, dos device map, etc. + */ + InitSystemSharedUserPage ((PCHAR)KeLoaderBlock.CommandLine); + + /* Create 'ReactOSInitDone' event */ + RtlInitUnicodeString(&Name, L"\\ReactOSInitDone"); + InitializeObjectAttributes(&ObjectAttributes, + &Name, + 0, + NULL, + NULL); + Status = ZwCreateEvent(&InitDoneEventHandle, + EVENT_ALL_ACCESS, + &ObjectAttributes, + SynchronizationEvent, + FALSE); /* Not signalled */ + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to create 'ReactOSInitDone' event (Status 0x%x)\n", Status); + InitDoneEventHandle = INVALID_HANDLE_VALUE; + } + + /* + * Launch initial process + */ + Status = LdrLoadInitialProcess(&ProcessHandle, + &ThreadHandle); + if (!NT_SUCCESS(Status)) + { + KEBUGCHECKEX(SESSION4_INITIALIZATION_FAILED, Status, 0, 0, 0); + } + + if (InitDoneEventHandle != INVALID_HANDLE_VALUE) + { + HANDLE Handles[2]; /* Init event, Initial process */ + + Handles[0] = InitDoneEventHandle; + Handles[1] = ProcessHandle; + + /* Wait for the system to be initialized */ + Timeout.QuadPart = (LONGLONG)-1200000000; /* 120 second timeout */ + Status = ZwWaitForMultipleObjects(((LONG) sizeof(Handles) / sizeof(HANDLE)), + Handles, + WaitAny, + FALSE, /* Non-alertable */ + &Timeout); + if (!NT_SUCCESS(Status)) + { + DPRINT1("NtWaitForMultipleObjects failed with status 0x%x!\n", Status); + } + else if (Status == STATUS_TIMEOUT) + { + DPRINT1("WARNING: System not initialized after 120 seconds.\n"); + } + else if (Status == STATUS_WAIT_0 + 1) + { + /* + * Crash the system if the initial process was terminated. + */ + KEBUGCHECKEX(SESSION5_INITIALIZATION_FAILED, Status, 0, 0, 0); + } + + if (!NoGuiBoot) + { + InbvEnableBootDriver(FALSE); + } + + ZwSetEvent(InitDoneEventHandle, NULL); + + ZwClose(InitDoneEventHandle); + } + else + { + /* On failure to create 'ReactOSInitDone' event, go to text mode ASAP */ + if (!NoGuiBoot) + { + InbvEnableBootDriver(FALSE); + } + + /* + * Crash the system if the initial process terminates within 5 seconds. + */ + Timeout.QuadPart = (LONGLONG)-50000000; /* 5 second timeout */ + Status = ZwWaitForSingleObject(ProcessHandle, + FALSE, + &Timeout); + if (Status != STATUS_TIMEOUT) + { + KEBUGCHECKEX(SESSION5_INITIALIZATION_FAILED, Status, 1, 0, 0); + } + } /* - * @implemented + * Tell ke/timer.c it's okay to run. */ -ULONG -STDCALL -KeGetRecommendedSharedDataAlignment(VOID) -{ - return KeLargestCacheLine; + + KiTimerSystemAuditing = 1; + + ZwClose(ThreadHandle); + ZwClose(ProcessHandle); } -VOID -__attribute((noinline)) +VOID __attribute((noinline)) KiSystemStartup(BOOLEAN BootProcessor) { - DPRINT("KiSystemStartup(%d)\n", BootProcessor); - - /* Initialize the Application Processor */ - if (!BootProcessor) KeApplicationProcessorInit(); - - /* Initialize the Processor with HAL */ - HalInitializeProcessor(KeNumberProcessors, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock); - - /* Load the Kernel if this is the Boot CPU, else inialize the App CPU only */ - if (BootProcessor) { - - /* Initialize the Kernel Executive */ - ExpInitializeExecutive(); - - /* Free Initial Memory */ - MiFreeInitMemory(); - - /* Never returns */ - PsTerminateSystemThread(STATUS_SUCCESS); - } else { - - /* Do application processor initialization */ - PsApplicationProcessorInit(); - - /* Lower IRQL and go to Idle Thread */ - KeLowerIrql(PASSIVE_LEVEL); - PsIdleThreadMain(NULL); - } - - /* Bug Check and loop forever if anything failed */ - KEBUGCHECK(0); - for(;;); + DPRINT1("KiSystemStartup(%d)\n", BootProcessor); + if (BootProcessor) + { + } + else + { + KeApplicationProcessorInit(); + } + + HalInitializeProcessor(KeNumberProcessors, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock); + + if (BootProcessor) + { + ExpInitializeExecutive(); + MiFreeInitMemory(); + /* Never returns */ + PsTerminateSystemThread(STATUS_SUCCESS); + } + else + { + /* Do application processor initialization */ + PsApplicationProcessorInit(); + KeLowerIrql(PASSIVE_LEVEL); + PsIdleThreadMain(NULL); + } + KEBUGCHECK(0); + for(;;); } +VOID INIT_FUNCTION +_main (ULONG MultiBootMagic, PLOADER_PARAMETER_BLOCK _LoaderBlock) /* * FUNCTION: Called by the boot loader to start the kernel * ARGUMENTS: @@ -128,158 +877,172 @@ KiSystemStartup(BOOLEAN BootProcessor) * NOTE: The boot parameters are stored in low memory which will become * invalid after the memory managment is initialized so we make a local copy. */ -VOID -INIT_FUNCTION -_main(ULONG MultiBootMagic, - PLOADER_PARAMETER_BLOCK _LoaderBlock) { - ULONG i; - ULONG size; - ULONG HalBase; - ULONG DriverBase; - ULONG DriverSize; - PIMAGE_NT_HEADERS NtHeader; - PIMAGE_OPTIONAL_HEADER OptHead; - CHAR* s; - - /* Set up the Stacks (Initial Kernel Stack and Double Trap Stack)*/ - trap_stack = PAGE_ROUND_UP(&double_trap_stack); - trap_stack_top = trap_stack + 3 * PAGE_SIZE; - init_stack = PAGE_ROUND_UP(&kernel_stack); - init_stack_top = init_stack + 3 * PAGE_SIZE; + ULONG i; + ULONG size; + ULONG HalBase; + ULONG DriverBase; + ULONG DriverSize; + + /* Set up the Stacks */ + trap_stack = PAGE_ROUND_UP(&double_trap_stack); + trap_stack_top = trap_stack + 3 * PAGE_SIZE; + init_stack = PAGE_ROUND_UP(&kernel_stack); + init_stack_top = init_stack + 3 * PAGE_SIZE; - /* Copy the Loader Block Data locally since Low-Memory will be wiped */ - memcpy(&KeLoaderBlock, _LoaderBlock, sizeof(LOADER_PARAMETER_BLOCK)); - memcpy(&KeLoaderModules[1], - (PVOID)KeLoaderBlock.ModsAddr, - sizeof(LOADER_MODULE) * KeLoaderBlock.ModsCount); - KeLoaderBlock.ModsCount++; - KeLoaderBlock.ModsAddr = (ULONG)&KeLoaderModules; - - /* Save the Base Address */ - MmSystemRangeStart = (PVOID)KeLoaderBlock.KernelBase; + /* + * Copy the parameters to a local buffer because lowmem will go away + */ + memcpy(&KeLoaderBlock, _LoaderBlock, sizeof(LOADER_PARAMETER_BLOCK)); + memcpy(&KeLoaderModules[1], (PVOID)KeLoaderBlock.ModsAddr, + sizeof(LOADER_MODULE) * KeLoaderBlock.ModsCount); + KeLoaderBlock.ModsCount++; + KeLoaderBlock.ModsAddr = (ULONG)&KeLoaderModules; + + /* Save the Base Address */ + MmSystemRangeStart = (PVOID)KeLoaderBlock.KernelBase; - /* Set the Command Line */ - strcpy(KeLoaderCommandLine, (PCHAR)_LoaderBlock->CommandLine); - KeLoaderBlock.CommandLine = (ULONG)KeLoaderCommandLine; + /* + * Convert a path specification in the grub format to one understood by the + * rest of the kernel. + */ + if (((PUCHAR)_LoaderBlock->CommandLine)[0] == '(') + { + ULONG DiskNumber = 0, PartNumber = 0; + PCH p; + CHAR Temp[256]; + PCH options; + PCH s1; + + if (((PUCHAR)_LoaderBlock->CommandLine)[1] == 'h' && + ((PUCHAR)_LoaderBlock->CommandLine)[2] == 'd') + { + DiskNumber = ((PCHAR)_LoaderBlock->CommandLine)[3] - '0'; + PartNumber = ((PCHAR)_LoaderBlock->CommandLine)[5] - '0'; + } + strcpy(Temp, &((PCHAR)_LoaderBlock->CommandLine)[7]); + if ((options = strchr(Temp, ' ')) != NULL) + { + *options = 0; + options++; + } + else + { + options = ""; + } + if ((s1 = strrchr(Temp, '/')) != NULL) + { + *s1 = 0; + if ((s1 = strrchr(Temp, '/')) != NULL) + { + *s1 = 0; + } + } + sprintf(KeLoaderCommandLine, + "multi(0)disk(0)rdisk(%lu)partition(%lu)%s %s", + DiskNumber, PartNumber + 1, Temp, options); + + p = KeLoaderCommandLine; + while (*p != 0 && *p != ' ') + { + if ((*p) == '/') + { + (*p) = '\\'; + } + p++; + } + DPRINT1("Command Line: %s\n", KeLoaderCommandLine); + } + else + { + strcpy(KeLoaderCommandLine, (PCHAR)_LoaderBlock->CommandLine); + } + KeLoaderBlock.CommandLine = (ULONG)KeLoaderCommandLine; - /* Write the first Module (the Kernel) */ - strcpy(KeLoaderModuleStrings[0], "ntoskrnl.exe"); - KeLoaderModules[0].String = (ULONG)KeLoaderModuleStrings[0]; - KeLoaderModules[0].ModStart = KERNEL_BASE; - - /* Read PE Data */ - NtHeader = RtlImageNtHeader((PVOID)KeLoaderModules[0].ModStart); - OptHead = &NtHeader->OptionalHeader; - - /* Set Kernel Ending */ + strcpy(KeLoaderModuleStrings[0], "ntoskrnl.exe"); + KeLoaderModules[0].String = (ULONG)KeLoaderModuleStrings[0]; + KeLoaderModules[0].ModStart = KERNEL_BASE; + /* Take this value from the PE... */ + PIMAGE_NT_HEADERS NtHeader = RtlImageNtHeader((PVOID)KeLoaderModules[0].ModStart); + PIMAGE_OPTIONAL_HEADER OptHead = &NtHeader->OptionalHeader; KeLoaderModules[0].ModEnd = KeLoaderModules[0].ModStart + PAGE_ROUND_UP((ULONG)OptHead->SizeOfImage); - - /* Create a block for each module */ - for (i = 1; i < KeLoaderBlock.ModsCount; i++) { - - /* Check if we have to copy the path or not */ - if ((s = strrchr((PCHAR)KeLoaderModules[i].String, '/')) != 0) { - - strcpy(KeLoaderModuleStrings[i], s + 1); - - } else { - - strcpy(KeLoaderModuleStrings[i], (PCHAR)KeLoaderModules[i].String); - } - - /* Substract the base Address in Physical Memory */ - KeLoaderModules[i].ModStart -= 0x200000; - - /* Add the Kernel Base Address in Virtual Memory */ - KeLoaderModules[i].ModStart += KERNEL_BASE; - - /* Substract the base Address in Physical Memory */ - KeLoaderModules[i].ModEnd -= 0x200000; - - /* Add the Kernel Base Address in Virtual Memory */ - KeLoaderModules[i].ModEnd += KERNEL_BASE; - - /* Select the proper String */ - KeLoaderModules[i].String = (ULONG)KeLoaderModuleStrings[i]; + for (i = 1; i < KeLoaderBlock.ModsCount; i++) + { + CHAR* s; + if ((s = strrchr((PCHAR)KeLoaderModules[i].String, '/')) != 0) + { + strcpy(KeLoaderModuleStrings[i], s + 1); + } + else + { + strcpy(KeLoaderModuleStrings[i], (PCHAR)KeLoaderModules[i].String); + } + KeLoaderModules[i].ModStart -= 0x200000; + KeLoaderModules[i].ModStart += KERNEL_BASE; + KeLoaderModules[i].ModEnd -= 0x200000; + KeLoaderModules[i].ModEnd += KERNEL_BASE; + KeLoaderModules[i].String = (ULONG)KeLoaderModuleStrings[i]; } - /* Choose last module address as the final kernel address */ - LastKernelAddress = PAGE_ROUND_UP(KeLoaderModules[KeLoaderBlock.ModsCount - 1].ModEnd); - - /* Low level architecture specific initialization */ - KeInit1((PCHAR)KeLoaderBlock.CommandLine, &LastKernelAddress); - - /* Select the HAL Base */ - HalBase = KeLoaderModules[1].ModStart; - - /* Choose Driver Base */ - DriverBase = LastKernelAddress; - LdrHalBase = (ULONG_PTR)DriverBase; - - /* Initialize Module Management */ - LdrInitModuleManagement(); - - /* Load HAL.DLL with the PE Loader */ - LdrSafePEProcessModule((PVOID)HalBase, - (PVOID)DriverBase, - (PVOID)KERNEL_BASE, - &DriverSize); - - /* Increase the last kernel address with the size of HAL */ - LastKernelAddress += PAGE_ROUND_UP(DriverSize); - - /* Load the Kernel with the PE Loader */ - LdrSafePEProcessModule((PVOID)KERNEL_BASE, - (PVOID)KERNEL_BASE, - (PVOID)DriverBase, - &DriverSize); - - /* Now select the final beginning and ending Kernel Addresses */ - FirstKrnlPhysAddr = KeLoaderModules[0].ModStart - KERNEL_BASE + 0x200000; - LastKrnlPhysAddr = LastKernelAddress - KERNEL_BASE + 0x200000; - - KeMemoryMapRangeCount = 0; - if (KeLoaderBlock.Flags & MB_FLAGS_MMAP_INFO) { - - /* We have a memory map from the nice BIOS */ - size = *((PULONG)(KeLoaderBlock.MmapAddr - sizeof(ULONG))); - i = 0; - - /* Map it until we run out of size */ - while (i < KeLoaderBlock.MmapLength) { - - /* Copy into the Kernel Memory Map */ - memcpy (&KeMemoryMap[KeMemoryMapRangeCount], - (PVOID)(KeLoaderBlock.MmapAddr + i), - sizeof(ADDRESS_RANGE)); - - /* Increase Memory Map Count */ - KeMemoryMapRangeCount++; - - /* Increase Size */ - i += size; + LastKernelAddress = PAGE_ROUND_UP(KeLoaderModules[KeLoaderBlock.ModsCount - 1].ModEnd); + + /* Low level architecture specific initialization */ + KeInit1((PCHAR)KeLoaderBlock.CommandLine, &LastKernelAddress); + + HalBase = KeLoaderModules[1].ModStart; + DriverBase = LastKernelAddress; + LdrHalBase = (ULONG_PTR)DriverBase; + + LdrInitModuleManagement(); + + /* + * Process hal.dll + */ + LdrSafePEProcessModule((PVOID)HalBase, (PVOID)DriverBase, (PVOID)KERNEL_BASE, &DriverSize); + + LastKernelAddress += PAGE_ROUND_UP(DriverSize); + + /* + * Process ntoskrnl.exe + */ + LdrSafePEProcessModule((PVOID)KERNEL_BASE, (PVOID)KERNEL_BASE, (PVOID)DriverBase, &DriverSize); + + /* Now our imports from HAL are fixed. This is the first */ + /* time in the boot process that we can use HAL */ + + FirstKrnlPhysAddr = KeLoaderModules[0].ModStart - KERNEL_BASE + 0x200000; + LastKrnlPhysAddr = LastKernelAddress - KERNEL_BASE + 0x200000; + + KeMemoryMapRangeCount = 0; + if (KeLoaderBlock.Flags & MB_FLAGS_MMAP_INFO) + { + /* We have a memory map from the nice BIOS */ + size = *((PULONG)(KeLoaderBlock.MmapAddr - sizeof(ULONG))); + i = 0; + while (i < KeLoaderBlock.MmapLength) + { + memcpy (&KeMemoryMap[KeMemoryMapRangeCount], + (PVOID)(KeLoaderBlock.MmapAddr + i), + sizeof(ADDRESS_RANGE)); + KeMemoryMapRangeCount++; + i += size; } - - /* Save data */ - KeLoaderBlock.MmapLength = KeMemoryMapRangeCount * sizeof(ADDRESS_RANGE); - KeLoaderBlock.MmapAddr = (ULONG)KeMemoryMap; - - } else { - - /* Nothing from BIOS */ - KeLoaderBlock.MmapLength = 0; - KeLoaderBlock.MmapAddr = (ULONG)KeMemoryMap; + KeLoaderBlock.MmapLength = KeMemoryMapRangeCount * sizeof(ADDRESS_RANGE); + KeLoaderBlock.MmapAddr = (ULONG)KeMemoryMap; } - - /* Initialize the Debugger */ - KdInitSystem (0, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock); - - /* Initialize HAL */ - HalInitSystem (0, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock); - - /* Do general System Startup */ - KiSystemStartup(1); + else + { + KeLoaderBlock.MmapLength = 0; + KeLoaderBlock.MmapAddr = (ULONG)KeMemoryMap; + } + + KdInitSystem (0, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock); + HalInitSystem (0, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock); + + DPRINT1("_main (%x, %x)\n", MultiBootMagic, _LoaderBlock); + + + KiSystemStartup(1); } /* EOF */ diff --git a/reactos/ntoskrnl/ke/mutex.c b/reactos/ntoskrnl/ke/mutex.c index 992aa31c6cc..3532781082c 100644 --- a/reactos/ntoskrnl/ke/mutex.c +++ b/reactos/ntoskrnl/ke/mutex.c @@ -3,19 +3,14 @@ * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * FILE: ntoskrnl/ke/mutex.c - * PURPOSE: Implements Mutexes and Mutants (that silly davec...) + * PURPOSE: Implements mutex * - * PROGRAMMERS: - * Alex Ionescu (alex@relsoft.net) - Reorganized/commented some of the code. - * Simplified some functions, fixed some return values and - * corrected some minor bugs, added debug output. - * David Welch (welch@mcmail.com) + * PROGRAMMERS: David Welch (welch@mcmail.com) */ /* INCLUDES *****************************************************************/ #include -#define NDEBUG #include /* FUNCTIONS *****************************************************************/ @@ -23,212 +18,176 @@ /* * @implemented */ -VOID -STDCALL -KeInitializeMutant(IN PKMUTANT Mutant, - IN BOOLEAN InitialOwner) +VOID STDCALL +KeInitializeMutex(IN PKMUTEX Mutex, + IN ULONG Level) { - ULONG Signaled = TRUE; - PKTHREAD CurrentThread = NULL; - KIRQL OldIrql; - - DPRINT("KeInitializeMutant: %x\n", Mutant); - - /* Check if we have an initial owner */ - if (InitialOwner == TRUE) { - - /* In this case, the object is not signaled */ - Signaled = FALSE; - - /* We also need to associate a thread */ - CurrentThread = KeGetCurrentThread(); - - /* We're about to touch the Thread, so lock the Dispatcher */ - OldIrql = KeAcquireDispatcherDatabaseLock(); - - /* And insert it into its list */ - InsertTailList(&CurrentThread->MutantListHead, &Mutant->MutantListEntry); - - /* Release Dispatcher Lock */ - KeReleaseDispatcherDatabaseLock(OldIrql); - DPRINT("Mutant with Initial Owner\n"); - - } else { - - /* In this case, we don't have an owner yet */ - Mutant->OwnerThread = NULL; - } - - /* Now we set up the Dispatcher Header */ - KeInitializeDispatcherHeader(&Mutant->Header, - MutantObject, - sizeof(KMUTANT) / sizeof(ULONG), - Signaled); - - /* Initialize the default data */ - Mutant->OwnerThread = CurrentThread; - Mutant->Abandoned = FALSE; - Mutant->ApcDisable = 0; + KeInitializeDispatcherHeader(&Mutex->Header, + InternalMutexType, + sizeof(KMUTEX) / sizeof(ULONG), + 1); + Mutex->MutantListEntry.Flink = NULL; + Mutex->MutantListEntry.Blink = NULL; + Mutex->OwnerThread = NULL; + Mutex->Abandoned = FALSE; + Mutex->ApcDisable = 1; } /* * @implemented */ -VOID -STDCALL -KeInitializeMutex(IN PKMUTEX Mutex, - IN ULONG Level) +LONG STDCALL +KeReadStateMutex(IN PKMUTEX Mutex) { - DPRINT("KeInitializeMutex: %x\n", Mutex); - - - /* Set up the Dispatcher Header */ - KeInitializeDispatcherHeader(&Mutex->Header, - MutantObject, - sizeof(KMUTEX) / sizeof(ULONG), - 1); - - /* Initialize the default data */ - Mutex->OwnerThread = NULL; - Mutex->Abandoned = FALSE; - Mutex->ApcDisable = 1; - InitializeListHead(&Mutex->Header.WaitListHead); + return(Mutex->Header.SignalState); } /* * @implemented */ -LONG -STDCALL -KeReadStateMutant(IN PKMUTANT Mutant) +LONG STDCALL +KeReleaseMutex(IN PKMUTEX Mutex, + IN BOOLEAN Wait) { - /* Return the Signal State */ - return(Mutant->Header.SignalState); + KIRQL OldIrql; + + OldIrql = KeAcquireDispatcherDatabaseLock(); + if (Mutex->OwnerThread != KeGetCurrentThread()) + { + DbgPrint("THREAD_NOT_MUTEX_OWNER: Mutex %p\n", Mutex); + KEBUGCHECK(THREAD_NOT_MUTEX_OWNER); + } + Mutex->Header.SignalState++; + ASSERT(Mutex->Header.SignalState <= 1); + if (Mutex->Header.SignalState == 1) + { + Mutex->OwnerThread = NULL; + if (Mutex->MutantListEntry.Flink && Mutex->MutantListEntry.Blink) + RemoveEntryList(&Mutex->MutantListEntry); + KiDispatcherObjectWake(&Mutex->Header, IO_NO_INCREMENT); + } + + if (Wait == FALSE) + { + KeReleaseDispatcherDatabaseLock(OldIrql); + } + else + { + KTHREAD *Thread = KeGetCurrentThread(); + Thread->WaitNext = TRUE; + Thread->WaitIrql = OldIrql; + } + + return(0); } /* * @implemented */ -LONG -STDCALL -KeReadStateMutex(IN PKMUTEX Mutex) +NTSTATUS STDCALL +KeWaitForMutexObject(IN PKMUTEX Mutex, + IN KWAIT_REASON WaitReason, + IN KPROCESSOR_MODE WaitMode, + IN BOOLEAN Alertable, + IN PLARGE_INTEGER Timeout) { - /* Return the Signal State */ - return(Mutex->Header.SignalState); + return(KeWaitForSingleObject(Mutex,WaitReason,WaitMode,Alertable,Timeout)); } + /* * @implemented */ -LONG -STDCALL -KeReleaseMutant(IN PKMUTANT Mutant, - IN KPRIORITY Increment, - IN BOOLEAN Abandon, - IN BOOLEAN Wait) +VOID STDCALL +KeInitializeMutant(IN PKMUTANT Mutant, + IN BOOLEAN InitialOwner) { - KIRQL OldIrql; - LONG PreviousState; - PKTHREAD CurrentThread = KeGetCurrentThread(); - - DPRINT("KeReleaseMutant: %x\n", Mutant); - - /* Lock the Dispatcher Database */ - OldIrql = KeAcquireDispatcherDatabaseLock(); - - /* Save the Previous State */ - PreviousState = Mutant->Header.SignalState; - - /* Check if it is to be abandonned */ - if (Abandon == FALSE) { - - /* Make sure that the Owner Thread is the current Thread */ - if (Mutant->OwnerThread != CurrentThread) { - - DPRINT1("Trying to touch a Mutant that the caller doesn't own!\n"); - ExRaiseStatus(STATUS_MUTANT_NOT_OWNED); - } - - /* If the thread owns it, then increase the signal state */ - Mutant->Header.SignalState++; - - } else { - - /* It's going to be abandonned */ - DPRINT("Abandonning the Mutant\n"); - Mutant->Header.SignalState = 1; - Mutant->Abandoned = TRUE; - } - - /* Check if the signal state is only single */ - if (Mutant->Header.SignalState == 1) { - - if (PreviousState <= 0) { - - DPRINT("Removing Mutant\n"); - RemoveEntryList(&Mutant->MutantListEntry); - } - - /* Remove the Owning Thread and wake it */ - Mutant->OwnerThread = NULL; - - /* Check if the Wait List isn't empty */ - DPRINT("Checking whether to wake the Mutant\n"); - if (!IsListEmpty(&Mutant->Header.WaitListHead)) { - - /* Wake the Mutant */ - DPRINT("Waking the Mutant\n"); - KiWaitTest(&Mutant->Header, Increment); - } + if (InitialOwner == TRUE) + { + KeInitializeDispatcherHeader(&Mutant->Header, + InternalMutexType, + sizeof(KMUTANT) / sizeof(ULONG), + 0); + InsertTailList(&KeGetCurrentThread()->MutantListHead, + &Mutant->MutantListEntry); + Mutant->OwnerThread = KeGetCurrentThread(); } - - /* If the Wait is true, then return with a Wait and don't unlock the Dispatcher Database */ - if (Wait == FALSE) { - - /* Release the Lock */ - KeReleaseDispatcherDatabaseLock(OldIrql); - - } else { - - /* Set a wait */ - CurrentThread->WaitNext = TRUE; - CurrentThread->WaitIrql = OldIrql; + else + { + KeInitializeDispatcherHeader(&Mutant->Header, + InternalMutexType, + sizeof(KMUTANT) / sizeof(ULONG), + 1); + Mutant->MutantListEntry.Flink = NULL; + Mutant->MutantListEntry.Blink = NULL; + Mutant->OwnerThread = NULL; } - - /* Return the previous state */ - return PreviousState; + Mutant->Abandoned = FALSE; + Mutant->ApcDisable = 0; } /* * @implemented */ -LONG -STDCALL -KeReleaseMutex(IN PKMUTEX Mutex, - IN BOOLEAN Wait) +LONG STDCALL +KeReadStateMutant(IN PKMUTANT Mutant) { - - /* There's no difference at this level between the two */ - return KeReleaseMutant(Mutex, IO_NO_INCREMENT, FALSE, Wait); + return(Mutant->Header.SignalState); } /* * @implemented */ -NTSTATUS -STDCALL -KeWaitForMutexObject(IN PKMUTEX Mutex, - IN KWAIT_REASON WaitReason, - IN KPROCESSOR_MODE WaitMode, - IN BOOLEAN Alertable, - IN PLARGE_INTEGER Timeout) +LONG STDCALL +KeReleaseMutant(IN PKMUTANT Mutant, + IN KPRIORITY Increment, + IN BOOLEAN Abandon, + IN BOOLEAN Wait) { - /* This is a simple macro. Export the function here though */ - return KeWaitForSingleObject(Mutex, - WaitReason, - WaitMode, - Alertable, - Timeout); + KIRQL OldIrql; + + OldIrql = KeAcquireDispatcherDatabaseLock(); + if (Abandon == FALSE) + { + if (Mutant->OwnerThread != NULL && Mutant->OwnerThread != KeGetCurrentThread()) + { + DbgPrint("THREAD_NOT_MUTEX_OWNER: Mutant->OwnerThread %p CurrentThread %p\n", + Mutant->OwnerThread, + KeGetCurrentThread()); + KEBUGCHECK(THREAD_NOT_MUTEX_OWNER); + } + Mutant->Header.SignalState++; + ASSERT(Mutant->Header.SignalState <= 1); + } + else + { + if (Mutant->OwnerThread != NULL) + { + Mutant->Header.SignalState = 1; + Mutant->Abandoned = TRUE; + } + } + + if (Mutant->Header.SignalState == 1) + { + Mutant->OwnerThread = NULL; + if (Mutant->MutantListEntry.Flink && Mutant->MutantListEntry.Blink) + RemoveEntryList(&Mutant->MutantListEntry); + KiDispatcherObjectWake(&Mutant->Header, Increment); + } + + if (Wait == FALSE) + { + KeReleaseDispatcherDatabaseLock(OldIrql); + } + else + { + KTHREAD *Thread = KeGetCurrentThread(); + Thread->WaitNext = TRUE; + Thread->WaitIrql = OldIrql; + } + + return(0); } /* EOF */ diff --git a/reactos/ntoskrnl/ke/queue.c b/reactos/ntoskrnl/ke/queue.c index 6a3d63f2566..9c478709de8 100644 --- a/reactos/ntoskrnl/ke/queue.c +++ b/reactos/ntoskrnl/ke/queue.c @@ -16,482 +16,245 @@ /* FUNCTIONS *****************************************************************/ -LONG STDCALL KiInsertQueue(IN PKQUEUE Queue, IN PLIST_ENTRY Entry, BOOLEAN Head); - + /* * @implemented */ -VOID -STDCALL +VOID STDCALL KeInitializeQueue(IN PKQUEUE Queue, - IN ULONG Count OPTIONAL) + IN ULONG Count OPTIONAL) { - DPRINT("KeInitializeQueue %x\n", Queue); - - /* Initialize the Header */ - KeInitializeDispatcherHeader(&Queue->Header, - QueueObject, - sizeof(KQUEUE)/sizeof(ULONG), - 0); - - /* Initialize the Lists */ - InitializeListHead(&Queue->EntryListHead); - InitializeListHead(&Queue->ThreadListHead); - - /* Set the Current and Maximum Count */ - Queue->CurrentCount = 0; - Queue->MaximumCount = (Count == 0) ? (ULONG) KeNumberProcessors : Count; + KeInitializeDispatcherHeader(&Queue->Header, + InternalQueueType, + sizeof(KQUEUE)/sizeof(ULONG), + 0); + InitializeListHead(&Queue->EntryListHead); + InitializeListHead(&Queue->ThreadListHead); + Queue->CurrentCount = 0; + Queue->MaximumCount = (Count == 0) ? (ULONG) KeNumberProcessors : Count; } + /* * @implemented + * + * Returns number of entries in the queue */ -LONG -STDCALL -KeInsertHeadQueue(IN PKQUEUE Queue, - IN PLIST_ENTRY Entry) +LONG STDCALL +KeReadStateQueue(IN PKQUEUE Queue) +{ + return(Queue->Header.SignalState); +} + +/* + * Returns the previous number of entries in the queue + */ +LONG STDCALL +KiInsertQueue( + IN PKQUEUE Queue, + IN PLIST_ENTRY Entry, + BOOLEAN Head + ) { - LONG PreviousState; - KIRQL OldIrql; - - DPRINT("KeInsertHeadQueue %x\n", Queue); - - /* Lock the Dispatcher Database */ - OldIrql = KeAcquireDispatcherDatabaseLock(); - - /* Insert the Queue */ - PreviousState = KiInsertQueue(Queue, Entry, TRUE); - - /* Release the Dispatcher Lock */ - KeReleaseDispatcherDatabaseLock(OldIrql); + ULONG InitialState; + + DPRINT("KiInsertQueue(Queue %x, Entry %x)\n", Queue, Entry); - /* Return previous State */ - return PreviousState; + InitialState = Queue->Header.SignalState; + + if (Head) + { + InsertHeadList(&Queue->EntryListHead, Entry); + } + else + { + InsertTailList(&Queue->EntryListHead, Entry); + } + + //inc. num entries in queue + Queue->Header.SignalState++; + + /* Why the KeGetCurrentThread()->Queue != Queue? + * KiInsertQueue might be called from an APC for the current thread. + * -Gunnar + */ + if (Queue->CurrentCount < Queue->MaximumCount && + !IsListEmpty(&Queue->Header.WaitListHead) && + KeGetCurrentThread()->Queue != Queue) + { + KiDispatcherObjectWake(&Queue->Header, IO_NO_INCREMENT); + } + + return InitialState; } + + /* * @implemented */ LONG STDCALL -KeInsertQueue(IN PKQUEUE Queue, - IN PLIST_ENTRY Entry) +KeInsertHeadQueue(IN PKQUEUE Queue, + IN PLIST_ENTRY Entry) { - LONG PreviousState; - KIRQL OldIrql; - - DPRINT("KeInsertQueue %x\n", Queue); - - /* Lock the Dispatcher Database */ - OldIrql = KeAcquireDispatcherDatabaseLock(); - - /* Insert the Queue */ - PreviousState = KiInsertQueue(Queue, Entry, FALSE); - - /* Release the Dispatcher Lock */ - KeReleaseDispatcherDatabaseLock(OldIrql); + LONG Result; + KIRQL OldIrql; + + OldIrql = KeAcquireDispatcherDatabaseLock(); + Result = KiInsertQueue(Queue,Entry,TRUE); + KeReleaseDispatcherDatabaseLock(OldIrql); - /* Return previous State */ - return PreviousState; + return Result; } + /* * @implemented - * - * Returns number of entries in the queue */ -LONG -STDCALL -KeReadStateQueue(IN PKQUEUE Queue) +LONG STDCALL +KeInsertQueue(IN PKQUEUE Queue, + IN PLIST_ENTRY Entry) { - /* Returns the Signal State */ - return(Queue->Header.SignalState); + LONG Result; + KIRQL OldIrql; + + OldIrql = KeAcquireDispatcherDatabaseLock(); + Result = KiInsertQueue(Queue,Entry,FALSE); + KeReleaseDispatcherDatabaseLock(OldIrql); + + return Result; } + /* * @implemented */ -PLIST_ENTRY -STDCALL +PLIST_ENTRY STDCALL KeRemoveQueue(IN PKQUEUE Queue, - IN KPROCESSOR_MODE WaitMode, - IN PLARGE_INTEGER Timeout OPTIONAL) + IN KPROCESSOR_MODE WaitMode, + IN PLARGE_INTEGER Timeout OPTIONAL) { - PLIST_ENTRY ListEntry; - NTSTATUS Status; - PKTHREAD Thread = KeGetCurrentThread(); - KIRQL OldIrql; - PKQUEUE PreviousQueue; - PKWAIT_BLOCK WaitBlock; - PKWAIT_BLOCK TimerWaitBlock; - PKTIMER Timer; - - DPRINT("KeRemoveQueue %x\n", Queue); - - /* Check if the Lock is already held */ - if (Thread->WaitNext) { - - DPRINT("Lock is already held\n"); - - } else { - - /* Lock the Dispatcher Database */ - DPRINT("Lock not held, acquiring\n"); - OldIrql = KeAcquireDispatcherDatabaseLock(); - Thread->WaitIrql = OldIrql; - } - - /* This is needed so that we can set the new queue right here, before additional processing */ - PreviousQueue = Thread->Queue; - Thread->Queue = Queue; - - /* Check if this is a different queue */ - if (Queue != PreviousQueue) { - - /* - * INVESTIGATE: What is the Thread->QueueListEntry used for? It's linked it into the - * Queue->ThreadListHead when the thread registers with the queue and unlinked when - * the thread registers with a new queue. The Thread->Queue already tells us what - * queue the thread is registered with. - * -Gunnar - */ - DPRINT("Different Queue\n"); - if (PreviousQueue) { - - /* Remove from this list */ - DPRINT("Removing Old Queue\n"); - RemoveEntryList(&Thread->QueueListEntry); - - /* Wake the queue */ - DPRINT("Activating new thread\n"); - KiWakeQueue(PreviousQueue); + PLIST_ENTRY ListEntry; + NTSTATUS Status; + PKTHREAD Thread = KeGetCurrentThread(); + KIRQL OldIrql; + + OldIrql = KeAcquireDispatcherDatabaseLock (); + + if (Thread->Queue != Queue) + { + /* + * INVESTIGATE: What is the Thread->QueueListEntry used for? It's linked it into the + * Queue->ThreadListHead when the thread registers with the queue and unlinked when + * the thread registers with a new queue. The Thread->Queue already tells us what + * queue the thread is registered with. + * -Gunnar + */ + + //unregister thread from previous queue (if any) + if (Thread->Queue) + { + RemoveEntryList(&Thread->QueueListEntry); + Thread->Queue->CurrentCount--; + + if (Thread->Queue->CurrentCount < Thread->Queue->MaximumCount && + !IsListEmpty(&Thread->Queue->EntryListHead)) + { + KiDispatcherObjectWake(&Thread->Queue->Header, 0); + } } - /* Insert in this new Queue */ - DPRINT("Inserting new Queue!\n"); - InsertTailList(&Queue->ThreadListHead, &Thread->QueueListEntry); + // register thread with this queue + InsertTailList(&Queue->ThreadListHead, &Thread->QueueListEntry); + Thread->Queue = Queue; + } + else /* if (Thread->Queue == Queue) */ + { + //dec. num running threads + Queue->CurrentCount--; + } + + + - } else { - - /* Same queue, decrement waiting threads */ - DPRINT("Same Queue!\n"); - Queue->CurrentCount--; - } - - /* Loop until the queue is processed */ - while (TRUE) { - - /* Get the Entry */ - ListEntry = Queue->EntryListHead.Flink; - - /* Check if the counts are valid and if there is still a queued entry */ - if ((Queue->CurrentCount < Queue->MaximumCount) && - (ListEntry != &Queue->EntryListHead)) { - - /* Remove the Entry and Save it */ - DPRINT("Removing Queue Entry. CurrentCount: %d, Maximum Count: %d\n", - Queue->CurrentCount, Queue->MaximumCount); - ListEntry = RemoveHeadList(&Queue->EntryListHead); - - /* Decrease the number of entries */ - Queue->Header.SignalState--; - - /* Increase numbef of running threads */ - Queue->CurrentCount++; - - /* Check if the entry is valid. If not, bugcheck */ - if (!ListEntry->Flink || !ListEntry->Blink) { - - KEBUGCHECK(INVALID_WORK_QUEUE_ITEM); - } - - /* Remove the Entry */ - RemoveEntryList(ListEntry); - - /* Nothing to wait on */ - break; - - } else { - - /* Do the wait */ - DPRINT("Waiting on Queue Entry. CurrentCount: %d, Maximum Count: %d\n", - Queue->CurrentCount, Queue->MaximumCount); - - /* Use the Thread's Wait Block, it's big enough */ - Thread->WaitBlockList = &Thread->WaitBlock[0]; - - /* Fail if there's an APC Pending */ - if (WaitMode == UserMode && Thread->ApcState.UserApcPending) { - - /* Return the status and increase the pending threads */ - ListEntry = (PLIST_ENTRY)STATUS_USER_APC; - Queue->CurrentCount++; - - /* Nothing to wait on */ - break; - } - - /* Build the Wait Block */ - WaitBlock = &Thread->WaitBlock[0]; - WaitBlock->Object = (PVOID)Queue; - WaitBlock->WaitKey = STATUS_SUCCESS; - WaitBlock->WaitType = WaitAny; - WaitBlock->Thread = Thread; - WaitBlock->NextWaitBlock = NULL; - - Thread->WaitStatus = STATUS_SUCCESS; - - /* We need to wait for the object... check if we have a timeout */ - if (Timeout) { - - /* If it's zero, then don't do any waiting */ - if (!Timeout->QuadPart) { - - /* Instant Timeout, return the status and increase the pending threads */ - DPRINT("Queue Wait has timed out\n"); - ListEntry = (PLIST_ENTRY)STATUS_TIMEOUT; - Queue->CurrentCount++; - - /* Nothing to wait on */ - break; - } - - /* - * Set up the Timer. We'll use the internal function so that we can - * hold on to the dispatcher lock. - */ - Timer = &Thread->Timer; - TimerWaitBlock = &Thread->WaitBlock[1]; - - /* Set up the Timer Wait Block */ - TimerWaitBlock->Object = (PVOID)Timer; - TimerWaitBlock->Thread = Thread; - TimerWaitBlock->WaitKey = STATUS_TIMEOUT; - TimerWaitBlock->WaitType = WaitAny; - TimerWaitBlock->NextWaitBlock = NULL; - - /* Link the timer to this Wait Block */ - InitializeListHead(&Timer->Header.WaitListHead); - InsertTailList(&Timer->Header.WaitListHead, &TimerWaitBlock->WaitListEntry); - - /* Create Timer */ - DPRINT("Creating Timer with timeout %I64d\n", *Timeout); - KiInsertTimer(Timer, *Timeout); - } - - /* Insert the wait block into the Queues's wait list */ - WaitBlock = Thread->WaitBlockList; - InsertTailList(&Queue->Header.WaitListHead, &WaitBlock->WaitListEntry); - - /* Block the Thread */ - DPRINT("Blocking the Thread: %x %x!\n", KeGetCurrentThread(), Thread); - PsBlockThread(&Status, - FALSE, - WaitMode, - WrQueue); - - /* Reset the wait reason */ - Thread->WaitReason = 0; - - /* Check if we were executing an APC */ - if (Status != STATUS_KERNEL_APC) { - - /* Done Waiting */ - DPRINT("Done waking queue. Thread: %x %x!\n", KeGetCurrentThread(), Thread); - return (PLIST_ENTRY)Status; - } - - /* Acquire again the lock */ - DPRINT("Looping again\n"); - OldIrql = KeAcquireDispatcherDatabaseLock(); - - /* Save the new IRQL and decrease number of waiting threads */ - Thread->WaitIrql = OldIrql; - Queue->CurrentCount--; - } - } - - /* Unlock Database and return */ - KeReleaseDispatcherDatabaseLock(Thread->WaitIrql); - DPRINT("Returning. CurrentCount: %d, Maximum Count: %d\n", - Queue->CurrentCount, Queue->MaximumCount); - return ListEntry; + while (TRUE) + { + if (Queue->CurrentCount < Queue->MaximumCount && !IsListEmpty(&Queue->EntryListHead)) + { + ListEntry = RemoveHeadList(&Queue->EntryListHead); + //dec. num entries in queue + Queue->Header.SignalState--; + //inc. num running threads + Queue->CurrentCount++; + + KeReleaseDispatcherDatabaseLock(OldIrql); + return ListEntry; + } + else + { + //inform KeWaitXxx that we are holding disp. lock + Thread->WaitNext = TRUE; + Thread->WaitIrql = OldIrql; + + Status = KeWaitForSingleObject(Queue, + WrQueue, + WaitMode, + TRUE, //bAlertable + Timeout); + + if (Status == STATUS_TIMEOUT || Status == STATUS_USER_APC) + { + return (PVOID)Status; + } + + OldIrql = KeAcquireDispatcherDatabaseLock (); + } + } } + /* * @implemented */ -PLIST_ENTRY -STDCALL +PLIST_ENTRY STDCALL KeRundownQueue(IN PKQUEUE Queue) { - PLIST_ENTRY EnumEntry; - PLIST_ENTRY FirstEntry; - PKTHREAD Thread; - KIRQL OldIrql; - - DPRINT("KeRundownQueue(Queue %x)\n", Queue); - - /* Get the Dispatcher Lock */ - OldIrql = KeAcquireDispatcherDatabaseLock(); - - /* Get the First Empty Entry */ - FirstEntry = Queue->EntryListHead.Flink; - - /* Make sure the list is not empty */ - if (FirstEntry == &Queue->EntryListHead) { - - /* It is, so don't return anything */ - EnumEntry = NULL; - - } else { - - /* Remove it */ - RemoveEntryList(&Queue->EntryListHead); - } - - /* Unlink threads and clear their Thread->Queue */ - while (!IsListEmpty(&Queue->ThreadListHead)) { - - /* Get the Entry and Remove it */ - EnumEntry = RemoveHeadList(&Queue->ThreadListHead); - - /* Get the Entry's Thread */ - Thread = CONTAINING_RECORD(EnumEntry, KTHREAD, QueueListEntry); - - /* Kill its Queue */ - Thread->Queue = NULL; - } - - /* Release the lock and return */ - KeReleaseDispatcherDatabaseLock(OldIrql); - return FirstEntry; -} + PLIST_ENTRY EnumEntry; + PKTHREAD Thread; + KIRQL OldIrql; -/* - * Called when a thread which has a queue entry is entering a wait state - */ -VOID -FASTCALL -KiWakeQueue(IN PKQUEUE Queue) -{ - PLIST_ENTRY QueueEntry; - PLIST_ENTRY WaitEntry; - PKWAIT_BLOCK WaitBlock; - - /* Decrement the number of active threads */ - DPRINT("KiWakeQueue: %x. Thread: %x\n", Queue, KeGetCurrentThread()); - Queue->CurrentCount--; - - /* Make sure the counts are OK */ - if (Queue->CurrentCount < Queue->MaximumCount) { - - /* Get the Queue Entry */ - QueueEntry = Queue->EntryListHead.Flink; - - /* Get the Wait Entry */ - WaitEntry = Queue->Header.WaitListHead.Blink; - DPRINT("Queue Count is ok, Queue entries: %x, %x\n", QueueEntry, WaitEntry); - - /* Make sure that the Queue List isn't empty and that this entry is valid */ - if (!IsListEmpty(&Queue->Header.WaitListHead) && - (QueueEntry != &Queue->EntryListHead)) { - - /* Remove this entry */ - DPRINT("Queue in List, removing it\n"); - RemoveEntryList(QueueEntry); - QueueEntry->Flink = NULL; - - /* Decrease the Signal State */ - Queue->Header.SignalState--; - - /* Unwait the Thread */ - DPRINT("Unwaiting Thread\n"); - WaitBlock = CONTAINING_RECORD(WaitEntry, KWAIT_BLOCK, WaitListEntry); - KiAbortWaitThread(WaitBlock->Thread, (NTSTATUS)QueueEntry); - } - } -} + DPRINT("KeRundownQueue(Queue %x)\n", Queue); -/* - * Returns the previous number of entries in the queue - */ -LONG -STDCALL -KiInsertQueue(IN PKQUEUE Queue, - IN PLIST_ENTRY Entry, - BOOLEAN Head) -{ - ULONG InitialState; - PKTHREAD Thread = KeGetCurrentThread(); - PKWAIT_BLOCK WaitBlock; - PLIST_ENTRY WaitEntry; - - DPRINT("KiInsertQueue(Queue %x, Entry %x)\n", Queue, Entry); - - /* Save the old state */ - InitialState = Queue->Header.SignalState; + /* I'm just guessing how this should work:-/ + * -Gunnar + */ - /* Get the Entry */ - WaitEntry = Queue->Header.WaitListHead.Blink; - DPRINT("Initial State, WaitEntry: %d, %x\n", InitialState, WaitEntry); - - /* - * Why the KeGetCurrentThread()->Queue != Queue? - * KiInsertQueue might be called from an APC for the current thread. - * -Gunnar - */ - if ((Queue->CurrentCount < Queue->MaximumCount) && - (WaitEntry != &Queue->Header.WaitListHead) && - ((Thread->Queue != Queue) || (Thread->WaitReason != WrQueue))) { - - /* Remove the wait entry */ - DPRINT("Removing Entry\n"); - RemoveEntryList(WaitEntry); - - /* Get the Wait Block and Thread */ - WaitBlock = CONTAINING_RECORD(WaitEntry, KWAIT_BLOCK, WaitListEntry); - DPRINT("Got wait block: %x\n", WaitBlock); - Thread = WaitBlock->Thread; - - /* Reset the wait reason */ - Thread->WaitReason = 0; - - /* Increase the waiting threads */ - Queue->CurrentCount++; - - /* Check if there's a Thread Timer */ - if (Thread->Timer.Header.Inserted) { - - /* Cancel the Thread Timer with the no-lock fastpath */ - DPRINT("Removing the Thread's Timer\n"); - Thread->Timer.Header.Inserted = FALSE; - RemoveEntryList(&Thread->Timer.TimerListEntry); - } - - /* Reschedule the Thread */ - DPRINT("Unblocking the Thread\n"); - PsUnblockThread((PETHREAD)Thread, (PNTSTATUS)&Entry, 0); - - } else { - - /* Increase the Entries */ - DPRINT("Adding new Queue Entry: %d %d\n", Head, Queue->Header.SignalState); - Queue->Header.SignalState++; - - if (Head) { - - InsertHeadList(&Queue->EntryListHead, Entry); - - } else { - - InsertTailList(&Queue->EntryListHead, Entry); - } - } - - /* Return the previous state */ - DPRINT("Returning\n"); - return InitialState; + OldIrql = KeAcquireDispatcherDatabaseLock (); + + //no thread must wait on queue at rundown + ASSERT(IsListEmpty(&Queue->Header.WaitListHead)); + + // unlink threads and clear their Thread->Queue + while (!IsListEmpty(&Queue->ThreadListHead)) + { + EnumEntry = RemoveHeadList(&Queue->ThreadListHead); + Thread = CONTAINING_RECORD(EnumEntry, KTHREAD, QueueListEntry); + Thread->Queue = NULL; + } + + if (IsListEmpty(&Queue->EntryListHead)) + { + EnumEntry = NULL; + } + else + { + EnumEntry = Queue->EntryListHead.Flink; + } + + KeReleaseDispatcherDatabaseLock (OldIrql); + + return EnumEntry; } /* EOF */ diff --git a/reactos/ntoskrnl/ke/sem.c b/reactos/ntoskrnl/ke/sem.c index f94990509fd..9408e66948c 100644 --- a/reactos/ntoskrnl/ke/sem.c +++ b/reactos/ntoskrnl/ke/sem.c @@ -19,39 +19,36 @@ /* * @implemented */ -VOID -STDCALL -KeInitializeSemaphore(PKSEMAPHORE Semaphore, - LONG Count, - LONG Limit) +VOID STDCALL +KeInitializeSemaphore (PKSEMAPHORE Semaphore, + LONG Count, + LONG Limit) { - - DPRINT("KeInitializeSemaphore Sem: %x\n", Semaphore); - - /* Simply Initialize the Header */ - KeInitializeDispatcherHeader(&Semaphore->Header, - SemaphoreObject, - sizeof(KSEMAPHORE)/sizeof(ULONG), - Count); - - /* Set the Limit */ - Semaphore->Limit = Limit; + KeInitializeDispatcherHeader(&Semaphore->Header, + InternalSemaphoreType, + sizeof(KSEMAPHORE)/sizeof(ULONG), + Count); + Semaphore->Limit=Limit; } /* * @implemented */ -LONG -STDCALL -KeReadStateSemaphore(PKSEMAPHORE Semaphore) +LONG STDCALL +KeReadStateSemaphore (PKSEMAPHORE Semaphore) { - /* Just return the Signal State */ - return(Semaphore->Header.SignalState); + return(Semaphore->Header.SignalState); } /* * @implemented - * + */ +LONG STDCALL +KeReleaseSemaphore (PKSEMAPHORE Semaphore, + KPRIORITY Increment, + LONG Adjustment, + BOOLEAN Wait) +/* * FUNCTION: KeReleaseSemaphore releases a given semaphore object. This * routine supplies a runtime priority boost for waiting threads. If this * call sets the semaphore to the Signaled state, the semaphore count is @@ -71,65 +68,40 @@ KeReadStateSemaphore(PKSEMAPHORE Semaphore) * RETURNS: If the return value is zero, the previous state of the semaphore * object is Not-Signaled. */ -LONG -STDCALL -KeReleaseSemaphore(PKSEMAPHORE Semaphore, - KPRIORITY Increment, - LONG Adjustment, - BOOLEAN Wait) - { - ULONG InitialState; - KIRQL OldIrql; - PKTHREAD CurrentThread; + ULONG InitialState; + KIRQL OldIrql; - DPRINT("KeReleaseSemaphore(Semaphore %x, Increment %d, Adjustment %d, Wait %d)\n", - Semaphore, - Increment, - Adjustment, - Wait); + DPRINT("KeReleaseSemaphore(Semaphore %x, Increment %d, Adjustment %d, " + "Wait %d)\n", Semaphore, Increment, Adjustment, Wait); - /* Lock the Dispatcher Database */ - OldIrql = KeAcquireDispatcherDatabaseLock(); + OldIrql = KeAcquireDispatcherDatabaseLock(); - /* Save the Old State */ - InitialState = Semaphore->Header.SignalState; - - /* Check if the Limit was exceeded */ - if (Semaphore->Limit < (LONG) InitialState + Adjustment || - InitialState > InitialState + Adjustment) { - - /* Raise an error if it was exceeded */ - KeReleaseDispatcherDatabaseLock(OldIrql); - ExRaiseStatus(STATUS_SEMAPHORE_LIMIT_EXCEEDED); + InitialState = Semaphore->Header.SignalState; + if (Semaphore->Limit < (LONG) InitialState + Adjustment || + InitialState > InitialState + Adjustment) + { + ExRaiseStatus(STATUS_SEMAPHORE_LIMIT_EXCEEDED); } - /* Now set the new state */ - Semaphore->Header.SignalState += Adjustment; - - /* Check if we should wake it */ - if (InitialState == 0 && !IsListEmpty(&Semaphore->Header.WaitListHead)) { - - /* Wake the Semaphore */ - KiWaitTest(&Semaphore->Header, SEMAPHORE_INCREMENT); + Semaphore->Header.SignalState += Adjustment; + if (InitialState == 0) + { + KiDispatcherObjectWake(&Semaphore->Header, SEMAPHORE_INCREMENT); } - /* If the Wait is true, then return with a Wait and don't unlock the Dispatcher Database */ - if (Wait == FALSE) { - - /* Release the Lock */ - KeReleaseDispatcherDatabaseLock(OldIrql); - - } else { - - /* Set a wait */ - CurrentThread = KeGetCurrentThread(); - CurrentThread->WaitNext = TRUE; - CurrentThread->WaitIrql = OldIrql; + if (Wait == FALSE) + { + KeReleaseDispatcherDatabaseLock(OldIrql); + } + else + { + KTHREAD *Thread = KeGetCurrentThread(); + Thread->WaitNext = TRUE; + Thread->WaitIrql = OldIrql; } - /* Return the previous state */ - return InitialState; + return(InitialState); } /* EOF */ diff --git a/reactos/ntoskrnl/ke/timer.c b/reactos/ntoskrnl/ke/timer.c index de101af8b1c..c46db9ddcff 100644 --- a/reactos/ntoskrnl/ke/timer.c +++ b/reactos/ntoskrnl/ke/timer.c @@ -107,11 +107,12 @@ KeInitializeTimerEx (PKTIMER Timer, /* Initialize the Dispatch Header */ KeInitializeDispatcherHeader(&Timer->Header, - TimerNotificationObject + Type, + InternalNotificationTimer + Type, sizeof(KTIMER) / sizeof(ULONG), FALSE); - /* Initalize the Other data */ + /* Initalize the List Head and other data */ + InitializeListHead(&Timer->Header.WaitListHead); Timer->DueTime.QuadPart = 0; Timer->Period = 0; } @@ -195,6 +196,7 @@ KeSetTimerEx (PKTIMER Timer, Timer->Dpc = Dpc; Timer->Period = Period; Timer->Header.SignalState = FALSE; + Timer->Header.Absolute = FALSE; /* Insert it */ if (!KiInsertTimer(Timer, DueTime)) { @@ -294,7 +296,7 @@ KiHandleExpiredTimer(PKTIMER Timer) /* Set it as Signaled */ DPRINT("Setting Timer as Signaled\n"); Timer->Header.SignalState = TRUE; - KiWaitTest(&Timer->Header, 0); + KiDispatcherObjectWake(&Timer->Header, 0); /* If the Timer is periodic, reinsert the timer with the new due time */ if (Timer->Period) { @@ -304,7 +306,7 @@ KiHandleExpiredTimer(PKTIMER Timer) if (!KiInsertTimer(Timer, DueTime)) { /* FIXME: I will think about how to handle this and fix it ASAP -- Alex */ - DPRINT("CRITICAL UNHANDLED CASE: TIMER ALREADY EXPIRED!!!\n"); + DPRINT1("CRITICAL UNHANDLED CASE: TIMER ALREADY EXPIRED!!!\n"); }; } @@ -336,10 +338,8 @@ KiInsertTimer(PKTIMER Timer, DPRINT("KiInsertTimer(Timer %x DueTime %I64d)\n", Timer, DueTime.QuadPart); - /* Set default data */ + /* Set it as Inserted */ Timer->Header.Inserted = TRUE; - Timer->Header.Absolute = FALSE; - if (!Timer->Period) Timer->Header.SignalState = FALSE; /* Convert to relative time if needed */ if (DueTime.u.HighPart >= 0) { diff --git a/reactos/ntoskrnl/ke/wait.c b/reactos/ntoskrnl/ke/wait.c index 7f65c81079b..a6575e9bb88 100644 --- a/reactos/ntoskrnl/ke/wait.c +++ b/reactos/ntoskrnl/ke/wait.c @@ -1,11 +1,16 @@ -/* +/* $Id$ + * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS project * FILE: ntoskrnl/ke/wait.c * PURPOSE: Manages non-busy waiting * - * PROGRAMMERS: Alex Ionescu - Fixes and optimization. - * Gunnar Dalsnes - Implementation + * PROGRAMMERS: David Welch (welch@mcmail.com) + * Phillip Susi + */ + +/* NOTES ******************************************************************** + * */ /* INCLUDES ******************************************************************/ @@ -19,51 +24,387 @@ static KSPIN_LOCK DispatcherDatabaseLock; -/* Tells us if the Timer or Event is a Syncronization or Notification Object */ -#define TIMER_OR_EVENT_TYPE 0x7L +#define KeDispatcherObjectWakeOne(hdr, increment) KeDispatcherObjectWakeOneOrAll(hdr, increment, FALSE) +#define KeDispatcherObjectWakeAll(hdr, increment) KeDispatcherObjectWakeOneOrAll(hdr, increment, TRUE) -/* One of the Reserved Wait Blocks, this one is for the Thread's Timer */ -#define TIMER_WAIT_BLOCK 0x3L +extern POBJECT_TYPE EXPORTED ExMutantObjectType; +extern POBJECT_TYPE EXPORTED ExSemaphoreObjectType; +extern POBJECT_TYPE EXPORTED ExTimerType; /* FUNCTIONS *****************************************************************/ +VOID KeInitializeDispatcherHeader(DISPATCHER_HEADER* Header, + ULONG Type, + ULONG Size, + ULONG SignalState) +{ + Header->Type = (UCHAR)Type; + Header->Absolute = 0; + Header->Inserted = 0; + Header->Size = (UCHAR)Size; + Header->SignalState = SignalState; + InitializeListHead(&(Header->WaitListHead)); +} + + +KIRQL +KeAcquireDispatcherDatabaseLock(VOID) +/* + * PURPOSE: Acquires the dispatcher database lock for the caller + */ +{ + KIRQL OldIrql; + + DPRINT("KeAcquireDispatcherDatabaseLock()\n"); + + KeAcquireSpinLock (&DispatcherDatabaseLock, &OldIrql); + return OldIrql; +} + + VOID -inline -FASTCALL -KiCheckAlertability(BOOLEAN Alertable, - PKTHREAD CurrentThread, - KPROCESSOR_MODE WaitMode, - PNTSTATUS Status) +KeAcquireDispatcherDatabaseLockAtDpcLevel(VOID) +/* + * PURPOSE: Acquires the dispatcher database lock for the caller + */ { - /* At this point, we have to do a wait, so make sure we can make the thread Alertable if requested */ - if (Alertable) { - - /* If the Thread is Alerted, set the Wait Status accordingly */ - if (CurrentThread->Alerted[(int)WaitMode]) { - - CurrentThread->Alerted[(int)WaitMode] = FALSE; - DPRINT("Thread was Alerted\n"); - *Status = STATUS_ALERTED; - - /* If there are User APCs Pending, then we can't really be alertable */ - } else if ((!IsListEmpty(&CurrentThread->ApcState.ApcListHead[UserMode])) && - (WaitMode == UserMode)) { - - DPRINT("APCs are Pending\n"); - CurrentThread->ApcState.UserApcPending = TRUE; - *Status = STATUS_USER_APC; - } - - /* If there are User APCs Pending and we are waiting in usermode, then we must notify the caller */ - } else if ((CurrentThread->ApcState.UserApcPending) && (WaitMode == UserMode)) { - DPRINT("APCs are Pending\n"); - *Status = STATUS_USER_APC; - } + DPRINT("KeAcquireDispatcherDatabaseLockAtDpcLevel()\n"); + + KeAcquireSpinLockAtDpcLevel (&DispatcherDatabaseLock); +} + + +VOID +KeReleaseDispatcherDatabaseLock(KIRQL OldIrql) +{ + DPRINT("KeReleaseDispatcherDatabaseLock(OldIrql %x)\n",OldIrql); + if (!KeIsExecutingDpc() && + OldIrql < DISPATCH_LEVEL && + KeGetCurrentThread() != NULL && + KeGetCurrentThread() == KeGetCurrentKPCR()->PrcbData.IdleThread) + { + PsDispatchThreadNoLock(THREAD_STATE_READY); + KeLowerIrql(OldIrql); + } + else + { + KeReleaseSpinLock(&DispatcherDatabaseLock, OldIrql); + } +} + + +VOID +KeReleaseDispatcherDatabaseLockFromDpcLevel(VOID) +{ + DPRINT("KeReleaseDispatcherDatabaseLock()\n"); + + KeReleaseSpinLockFromDpcLevel(&DispatcherDatabaseLock); +} + + +static BOOLEAN +KiSideEffectsBeforeWake(DISPATCHER_HEADER * hdr, + PKTHREAD Thread) +/* + * FUNCTION: Perform side effects on object before a wait for a thread is + * satisfied + */ +{ + BOOLEAN Abandoned = FALSE; + + switch (hdr->Type) + { + case InternalSynchronizationEvent: + hdr->SignalState = 0; + break; + + case InternalQueueType: + break; + + case InternalSemaphoreType: + hdr->SignalState--; + break; + + case InternalProcessType: + break; + + case InternalThreadType: + break; + + case InternalNotificationEvent: + break; + + case InternalSynchronizationTimer: + hdr->SignalState = FALSE; + break; + + case InternalNotificationTimer: + break; + + case InternalMutexType: + { + PKMUTEX Mutex; + + Mutex = CONTAINING_RECORD(hdr, KMUTEX, Header); + hdr->SignalState--; + ASSERT(hdr->SignalState <= 1); + if (hdr->SignalState == 0) + { + if (Thread == NULL) + { + DPRINT("Thread == NULL!\n"); + KEBUGCHECK(0); + } + Abandoned = Mutex->Abandoned; + if (Thread != NULL) + InsertTailList(&Thread->MutantListHead, &Mutex->MutantListEntry); + Mutex->OwnerThread = Thread; + Mutex->Abandoned = FALSE; + } + } + break; + + default: + DbgPrint("(%s:%d) Dispatcher object %x has unknown type\n", __FILE__, __LINE__, hdr); + KEBUGCHECK(0); + } + + return Abandoned; +} + +static BOOLEAN +KiIsObjectSignalled(DISPATCHER_HEADER * hdr, + PKTHREAD Thread) +{ + if (hdr->Type == InternalMutexType) + { + PKMUTEX Mutex; + + Mutex = CONTAINING_RECORD(hdr, KMUTEX, Header); + + ASSERT(hdr->SignalState <= 1); + + if ((hdr->SignalState < 1 && Mutex->OwnerThread == Thread) || hdr->SignalState == 1) + { + return (TRUE); + } + else + { + return (FALSE); + } + } + + if (hdr->SignalState <= 0) + { + return (FALSE); + } + else + { + return (TRUE); + } +} + +/* Must be called with the dispatcher lock held */ +BOOLEAN KiAbortWaitThread(PKTHREAD Thread, NTSTATUS WaitStatus) +{ + PKWAIT_BLOCK WaitBlock; + BOOLEAN WasWaiting; + + /* if we are blocked, we must be waiting on something also */ + ASSERT((Thread->State == THREAD_STATE_BLOCKED) == (Thread->WaitBlockList != NULL)); + + WaitBlock = (PKWAIT_BLOCK)Thread->WaitBlockList; + WasWaiting = (WaitBlock != NULL); + + while (WaitBlock) + { + RemoveEntryList(&WaitBlock->WaitListEntry); + WaitBlock = WaitBlock->NextWaitBlock; + } + + Thread->WaitBlockList = NULL; + + if (WasWaiting) + { + PsUnblockThread((PETHREAD)Thread, &WaitStatus, 0); + } + return WasWaiting; +} + +static BOOLEAN +KeDispatcherObjectWakeOneOrAll(DISPATCHER_HEADER * hdr, + KPRIORITY increment, + BOOLEAN WakeAll) +{ + PKWAIT_BLOCK Waiter; + PKWAIT_BLOCK WaiterHead; + PLIST_ENTRY EnumEntry; + NTSTATUS Status; + BOOLEAN Abandoned; + BOOLEAN AllSignaled; + BOOLEAN WakedAny = FALSE; + + DPRINT("KeDispatcherObjectWakeOnOrAll(hdr %x)\n", hdr); + DPRINT ("hdr->WaitListHead.Flink %x hdr->WaitListHead.Blink %x\n", + hdr->WaitListHead.Flink, hdr->WaitListHead.Blink); + + if (IsListEmpty(&hdr->WaitListHead)) + { + return (FALSE); + } + + //enum waiters for this dispatcher object + EnumEntry = hdr->WaitListHead.Flink; + while (EnumEntry != &hdr->WaitListHead && (WakeAll || !WakedAny)) + { + WaiterHead = CONTAINING_RECORD(EnumEntry, KWAIT_BLOCK, WaitListEntry); + DPRINT("current_entry %x current %x\n", EnumEntry, WaiterHead); + EnumEntry = EnumEntry->Flink; + ASSERT(WaiterHead->Thread != NULL); + ASSERT(WaiterHead->Thread->WaitBlockList != NULL); + + Abandoned = FALSE; + + if (WaiterHead->WaitType == WaitAny) + { + DPRINT("WaitAny: Remove all wait blocks.\n"); + for (Waiter = WaiterHead->Thread->WaitBlockList; Waiter; Waiter = Waiter->NextWaitBlock) + { + RemoveEntryList(&Waiter->WaitListEntry); + } + + WaiterHead->Thread->WaitBlockList = NULL; + + /* + * If a WakeAll KiSideEffectsBeforeWake(hdr,.. will be called several times, + * but thats ok since WakeAll objects has no sideeffects. + */ + Abandoned |= KiSideEffectsBeforeWake(hdr, WaiterHead->Thread); + } + else + { + DPRINT("WaitAll: All WaitAll objects must be signaled.\n"); + + AllSignaled = TRUE; + + //all WaitAll obj. for thread need to be signaled to satisfy a wake + for (Waiter = WaiterHead->Thread->WaitBlockList; Waiter; Waiter = Waiter->NextWaitBlock) + { + //no need to check hdr since it has to be signaled + if (Waiter->WaitType == WaitAll && Waiter->Object != hdr) + { + if (!KiIsObjectSignalled(Waiter->Object, Waiter->Thread)) + { + AllSignaled = FALSE; + break; + } + } + } + + if (AllSignaled) + { + for (Waiter = WaiterHead->Thread->WaitBlockList; Waiter; Waiter = Waiter->NextWaitBlock) + { + RemoveEntryList(&Waiter->WaitListEntry); + + if (Waiter->WaitType == WaitAll) + { + Abandoned |= KiSideEffectsBeforeWake(Waiter->Object, Waiter->Thread); + } + + //no WaitAny objects can possibly be signaled since we are here + ASSERT(!(Waiter->WaitType == WaitAny + && KiIsObjectSignalled(Waiter->Object, Waiter->Thread))); + } + + WaiterHead->Thread->WaitBlockList = NULL; + } + } + + if (WaiterHead->Thread->WaitBlockList == NULL) + { + Status = WaiterHead->WaitKey; + if (Abandoned) + { + DPRINT("Abandoned mutex among objects"); + Status += STATUS_ABANDONED_WAIT_0; + } + + WakedAny = TRUE; + DPRINT("Waking %x status = %x\n", WaiterHead->Thread, Status); + PsUnblockThread(CONTAINING_RECORD(WaiterHead->Thread, ETHREAD, Tcb), + &Status, increment); + } + } + + return WakedAny; +} + + +BOOLEAN KiDispatcherObjectWake(DISPATCHER_HEADER* hdr, KPRIORITY increment) +/* + * FUNCTION: Wake threads waiting on a dispatcher object + * NOTE: The exact semantics of waking are dependant on the type of object + */ +{ + BOOL Ret; + + DPRINT("Entering KeDispatcherObjectWake(hdr %x)\n",hdr); +// DPRINT("hdr->WaitListHead %x hdr->WaitListHead.Flink %x\n", +// &hdr->WaitListHead,hdr->WaitListHead.Flink); + DPRINT("hdr->Type %x\n",hdr->Type); + switch (hdr->Type) + { + case InternalNotificationEvent: + return(KeDispatcherObjectWakeAll(hdr, increment)); + + case InternalNotificationTimer: + return(KeDispatcherObjectWakeAll(hdr, increment)); + + case InternalSynchronizationEvent: + return(KeDispatcherObjectWakeOne(hdr, increment)); + + case InternalSynchronizationTimer: + return(KeDispatcherObjectWakeOne(hdr, increment)); + + case InternalQueueType: + return(KeDispatcherObjectWakeOne(hdr, increment)); + + case InternalSemaphoreType: + DPRINT("hdr->SignalState %d\n", hdr->SignalState); + if(hdr->SignalState>0) + { + do + { + DPRINT("Waking one semaphore waiter\n"); + Ret = KeDispatcherObjectWakeOne(hdr, increment); + } while(hdr->SignalState > 0 && Ret) ; + return(Ret); + } + else return FALSE; + + case InternalProcessType: + return(KeDispatcherObjectWakeAll(hdr, increment)); + + case InternalThreadType: + return(KeDispatcherObjectWakeAll(hdr, increment)); + + case InternalMutexType: + return(KeDispatcherObjectWakeOne(hdr, increment)); + } + DbgPrint("Dispatcher object %x has unknown type %d\n", hdr, hdr->Type); + KEBUGCHECK(0); + return(FALSE); } /* * @implemented - * + */ +NTSTATUS STDCALL +KeDelayExecutionThread (KPROCESSOR_MODE WaitMode, + BOOLEAN Alertable, + PLARGE_INTEGER Interval) +/* * FUNCTION: Puts the current thread into an alertable or nonalertable * wait state for a given internal * ARGUMENTS: @@ -72,102 +413,27 @@ KiCheckAlertability(BOOLEAN Alertable, * Interval = Specifies the interval to wait * RETURNS: Status */ -NTSTATUS -STDCALL -KeDelayExecutionThread(KPROCESSOR_MODE WaitMode, - BOOLEAN Alertable, - PLARGE_INTEGER Interval) { - PKWAIT_BLOCK TimerWaitBlock; - PKTIMER ThreadTimer; - PKTHREAD CurrentThread = KeGetCurrentThread(); - NTSTATUS Status; + PKTHREAD Thread = KeGetCurrentThread(); - DPRINT("Entering KeDelayExecutionThread\n"); - - /* Check if the lock is already held */ - if (CurrentThread->WaitNext) { - - /* Lock is held, disable Wait Next */ - DPRINT("Lock is held\n"); - CurrentThread->WaitNext = FALSE; - - } else { - - /* Lock not held, acquire it */ - DPRINT("Lock is not held, acquiring\n"); - CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock(); - } - - /* Use built-in Wait block */ - TimerWaitBlock = &CurrentThread->WaitBlock[TIMER_WAIT_BLOCK]; - - /* Start Wait Loop */ - do { - - /* We are going to wait no matter what (that's the point), so test Alertability */ - KiCheckAlertability(Alertable, CurrentThread, KernelMode, &Status); - - /* Set Timer */ - ThreadTimer = &CurrentThread->Timer; - - /* Setup the Wait Block */ - CurrentThread->WaitBlockList = TimerWaitBlock; - TimerWaitBlock->Object = (PVOID)ThreadTimer; - TimerWaitBlock->Thread = CurrentThread; - TimerWaitBlock->WaitKey = (USHORT)STATUS_TIMEOUT; - TimerWaitBlock->WaitType = WaitAny; - TimerWaitBlock->NextWaitBlock = NULL; - - /* Link the timer to this Wait Block */ - InitializeListHead(&ThreadTimer->Header.WaitListHead); - InsertTailList(&ThreadTimer->Header.WaitListHead, &TimerWaitBlock->WaitListEntry); - - /* Insert the Timer into the Timer Lists and enable it */ - if (!KiInsertTimer(ThreadTimer, *Interval)) { - - /* FIXME: Unhandled case...what should we do? */ - DPRINT1("Could not create timer for KeDelayExecutionThread\n"); - } - - /* Handle Kernel Queues */ - if (CurrentThread->Queue) { - - DPRINT("Waking Queue\n"); - KiWakeQueue(CurrentThread->Queue); - } - - /* Block the Thread */ - DPRINT("Blocking the Thread: %d, %d, %x\n", Alertable, WaitMode, KeGetCurrentThread()); - PsBlockThread(&Status, - Alertable, - WaitMode, - DelayExecution); - - /* Check if we were executing an APC or if we timed out */ - if (Status != STATUS_KERNEL_APC) { - - /* This is a good thing */ - if (Status == STATUS_TIMEOUT) Status = STATUS_SUCCESS; - - /* Return Status */ - return Status; - } - - DPRINT("Looping Again\n"); - CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock(); - - } while (TRUE); - - /* Release the Lock, we are done */ - DPRINT("Returning from KeDelayExecutionThread(), %x. Status: %d\n", KeGetCurrentThread(), Status); - KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql); - return Status; + KeSetTimer(&Thread->Timer, *Interval, NULL); + return (KeWaitForSingleObject(&Thread->Timer, + (WaitMode == KernelMode) ? Executive : UserRequest, /* TMN: Was unconditionally Executive */ + WaitMode, /* TMN: Was UserMode */ + Alertable, + NULL)); } /* * @implemented - * + */ +NTSTATUS STDCALL +KeWaitForSingleObject(PVOID Object, + KWAIT_REASON WaitReason, + KPROCESSOR_MODE WaitMode, + BOOLEAN Alertable, + PLARGE_INTEGER Timeout) +/* * FUNCTION: Puts the current thread into a wait state until the * given dispatcher object is set to signalled * ARGUMENTS: @@ -180,174 +446,52 @@ KeDelayExecutionThread(KPROCESSOR_MODE WaitMode, * Timeout = Optional timeout value * RETURNS: Status */ -NTSTATUS -STDCALL -KeWaitForSingleObject(PVOID Object, - KWAIT_REASON WaitReason, - KPROCESSOR_MODE WaitMode, - BOOLEAN Alertable, - PLARGE_INTEGER Timeout) { - PDISPATCHER_HEADER CurrentObject; - PKWAIT_BLOCK WaitBlock; - PKWAIT_BLOCK TimerWaitBlock; - PKTIMER ThreadTimer; - PKTHREAD CurrentThread = KeGetCurrentThread(); - NTSTATUS Status; - NTSTATUS WaitStatus; - - DPRINT("Entering KeWaitForSingleObject\n"); - - /* Check if the lock is already held */ - if (CurrentThread->WaitNext) { - - /* Lock is held, disable Wait Next */ - DPRINT("Lock is held\n"); - CurrentThread->WaitNext = FALSE; - - } else { - - /* Lock not held, acquire it */ - DPRINT("Lock is not held, acquiring\n"); - CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock(); - } - - /* Start the actual Loop */ - do { - - /* Get the current Wait Status */ - WaitStatus = CurrentThread->WaitStatus; - - /* Append wait block to the KTHREAD wait block list */ - CurrentThread->WaitBlockList = WaitBlock = &CurrentThread->WaitBlock[0]; - - /* Get the Current Object */ - CurrentObject = (PDISPATCHER_HEADER)Object; - - /* FIXME: - * Temporary hack until my Object Manager re-write. Basically some objects, like - * the File Object, but also LPCs and others, are actually waitable on their event. - * The Object Manager sets this up in The ObjectTypeInformation->DefaultObject member, - * by using pretty much the same kind of hack as us. Normal objects point to themselves - * in that pointer. Then, NtWaitForXXX will populate the WaitList that gets sent to us by - * using ->DefaultObject, so the proper actual objects will be sent to us. Until then however, - * I will keep this hack here, since there's no need to make an interim hack until the rewrite - * -- Alex Ionescu 24/02/05 - */ - if (CurrentObject->Type == IO_TYPE_FILE) { - - DPRINT1("Hack used: %x\n", &((PFILE_OBJECT)CurrentObject)->Event); - CurrentObject = (PDISPATCHER_HEADER)(&((PFILE_OBJECT)CurrentObject)->Event); - } - - /* Check if the Object is Signaled */ - if (KiIsObjectSignaled(CurrentObject, CurrentThread)) { - - /* Just unwait this guy and exit */ - if (CurrentObject->SignalState != MINLONG) { - - /* It has a normal signal state, so unwait it and return */ - KiSatisfyObjectWait(CurrentObject, CurrentThread); - Status = STATUS_WAIT_0; - goto WaitDone; - - } else { - - /* Is this a Mutant? */ - if (CurrentObject->Type == MutantObject) { - - /* According to wasm.ru, we must raise this exception (tested and true) */ - KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql); - ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED); - } - } - } - - /* Set up the Wait Block */ - WaitBlock->Object = CurrentObject; - WaitBlock->Thread = CurrentThread; - WaitBlock->WaitKey = (USHORT)(STATUS_WAIT_0); - WaitBlock->WaitType = WaitAny; - WaitBlock->NextWaitBlock = NULL; - - /* Make sure we can satisfy the Alertable request */ - KiCheckAlertability(Alertable, CurrentThread, WaitMode, &Status); - - /* Set the Wait Status */ - CurrentThread->WaitStatus = Status; - - /* Enable the Timeout Timer if there was any specified */ - if (Timeout != NULL) { - - /* However if 0 timeout was specified, then we must fail since we need to peform a wait */ - if (!Timeout->QuadPart) { - - /* Return a timeout */ - Status = STATUS_TIMEOUT; - goto WaitDone; - } - - /* Point to Timer Wait Block and Thread Timer */ - TimerWaitBlock = &CurrentThread->WaitBlock[TIMER_WAIT_BLOCK]; - ThreadTimer = &CurrentThread->Timer; + return KeWaitForMultipleObjects(1, + &Object, + WaitAny, + WaitReason, + WaitMode, + Alertable, + Timeout, + NULL); +} - /* Connect the Timer Wait Block */ - WaitBlock->NextWaitBlock = TimerWaitBlock; - - /* Set up the Timer Wait Block */ - TimerWaitBlock->Object = (PVOID)ThreadTimer; - TimerWaitBlock->Thread = CurrentThread; - TimerWaitBlock->WaitKey = STATUS_TIMEOUT; - TimerWaitBlock->WaitType = WaitAny; - TimerWaitBlock->NextWaitBlock = NULL; - - /* Link the timer to this Wait Block */ - InitializeListHead(&ThreadTimer->Header.WaitListHead); - InsertTailList(&ThreadTimer->Header.WaitListHead, &TimerWaitBlock->WaitListEntry); - /* Insert the Timer into the Timer Lists and enable it */ - if (!KiInsertTimer(ThreadTimer, *Timeout)) { +inline +PVOID +KiGetWaitableObjectFromObject(PVOID Object) +{ + //special case when waiting on file objects + if ( ((PDISPATCHER_HEADER)Object)->Type == InternalFileType) + { + return &((PFILE_OBJECT)Object)->Event; + } - /* Return a timeout if we couldn't insert the timer for some reason */ - Status = STATUS_TIMEOUT; - goto WaitDone; - } - } + return Object; +} - /* Link the Object to this Wait Block */ - InsertTailList(&CurrentObject->WaitListHead, &WaitBlock->WaitListEntry); - - /* Handle Kernel Queues */ - if (CurrentThread->Queue) { - - DPRINT("Waking Queue\n"); - KiWakeQueue(CurrentThread->Queue); - } - /* Block the Thread */ - DPRINT("Blocking the Thread: %d, %d, %d, %x\n", Alertable, WaitMode, WaitReason, KeGetCurrentThread()); - PsBlockThread(&Status, - Alertable, - WaitMode, - (UCHAR)WaitReason); - - /* Check if we were executing an APC */ - if (Status != STATUS_KERNEL_APC) { - - /* Return Status */ - return Status; - } - - DPRINT("Looping Again\n"); - CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock(); - - } while (TRUE); - -WaitDone: - /* Release the Lock, we are done */ - DPRINT("Returning from KeWaitForMultipleObjects(), %x. Status: %d\n", KeGetCurrentThread(), Status); - KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql); - return Status; +inline BOOL +KiIsObjectWaitable(PVOID Object) +{ + POBJECT_HEADER Header; + Header = BODY_TO_HEADER(Object); + if (Header->ObjectType == ExEventObjectType || + Header->ObjectType == ExIoCompletionType || + Header->ObjectType == ExMutantObjectType || + Header->ObjectType == ExSemaphoreObjectType || + Header->ObjectType == ExTimerType || + Header->ObjectType == PsProcessType || + Header->ObjectType == PsThreadType || + Header->ObjectType == IoFileObjectType) + { + return TRUE; + } + else + { + return FALSE; + } } /* @@ -363,544 +507,558 @@ KeWaitForMultipleObjects(ULONG Count, PLARGE_INTEGER Timeout, PKWAIT_BLOCK WaitBlockArray) { - PDISPATCHER_HEADER CurrentObject; - PKWAIT_BLOCK WaitBlock; - PKWAIT_BLOCK TimerWaitBlock; - PKTIMER ThreadTimer; - PKTHREAD CurrentThread = KeGetCurrentThread(); - ULONG AllObjectsSignaled; - ULONG WaitIndex; - NTSTATUS Status; - NTSTATUS WaitStatus; - - DPRINT("Entering KeWaitForMultipleObjects(Count %lu Object[] %p) " - "PsGetCurrentThread() %x, Timeout %x\n", Count, Object, PsGetCurrentThread(), Timeout); - - /* Set the Current Thread */ - CurrentThread = KeGetCurrentThread(); - - /* Check if the lock is already held */ - if (CurrentThread->WaitNext) { - - /* Lock is held, disable Wait Next */ - DPRINT("Lock is held\n"); - CurrentThread->WaitNext = FALSE; - - } else { - - /* Lock not held, acquire it */ - DPRINT("Lock is not held, acquiring\n"); - CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock(); - } + DISPATCHER_HEADER *hdr; + PKWAIT_BLOCK blk; + PKTHREAD CurrentThread; + ULONG CountSignaled; + ULONG i; + NTSTATUS Status; + KIRQL OldIrql; + BOOLEAN Abandoned; + NTSTATUS WaitStatus; - /* Make sure the Wait Count is valid for the Thread and Maximum Wait Objects */ - if (!WaitBlockArray) { - - /* Check in regards to the Thread Object Limit */ - if (Count > THREAD_WAIT_OBJECTS) { - - DPRINT1("(%s:%d) Too many objects!\n", __FILE__, __LINE__); - KEBUGCHECK(MAXIMUM_WAIT_OBJECTS_EXCEEDED); - } - - /* Use the Thread's Wait Block */ - WaitBlockArray = &CurrentThread->WaitBlock[0]; - - } else { - - /* Using our own Block Array. Check in regards to System Object Limit */ - if (Count > MAXIMUM_WAIT_OBJECTS) { - - DPRINT1("(%s:%d) Too many objects!\n", __FILE__, __LINE__); - KEBUGCHECK(MAXIMUM_WAIT_OBJECTS_EXCEEDED); - } - } - - /* Start the actual Loop */ - do { - - /* Get the current Wait Status */ - WaitStatus = CurrentThread->WaitStatus; - - /* Append wait block to the KTHREAD wait block list */ - CurrentThread->WaitBlockList = WaitBlock = WaitBlockArray; - - /* Check if the wait is (already) satisfied */ - AllObjectsSignaled = TRUE; - - /* First, we'll try to satisfy the wait directly */ - for (WaitIndex = 0; WaitIndex < Count; WaitIndex++) { - - /* Get the Current Object */ - CurrentObject = (PDISPATCHER_HEADER)Object[WaitIndex]; - - /* FIXME: - * Temporary hack until my Object Manager re-write. Basically some objects, like - * the File Object, but also LPCs and others, are actually waitable on their event. - * The Object Manager sets this up in The ObjectTypeInformation->DefaultObject member, - * by using pretty much the same kind of hack as us. Normal objects point to themselves - * in that pointer. Then, NtWaitForXXX will populate the WaitList that gets sent to us by - * using ->DefaultObject, so the proper actual objects will be sent to us. Until then however, - * I will keep this hack here, since there's no need to make an interim hack until the rewrite - * -- Alex Ionescu 24/02/05 - */ - if (CurrentObject->Type == IO_TYPE_FILE) { - - DPRINT1("Hack used: %x\n", &((PFILE_OBJECT)CurrentObject)->Event); - CurrentObject = (PDISPATCHER_HEADER)(&((PFILE_OBJECT)CurrentObject)->Event); - } + DPRINT("Entering KeWaitForMultipleObjects(Count %lu Object[] %p) " + "PsGetCurrentThread() %x\n", Count, Object, PsGetCurrentThread()); - /* Check if the Object is Signaled */ - if (KiIsObjectSignaled(CurrentObject, CurrentThread)) { - - /* Check what kind of wait this is */ - if (WaitType == WaitAny) { - - /* This is a Wait Any, so just unwait this guy and exit */ - if (CurrentObject->SignalState != MINLONG) { - - /* It has a normal signal state, so unwait it and return */ - KiSatisfyObjectWait(CurrentObject, CurrentThread); - Status = STATUS_WAIT_0 | WaitIndex; - goto WaitDone; - - } else { - - /* Is this a Mutant? */ - if (CurrentObject->Type == MutantObject) { - - /* According to wasm.ru, we must raise this exception (tested and true) */ - KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql); - ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED); - } - } - } - - } else { - - /* One of the objects isn't signaled... if this is a WaitAll, we will fail later */ - AllObjectsSignaled = FALSE; - } + ASSERT(0 < Count && Count <= MAXIMUM_WAIT_OBJECTS); - /* Set up a Wait Block for this Object */ - WaitBlock->Object = CurrentObject; - WaitBlock->Thread = CurrentThread; - WaitBlock->WaitKey = (USHORT)(STATUS_WAIT_0 + WaitIndex); - WaitBlock->WaitType = (USHORT)WaitType; - WaitBlock->NextWaitBlock = WaitBlock + 1; - - /* Move to the next Wait Block */ - WaitBlock = WaitBlock->NextWaitBlock; - } - - /* Return to the Root Wait Block */ - WaitBlock--; - WaitBlock->NextWaitBlock = NULL; - - /* Check if this is a Wait All and all the objects are signaled */ - if ((WaitType == WaitAll) && (AllObjectsSignaled)) { - - /* Return to the Root Wait Block */ - WaitBlock = CurrentThread->WaitBlockList; - - /* Satisfy their Waits and return to the caller */ - KiSatisifyMultipleObjectWaits(WaitBlock); - Status = STATUS_WAIT_0; - goto WaitDone; - } - - /* Make sure we can satisfy the Alertable request */ - KiCheckAlertability(Alertable, CurrentThread, WaitMode, &Status); - - /* Set the Wait Status */ - CurrentThread->WaitStatus = Status; - - /* Enable the Timeout Timer if there was any specified */ - if (Timeout != NULL) { - - /* However if 0 timeout was specified, then we must fail since we need to peform a wait */ - if (!Timeout->QuadPart) { - - /* Return a timeout */ - Status = STATUS_TIMEOUT; - goto WaitDone; - } - - /* Point to Timer Wait Block and Thread Timer */ - TimerWaitBlock = &CurrentThread->WaitBlock[TIMER_WAIT_BLOCK]; - ThreadTimer = &CurrentThread->Timer; + CurrentThread = KeGetCurrentThread(); - /* Connect the Timer Wait Block */ - WaitBlock->NextWaitBlock = TimerWaitBlock; - - /* Set up the Timer Wait Block */ - TimerWaitBlock->Object = (PVOID)ThreadTimer; - TimerWaitBlock->Thread = CurrentThread; - TimerWaitBlock->WaitKey = STATUS_TIMEOUT; - TimerWaitBlock->WaitType = WaitAny; - TimerWaitBlock->NextWaitBlock = NULL; - - /* Link the timer to this Wait Block */ - InitializeListHead(&ThreadTimer->Header.WaitListHead); + /* + * Work out where we are going to put the wait blocks + */ + if (WaitBlockArray == NULL) + { + if (Count > THREAD_WAIT_OBJECTS) + { + DPRINT("(%s:%d) Too many objects!\n", __FILE__, __LINE__); + return (STATUS_UNSUCCESSFUL); + } + WaitBlockArray = &CurrentThread->WaitBlock[0]; + } + else + { + if (Count > MAXIMUM_WAIT_OBJECTS) + { + DPRINT("(%s:%d) Too many objects!\n", __FILE__, __LINE__); + return (STATUS_UNSUCCESSFUL); + } + } - /* Insert the Timer into the Timer Lists and enable it */ - if (!KiInsertTimer(ThreadTimer, *Timeout)) { - /* Return a timeout if we couldn't insert the timer for some reason */ - Status = STATUS_TIMEOUT; - goto WaitDone; - } - } - /* Insert into Object's Wait List*/ - WaitBlock = CurrentThread->WaitBlockList; - while (WaitBlock) { - - /* Get the Current Object */ - CurrentObject = WaitBlock->Object; - - /* Link the Object to this Wait Block */ - InsertTailList(&CurrentObject->WaitListHead, &WaitBlock->WaitListEntry); - - /* Move to the next Wait Block */ - WaitBlock = WaitBlock->NextWaitBlock; - } - - /* Handle Kernel Queues */ - if (CurrentThread->Queue) { - - DPRINT("Waking Queue\n"); - KiWakeQueue(CurrentThread->Queue); - } - - /* Block the Thread */ - DPRINT("Blocking the Thread: %d, %d, %d, %x\n", Alertable, WaitMode, WaitReason, KeGetCurrentThread()); - PsBlockThread(&Status, - Alertable, - WaitMode, - (UCHAR)WaitReason); - - /* Check if we were executing an APC */ - if (Status != STATUS_KERNEL_APC) { - - /* Return Status */ - return Status; - } - - DPRINT("Looping Again\n"); - CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock(); - - } while (TRUE); - -WaitDone: - /* Release the Lock, we are done */ - DPRINT("Returning from KeWaitForMultipleObjects(), %x. Status: %d\n", KeGetCurrentThread(), Status); - KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql); - return Status; -} + /* + * Set up the timeout if required + */ + if (Timeout != NULL && Timeout->QuadPart != 0) + { + KeSetTimer(&CurrentThread->Timer, *Timeout, NULL); + } -VOID -FASTCALL -KiSatisfyObjectWait(PDISPATCHER_HEADER Object, - PKTHREAD Thread) + do + { + if (CurrentThread->WaitNext) + { + CurrentThread->WaitNext = FALSE; + OldIrql = CurrentThread->WaitIrql; + } + else + { + OldIrql = KeAcquireDispatcherDatabaseLock (); + } -{ - /* Special case for Mutants */ - if (Object->Type == MutantObject) { - - /* Decrease the Signal State */ - Object->SignalState--; - - /* Check if it's now non-signaled */ - if (Object->SignalState == 0) { - - /* Set the Owner Thread */ - ((PKMUTANT)Object)->OwnerThread = Thread; - - /* Disable APCs if needed */ - Thread->KernelApcDisable -= ((PKMUTANT)Object)->ApcDisable; + /* Get the current Wait Status */ + WaitStatus = CurrentThread->WaitStatus; + + if (Alertable) { + + /* If the Thread is Alerted, set the Wait Status accordingly */ + if (CurrentThread->Alerted[(int)WaitMode]) { - /* Check if it's abandoned */ - if (((PKMUTANT)Object)->Abandoned) { + CurrentThread->Alerted[(int)WaitMode] = FALSE; + DPRINT("Thread was Alerted\n"); + WaitStatus = STATUS_ALERTED; - /* Unabandon it */ - ((PKMUTANT)Object)->Abandoned = FALSE; - - /* Return Status */ - Thread->WaitStatus = STATUS_ABANDONED; - } + /* If there are User APCs Pending, then we can't really be alertable */ + } else if ((!IsListEmpty(&CurrentThread->ApcState.ApcListHead[UserMode])) && + (WaitMode == UserMode)) { - /* Insert it into the Mutant List */ - InsertHeadList(&Thread->MutantListHead, &((PKMUTANT)Object)->MutantListEntry); + DPRINT1("APCs are Pending\n"); + CurrentThread->ApcState.UserApcPending = TRUE; + WaitStatus = STATUS_USER_APC; } - - } else if ((Object->Type & TIMER_OR_EVENT_TYPE) == EventSynchronizationObject) { - - /* These guys (Syncronization Timers and Events) just get un-signaled */ - Object->SignalState = 0; - } else if (Object->Type == SemaphoreObject) { + /* If there are User APCs Pending and we are waiting in usermode, then we must notify the caller */ + } else if ((CurrentThread->ApcState.UserApcPending) && (WaitMode == UserMode)) { + DPRINT1("APCs are Pending\n"); + WaitStatus = STATUS_USER_APC; + } - /* These ones can have multiple signalings, so we only decrease it */ - Object->SignalState--; - } -} + /* + * Check if the wait is (already) satisfied + */ + CountSignaled = 0; + Abandoned = FALSE; + for (i = 0; i < Count; i++) + { + hdr = (DISPATCHER_HEADER *) KiGetWaitableObjectFromObject(Object[i]); -VOID -FASTCALL -KiWaitTest(PDISPATCHER_HEADER Object, - KPRIORITY Increment) -{ - PLIST_ENTRY WaitEntry; - PLIST_ENTRY WaitList; - PKWAIT_BLOCK CurrentWaitBlock; - PKWAIT_BLOCK NextWaitBlock; - - /* Loop the Wait Entries */ - DPRINT("KiWaitTest for Object: %x\n", Object); - WaitList = &Object->WaitListHead; - WaitEntry = WaitList->Flink; - while ((WaitEntry != WaitList) && (Object->SignalState > 0)) { - - /* Get the current wait block */ - CurrentWaitBlock = CONTAINING_RECORD(WaitEntry, KWAIT_BLOCK, WaitListEntry); - - /* Check the current Wait Mode */ - if (CurrentWaitBlock->WaitType == WaitAny) { - - /* Easy case, satisfy only this wait */ - DPRINT("Satisfiying a Wait any\n"); - WaitEntry = WaitEntry->Blink; - KiSatisfyObjectWait(Object, CurrentWaitBlock->Thread); - - } else { - - /* Everything must be satisfied */ - DPRINT("Checking for a Wait All\n"); - NextWaitBlock = CurrentWaitBlock->NextWaitBlock; - - /* Loop first to make sure they are valid */ - while (NextWaitBlock) { - - /* Check if the object is signaled */ - if (!KiIsObjectSignaled(Object, CurrentWaitBlock->Thread)) { - - /* It's not, move to the next one */ - DPRINT1("One of the object is non-signaled, sorry.\n"); - goto SkipUnwait; - } - - /* Go to the next Wait block */ - NextWaitBlock = NextWaitBlock->NextWaitBlock; + if (KiIsObjectSignalled(hdr, CurrentThread)) + { + CountSignaled++; + + if (WaitType == WaitAny) + { + Abandoned = KiSideEffectsBeforeWake(hdr, CurrentThread) ? TRUE : Abandoned; + + KeReleaseDispatcherDatabaseLock(OldIrql); + + if (Timeout != NULL && Timeout->QuadPart != 0) + { + KeCancelTimer(&CurrentThread->Timer); + } + + DPRINT("One object is (already) signaled!\n"); + if (Abandoned == TRUE) + { + return (STATUS_ABANDONED_WAIT_0 + i); + } + + return (STATUS_WAIT_0 + i); } - - /* All the objects are signaled, we can satisfy */ - DPRINT("Satisfiying a Wait All\n"); - WaitEntry = WaitEntry->Blink; - KiSatisifyMultipleObjectWaits(CurrentWaitBlock); - } - - /* All waits satisfied, unwait the thread */ - DPRINT("Unwaiting the Thread\n"); - KiAbortWaitThread(CurrentWaitBlock->Thread, CurrentWaitBlock->WaitKey); + } + } -SkipUnwait: - /* Next entry */ - WaitEntry = WaitEntry->Flink; - } - - DPRINT("Done\n"); -} + Abandoned = FALSE; + if ((WaitType == WaitAll) && (CountSignaled == Count)) + { + for (i = 0; i < Count; i++) + { + hdr = (DISPATCHER_HEADER *) KiGetWaitableObjectFromObject(Object[i]); + Abandoned = KiSideEffectsBeforeWake(hdr, CurrentThread) ? TRUE : Abandoned; + } -/* Must be called with the dispatcher lock held */ -VOID -FASTCALL -KiAbortWaitThread(PKTHREAD Thread, - NTSTATUS WaitStatus) -{ - PKWAIT_BLOCK WaitBlock; + KeReleaseDispatcherDatabaseLock(OldIrql); + + if (Timeout != NULL && Timeout->QuadPart != 0) + { + KeCancelTimer(&CurrentThread->Timer); + } - /* If we are blocked, we must be waiting on something also */ - DPRINT("KiAbortWaitThread: %x, Status: %x, %x \n", Thread, WaitStatus, Thread->WaitBlockList); - ASSERT((Thread->State == THREAD_STATE_BLOCKED) == (Thread->WaitBlockList != NULL)); + DPRINT("All objects are (already) signaled!\n"); - /* Remove the Wait Blocks from the list */ - DPRINT("Removing waits\n"); - WaitBlock = Thread->WaitBlockList; - while (WaitBlock) { - - /* Remove it */ - DPRINT("Removing Waitblock: %x, %x\n", WaitBlock, WaitBlock->NextWaitBlock); - RemoveEntryList(&WaitBlock->WaitListEntry); - - /* Go to the next one */ - WaitBlock = WaitBlock->NextWaitBlock; - }; - - /* Check if there's a Thread Timer */ - if (Thread->Timer.Header.Inserted) { - - /* Cancel the Thread Timer with the no-lock fastpath */ - DPRINT("Removing the Thread's Timer\n"); - Thread->Timer.Header.Inserted = FALSE; - RemoveEntryList(&Thread->Timer.TimerListEntry); - } - - /* Increment the Queue's active threads */ - if (Thread->Queue) { - - DPRINT("Incrementing Queue's active threads\n"); - Thread->Queue->CurrentCount++; - } + if (Abandoned == TRUE) + { + return (STATUS_ABANDONED_WAIT_0); + } - /* Reschedule the Thread */ - DPRINT("Unblocking the Thread\n"); - PsUnblockThread((PETHREAD)Thread, &WaitStatus, 0); -} + return (STATUS_WAIT_0); + } -BOOLEAN -inline -FASTCALL -KiIsObjectSignaled(PDISPATCHER_HEADER Object, - PKTHREAD Thread) -{ - /* Mutants are...well...mutants! */ - if (Object->Type == MutantObject) { - - ASSERT(hdr->SignalState <= 1); - - /* - * Because Cutler hates mutants, they are actually signaled if the Signal State is <= 0 - * Well, only if they are recursivly acquired (i.e if we own it right now). - * Of course, they are also signaled if their signal state is 1. - */ - if ((Object->SignalState <= 0 && ((PKMUTANT)Object)->OwnerThread == Thread) || - (Object->SignalState == 1)) { - - /* Signaled Mutant */ - return (TRUE); - - } else { - - /* Unsignaled Mutant */ - return (FALSE); - } - } - - /* Any other object is not a mutated freak, so let's use logic */ - return (!Object->SignalState <= 0); -} + //zero timeout is used for testing if the object(s) can be immediately acquired + if (Timeout != NULL && Timeout->QuadPart == 0) + { + KeReleaseDispatcherDatabaseLock(OldIrql); + return STATUS_TIMEOUT; + } -BOOL -inline -FASTCALL -KiIsObjectWaitable(PVOID Object) -{ - POBJECT_HEADER Header; - Header = BODY_TO_HEADER(Object); - - if (Header->ObjectType == ExEventObjectType || - Header->ObjectType == ExIoCompletionType || - Header->ObjectType == ExMutantObjectType || - Header->ObjectType == ExSemaphoreObjectType || - Header->ObjectType == ExTimerType || - Header->ObjectType == PsProcessType || - Header->ObjectType == PsThreadType || - Header->ObjectType == IoFileObjectType) { - - return TRUE; - - } else { - - return FALSE; - } -} + /* + * Check if we have already timed out + */ + if (Timeout != NULL && KiIsObjectSignalled(&CurrentThread->Timer.Header, CurrentThread)) + { + KiSideEffectsBeforeWake(&CurrentThread->Timer.Header, CurrentThread); + KeReleaseDispatcherDatabaseLock(OldIrql); + KeCancelTimer(&CurrentThread->Timer); + return (STATUS_TIMEOUT); + } -VOID -inline -FASTCALL -KiSatisifyMultipleObjectWaits(PKWAIT_BLOCK WaitBlock) -{ - PKTHREAD WaitThread = WaitBlock->Thread; - - /* Loop through all the Wait Blocks, and wake each Object */ - while (WaitBlock) { + /* Append wait block to the KTHREAD wait block list */ + CurrentThread->WaitBlockList = blk = WaitBlockArray; + + /* + * Set up the wait + */ + CurrentThread->WaitStatus = WaitStatus;; + + for (i = 0; i < Count; i++) + { + hdr = (DISPATCHER_HEADER *) KiGetWaitableObjectFromObject(Object[i]); + + blk->Object = KiGetWaitableObjectFromObject(Object[i]); + blk->Thread = CurrentThread; + blk->WaitKey = (USHORT)(STATUS_WAIT_0 + i); + blk->WaitType = (USHORT)WaitType; + + if (i == (Count - 1)) + { + if (Timeout != NULL) + { + blk->NextWaitBlock = &CurrentThread->WaitBlock[3]; + } + else + { + blk->NextWaitBlock = NULL; + } + } + else + { + blk->NextWaitBlock = blk + 1; + } + + /* + * add wait block to disp. obj. wait list + * Use FIFO for all waits except for queues which use LIFO + */ + if (WaitReason == WrQueue) + { + InsertHeadList(&hdr->WaitListHead, &blk->WaitListEntry); + } + else + { + InsertTailList(&hdr->WaitListHead, &blk->WaitListEntry); + } + + blk = blk->NextWaitBlock; + } + + if (Timeout != NULL) + { + CurrentThread->WaitBlock[3].Object = (PVOID) & CurrentThread->Timer; + CurrentThread->WaitBlock[3].Thread = CurrentThread; + CurrentThread->WaitBlock[3].WaitKey = STATUS_TIMEOUT; + CurrentThread->WaitBlock[3].WaitType = WaitAny; + CurrentThread->WaitBlock[3].NextWaitBlock = NULL; + + InsertTailList(&CurrentThread->Timer.Header.WaitListHead, + &CurrentThread->WaitBlock[3].WaitListEntry); + } + + //kernel queues + if (CurrentThread->Queue && WaitReason != WrQueue) + { + DPRINT("queue: sleep on something else\n"); + CurrentThread->Queue->CurrentCount--; - /* Wake the Object */ - KiSatisfyObjectWait(WaitBlock->Object, WaitThread); - WaitBlock = WaitBlock->NextWaitBlock; - } -} + //wake another thread + if (CurrentThread->Queue->CurrentCount < CurrentThread->Queue->MaximumCount && + !IsListEmpty(&CurrentThread->Queue->EntryListHead)) + { + KiDispatcherObjectWake(&CurrentThread->Queue->Header, IO_NO_INCREMENT); + } + } -VOID -inline -FASTCALL -KeInitializeDispatcherHeader(DISPATCHER_HEADER* Header, - ULONG Type, - ULONG Size, - ULONG SignalState) -{ - Header->Type = (UCHAR)Type; - Header->Absolute = 0; - Header->Inserted = 0; - Header->Size = (UCHAR)Size; - Header->SignalState = SignalState; - InitializeListHead(&(Header->WaitListHead)); -} + PsBlockThread(&Status, Alertable, WaitMode, TRUE, OldIrql, (UCHAR)WaitReason); -KIRQL -inline -FASTCALL -KeAcquireDispatcherDatabaseLock(VOID) -{ - KIRQL OldIrql; + //kernel queues + OldIrql = KeAcquireDispatcherDatabaseLock (); + if (CurrentThread->Queue && WaitReason != WrQueue) + { + DPRINT("queue: wake from something else\n"); + CurrentThread->Queue->CurrentCount++; + } + if (Status == STATUS_KERNEL_APC) + { + CurrentThread->WaitNext = TRUE; + CurrentThread->WaitIrql = OldIrql; + } + else + { + KeReleaseDispatcherDatabaseLock(OldIrql); + } + + } while (Status == STATUS_KERNEL_APC); + - KeAcquireSpinLock (&DispatcherDatabaseLock, &OldIrql); - return OldIrql; + if (Timeout != NULL) + { + KeCancelTimer(&CurrentThread->Timer); + } + + DPRINT("Returning from KeWaitForMultipleObjects()\n"); + return (Status); } -VOID -inline -FASTCALL -KeAcquireDispatcherDatabaseLockAtDpcLevel(VOID) +VOID KeInitializeDispatcher(VOID) { - KeAcquireSpinLockAtDpcLevel (&DispatcherDatabaseLock); + KeInitializeSpinLock(&DispatcherDatabaseLock); } -VOID -inline -FASTCALL -KeInitializeDispatcher(VOID) +NTSTATUS STDCALL +NtWaitForMultipleObjects(IN ULONG ObjectCount, + IN PHANDLE ObjectsArray, + IN WAIT_TYPE WaitType, + IN BOOLEAN Alertable, + IN PLARGE_INTEGER TimeOut OPTIONAL) { - /* Initialize the Dispatcher Lock */ - KeInitializeSpinLock(&DispatcherDatabaseLock); + KWAIT_BLOCK WaitBlockArray[MAXIMUM_WAIT_OBJECTS]; + HANDLE SafeObjectsArray[MAXIMUM_WAIT_OBJECTS]; + PVOID ObjectPtrArray[MAXIMUM_WAIT_OBJECTS]; + ULONG i, j; + KPROCESSOR_MODE PreviousMode; + LARGE_INTEGER SafeTimeOut; + NTSTATUS Status = STATUS_SUCCESS; + + DPRINT("NtWaitForMultipleObjects(ObjectCount %lu ObjectsArray[] %x, Alertable %d, " + "TimeOut %x)\n", ObjectCount,ObjectsArray,Alertable,TimeOut); + + PreviousMode = ExGetPreviousMode(); + + if (ObjectCount > MAXIMUM_WAIT_OBJECTS) + return STATUS_UNSUCCESSFUL; + if (0 == ObjectCount) + return STATUS_INVALID_PARAMETER; + + if(PreviousMode != KernelMode) + { + _SEH_TRY + { + ProbeForRead(ObjectsArray, + ObjectCount * sizeof(ObjectsArray[0]), + sizeof(ULONG)); + /* make a copy so we don't have to guard with SEH later and keep track of + what objects we referenced in case dereferencing pointers suddenly fails */ + RtlCopyMemory(SafeObjectsArray, ObjectsArray, ObjectCount * sizeof(ObjectsArray[0])); + ObjectsArray = SafeObjectsArray; + + if(TimeOut != NULL) + { + ProbeForRead(TimeOut, + sizeof(LARGE_INTEGER), + sizeof(ULONG)); + /* make a local copy of the timeout on the stack */ + SafeTimeOut = *TimeOut; + TimeOut = &SafeTimeOut; + } + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + + if(!NT_SUCCESS(Status)) + { + return Status; + } + } + + /* reference all objects */ + for (i = 0; i < ObjectCount; i++) + { + Status = ObReferenceObjectByHandle(ObjectsArray[i], + SYNCHRONIZE, + NULL, + PreviousMode, + &ObjectPtrArray[i], + NULL); + if (!NT_SUCCESS(Status) || !KiIsObjectWaitable(ObjectPtrArray[i])) + { + if (NT_SUCCESS(Status)) + { + DPRINT1("Waiting for object type '%wZ' is not supported\n", + &BODY_TO_HEADER(ObjectPtrArray[i])->ObjectType->TypeName); + Status = STATUS_HANDLE_NOT_WAITABLE; + i++; + } + /* dereference all referenced objects */ + for (j = 0; j < i; j++) + { + ObDereferenceObject(ObjectPtrArray[j]); + } + + return(Status); + } + } + + Status = KeWaitForMultipleObjects(ObjectCount, + ObjectPtrArray, + WaitType, + UserRequest, + PreviousMode, + Alertable, + TimeOut, + WaitBlockArray); + + /* dereference all objects */ + for (i = 0; i < ObjectCount; i++) + { + ObDereferenceObject(ObjectPtrArray[i]); + } + + return(Status); } -VOID -inline -FASTCALL -KeReleaseDispatcherDatabaseLock(KIRQL OldIrql) + +/* + * @implemented + */ +NTSTATUS STDCALL +NtWaitForSingleObject(IN HANDLE ObjectHandle, + IN BOOLEAN Alertable, + IN PLARGE_INTEGER TimeOut OPTIONAL) { - /* If it's the idle thread, dispatch */ - if (!KeIsExecutingDpc() && OldIrql < DISPATCH_LEVEL && KeGetCurrentThread() != NULL && - KeGetCurrentThread() == KeGetCurrentKPCR()->PrcbData.IdleThread) { - - PsDispatchThreadNoLock(THREAD_STATE_READY); - KeLowerIrql(OldIrql); - - } else { - - /* Just release the spin lock */ - KeReleaseSpinLock(&DispatcherDatabaseLock, OldIrql); - } + PVOID ObjectPtr; + KPROCESSOR_MODE PreviousMode; + LARGE_INTEGER SafeTimeOut; + NTSTATUS Status = STATUS_SUCCESS; + + DPRINT("NtWaitForSingleObject(ObjectHandle %x, Alertable %d, TimeOut %x)\n", + ObjectHandle,Alertable,TimeOut); + + PreviousMode = ExGetPreviousMode(); + + if(TimeOut != NULL && PreviousMode != KernelMode) + { + _SEH_TRY + { + ProbeForRead(TimeOut, + sizeof(LARGE_INTEGER), + sizeof(ULONG)); + /* make a copy on the stack */ + SafeTimeOut = *TimeOut; + TimeOut = &SafeTimeOut; + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + + if(!NT_SUCCESS(Status)) + { + return Status; + } + } + + Status = ObReferenceObjectByHandle(ObjectHandle, + SYNCHRONIZE, + NULL, + PreviousMode, + &ObjectPtr, + NULL); + if (!NT_SUCCESS(Status)) + { + return(Status); + } + if (!KiIsObjectWaitable(ObjectPtr)) + { + DPRINT1("Waiting for object type '%wZ' is not supported\n", + &BODY_TO_HEADER(ObjectPtr)->ObjectType->TypeName); + Status = STATUS_HANDLE_NOT_WAITABLE; + } + else + { + Status = KeWaitForSingleObject(ObjectPtr, + UserRequest, + PreviousMode, + Alertable, + TimeOut); + } + + ObDereferenceObject(ObjectPtr); + + return(Status); } -VOID -inline -FASTCALL -KeReleaseDispatcherDatabaseLockFromDpcLevel(VOID) + +NTSTATUS STDCALL +NtSignalAndWaitForSingleObject(IN HANDLE ObjectHandleToSignal, + IN HANDLE WaitableObjectHandle, + IN BOOLEAN Alertable, + IN PLARGE_INTEGER TimeOut OPTIONAL) { - KeReleaseSpinLockFromDpcLevel(&DispatcherDatabaseLock); -} + KPROCESSOR_MODE PreviousMode; + DISPATCHER_HEADER* hdr; + PVOID SignalObj; + PVOID WaitObj; + LARGE_INTEGER SafeTimeOut; + NTSTATUS Status = STATUS_SUCCESS; -/* EOF */ + PreviousMode = ExGetPreviousMode(); + + if(TimeOut != NULL && PreviousMode != KernelMode) + { + _SEH_TRY + { + ProbeForRead(TimeOut, + sizeof(LARGE_INTEGER), + sizeof(ULONG)); + /* make a copy on the stack */ + SafeTimeOut = *TimeOut; + TimeOut = &SafeTimeOut; + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + + if(!NT_SUCCESS(Status)) + { + return Status; + } + } + + Status = ObReferenceObjectByHandle(ObjectHandleToSignal, + 0, + NULL, + PreviousMode, + &SignalObj, + NULL); + if (!NT_SUCCESS(Status)) + { + return Status; + } + + Status = ObReferenceObjectByHandle(WaitableObjectHandle, + SYNCHRONIZE, + NULL, + PreviousMode, + &WaitObj, + NULL); + if (!NT_SUCCESS(Status)) + { + ObDereferenceObject(SignalObj); + return Status; + } + + hdr = (DISPATCHER_HEADER *)SignalObj; + switch (hdr->Type) + { + case InternalNotificationEvent: + case InternalSynchronizationEvent: + KeSetEvent(SignalObj, + EVENT_INCREMENT, + TRUE); + break; + + case InternalMutexType: + KeReleaseMutex(SignalObj, + TRUE); + break; + + case InternalSemaphoreType: + KeReleaseSemaphore(SignalObj, + SEMAPHORE_INCREMENT, + 1, + TRUE); + break; + + default: + ObDereferenceObject(SignalObj); + ObDereferenceObject(WaitObj); + return STATUS_OBJECT_TYPE_MISMATCH; + } + + Status = KeWaitForSingleObject(WaitObj, + UserRequest, + PreviousMode, + Alertable, + TimeOut); + + ObDereferenceObject(SignalObj); + ObDereferenceObject(WaitObj); + + return Status; +} diff --git a/reactos/ntoskrnl/ntoskrnl.def b/reactos/ntoskrnl/ntoskrnl.def index 4063cc53e7b..461ebe6aa04 100644 --- a/reactos/ntoskrnl/ntoskrnl.def +++ b/reactos/ntoskrnl/ntoskrnl.def @@ -122,6 +122,7 @@ ExIsResourceAcquiredExclusiveLite@4 ExIsResourceAcquiredSharedLite@4 ExLocalTimeToSystemTime@8 ExNotifyCallback@12 +ExPostSystemEvent@12 ExQueryPoolBlockSize@8 ExQueueWorkItem@8 ExRaiseAccessViolation@0 @@ -529,7 +530,7 @@ Ke386IoSetAccessProcess@8 Ke386QueryIoAccessMap@8 Ke386SetIoAccessMap@8 KeAcquireSpinLockAtDpcLevel@4 -@KeAcquireDispatcherDatabaseLockAtDpcLevel@0 +KeAcquireDispatcherDatabaseLockAtDpcLevel @KeAcquireInStackQueuedSpinLockAtDpcLevel@8 KeAcquireInterruptSpinLock@4 KeAddSystemServiceTable@20 @@ -610,7 +611,7 @@ KeReadStateSemaphore@4 KeReadStateTimer@4 KeRegisterBugCheckCallback@20 KeRegisterBugCheckReasonCallback@16 -@KeReleaseDispatcherDatabaseLockFromDpcLevel@0 +KeReleaseDispatcherDatabaseLockFromDpcLevel @KeReleaseInStackQueuedSpinLockFromDpcLevel@4 KeReleaseInterruptSpinLock@8 KeReleaseMutant@16 diff --git a/reactos/ntoskrnl/ntoskrnl.mc b/reactos/ntoskrnl/ntoskrnl.mc index fafa73a6c3c..1458a0eca28 100644 --- a/reactos/ntoskrnl/ntoskrnl.mc +++ b/reactos/ntoskrnl/ntoskrnl.mc @@ -987,22 +987,6 @@ Language=English INVALID_WORK_QUEUE_ITEM . -MessageId=0xE1 -Severity=Success -Facility=System -SymbolicName=WORKER_THREAD_RETURNED_AT_BAD_IRQL -Language=English -WORKER_THREAD_RETURNED_AT_BAD_IRQL -. - -MessageId=0xFA -Severity=Success -Facility=System -SymbolicName=IMPERSONATING_WORKER_THREAD -Language=English -IMPERSONATING_WORKER_THREAD -. - MessageId=0x9A Severity=Informational Facility=System diff --git a/reactos/ntoskrnl/ob/wait.c b/reactos/ntoskrnl/ob/wait.c deleted file mode 100644 index 1b693c6ba6b..00000000000 --- a/reactos/ntoskrnl/ob/wait.c +++ /dev/null @@ -1,300 +0,0 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS kernel - * FILE: ntoskrnl/ob/wait.c - * PURPOSE: Handles Waiting on Objects - * - * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) - Created file - * David Welch (welch@mcmail.com) - */ - -/* INCLUDES ******************************************************************/ - -#include -#define NDEBUG -#include - -/* FUNCTIONS *****************************************************************/ - -BOOL inline FASTCALL KiIsObjectWaitable(PVOID Object); - -NTSTATUS STDCALL -NtWaitForMultipleObjects(IN ULONG ObjectCount, - IN PHANDLE ObjectsArray, - IN WAIT_TYPE WaitType, - IN BOOLEAN Alertable, - IN PLARGE_INTEGER TimeOut OPTIONAL) -{ - KWAIT_BLOCK WaitBlockArray[MAXIMUM_WAIT_OBJECTS]; - HANDLE SafeObjectsArray[MAXIMUM_WAIT_OBJECTS]; - PVOID ObjectPtrArray[MAXIMUM_WAIT_OBJECTS]; - ULONG i, j; - KPROCESSOR_MODE PreviousMode; - LARGE_INTEGER SafeTimeOut; - NTSTATUS Status = STATUS_SUCCESS; - - DPRINT("NtWaitForMultipleObjects(ObjectCount %lu ObjectsArray[] %x, Alertable %d, " - "TimeOut %x)\n", ObjectCount,ObjectsArray,Alertable,TimeOut); - - PreviousMode = ExGetPreviousMode(); - - if (ObjectCount > MAXIMUM_WAIT_OBJECTS) - return STATUS_UNSUCCESSFUL; - if (0 == ObjectCount) - return STATUS_INVALID_PARAMETER; - - if(PreviousMode != KernelMode) - { - _SEH_TRY - { - ProbeForRead(ObjectsArray, - ObjectCount * sizeof(ObjectsArray[0]), - sizeof(ULONG)); - /* make a copy so we don't have to guard with SEH later and keep track of - what objects we referenced in case dereferencing pointers suddenly fails */ - RtlCopyMemory(SafeObjectsArray, ObjectsArray, ObjectCount * sizeof(ObjectsArray[0])); - ObjectsArray = SafeObjectsArray; - - if(TimeOut != NULL) - { - ProbeForRead(TimeOut, - sizeof(LARGE_INTEGER), - sizeof(ULONG)); - /* make a local copy of the timeout on the stack */ - SafeTimeOut = *TimeOut; - TimeOut = &SafeTimeOut; - } - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - - if(!NT_SUCCESS(Status)) - { - return Status; - } - } - - /* reference all objects */ - for (i = 0; i < ObjectCount; i++) - { - Status = ObReferenceObjectByHandle(ObjectsArray[i], - SYNCHRONIZE, - NULL, - PreviousMode, - &ObjectPtrArray[i], - NULL); - if (!NT_SUCCESS(Status) || !KiIsObjectWaitable(ObjectPtrArray[i])) - { - if (NT_SUCCESS(Status)) - { - DPRINT1("Waiting for object type '%wZ' is not supported\n", - &BODY_TO_HEADER(ObjectPtrArray[i])->ObjectType->TypeName); - Status = STATUS_HANDLE_NOT_WAITABLE; - i++; - } - /* dereference all referenced objects */ - for (j = 0; j < i; j++) - { - ObDereferenceObject(ObjectPtrArray[j]); - } - - return(Status); - } - } - - Status = KeWaitForMultipleObjects(ObjectCount, - ObjectPtrArray, - WaitType, - UserRequest, - PreviousMode, - Alertable, - TimeOut, - WaitBlockArray); - - /* dereference all objects */ - for (i = 0; i < ObjectCount; i++) - { - ObDereferenceObject(ObjectPtrArray[i]); - } - - return(Status); -} - - -/* - * @implemented - */ -NTSTATUS STDCALL -NtWaitForSingleObject(IN HANDLE ObjectHandle, - IN BOOLEAN Alertable, - IN PLARGE_INTEGER TimeOut OPTIONAL) -{ - PVOID ObjectPtr; - KPROCESSOR_MODE PreviousMode; - LARGE_INTEGER SafeTimeOut; - NTSTATUS Status = STATUS_SUCCESS; - - DPRINT("NtWaitForSingleObject(ObjectHandle %x, Alertable %d, TimeOut %x)\n", - ObjectHandle,Alertable,TimeOut); - - PreviousMode = ExGetPreviousMode(); - - if(TimeOut != NULL && PreviousMode != KernelMode) - { - _SEH_TRY - { - ProbeForRead(TimeOut, - sizeof(LARGE_INTEGER), - sizeof(ULONG)); - /* make a copy on the stack */ - SafeTimeOut = *TimeOut; - TimeOut = &SafeTimeOut; - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - - if(!NT_SUCCESS(Status)) - { - return Status; - } - } - - Status = ObReferenceObjectByHandle(ObjectHandle, - SYNCHRONIZE, - NULL, - PreviousMode, - &ObjectPtr, - NULL); - if (!NT_SUCCESS(Status)) - { - return(Status); - } - if (!KiIsObjectWaitable(ObjectPtr)) - { - DPRINT1("Waiting for object type '%wZ' is not supported\n", - &BODY_TO_HEADER(ObjectPtr)->ObjectType->TypeName); - Status = STATUS_HANDLE_NOT_WAITABLE; - } - else - { - Status = KeWaitForSingleObject(ObjectPtr, - UserRequest, - PreviousMode, - Alertable, - TimeOut); - } - - ObDereferenceObject(ObjectPtr); - - return(Status); -} - - -NTSTATUS STDCALL -NtSignalAndWaitForSingleObject(IN HANDLE ObjectHandleToSignal, - IN HANDLE WaitableObjectHandle, - IN BOOLEAN Alertable, - IN PLARGE_INTEGER TimeOut OPTIONAL) -{ - KPROCESSOR_MODE PreviousMode; - DISPATCHER_HEADER* hdr; - PVOID SignalObj; - PVOID WaitObj; - LARGE_INTEGER SafeTimeOut; - NTSTATUS Status = STATUS_SUCCESS; - - PreviousMode = ExGetPreviousMode(); - - if(TimeOut != NULL && PreviousMode != KernelMode) - { - _SEH_TRY - { - ProbeForRead(TimeOut, - sizeof(LARGE_INTEGER), - sizeof(ULONG)); - /* make a copy on the stack */ - SafeTimeOut = *TimeOut; - TimeOut = &SafeTimeOut; - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - - if(!NT_SUCCESS(Status)) - { - return Status; - } - } - - Status = ObReferenceObjectByHandle(ObjectHandleToSignal, - 0, - NULL, - PreviousMode, - &SignalObj, - NULL); - if (!NT_SUCCESS(Status)) - { - return Status; - } - - Status = ObReferenceObjectByHandle(WaitableObjectHandle, - SYNCHRONIZE, - NULL, - PreviousMode, - &WaitObj, - NULL); - if (!NT_SUCCESS(Status)) - { - ObDereferenceObject(SignalObj); - return Status; - } - - hdr = (DISPATCHER_HEADER *)SignalObj; - switch (hdr->Type) - { - case EventNotificationObject: - case EventSynchronizationObject: - KeSetEvent(SignalObj, - EVENT_INCREMENT, - TRUE); - break; - - case MutantObject: - KeReleaseMutex(SignalObj, - TRUE); - break; - - case SemaphoreObject: - KeReleaseSemaphore(SignalObj, - SEMAPHORE_INCREMENT, - 1, - TRUE); - break; - - default: - ObDereferenceObject(SignalObj); - ObDereferenceObject(WaitObj); - return STATUS_OBJECT_TYPE_MISMATCH; - } - - Status = KeWaitForSingleObject(WaitObj, - UserRequest, - PreviousMode, - Alertable, - TimeOut); - - ObDereferenceObject(SignalObj); - ObDereferenceObject(WaitObj); - - return Status; -} - -/* EOF */ diff --git a/reactos/ntoskrnl/ps/kill.c b/reactos/ntoskrnl/ps/kill.c index 6344b7eb6d6..1837f096b5a 100644 --- a/reactos/ntoskrnl/ps/kill.c +++ b/reactos/ntoskrnl/ps/kill.c @@ -204,7 +204,7 @@ PsTerminateCurrentThread(NTSTATUS ExitStatus) oldIrql = KeAcquireDispatcherDatabaseLock(); CurrentThread->Tcb.DispatcherHeader.SignalState = TRUE; - KiWaitTest(&CurrentThread->Tcb.DispatcherHeader, IO_NO_INCREMENT); + KiDispatcherObjectWake(&CurrentThread->Tcb.DispatcherHeader, IO_NO_INCREMENT); KeReleaseDispatcherDatabaseLock (oldIrql); /* The last thread shall close the door on exit */ @@ -331,7 +331,7 @@ PiTerminateProcess(PEPROCESS Process, } OldIrql = KeAcquireDispatcherDatabaseLock (); Process->Pcb.DispatcherHeader.SignalState = TRUE; - KiWaitTest(&Process->Pcb.DispatcherHeader, IO_NO_INCREMENT); + KiDispatcherObjectWake(&Process->Pcb.DispatcherHeader, IO_NO_INCREMENT); KeReleaseDispatcherDatabaseLock (OldIrql); ObDereferenceObject(Process); return(STATUS_SUCCESS); diff --git a/reactos/ntoskrnl/ps/process.c b/reactos/ntoskrnl/ps/process.c index 94d5f83e2df..ac2f018c615 100644 --- a/reactos/ntoskrnl/ps/process.c +++ b/reactos/ntoskrnl/ps/process.c @@ -374,7 +374,7 @@ PsInitProcessManagment(VOID) PsInitialSystemProcess->Pcb.ThreadQuantum = 6; InitializeListHead(&PsInitialSystemProcess->Pcb.ThreadListHead); KeInitializeDispatcherHeader(&PsInitialSystemProcess->Pcb.DispatcherHeader, - ProcessObject, + InternalProcessType, sizeof(EPROCESS), FALSE); KProcess = &PsInitialSystemProcess->Pcb; @@ -823,7 +823,7 @@ exitdereferenceobjects: } KeInitializeDispatcherHeader(&KProcess->DispatcherHeader, - ProcessObject, + InternalProcessType, sizeof(EPROCESS), FALSE); diff --git a/reactos/ntoskrnl/ps/thread.c b/reactos/ntoskrnl/ps/thread.c index 4c21a919891..ee9ad920917 100644 --- a/reactos/ntoskrnl/ps/thread.c +++ b/reactos/ntoskrnl/ps/thread.c @@ -437,7 +437,6 @@ VOID PsDispatchThreadNoLock (ULONG NewThreadStatus) OldThread = CurrentThread; CurrentThread = Candidate; - IdleThread = KeGetCurrentKPCR()->PrcbData.IdleThread; if (&OldThread->Tcb == IdleThread) @@ -546,46 +545,49 @@ PsUnblockThread(PETHREAD Thread, PNTSTATUS WaitStatus, KPRIORITY Increment) } VOID -STDCALL -PsBlockThread(PNTSTATUS Status, - UCHAR Alertable, - ULONG WaitMode, - UCHAR WaitReason) +PsBlockThread(PNTSTATUS Status, UCHAR Alertable, ULONG WaitMode, + BOOLEAN DispatcherLock, KIRQL WaitIrql, UCHAR WaitReason) { - PKTHREAD Thread = KeGetCurrentThread(); - PKWAIT_BLOCK WaitBlock; + KIRQL oldIrql; + PKTHREAD KThread; + PETHREAD Thread; + PKWAIT_BLOCK WaitBlock; - if (Thread->ApcState.KernelApcPending) { - - DPRINT("Dispatching Thread as ready (APC!)\n"); - - /* Remove Waits */ - WaitBlock = Thread->WaitBlockList; - while (WaitBlock) { - RemoveEntryList (&WaitBlock->WaitListEntry); - WaitBlock = WaitBlock->NextWaitBlock; - } - Thread->WaitBlockList = NULL; - - /* Dispatch it and return status */ - PsDispatchThreadNoLock (THREAD_STATE_READY); - if (Status != NULL) *Status = STATUS_KERNEL_APC; - - } else { - - /* Set the Thread Data as Requested */ - DPRINT("Dispatching Thread as blocked\n"); - Thread->Alertable = Alertable; - Thread->WaitMode = (UCHAR)WaitMode; - Thread->WaitReason = WaitReason; - - /* Dispatch it and return status */ - PsDispatchThreadNoLock(THREAD_STATE_BLOCKED); - if (Status != NULL) *Status = Thread->WaitStatus; + if (!DispatcherLock) + { + oldIrql = KeAcquireDispatcherDatabaseLock(); } - - DPRINT("Releasing Dispatcher Lock\n"); - KfLowerIrql(Thread->WaitIrql); + + KThread = KeGetCurrentThread(); + Thread = CONTAINING_RECORD (KThread, ETHREAD, Tcb); + if (KThread->ApcState.KernelApcPending) + { + WaitBlock = (PKWAIT_BLOCK)Thread->Tcb.WaitBlockList; + while (WaitBlock) + { + RemoveEntryList (&WaitBlock->WaitListEntry); + WaitBlock = WaitBlock->NextWaitBlock; + } + Thread->Tcb.WaitBlockList = NULL; + PsDispatchThreadNoLock (THREAD_STATE_READY); + if (Status != NULL) + { + *Status = STATUS_KERNEL_APC; + } + } + else + { + Thread->Tcb.Alertable = Alertable; + Thread->Tcb.WaitMode = (UCHAR)WaitMode; + Thread->Tcb.WaitReason = WaitReason; + PsDispatchThreadNoLock(THREAD_STATE_BLOCKED); + + if (Status != NULL) + { + *Status = Thread->Tcb.WaitStatus; + } + } + KeLowerIrql(WaitIrql); } VOID @@ -1052,16 +1054,6 @@ NtYieldExecution(VOID) return(STATUS_SUCCESS); } -/* - * NOT EXPORTED - */ -NTSTATUS -STDCALL -NtTestAlert(VOID) -{ - /* Check and Alert Thread if needed */ - return KeTestAlertThread(ExGetPreviousMode()) ? STATUS_ALERTED : STATUS_SUCCESS; -} /* * @implemented diff --git a/reactos/ntoskrnl/rtl/nls.c b/reactos/ntoskrnl/rtl/nls.c index e7dfab08a70..c56345c0f61 100644 --- a/reactos/ntoskrnl/rtl/nls.c +++ b/reactos/ntoskrnl/rtl/nls.c @@ -36,32 +36,7 @@ ULONG NlsUnicodeTableOffset = 0; /* FUNCTIONS *****************************************************************/ -VOID -INIT_FUNCTION -STDCALL -RtlpInitNls(VOID) -{ - ULONG_PTR BaseAddress; - - /* Import NLS Data */ - BaseAddress = CachedModules[AnsiCodepage]->ModStart; - RtlpImportAnsiCodePage((PUSHORT)BaseAddress, - CachedModules[AnsiCodepage]->ModEnd - BaseAddress); - - BaseAddress = CachedModules[OemCodepage]->ModStart; - RtlpImportOemCodePage((PUSHORT)BaseAddress, - CachedModules[OemCodepage]->ModEnd - BaseAddress); - - BaseAddress = CachedModules[UnicodeCasemap]->ModStart; - RtlpImportUnicodeCasemap((PUSHORT)BaseAddress, - CachedModules[UnicodeCasemap]->ModEnd - BaseAddress); - - /* Create initial NLS tables */ - RtlpCreateInitialNlsTables(); - - /* Create the NLS section */ - RtlpCreateNlsSection(); -} + VOID INIT_FUNCTION RtlpImportAnsiCodePage(PUSHORT TableBase, diff --git a/reactos/tools/nci/sysfuncs.lst b/reactos/tools/nci/sysfuncs.lst index 7b76c796e9e..f52329eb239 100644 --- a/reactos/tools/nci/sysfuncs.lst +++ b/reactos/tools/nci/sysfuncs.lst @@ -180,6 +180,7 @@ NtSetEaFile 4 NtSetEvent 2 NtSetHighEventPair 1 NtSetHighWaitLowEventPair 1 +NtSetHighWaitLowThread 0 NtSetInformationFile 5 NtSetInformationKey 4 NtSetInformationJobObject 4 @@ -191,6 +192,7 @@ NtSetIntervalProfile 2 NtSetLdtEntries 6 NtSetLowEventPair 1 NtSetLowWaitHighEventPair 1 +NtSetLowWaitHighThread 0 NtSetQuotaInformationFile 4 NtSetSecurityObject 3 NtSetSystemEnvironmentValue 2 -- 2.17.1