diff --git a/reactos/config b/reactos/config index 5a8c1f69da9..9a6cdff4812 100644 --- a/reactos/config +++ b/reactos/config @@ -15,7 +15,7 @@ ARCH := i386 # be optimze for. # -OARCH := i486 +OARCH := pentium2 # # Whether to compile in the kernel debugger @@ -30,7 +30,7 @@ DBG := 0 # # Whether to compile with optimizations # -OPTIMIZED := 0 +OPTIMIZED := 1 # # 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 987eb2ffeff..344793009e6 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 ThreadObject; +static PVOID QueueThreadObject; 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(ThreadObject, Executive, KernelMode, FALSE, 0); - ObDereferenceObject(ThreadObject); + KeWaitForSingleObject(QueueThreadObject, Executive, KernelMode, FALSE, 0); + ObDereferenceObject(QueueThreadObject); 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, &ThreadObject, NULL) != STATUS_SUCCESS) + if(ObReferenceObjectByHandle(ThreadHandle, STANDARD_RIGHTS_ALL, NULL, KernelMode, &QueueThreadObject, 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 4db6f6dd11b..2c438f6329f 100644 --- a/reactos/include/ddk/extypes.h +++ b/reactos/include/ddk/extypes.h @@ -30,6 +30,23 @@ 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 @@ -240,6 +257,10 @@ 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 bca07696b55..379cfc88a5a 100644 --- a/reactos/include/ddk/iotypes.h +++ b/reactos/include/ddk/iotypes.h @@ -886,6 +886,8 @@ 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 ce77b02599c..b938fc6c0b4 100644 --- a/reactos/include/ddk/ketypes.h +++ b/reactos/include/ddk/ketypes.h @@ -36,23 +36,34 @@ typedef VOID STDCALL_FUNC struct _DISPATCHER_HEADER; -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; +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; #include diff --git a/reactos/include/ntos/zwtypes.h b/reactos/include/ntos/zwtypes.h index 37ba0b14f6a..78f6d1eb26c 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 Count; - BOOLEAN Owned; - BOOLEAN Abandoned; + LONG CurrentCount; + BOOLEAN OwnedByCaller; + BOOLEAN AbandonedState; } MUTANT_BASIC_INFORMATION, *PMUTANT_BASIC_INFORMATION; diff --git a/reactos/lib/ntdll/def/ntdll.def b/reactos/lib/ntdll/def/ntdll.def index f9101bae979..66e909cdb9a 100644 --- a/reactos/lib/ntdll/def/ntdll.def +++ b/reactos/lib/ntdll/def/ntdll.def @@ -225,7 +225,6 @@ NtSetEaFile@16 NtSetEvent@8 NtSetHighEventPair@4 NtSetHighWaitLowEventPair@4 -NtSetHighWaitLowThread@0 NtSetInformationFile@20 NtSetInformationJobObject@16 NtSetInformationKey@16 @@ -238,7 +237,6 @@ NtSetIoCompletion@20 NtSetLdtEntries@24 NtSetLowEventPair@4 NtSetLowWaitHighEventPair@4 -NtSetLowWaitHighThread@0 NtSetSecurityObject@12 NtSetSystemEnvironmentValue@8 NtSetSystemInformation@12 @@ -849,7 +847,6 @@ ZwSetEaFile@16 ZwSetEvent@8 ZwSetHighEventPair@4 ZwSetHighWaitLowEventPair@4 -ZwSetHighWaitLowThread@0 ZwSetInformationFile@20 ZwSetInformationKey@16 ZwSetInformationObject@16 @@ -861,7 +858,6 @@ 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 9dc41bf8ef9..ca482379398 100644 --- a/reactos/ntoskrnl/Makefile +++ b/reactos/ntoskrnl/Makefile @@ -101,10 +101,8 @@ 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 \ @@ -118,7 +116,6 @@ OBJECTS_KE = \ ke/spinlock.o \ ke/timer.o \ ke/wait.o \ - ke/alert.o # Memory Manager (Mm) OBJECTS_MM = \ @@ -219,7 +216,8 @@ OBJECTS_OB = \ ob/object.o \ ob/sdcache.o \ ob/security.o \ - ob/symlink.o + ob/symlink.o \ + ob/wait.o # Process Manager (Ps) OBJECTS_PS = \ @@ -242,6 +240,7 @@ 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 304192c8e7d..919c3077164 100644 --- a/reactos/ntoskrnl/cm/registry.c +++ b/reactos/ntoskrnl/cm/registry.c @@ -241,6 +241,29 @@ 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 new file mode 100644 index 00000000000..d1d99a57751 --- /dev/null +++ b/reactos/ntoskrnl/ex/error.c @@ -0,0 +1,163 @@ +/* + * 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 4db20f50ba5..c05fedb56a6 100644 --- a/reactos/ntoskrnl/ex/event.c +++ b/reactos/ntoskrnl/ex/event.c @@ -19,531 +19,489 @@ 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}; + 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 */ +static const INFORMATION_CLASS_INFO ExEventInfoClass[] = { + + /* EventBasicInformation */ + ICI_SQ_SAME( sizeof(EVENT_BASIC_INFORMATION), sizeof(ULONG), ICIF_QUERY), }; /* FUNCTIONS *****************************************************************/ -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 +VOID +INIT_FUNCTION ExpInitializeEventImplementation(VOID) { - 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); + /* 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); } - /* * @implemented */ -NTSTATUS STDCALL +NTSTATUS +STDCALL NtClearEvent(IN HANDLE EventHandle) { - PKEVENT Event; - NTSTATUS Status; - - PAGED_CODE(); + PKEVENT Event; + NTSTATUS Status; + + PAGED_CODE(); + /* Reference the Object */ Status = ObReferenceObjectByHandle(EventHandle, - EVENT_MODIFY_STATE, - ExEventObjectType, - ExGetPreviousMode(), - (PVOID*)&Event, - NULL); - if(NT_SUCCESS(Status)) - { - KeClearEvent(Event); - ObDereferenceObject(Event); - } + EVENT_MODIFY_STATE, + ExEventObjectType, + ExGetPreviousMode(), + (PVOID*)&Event, + NULL); - return Status; + /* Check for Success */ + if(NT_SUCCESS(Status)) { + + /* Clear the Event and Dereference */ + KeClearEvent(Event); + ObDereferenceObject(Event); + } + + /* Return Status */ + return Status; } /* * @implemented */ -NTSTATUS STDCALL -NtCreateEvent(OUT PHANDLE EventHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, - IN EVENT_TYPE EventType, - IN BOOLEAN InitialState) -{ - KPROCESSOR_MODE PreviousMode; - PKEVENT Event; - HANDLE hEvent; - NTSTATUS Status = STATUS_SUCCESS; - - PAGED_CODE(); - - 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; - } - } - - 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 -NtOpenEvent(OUT PHANDLE EventHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes) -{ - HANDLE hEvent; - KPROCESSOR_MODE PreviousMode; - NTSTATUS Status = STATUS_SUCCESS; - - 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; - } - } - - Status = ObOpenObjectByName(ObjectAttributes, - ExEventObjectType, - NULL, - PreviousMode, - DesiredAccess, - NULL, - &hEvent); - - if(NT_SUCCESS(Status)) - { - _SEH_TRY - { - *EventHandle = hEvent; - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - } - - return Status; -} - - -/* - * @implemented - */ -NTSTATUS STDCALL -NtPulseEvent(IN HANDLE EventHandle, - OUT PLONG PreviousState OPTIONAL) -{ - PKEVENT Event; - KPROCESSOR_MODE PreviousMode; - NTSTATUS Status = STATUS_SUCCESS; - - PAGED_CODE(); - - 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; - - 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; -} - - -/* - * @implemented - */ -NTSTATUS STDCALL -NtQueryEvent(IN HANDLE EventHandle, - IN EVENT_INFORMATION_CLASS EventInformationClass, - OUT PVOID EventInformation, - IN ULONG EventInformationLength, - OUT PULONG ReturnLength OPTIONAL) -{ - PKEVENT Event; - KPROCESSOR_MODE PreviousMode; - NTSTATUS Status = STATUS_SUCCESS; - - 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; -} - - -/* - * @implemented - */ -NTSTATUS STDCALL -NtResetEvent(IN HANDLE EventHandle, - OUT PLONG PreviousState OPTIONAL) -{ - PKEVENT Event; - KPROCESSOR_MODE PreviousMode; - NTSTATUS Status = STATUS_SUCCESS; - - 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; - } - } - - Status = ObReferenceObjectByHandle(EventHandle, - EVENT_MODIFY_STATE, - ExEventObjectType, - PreviousMode, - (PVOID*)&Event, - NULL); - if(NT_SUCCESS(Status)) - { - LONG Prev = KeResetEvent(Event); - ObDereferenceObject(Event); - - if(PreviousState != NULL) - { - _SEH_TRY - { - *PreviousState = Prev; - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - } - } - - return Status; -} - - -/* - * @implemented - */ -NTSTATUS STDCALL -NtSetEvent(IN HANDLE EventHandle, - OUT PLONG PreviousState OPTIONAL) -{ - PKEVENT Event; - KPROCESSOR_MODE PreviousMode; - NTSTATUS Status = STATUS_SUCCESS; - - 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; - } - } - - 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; -} - - -/* - * @unimplemented - */ -NTSTATUS +NTSTATUS STDCALL -NtTraceEvent( - IN ULONG TraceHandle, - IN ULONG Flags, - IN ULONG TraceHeaderLength, - IN struct _EVENT_TRACE_HEADER* TraceHeader - ) +NtCreateEvent(OUT PHANDLE EventHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN EVENT_TYPE EventType, + IN BOOLEAN InitialState) { - UNIMPLEMENTED; - return STATUS_NOT_IMPLEMENTED; + KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); + PKEVENT Event; + HANDLE hEvent; + NTSTATUS Status = STATUS_SUCCESS; + + PAGED_CODE(); + + /* Check Output Safety */ + 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); + + /* 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; } +/* + * @implemented + */ +NTSTATUS +STDCALL +NtOpenEvent(OUT PHANDLE EventHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes) +{ + HANDLE hEvent; + KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); + 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; + + if(!NT_SUCCESS(Status)) return Status; + } + + /* Open the Object */ + 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; + } + + /* Return status */ + return Status; +} + +/* + * @implemented + */ +NTSTATUS +STDCALL +NtPulseEvent(IN HANDLE EventHandle, + OUT PLONG PreviousState OPTIONAL) +{ + PKEVENT Event; + KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); + 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; + + 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); + + /* Return it */ + if(PreviousState) { + + _SEH_TRY { + + *PreviousState = Prev; + + } _SEH_HANDLE { + + Status = _SEH_GetExceptionCode(); + + } _SEH_END; + } + } + + /* Return Status */ + return Status; +} + + +/* + * @implemented + */ +NTSTATUS +STDCALL +NtQueryEvent(IN HANDLE EventHandle, + 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; + } + + /* 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); + } + + /* Return status */ + return Status; +} + +/* + * @implemented + */ +NTSTATUS +STDCALL +NtResetEvent(IN HANDLE EventHandle, + OUT PLONG PreviousState OPTIONAL) +{ + PKEVENT Event; + KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); + 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; + } + + /* 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); + + /* Return it */ + if(PreviousState) { + + _SEH_TRY { + + *PreviousState = Prev; + + } _SEH_HANDLE { + + Status = _SEH_GetExceptionCode(); + + } _SEH_END; + } + } + + /* Return Status */ + return Status; +} + +/* + * @implemented + */ +NTSTATUS +STDCALL +NtSetEvent(IN HANDLE EventHandle, + OUT PLONG PreviousState OPTIONAL) +{ + PKEVENT Event; + KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); + 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; + } + + /* 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; + } + } + + /* Return Status */ + return Status; +} /* EOF */ diff --git a/reactos/ntoskrnl/ex/evtpair.c b/reactos/ntoskrnl/ex/evtpair.c index 15b05e6bbc3..05876a7f731 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: David Welch (welch@mcmail.com) + * PROGRAMMERS: Alex Ionescu (Commented, reorganized, removed Thread Pair, used KeInitializeEventPair, added SEH) + * David Welch (welch@mcmail.com) * Skywing (skywing@valhallalegends.com) */ @@ -15,588 +15,394 @@ #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 *****************************************************************/ -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 +VOID +INIT_FUNCTION ExpInitializeEventPairImplementation(VOID) { - 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); + /* 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); } - -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; - NTSTATUS Status = STATUS_SUCCESS; + PKEVENT_PAIR EventPair; + HANDLE hEventPair; + KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); + NTSTATUS Status = STATUS_SUCCESS; + + DPRINT1("NtCreateEventPair: %x\n", EventPairHandle); - PAGED_CODE(); - - PreviousMode = ExGetPreviousMode(); - - if(PreviousMode == UserMode) - { - _SEH_TRY - { - ProbeForWrite(EventPairHandle, - sizeof(HANDLE), - sizeof(ULONG)); - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; + /* Check Output Safety */ + if(PreviousMode == UserMode) { + + _SEH_TRY { + + ProbeForWrite(EventPairHandle, + sizeof(HANDLE), + sizeof(ULONG)); + } _SEH_HANDLE { + + Status = _SEH_GetExceptionCode(); + + } _SEH_END; - if(!NT_SUCCESS(Status)) - { - return Status; - } - } + 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; + } + } - 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; + /* Return Status */ + 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; - NTSTATUS Status = STATUS_SUCCESS; + HANDLE hEventPair; + KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); + NTSTATUS Status = STATUS_SUCCESS; - PAGED_CODE(); - - PreviousMode = ExGetPreviousMode(); - - if(PreviousMode == UserMode) - { - _SEH_TRY - { - ProbeForWrite(EventPairHandle, - sizeof(HANDLE), - sizeof(ULONG)); - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; + /* Check Output Safety */ + if(PreviousMode == UserMode) { + + _SEH_TRY { + + ProbeForWrite(EventPairHandle, + sizeof(HANDLE), + sizeof(ULONG)); + } _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; - } + 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; + } - return Status; + /* Return status */ + return Status; } -NTSTATUS STDCALL +NTSTATUS +STDCALL NtSetHighEventPair(IN HANDLE EventPairHandle) { - PKEVENT_PAIR EventPair; - KPROCESSOR_MODE PreviousMode; - NTSTATUS Status; - - PAGED_CODE(); + PKEVENT_PAIR EventPair; + KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); + NTSTATUS Status; - DPRINT("NtSetHighEventPair(EventPairHandle %x)\n", - EventPairHandle); - - PreviousMode = ExGetPreviousMode(); + DPRINT1("NtSetHighEventPair(EventPairHandle %x)\n", EventPairHandle); - Status = ObReferenceObjectByHandle(EventPairHandle, - SYNCHRONIZE, - ExEventPairObjectType, - PreviousMode, - (PVOID*)&EventPair, - NULL); - if(NT_SUCCESS(Status)) - { - KeSetEvent(&EventPair->HighEvent, - EVENT_INCREMENT, - FALSE); + /* 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); - ObDereferenceObject(EventPair); - } + /* Dereference Object */ + ObDereferenceObject(EventPair); + } - return Status; + /* Return status */ + return Status; } -NTSTATUS STDCALL +NTSTATUS +STDCALL NtSetHighWaitLowEventPair(IN HANDLE EventPairHandle) { - PKEVENT_PAIR EventPair; - KPROCESSOR_MODE PreviousMode; - NTSTATUS Status; + 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); + } - 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; + /* Return status */ + return Status; } - -NTSTATUS STDCALL +NTSTATUS +STDCALL NtSetLowEventPair(IN HANDLE EventPairHandle) { - PKEVENT_PAIR EventPair; - KPROCESSOR_MODE PreviousMode; - NTSTATUS Status; - - PAGED_CODE(); + PKEVENT_PAIR EventPair; + KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); + NTSTATUS Status; - DPRINT("NtSetLowEventPair(EventPairHandle %x)\n", - EventPairHandle); - - PreviousMode = ExGetPreviousMode(); + DPRINT1("NtSetHighEventPair(EventPairHandle %x)\n", EventPairHandle); - Status = ObReferenceObjectByHandle(EventPairHandle, - SYNCHRONIZE, - ExEventPairObjectType, - PreviousMode, - (PVOID*)&EventPair, - NULL); - if(NT_SUCCESS(Status)) - { - KeSetEvent(&EventPair->LowEvent, - EVENT_INCREMENT, - FALSE); + /* 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); - ObDereferenceObject(EventPair); - } - - return Status; + /* Dereference Object */ + ObDereferenceObject(EventPair); + } + + /* Return status */ + return Status; } NTSTATUS STDCALL NtSetLowWaitHighEventPair(IN HANDLE EventPairHandle) { - PKEVENT_PAIR EventPair; - KPROCESSOR_MODE PreviousMode; - NTSTATUS Status; + 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); + } - PAGED_CODE(); - - DPRINT("NtSetLowWaitHighEventPair(EventPairHandle %x)\n", - EventPairHandle); - - PreviousMode = ExGetPreviousMode(); - - 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; + /* Return status */ + return Status; } -NTSTATUS STDCALL +NTSTATUS +STDCALL NtWaitLowEventPair(IN HANDLE EventPairHandle) { - PKEVENT_PAIR EventPair; - KPROCESSOR_MODE PreviousMode; - NTSTATUS Status; - - PAGED_CODE(); + PKEVENT_PAIR EventPair; + KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); + NTSTATUS Status; - DPRINT("NtWaitLowEventPair(EventPairHandle %x)\n", - EventPairHandle); + 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); - PreviousMode = ExGetPreviousMode(); + /* Dereference Object */ + ObDereferenceObject(EventPair); + } - Status = ObReferenceObjectByHandle(EventPairHandle, - SYNCHRONIZE, - ExEventPairObjectType, - PreviousMode, - (PVOID*)&EventPair, - NULL); - if(NT_SUCCESS(Status)) - { - KeWaitForSingleObject(&EventPair->LowEvent, - WrEventPair, - PreviousMode, - FALSE, - NULL); - - ObDereferenceObject(EventPair); - } - - return Status; + /* Return status */ + return Status; } - -NTSTATUS STDCALL +NTSTATUS +STDCALL NtWaitHighEventPair(IN HANDLE EventPairHandle) { - PKEVENT_PAIR EventPair; - KPROCESSOR_MODE PreviousMode; - NTSTATUS Status; + 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); + } - PAGED_CODE(); - - DPRINT("NtWaitHighEventPair(EventPairHandle %x)\n", - EventPairHandle); - - PreviousMode = ExGetPreviousMode(); - - Status = ObReferenceObjectByHandle(EventPairHandle, - SYNCHRONIZE, - ExEventPairObjectType, - PreviousMode, - (PVOID*)&EventPair, - NULL); - if(NT_SUCCESS(Status)) - { - KeWaitForSingleObject(&EventPair->HighEvent, - WrEventPair, - PreviousMode, - FALSE, - NULL); - - ObDereferenceObject(EventPair); - } - - return Status; + /* Return status */ + 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 c47ef4f05b4..878be047b4f 100644 --- a/reactos/ntoskrnl/ex/init.c +++ b/reactos/ntoskrnl/ex/init.c @@ -1,21 +1,630 @@ -/* $Id:$ - * +/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * FILE: ntoskrnl/ex/init.c * PURPOSE: Executive initalization * - * PROGRAMMERS: Eric Kohl (ekohl@abo.rhein-zeitung.de) + * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) - Added ExpInitializeExecutive + * and optimized/cleaned it. + * 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) { @@ -25,7 +634,7 @@ ExInit2(VOID) VOID INIT_FUNCTION ExInit3 (VOID) { - ExInitializeWorkerThreads(); + ExpInitializeWorkerThreads(); ExpInitializeEventImplementation(); ExpInitializeEventPairImplementation(); ExpInitializeMutantImplementation(); @@ -35,28 +644,7 @@ ExInit3 (VOID) ExpInitializeProfileImplementation(); ExpWin32kInit(); ExpInitUuids(); -} - - -/* - * @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 */ + ExpInitializeCallbacks(); } /* EOF */ diff --git a/reactos/ntoskrnl/ex/mutant.c b/reactos/ntoskrnl/ex/mutant.c index f6a2d4b36c7..8c125e236b2 100644 --- a/reactos/ntoskrnl/ex/mutant.c +++ b/reactos/ntoskrnl/ex/mutant.c @@ -1,11 +1,13 @@ -/* $Id:$ - * +/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * FILE: ntoskrnl/ex/mutant.c - * PURPOSE: Synchronization primitives + * PURPOSE: Executive Management of Mutants * - * PROGRAMMERS: David Welch (welch@cwcom.net) + * PROGRAMMERS: + * Alex Ionescu - Fix tab/space mismatching, tiny fixes to query function and + * add more debug output. + * David Welch (welch@cwcom.net) */ /* INCLUDES *****************************************************************/ @@ -17,360 +19,342 @@ 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[] = -{ - ICI_SQ_SAME( sizeof(MUTANT_BASIC_INFORMATION), sizeof(ULONG), ICIF_QUERY ), /* MutantBasicInformation */ +static const INFORMATION_CLASS_INFO ExMutantInfoClass[] = { + + /* MutantBasicInformation */ + ICI_SQ_SAME( sizeof(MUTANT_BASIC_INFORMATION), sizeof(ULONG), ICIF_QUERY ), }; /* FUNCTIONS *****************************************************************/ - -NTSTATUS STDCALL -ExpCreateMutant(PVOID ObjectBody, - PVOID Parent, - PWSTR RemainingPath, - POBJECT_ATTRIBUTES ObjectAttributes) -{ - DPRINT("NtpCreateMutant(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 +VOID +STDCALL ExpDeleteMutant(PVOID ObjectBody) { - DPRINT("NtpDeleteMutant(ObjectBody %x)\n", ObjectBody); - KeReleaseMutant((PKMUTANT)ObjectBody, - MUTANT_INCREMENT, - TRUE, - FALSE); + DPRINT("ExpDeleteMutant(ObjectBody %x)\n", ObjectBody); + + /* Make sure to release the Mutant */ + KeReleaseMutant((PKMUTANT)ObjectBody, + MUTANT_INCREMENT, + TRUE, + FALSE); } - -VOID INIT_FUNCTION +VOID +INIT_FUNCTION ExpInitializeMutantImplementation(VOID) { - ExMutantObjectType = ExAllocatePool(NonPagedPool,sizeof(OBJECT_TYPE)); - RtlpCreateUnicodeString(&ExMutantObjectType->TypeName, L"Mutant", NonPagedPool); + /* Allocate the Object Type */ + ExMutantObjectType = ExAllocatePoolWithTag(NonPagedPool, sizeof(OBJECT_TYPE), TAG('M', 't', 'n', 't')); - 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); + /* 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); } - /* * @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; - HANDLE hMutant; - PKMUTEX Mutant; - NTSTATUS Status = STATUS_SUCCESS; - - 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); + KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); + HANDLE hMutant; + PKMUTANT Mutant; + NTSTATUS Status = STATUS_SUCCESS; - if(NT_SUCCESS(Status)) - { - _SEH_TRY - { - *MutantHandle = hMutant; - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - } - } - - return Status; -} - - -/* - * @implemented - */ -NTSTATUS STDCALL -NtOpenMutant(OUT PHANDLE MutantHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes) -{ - HANDLE hMutant; - KPROCESSOR_MODE PreviousMode; - NTSTATUS Status = STATUS_SUCCESS; + DPRINT("NtCreateMutant(0x%x, 0x%x, 0x%x)\n", MutantHandle, DesiredAccess, ObjectAttributes); - PAGED_CODE(); + /* Check Output Safety */ + if(PreviousMode == UserMode) { + + _SEH_TRY { + + ProbeForWrite(MutantHandle, + sizeof(HANDLE), + sizeof(ULONG)); + } _SEH_HANDLE { + + Status = _SEH_GetExceptionCode(); + + } _SEH_END; - 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)); + if(!NT_SUCCESS(Status)) return Status; } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; + + /* 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); - if(!NT_SUCCESS(Status)) - { - return Status; + /* 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; + } } - } - 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 -NtQueryMutant(IN HANDLE MutantHandle, - IN MUTANT_INFORMATION_CLASS MutantInformationClass, - OUT PVOID MutantInformation, - IN ULONG MutantInformationLength, - OUT PULONG ResultLength OPTIONAL) +NTSTATUS +STDCALL +NtOpenMutant(OUT PHANDLE MutantHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes) { - PKMUTANT Mutant; - KPROCESSOR_MODE PreviousMode; - NTSTATUS Status = STATUS_SUCCESS; - + HANDLE hMutant; + KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); + NTSTATUS Status = STATUS_SUCCESS; + PAGED_CODE(); - PreviousMode = ExGetPreviousMode(); + DPRINT("NtOpenMutant(0x%x, 0x%x, 0x%x)\n", MutantHandle, DesiredAccess, ObjectAttributes); - 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 -NtReleaseMutant(IN HANDLE MutantHandle, - IN PLONG PreviousCount OPTIONAL) -{ - PKMUTANT Mutant; - KPROCESSOR_MODE PreviousMode; - NTSTATUS Status = STATUS_SUCCESS; - - PAGED_CODE(); - - 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; + /* 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; - } - } + if(!NT_SUCCESS(Status)) return Status; + } + + /* Open the Object */ + Status = ObOpenObjectByName(ObjectAttributes, + ExMutantObjectType, + NULL, + PreviousMode, + DesiredAccess, + NULL, + &hMutant); - 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); + /* Check for success and return handle */ + if(NT_SUCCESS(Status)) { + + _SEH_TRY { + + *MutantHandle = hMutant; + + } _SEH_HANDLE { + + Status = _SEH_GetExceptionCode(); + + } _SEH_END; + } - if(PreviousCount != NULL) - { - _SEH_TRY - { - *PreviousCount = Prev; - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - } - } + /* Return Status */ + return Status; +} - return Status; +/* + * @implemented + */ +NTSTATUS +STDCALL +NtQueryMutant(IN HANDLE MutantHandle, + 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; + } + + 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; +} + + +/* + * @implemented + */ +NTSTATUS +STDCALL +NtReleaseMutant(IN HANDLE MutantHandle, + IN PLONG PreviousCount OPTIONAL) +{ + PKMUTANT Mutant; + KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); + 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; + } + } + + /* Return Status */ + return Status; } /* EOF */ diff --git a/reactos/ntoskrnl/ex/rundown.c b/reactos/ntoskrnl/ex/rundown.c index baf8a38248b..580d9bb4e4e 100644 --- a/reactos/ntoskrnl/ex/rundown.c +++ b/reactos/ntoskrnl/ex/rundown.c @@ -1,11 +1,10 @@ -/* $Id$ - * +/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * FILE: ntoskrnl/ex/rundown.c * PURPOSE: Rundown Protection Functions * - * PROGRAMMERS: No programmer listed. + * PROGRAMMERS: Alex Ionescu & Thomas Weidenmueller - Implementation */ /* INCLUDES *****************************************************************/ diff --git a/reactos/ntoskrnl/ex/sem.c b/reactos/ntoskrnl/ex/sem.c index 274ce8aed1d..ef9a41c5cef 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: David Welch (welch@mcmail.com) + * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)- Reformatting, bug fixes. + * David Welch (welch@mcmail.com) */ /* INCLUDES *****************************************************************/ @@ -19,345 +19,336 @@ 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}; + 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 */ +static const INFORMATION_CLASS_INFO ExSemaphoreInfoClass[] = { + + /* SemaphoreBasicInformation */ + ICI_SQ_SAME( sizeof(SEMAPHORE_BASIC_INFORMATION), sizeof(ULONG), ICIF_QUERY ), }; -/* 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 +VOID +INIT_FUNCTION ExpInitializeSemaphoreImplementation(VOID) { - 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); + + /* 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); } /* * @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; - NTSTATUS Status = STATUS_SUCCESS; + PKSEMAPHORE Semaphore; + HANDLE hSemaphore; + KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); + NTSTATUS Status = STATUS_SUCCESS; - PAGED_CODE(); + PAGED_CODE(); - 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); - - ObDereferenceObject(Semaphore); - - if(NT_SUCCESS(Status)) - { - _SEH_TRY - { - *SemaphoreHandle = hSemaphore; - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - } - } - - return Status; -} - - -/* - * @implemented - */ -NTSTATUS STDCALL -NtOpenSemaphore(OUT PHANDLE SemaphoreHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes) -{ - HANDLE hSemaphore; - KPROCESSOR_MODE PreviousMode; - NTSTATUS Status = STATUS_SUCCESS; - - PAGED_CODE(); - - 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 -NtQuerySemaphore(IN HANDLE SemaphoreHandle, - IN SEMAPHORE_INFORMATION_CLASS SemaphoreInformationClass, - OUT PVOID SemaphoreInformation, - IN ULONG SemaphoreInformationLength, - OUT PULONG ReturnLength OPTIONAL) -{ - PKSEMAPHORE Semaphore; - KPROCESSOR_MODE PreviousMode; - NTSTATUS Status = STATUS_SUCCESS; - - 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; -} - - -/* - * @implemented - */ -NTSTATUS STDCALL -NtReleaseSemaphore(IN HANDLE SemaphoreHandle, - IN LONG ReleaseCount, - OUT PLONG PreviousCount OPTIONAL) -{ - KPROCESSOR_MODE PreviousMode; - PKSEMAPHORE Semaphore; - NTSTATUS Status = STATUS_SUCCESS; - - PAGED_CODE(); - - 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); + /* Check Output Safety */ + if(PreviousMode == UserMode) { + + _SEH_TRY { + + ProbeForWrite(SemaphoreHandle, + sizeof(HANDLE), + sizeof(ULONG)); + } _SEH_HANDLE { + + Status = _SEH_GetExceptionCode(); + + } _SEH_END; - if(PreviousCount != NULL) - { - _SEH_TRY - { - *PreviousCount = PrevCount; - } - _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; + } + + /* 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; + } + } + + /* Return Status */ + return Status; +} + + +/* + * @implemented + */ +NTSTATUS +STDCALL +NtOpenSemaphore(OUT PHANDLE SemaphoreHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes) +{ + HANDLE hSemaphore; + KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); + 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; + } + + /* Return Status */ + return Status; +} + +/* + * @implemented + */ +NTSTATUS +STDCALL +NtQuerySemaphore(IN HANDLE SemaphoreHandle, + 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)) { + + _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); } + /* Return status */ return Status; } +/* + * @implemented + */ +NTSTATUS +STDCALL +NtReleaseSemaphore(IN HANDLE SemaphoreHandle, + IN LONG ReleaseCount, + OUT PLONG PreviousCount OPTIONAL) +{ + KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();; + 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; + } + + /* 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); + + /* Return it */ + if(PreviousCount) { + + _SEH_TRY { + + *PreviousCount = PrevCount; + + } _SEH_HANDLE { + + Status = _SEH_GetExceptionCode(); + + } _SEH_END; + } + } + + /* Return Status */ + return Status; +} + /* EOF */ diff --git a/reactos/ntoskrnl/ex/sysinfo.c b/reactos/ntoskrnl/ex/sysinfo.c index 2efe7292c20..352e3a84971 100644 --- a/reactos/ntoskrnl/ex/sysinfo.c +++ b/reactos/ntoskrnl/ex/sysinfo.c @@ -86,6 +86,20 @@ 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 fa0a2540d3d..c2ecdd59c6b 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,27 +498,23 @@ NtQueryTimer(IN HANDLE TimerHandle, /* Check for Success */ if(NT_SUCCESS(Status)) { - - switch(TimerInformationClass) { - case TimerBasicInformation: { - /* 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); + /* Return the Basic Information */ + _SEH_TRY { - if(ReturnLength != NULL) { - *ReturnLength = sizeof(TIMER_BASIC_INFORMATION); - } + /* 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); - } _SEH_HANDLE { + if(ReturnLength != NULL) *ReturnLength = sizeof(TIMER_BASIC_INFORMATION); + + } _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 8d7bac152fa..0a5f82f1588 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: David Welch (welch@mcmail.com) + * PROGRAMMERS: Alex Ionescu - Used correct work queue array and added some fixes and checks. + * Gunnar Dalsnes - Implemented */ /* INCLUDES ******************************************************************/ @@ -25,17 +25,10 @@ /* * PURPOSE: Queue of items waiting to be processed at normal priority */ -KQUEUE EiNormalWorkQueue; - -KQUEUE EiCriticalWorkQueue; - -KQUEUE EiHyperCriticalWorkQueue; +EX_WORK_QUEUE ExWorkerQueue[MaximumWorkQueue]; /* FUNCTIONS ****************************************************************/ -//static NTSTATUS STDCALL -static VOID STDCALL -ExWorkerThreadEntryPoint(IN PVOID context) /* * FUNCTION: Entry point for a worker thread * ARGUMENTS: @@ -44,138 +37,138 @@ ExWorkerThreadEntryPoint(IN PVOID context) * 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 item; - PLIST_ENTRY current; + PWORK_QUEUE_ITEM WorkItem; + PLIST_ENTRY QueueEntry; + WORK_QUEUE_TYPE WorkQueueType; + PEX_WORK_QUEUE WorkQueue; - while (TRUE) - { - current = KeRemoveQueue( (PKQUEUE)context, KernelMode, NULL ); - - /* can't happend since we do a KernelMode wait (and we're a system thread) */ - ASSERT((NTSTATUS)current != STATUS_USER_APC); - - /* 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 ExInitializeWorkQueue(PKQUEUE WorkQueue, - KPRIORITY Priority) -{ - ULONG i; - PETHREAD Thread; - HANDLE hThread; - - - for (i=0; iTcb, - Priority); - ObDereferenceObject(Thread); - ZwClose(hThread); - } + /* Wait for Something to Happen on the Queue */ + QueueEntry = KeRemoveQueue(&WorkQueue->WorkerQueue, KernelMode, NULL); + + /* Can't happen since we do a KernelMode wait (and we're a system thread) */ + ASSERT((NTSTATUS)QueueEntry != 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); + } + } } -VOID INIT_FUNCTION -ExInitializeWorkerThreads(VOID) +static +VOID +STDCALL +ExpInitializeWorkQueue(WORK_QUEUE_TYPE WorkQueueType, + KPRIORITY Priority) { - KeInitializeQueue( &EiNormalWorkQueue, NUMBER_OF_WORKER_THREADS ); - KeInitializeQueue( &EiCriticalWorkQueue , NUMBER_OF_WORKER_THREADS ); - KeInitializeQueue( &EiHyperCriticalWorkQueue , NUMBER_OF_WORKER_THREADS ); + 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); + + /* Dereference and close handle */ + ObDereferenceObject(Thread); + ZwClose(hThread); + } +} - ExInitializeWorkQueue(&EiNormalWorkQueue, - LOW_PRIORITY); - ExInitializeWorkQueue(&EiCriticalWorkQueue, - LOW_REALTIME_PRIORITY); - ExInitializeWorkQueue(&EiHyperCriticalWorkQueue, - HIGH_PRIORITY); +VOID +INIT_FUNCTION +ExpInitializeWorkerThreads(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); } /* * @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 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; - - } + + /* Insert the Queue */ + KeInsertQueue(&ExWorkerQueue[QueueType].WorkerQueue, &WorkItem->List); } /* EOF */ diff --git a/reactos/ntoskrnl/include/internal/ex.h b/reactos/ntoskrnl/include/internal/ex.h index 3596bfe2420..d42decd8737 100644 --- a/reactos/ntoskrnl/include/internal/ex.h +++ b/reactos/ntoskrnl/include/internal/ex.h @@ -98,24 +98,19 @@ ExInit3(VOID); VOID ExpInitTimeZoneInfo(VOID); VOID -ExInitializeWorkerThreads(VOID); +ExpInitializeWorkerThreads(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 43a29588163..5f86d9126f3 100644 --- a/reactos/ntoskrnl/include/internal/id.h +++ b/reactos/ntoskrnl/include/internal/id.h @@ -2,18 +2,5 @@ * 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 823c153c197..95d129cbe6e 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(VOID); +IopInitBootLog(BOOLEAN StartBootLog); VOID IopStartBootLog(VOID); diff --git a/reactos/ntoskrnl/include/internal/ke.h b/reactos/ntoskrnl/include/internal/ke.h index e9e78f6d9ef..c4f48eadd91 100644 --- a/reactos/ntoskrnl/include/internal/ke.h +++ b/reactos/ntoskrnl/include/internal/ke.h @@ -115,6 +115,17 @@ 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); @@ -144,30 +155,42 @@ VOID STDCALL KeUpdateRunTime(PKTRAP_FRAME TrapFrame, KIRQL Irql); VOID STDCALL KiExpireTimers(PKDPC Dpc, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2); -KIRQL KeAcquireDispatcherDatabaseLock(VOID); -VOID KeAcquireDispatcherDatabaseLockAtDpcLevel(VOID); -VOID KeReleaseDispatcherDatabaseLock(KIRQL Irql); -VOID KeReleaseDispatcherDatabaseLockFromDpcLevel(VOID); +KIRQL inline FASTCALL KeAcquireDispatcherDatabaseLock(VOID); +VOID inline FASTCALL KeAcquireDispatcherDatabaseLockAtDpcLevel(VOID); +VOID inline FASTCALL KeReleaseDispatcherDatabaseLock(KIRQL Irql); +VOID inline FASTCALL KeReleaseDispatcherDatabaseLockFromDpcLevel(VOID); BOOLEAN KiDispatcherObjectWake(DISPATCHER_HEADER* hdr, KPRIORITY increment); VOID STDCALL KeExpireTimers(PKDPC Apc, PVOID Arg1, PVOID Arg2, PVOID Arg3); -VOID KeInitializeDispatcherHeader(DISPATCHER_HEADER* Header, ULONG Type, +VOID inline FASTCALL KeInitializeDispatcherHeader(DISPATCHER_HEADER* Header, ULONG Type, ULONG Size, ULONG SignalState); VOID KeDumpStackFrames(PULONG Frame); BOOLEAN KiTestAlert(VOID); -BOOLEAN KiAbortWaitThread(struct _KTHREAD* Thread, NTSTATUS WaitStatus); +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); 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 KiInitializeUserApc(IN PVOID Reserved, +VOID STDCALL KiInitializeUserApc(IN PVOID Reserved, IN PKTRAP_FRAME TrapFrame, IN PKNORMAL_ROUTINE NormalRoutine, IN PVOID NormalContext, @@ -183,6 +206,7 @@ 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; @@ -194,7 +218,7 @@ VOID KeInitInterrupts(VOID); VOID KeInitTimer(VOID); VOID KeInitDpc(struct _KPCR* Pcr); VOID KeInitDispatcher(VOID); -VOID KeInitializeDispatcher(VOID); +VOID inline FASTCALL 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 46906e37767..84787cba712 100644 --- a/reactos/ntoskrnl/include/internal/nls.h +++ b/reactos/ntoskrnl/include/internal/nls.h @@ -29,6 +29,7 @@ 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 a98537fe3c0..972b42a09e8 100644 --- a/reactos/ntoskrnl/include/internal/ntoskrnl.h +++ b/reactos/ntoskrnl/include/internal/ntoskrnl.h @@ -49,10 +49,12 @@ VOID ExpInitializeProfileImplementation(VOID); */ VOID MmInitSystem(ULONG Phase, PLOADER_PARAMETER_BLOCK LoaderBlock, ULONG LastKernelAddress); VOID IoInit(VOID); -VOID IoInit2(VOID); +VOID IoInit2(BOOLEAN BootLog); +VOID STDCALL IoInit3(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 1be0eeefe19..c954fb7adc1 100644 --- a/reactos/ntoskrnl/include/internal/ps.h +++ b/reactos/ntoskrnl/include/internal/ps.h @@ -498,7 +498,9 @@ VOID STDCALL PsExitSpecialApc(PKAPC Apc, VOID +STDCALL KeInitializeThread(PKPROCESS Process, PKTHREAD Thread, BOOLEAN First); + NTSTATUS KeReleaseThread(PKTHREAD Thread); VOID @@ -525,8 +527,11 @@ VOID PsUnfreezeProcessThreads(PEPROCESS Process); ULONG PsEnumThreadsByProcess(PEPROCESS Process); PEPROCESS PsGetNextProcess(PEPROCESS OldProcess); VOID -PsBlockThread(PNTSTATUS Status, UCHAR Alertable, ULONG WaitMode, - BOOLEAN DispatcherLock, KIRQL WaitIrql, UCHAR WaitReason); +STDCALL +PsBlockThread(PNTSTATUS Status, + UCHAR Alertable, + ULONG WaitMode, + 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 71dc17b194a..9324dd9f6de 100644 --- a/reactos/ntoskrnl/io/bootlog.c +++ b/reactos/ntoskrnl/io/bootlog.c @@ -27,13 +27,14 @@ static ERESOURCE IopBootLogResource; /* FUNCTIONS ****************************************************************/ VOID INIT_FUNCTION -IopInitBootLog(VOID) +IopInitBootLog(BOOLEAN StartBootLog) { ExInitializeResourceLite(&IopBootLogResource); + if (StartBootLog) IopStartBootLog(); } -VOID +VOID INIT_FUNCTION IopStartBootLog(VOID) { IopBootLogCreate = TRUE; diff --git a/reactos/ntoskrnl/io/create.c b/reactos/ntoskrnl/io/create.c index b507fc51f93..6a2919e630e 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 = InternalFileType; + FileObject->Type = IO_TYPE_FILE; return(STATUS_SUCCESS); } @@ -240,7 +240,7 @@ IoCreateStreamFileObject(PFILE_OBJECT FileObject, CreatedFileObject->DeviceObject = DeviceObject->Vpb->DeviceObject; CreatedFileObject->Vpb = DeviceObject->Vpb; - CreatedFileObject->Type = InternalFileType; + CreatedFileObject->Type = IO_TYPE_FILE; 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 7cab4e63911..9e29e1cbef3 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 = InternalDriverType; + Object->Type = IO_TYPE_DRIVER; 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 de412e59036..d52fcc4f79f 100644 --- a/reactos/ntoskrnl/io/iocomp.c +++ b/reactos/ntoskrnl/io/iocomp.c @@ -1,5 +1,4 @@ -/* $Id$ - * +/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * FILE: ntoskrnl/io/iocomp.c @@ -18,66 +17,48 @@ 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 *****************************************************************/ -NTSTATUS +VOID 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; + PKQUEUE Queue = ObjectBody; + PLIST_ENTRY FirstEntry; + PLIST_ENTRY CurrentEntry; + PIO_COMPLETION_PACKET Packet; - DPRINT("IopDeleteIoCompletion()\n"); + DPRINT("IopDeleteIoCompletion()\n"); - KeRundownQueue(Queue); -} - - -/* - * @unimplemented - */ -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 - ) -{ - UNIMPLEMENTED; - return STATUS_NOT_IMPLEMENTED; + /* 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); + } } /* @@ -85,305 +66,278 @@ IoSetCompletionRoutineEx( */ NTSTATUS STDCALL -IoSetIoCompletion ( - IN PVOID IoCompletion, - IN PVOID KeyContext, - IN PVOID ApcContext, - IN NTSTATUS IoStatus, - IN ULONG_PTR IoStatusInformation, - IN BOOLEAN Quota - ) +IoSetIoCompletion(IN PVOID IoCompletion, + IN PVOID KeyContext, + IN PVOID ApcContext, + IN NTSTATUS IoStatus, + IN ULONG_PTR IoStatusInformation, + IN BOOLEAN Quota) { - PKQUEUE Queue = (PKQUEUE) IoCompletion; - PIO_COMPLETION_PACKET Packet; + PKQUEUE Queue = (PKQUEUE)IoCompletion; + PIO_COMPLETION_PACKET Packet; - Packet = ExAllocateFromNPagedLookasideList(&IoCompletionPacketLookaside); - if (NULL == Packet) - { - return STATUS_NO_MEMORY; - } + /* 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); - Packet->Key = KeyContext; - Packet->Context = ApcContext; - Packet->IoStatus.Status = IoStatus; - Packet->IoStatus.Information = IoStatusInformation; - - KeInsertQueue(Queue, &Packet->ListEntry); + /* Return Success */ + return STATUS_SUCCESS; +} - return STATUS_SUCCESS; +/* + * @unimplemented + */ +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) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; } VOID FASTCALL IopInitIoCompletionImplementation(VOID) { - 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; + /* 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; - ExInitializeNPagedLookasideList(&IoCompletionPacketLookaside, - NULL, - NULL, - 0, - sizeof(IO_COMPLETION_PACKET), - IOC_TAG, - 0); + /* Initialize the Lookaside List we'll use for packets */ + 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; + PKQUEUE Queue; + NTSTATUS Status; + KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); - Status = ObCreateObject(ExGetPreviousMode(), - ExIoCompletionType, - ObjectAttributes, - ExGetPreviousMode(), - NULL, - sizeof(KQUEUE), - 0, - 0, - (PVOID*)&Queue); - if (!NT_SUCCESS(Status)) - { - return Status; + /* 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); } - - Status = ObInsertObject ((PVOID)Queue, - NULL, - DesiredAccess, - 0, - NULL, - IoCompletionHandle); - if (!NT_SUCCESS(Status)) - { - ObDereferenceObject(Queue); - return Status; - } - - KeInitializeQueue(Queue, NumberOfConcurrentThreads); - ObDereferenceObject(Queue); - + + /* Return Status */ return STATUS_SUCCESS; - /* +} - CompletionPort = NULL OR ExistingCompletionPort - - */ +NTSTATUS +STDCALL +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; } -/* -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 - ) -{ - 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; + PKQUEUE Queue; + NTSTATUS Status; + KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); - if (IoCompletionInformationClass != IoCompletionBasicInformation) - { - return STATUS_INVALID_INFO_CLASS; - } - if (IoCompletionInformationLength < sizeof(IO_COMPLETION_BASIC_INFORMATION)) - { - return STATUS_INFO_LENGTH_MISMATCH; - } - - Status = ObReferenceObjectByHandle( IoCompletionHandle, + /* Get the Object */ + Status = ObReferenceObjectByHandle(IoCompletionHandle, IO_COMPLETION_QUERY_STATE, ExIoCompletionType, - UserMode, + PreviousMode, (PVOID*)&Queue, NULL); - if (NT_SUCCESS(Status)) - { - ((PIO_COMPLETION_BASIC_INFORMATION)IoCompletionInformation)->Depth = - Queue->Header.SignalState; + + /* Check for Success */ + if (NT_SUCCESS(Status)) { + + /* Return Info */ + ((PIO_COMPLETION_BASIC_INFORMATION)IoCompletionInformation)->Depth = KeReadStateQueue(Queue); + ObDereferenceObject(Queue); - ObDereferenceObject(Queue); + /* Return Result Length if needed */ + if (ResultLength) *ResultLength = sizeof(IO_COMPLETION_BASIC_INFORMATION); + } - if (ResultLength) *ResultLength = sizeof(IO_COMPLETION_BASIC_INFORMATION); - } - - return Status; + /* Return Status */ + 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; - - Status = ObReferenceObjectByHandle( IoCompletionHandle, + PKQUEUE Queue; + NTSTATUS Status; + PIO_COMPLETION_PACKET Packet; + PLIST_ENTRY ListEntry; + KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); + + /* Open the Object */ + Status = ObReferenceObjectByHandle(IoCompletionHandle, IO_COMPLETION_MODIFY_STATE, ExIoCompletionType, - UserMode, + PreviousMode, (PVOID*)&Queue, NULL); - if (!NT_SUCCESS(Status)) - { - return Status; - } + + /* Check for success */ + if (NT_SUCCESS(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 ); + /* Remove queue */ + ListEntry = KeRemoveQueue(Queue, PreviousMode, 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 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 ((NTSTATUS)ListEntry == STATUS_TIMEOUT) - { - return STATUS_TIMEOUT; - } - - ASSERT(ListEntry); - - 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; + /* Dereference the Object */ + ObDereferenceObject(Queue); + } + + /* Return status */ + return Status; } - -/* -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; - - Status = ObReferenceObjectByHandle( IoCompletionPortHandle, + NTSTATUS Status; + PKQUEUE Queue; + + /* Get the Object */ + Status = ObReferenceObjectByHandle(IoCompletionPortHandle, IO_COMPLETION_MODIFY_STATE, ExIoCompletionType, - UserMode, + ExGetPreviousMode(), (PVOID*)&Queue, NULL); - if (NT_SUCCESS(Status)) - { - Status = IoSetIoCompletion(Queue, CompletionKey, CompletionContext, - CompletionStatus, CompletionInformation, TRUE); - ObDereferenceObject(Queue); - } - - return Status; + + /* Check for Success */ + if (NT_SUCCESS(Status)) { + + /* Set the Completion */ + Status = IoSetIoCompletion(Queue, + CompletionKey, + CompletionContext, + CompletionStatus, + CompletionInformation, + TRUE); + ObDereferenceObject(Queue); + } + + /* Return status */ + return Status; } diff --git a/reactos/ntoskrnl/io/iomgr.c b/reactos/ntoskrnl/io/iomgr.c index 81852d21362..4cc4d60acfa 100644 --- a/reactos/ntoskrnl/io/iomgr.c +++ b/reactos/ntoskrnl/io/iomgr.c @@ -553,14 +553,17 @@ IoInit (VOID) } -VOID INIT_FUNCTION -IoInit2(VOID) +VOID +INIT_FUNCTION +IoInit2(BOOLEAN BootLog) { PDEVICE_NODE DeviceNode; PDRIVER_OBJECT DriverObject; MODULE_OBJECT ModuleObject; NTSTATUS Status; + IoCreateDriverList(); + KeInitializeSpinLock (&IoStatisticsLock); /* Initialize raw filesystem driver */ @@ -605,6 +608,56 @@ IoInit2(VOID) 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 8b9088270f5..9d01c6b1f55 100644 --- a/reactos/ntoskrnl/io/wmi.c +++ b/reactos/ntoskrnl/io/wmi.c @@ -249,4 +249,18 @@ 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 deleted file mode 100644 index 99084a862e4..00000000000 --- a/reactos/ntoskrnl/ke/alert.c +++ /dev/null @@ -1,150 +0,0 @@ -/* $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 5b47908713f..04d9786b5fb 100644 --- a/reactos/ntoskrnl/ke/apc.c +++ b/reactos/ntoskrnl/ke/apc.c @@ -1,5 +1,4 @@ -/* $Id$ - * +/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * FILE: ntoskrnl/ke/apc.c @@ -19,581 +18,820 @@ VOID PsTerminateCurrentThread(NTSTATUS ExitStatus); -#define TAG_KAPC TAG('K', 'A', 'P', 'C') - /* FUNCTIONS *****************************************************************/ -/* - * @implemented - */ +/*++ + * 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--; +} + +/*++ + * 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. + * + *--*/ 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) -/* - * 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 - */ +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) { - 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); + 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; + /* 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; - /* 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; + } } -/* - * @implemented - */ +/*++ + * 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. + * + *--*/ BOOLEAN STDCALL -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; - - ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); - DPRINT ("KeInsertQueueApc(Apc %x, SystemArgument1 %x, " - "SystemArgument2 %x)\n",Apc,SystemArgument1, - SystemArgument2); +KeInsertQueueApc(PKAPC Apc, + PVOID SystemArgument1, + PVOID SystemArgument2, + KPRIORITY PriorityBoost) - OldIrql = KeAcquireDispatcherDatabaseLock(); - - /* Get the Thread specified in the APC */ - Thread = Apc->Thread; - - /* Make sure the thread allows APC Queues. +{ + 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. * 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; + 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) { + /* 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; + 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) && + /* + * 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) && (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); - } + (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; + /* Return Sucess if we are here */ + KeReleaseDispatcherDatabaseLock(OldIrql); + return TRUE; } -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. - */ +/*++ + * 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) { - KIRQL OldIrql; - PKTHREAD Thread = Apc->Thread; + PKTHREAD Thread = KeGetCurrentThread(); - 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); + /* 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); + } + } } +/*++ + * 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; -/* - * @implemented - */ + 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. + * + *--*/ 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); + ASSERT_IRQL_EQUAL(APC_LEVEL); - /* Lock the APC Queue and Raise IRQL to Synch */ - KeAcquireSpinLock(&Thread->ApcQueueLock, &OldIrql); + /* 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; + /* 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); - } else { - /* Normal Kernel APC */ - if (Thread->ApcState.KernelApcInProgress || Thread->KernelApcDisable) { + /* Special APC */ + if (NormalRoutine == NULL) { + + /* Remove the APC from the list */ + Apc->Inserted = FALSE; + RemoveEntryList(ApcListEntry); - /* - * 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); + /* 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); - 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); + + } 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); - /* 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; + 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); + } - /* 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; + /* 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); + 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); - } + 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); } -VOID +/*++ + * 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 KiInitializeUserApc(IN PVOID Reserved, - 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 - */ + IN PKTRAP_FRAME TrapFrame, + IN PKNORMAL_ROUTINE NormalRoutine, + IN PVOID NormalContext, + IN PVOID SystemArgument1, + IN PVOID SystemArgument2) { - 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; } -/* - * @implemented - */ +/*++ + * 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. + * + *--*/ BOOLEAN STDCALL -KeAreApcsDisabled( - VOID - ) +KeAreApcsDisabled(VOID) { - return KeGetCurrentThread()->KernelApcDisable ? TRUE : FALSE; + /* Return the Kernel APC State */ + 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) -/* - * 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. - */ +NtQueueApcThread(HANDLE ThreadHandle, + PKNORMAL_ROUTINE ApcRoutine, + PVOID NormalContext, + PVOID SystemArgument1, + PVOID SystemArgument2) { + PKAPC Apc; + PETHREAD Thread; + KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); + NTSTATUS Status; - 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; - } + /* 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_KAPC); - if (Apc == NULL) { - ObDereferenceObject(Thread); - return(STATUS_NO_MEMORY); - } + /* Allocate an APC */ + Apc = ExAllocatePoolWithTag(NonPagedPool, sizeof(KAPC), TAG('P', 's', 'a', 'p')); + 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 2af3e26b721..fd2f58c96e7 100644 --- a/reactos/ntoskrnl/ke/bug.c +++ b/reactos/ntoskrnl/ke/bug.c @@ -47,6 +47,17 @@ KeDeregisterBugCheckCallback(PKBUGCHECK_CALLBACK_RECORD CallbackRecord) return FALSE; } +/* + * @unimplemented + */ +BOOLEAN +STDCALL +KeDeregisterBugCheckReasonCallback(IN PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord) +{ + UNIMPLEMENTED; + return FALSE; +} + /* * @implemented */ @@ -74,6 +85,20 @@ 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 1d4ca92a486..1657b5f592d 100644 --- a/reactos/ntoskrnl/ke/catch.c +++ b/reactos/ntoskrnl/ke/catch.c @@ -1,5 +1,4 @@ -/* $Id$ - * +/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * FILE: ntoskrnl/ke/catch.c @@ -21,282 +20,206 @@ ULONG RtlpDispatchException(IN PEXCEPTION_RECORD ExceptionRecord, IN PCONTEXT Context); +/* + * @unimplemented + */ +VOID +STDCALL +KiCoprocessorError(VOID) +{ + UNIMPLEMENTED; +} + +/* + * @unimplemented + */ +VOID +STDCALL +KiUnexpectedInterrupt(VOID) +{ + UNIMPLEMENTED; +} + VOID KiDispatchException(PEXCEPTION_RECORD ExceptionRecord, - PCONTEXT Context, - PKTRAP_FRAME Tf, - KPROCESSOR_MODE PreviousMode, - BOOLEAN SearchFrames) + PCONTEXT Context, + PKTRAP_FRAME Tf, + KPROCESSOR_MODE PreviousMode, + BOOLEAN SearchFrames) { - EXCEPTION_DISPOSITION Value; - CONTEXT TContext; - KD_CONTINUE_TYPE Action = kdHandleException; + EXCEPTION_DISPOSITION Value; + CONTEXT TContext; + KD_CONTINUE_TYPE Action = kdHandleException; - DPRINT("KiDispatchException() called\n"); + DPRINT("KiDispatchException() called\n"); + /* Increase number of Exception Dispatches */ + KeGetCurrentKPCR()->PrcbData.KeExceptionDispatchCount++; - /* PCR->KeExceptionDispatchCount++; */ - - if (Context == NULL) - { - TContext.ContextFlags = CONTEXT_FULL; - if (PreviousMode == UserMode) - { - TContext.ContextFlags = TContext.ContextFlags | CONTEXT_DEBUGGER; - } + 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; + } - KeTrapFrameToContext(Tf, &TContext); + /* Convert the Trapframe into a Context */ + KeTrapFrameToContext(Tf, &TContext); - Context = &TContext; + /* Use local stack context */ + Context = &TContext; } -#if 0 - if (ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) - { - Context->Eip--; +#if 0 /* FIXME: Isn't this right? With a break after? */ + if (ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) { + Context->Eip--; } #endif - - if (KdDebuggerEnabled && KdDebugState & KD_DEBUG_GDB) - { - Action = KdEnterDebuggerException (ExceptionRecord, Context, Tf); - } - if (Action == kdContinue) - { - return; + /* Check if a Debugger is enabled */ + if (KdDebuggerEnabled && KdDebugState & KD_DEBUG_GDB) { + + /* Break into it */ + Action = KdEnterDebuggerException (ExceptionRecord, Context, Tf); } + + /* 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) { - 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; + 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 - Action = KdbEnterDebuggerException (ExceptionRecord, PreviousMode, - Context, Tf, FALSE); - if (Action == kdContinue) - { - return; - } + /* Enter KDB if available */ + Action = KdbEnterDebuggerException(ExceptionRecord, + PreviousMode, + Context, + Tf, + FALSE); + + /* Exit if we're continuing */ + if (Action == kdContinue) return; #endif - /* FIXME: Forward exception to user mode debugger */ + /* 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)); - - 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 debugger */ - - /* FIXME: Forward the exception to the process exception port */ - -#ifdef KDBG - Action = KdbEnterDebuggerException (ExceptionRecord, PreviousMode, - Context, Tf, TRUE); - if (Action == kdContinue) - { - return; + /* 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 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; #endif - /* Terminate the offending thread */ - DPRINT1("Unhandled UserMode exception, terminating thread\n"); - ZwTerminateThread(NtCurrentThread(), ExceptionRecord->ExceptionCode); - } - else - { - /* PreviousMode == KernelMode */ + /* Terminate the offending thread */ + DPRINT1("Unhandled UserMode exception, terminating thread\n"); + ZwTerminateThread(NtCurrentThread(), ExceptionRecord->ExceptionCode); + + } else { + + /* This is Kernel Mode */ #ifdef KDBG - Action = KdbEnterDebuggerException (ExceptionRecord, PreviousMode, - Context, Tf, FALSE); - if (Action == kdContinue) - { - return; + /* Enter KDB if available */ + Action = KdbEnterDebuggerException(ExceptionRecord, + PreviousMode, + Context, + Tf, + FALSE); + + /* Exit if we're continuing */ + 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); +#ifdef KDBG + /* Enter KDB if available */ + Action = KdbEnterDebuggerException(ExceptionRecord, + PreviousMode, + Context, + Tf, + TRUE); + + /* Exit if we're continuing */ + if (Action == kdContinue) return; +#endif + KEBUGCHECKWITHTF(KMODE_EXCEPTION_NOT_HANDLED, 0, 0, 0, 0, Tf); } -#endif - - 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 - Action = KdbEnterDebuggerException (ExceptionRecord, PreviousMode, - Context, Tf, TRUE); - if (Action == kdContinue) - { - return; - } -#endif - 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 deleted file mode 100644 index e2428549b45..00000000000 --- a/reactos/ntoskrnl/ke/critical.c +++ /dev/null @@ -1,56 +0,0 @@ -/* $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 2aee866c39d..0d68ce65182 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,24 +60,18 @@ KeInitializeThreadedDpc(PKDPC Dpc, * NOTE: Callers can be running at any IRQL. */ { - 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; + 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; } /* * @implemented - */ -VOID -STDCALL -KeInitializeDpc (PKDPC Dpc, - PKDEFERRED_ROUTINE DeferredRoutine, - PVOID DeferredContext) -/* + * * FUNCTION: * Initalizes a DPC and registers the DeferredRoutine for it. * ARGUMENTS: @@ -86,24 +80,24 @@ KeInitializeDpc (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 = KDpc; - 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 = DpcObject; + 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 @@ -155,124 +149,141 @@ KeInsertQueueDpc (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; + KIRQL OldIrql; + PKPCR Pcr; - DPRINT("KeInsertQueueDpc(DPC %x, SystemArgument1 %x, SystemArgument2 %x)\n", - Dpc, SystemArgument1, SystemArgument2); + 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); - //} + /* 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); + } #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)); - } + 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); + /* 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); - } + /* 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 { + + /* 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: @@ -281,33 +292,36 @@ KeRemoveQueueDpc (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; } /* @@ -323,7 +337,8 @@ KeFlushQueuedDpcs(VOID) * Called when deleting a Driver. */ { - if (KeGetCurrentKPCR()->PrcbData.DpcData[0].DpcQueueDepth) HalRequestSoftwareInterrupt(DISPATCH_LEVEL); + /* Request an interrupt if needed */ + if (KeGetCurrentKPCR()->PrcbData.DpcData[0].DpcQueueDepth) HalRequestSoftwareInterrupt(DISPATCH_LEVEL); } /* @@ -332,10 +347,11 @@ KeFlushQueuedDpcs(VOID) BOOLEAN STDCALL KeIsExecutingDpc( - VOID + VOID ) { - return KeGetCurrentKPCR()->PrcbData.DpcRoutineActive; + /* Return if the Dpc Routine is active */ + return KeGetCurrentKPCR()->PrcbData.DpcRoutineActive; } /* @@ -349,39 +365,41 @@ KeIsExecutingDpc( */ VOID STDCALL -KeSetImportanceDpc (IN PKDPC Dpc, - IN KDPC_IMPORTANCE Importance) +KeSetImportanceDpc (IN PKDPC Dpc, + IN KDPC_IMPORTANCE Importance) { - Dpc->Importance = Importance; + /* Set the DPC 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) { - if (Number >= MAXIMUM_PROCESSORS) - { - Dpc->Number = 0; - } - else - { - ASSERT(Number < KeNumberProcessors); - Dpc->Number = Number + MAXIMUM_PROCESSORS; - } + /* 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; + } } -VOID -STDCALL -KiQuantumEnd(VOID) /* * FUNCTION: * Called when a quantum end occurs to check if priority should be changed @@ -389,152 +407,173 @@ KiQuantumEnd(VOID) * 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) { - 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); -} + 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); +} /* * @implemented - */ -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. */ +VOID +STDCALL +KiDispatchInterrupt(VOID) { - PLIST_ENTRY DpcEntry; - PKDPC Dpc; - KIRQL OldIrql; - PKPCR Pcr; + PLIST_ENTRY DpcEntry; + PKDPC Dpc; + KIRQL OldIrql; + PKPCR Pcr; - DPRINT("Dispatching Interrupts\n"); - ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); + DPRINT("Dispatching Interrupts\n"); + ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); - /* Set DPC Deliver to Active */ - Pcr = KeGetCurrentKPCR(); + /* 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); + 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; + 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--; + 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 deleted file mode 100644 index d6172aa1687..00000000000 --- a/reactos/ntoskrnl/ke/error.c +++ /dev/null @@ -1,98 +0,0 @@ -/* $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 75dde7be159..7683afa3b42 100644 --- a/reactos/ntoskrnl/ke/event.c +++ b/reactos/ntoskrnl/ke/event.c @@ -1,4 +1,4 @@ -/* $Id:$ +/* $Id$ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -19,121 +19,211 @@ /* * @implemented */ -VOID STDCALL KeClearEvent (PKEVENT Event) +VOID +STDCALL +KeClearEvent(PKEVENT Event) { - DPRINT("KeClearEvent(Event %x)\n", Event); - Event->Header.SignalState = FALSE; + DPRINT("KeClearEvent(Event %x)\n", Event); + + /* Reset Signal State */ + 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) { - 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)); + DPRINT("KeInitializeEvent(Event %x)\n", Event); + + /* Initialize the Dispatcher Header */ + KeInitializeDispatcherHeader(&Event->Header, + Type, + sizeof(Event) / sizeof(ULONG), + State); } /* * @implemented */ -LONG STDCALL KeReadStateEvent (PKEVENT Event) +VOID +STDCALL +KeInitializeEventPair(PKEVENT_PAIR EventPair) { - return(Event->Header.SignalState); -} - -/* - * @implemented - */ -LONG STDCALL KeResetEvent (PKEVENT Event) -{ - /* FIXME: must use interlocked func. everywhere! (wait.c) - * or use dispather lock instead - * -Gunnar */ - return(InterlockedExchange(&(Event->Header.SignalState),0)); -} - -/* - * @implemented - */ -LONG STDCALL KeSetEvent (PKEVENT Event, - KPRIORITY Increment, - BOOLEAN Wait) -{ - KIRQL OldIrql; - int ret; - - 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); + 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); } /* * @implemented */ LONG STDCALL -KePulseEvent (IN PKEVENT Event, - IN KPRIORITY Increment, - IN BOOLEAN Wait) +KePulseEvent(IN PKEVENT Event, + IN KPRIORITY Increment, + IN BOOLEAN Wait) { - KIRQL OldIrql; - LONG Ret; + KIRQL OldIrql; + LONG PreviousState; - 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); + 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); } - else - { - KTHREAD *Thread = KeGetCurrentThread(); - Thread->WaitNext = TRUE; - Thread->WaitIrql = OldIrql; + + /* 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 Ret; + /* Return the previous State */ + return PreviousState; +} + +/* + * @implemented + */ +LONG +STDCALL +KeReadStateEvent(PKEVENT Event) +{ + /* Return the Signal State */ + return Event->Header.SignalState; +} + +/* + * @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; +} + +/* + * @implemented + */ +LONG +STDCALL +KeSetEvent(PKEVENT Event, + KPRIORITY Increment, + 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); + } + } + + /* 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 */ + DPRINT("Done: %d\n", PreviousState); + return PreviousState; } /* @@ -141,27 +231,39 @@ KePulseEvent (IN PKEVENT Event, */ VOID STDCALL -KeSetEventBoostPriority( - IN PKEVENT Event, - IN PKTHREAD *Thread OPTIONAL -) +KeSetEventBoostPriority(IN PKEVENT Event, + IN PKTHREAD *Thread OPTIONAL) { - PKTHREAD WaitingThread; - KIRQL OldIrql; - - OldIrql = KeAcquireDispatcherDatabaseLock(); + 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); + } - /* 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); - - KeReleaseDispatcherDatabaseLock(OldIrql); + /* Release the Dispatcher Database Lock */ + KeReleaseDispatcherDatabaseLock(OldIrql); } /* EOF */ diff --git a/reactos/ntoskrnl/ke/i386/tskswitch.S b/reactos/ntoskrnl/ke/i386/tskswitch.S index a97577fa5ee..6d5038ae9bb 100644 --- a/reactos/ntoskrnl/ke/i386/tskswitch.S +++ b/reactos/ntoskrnl/ke/i386/tskswitch.S @@ -200,7 +200,7 @@ _Ki386ContextSwitch: */ sti - call _KeReleaseDispatcherDatabaseLockFromDpcLevel + call @KeReleaseDispatcherDatabaseLockFromDpcLevel@0 cmpl $0, _PiNrThreadsAwaitingReaping je 5f diff --git a/reactos/ntoskrnl/ke/kthread.c b/reactos/ntoskrnl/ke/kthread.c index 40b352fb11a..de1fd0bf367 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: David Welch (welch@cwcom.net) + * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) - Commented, reorganized some stuff, fixed/implemented some functions. + * David Welch (welch@cwcom.net) */ /* INCLUDES *****************************************************************/ @@ -16,19 +16,93 @@ /* FUNCTIONS *****************************************************************/ -VOID -KiServiceCheck (VOID) +ULONG +STDCALL +KeAlertResumeThread(IN PKTHREAD Thread) { - PETHREAD Thread; + ULONG PreviousCount; + KIRQL OldIrql; - Thread = PsGetCurrentThread(); + ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); + + /* Lock the Dispatcher Database and the APC Queue */ + OldIrql = KeAcquireDispatcherDatabaseLock(); + KiAcquireSpinLock(&Thread->ApcQueueLock); - if (Thread->Tcb.ServiceTable != KeServiceDescriptorTableShadow) - { - PsInitWin32Thread (Thread); - - Thread->Tcb.ServiceTable = KeServiceDescriptorTableShadow; + /* 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); + } + } + + /* Release Locks and return the Old State */ + KiReleaseSpinLock(&Thread->ApcQueueLock); + KeReleaseDispatcherDatabaseLock(OldIrql); + return PreviousCount; +} + +BOOLEAN +STDCALL +KeAlertThread(PKTHREAD Thread, + KPROCESSOR_MODE AlertMode) +{ + KIRQL OldIrql; + BOOLEAN PreviousState; + + /* 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; + } + } + + /* Release the Dispatcher Lock */ + KeReleaseDispatcherDatabaseLock(OldIrql); + + /* Return the old state */ + return PreviousState; } /* @@ -36,28 +110,231 @@ KiServiceCheck (VOID) */ 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 -KeFreeStackPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address, - PFN_TYPE Page, SWAPENTRY SwapEntry, BOOLEAN Dirty) +STDCALL +KeInitializeThread(PKPROCESS Process, + PKTHREAD Thread, + BOOLEAN First) { - ASSERT(SwapEntry == 0); - if (Page != 0) - { - MmReleasePageMemoryConsumer(MC_NPPOOL, Page); + 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; } + + /* + * 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 */ } /* @@ -65,11 +342,9 @@ KeFreeStackPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address, */ KPRIORITY STDCALL -KeQueryPriorityThread ( - IN PKTHREAD Thread - ) +KeQueryPriorityThread (IN PKTHREAD Thread) { - return Thread->Priority; + return Thread->Priority; } /* @@ -77,19 +352,29 @@ KeQueryPriorityThread ( */ ULONG STDCALL -KeQueryRuntimeThread( - IN PKTHREAD Thread, - OUT PULONG UserTime - ) +KeQueryRuntimeThread(IN PKTHREAD Thread, + OUT PULONG UserTime) { - /* Return the User Time */ - *UserTime = Thread->UserTime; - - /* Return the Kernel Time */ - return Thread->KernelTime; + /* Return the User Time */ + *UserTime = Thread->UserTime; + + /* Return the Kernel Time */ + return Thread->KernelTime; } -NTSTATUS +VOID +KeFreeStackPage(PVOID Context, + MEMORY_AREA* MemoryArea, + PVOID Address, + PFN_TYPE Page, + SWAPENTRY SwapEntry, + BOOLEAN Dirty) +{ + ASSERT(SwapEntry == 0); + if (Page) MmReleasePageMemoryConsumer(MC_NPPOOL, Page); +} + +NTSTATUS KeReleaseThread(PKTHREAD Thread) /* * FUNCTION: Releases the resource allocated for a thread by @@ -123,198 +408,26 @@ KeReleaseThread(PKTHREAD Thread) */ BOOLEAN STDCALL -KeSetKernelStackSwapEnable( - IN BOOLEAN Enable - ) +KeSetKernelStackSwapEnable(IN BOOLEAN Enable) { - PKTHREAD Thread; - BOOLEAN PreviousState; - - Thread = KeGetCurrentThread(); - - /* Save Old State */ - PreviousState = Thread->EnableStackSwap; - - /* Set New State */ - Thread->EnableStackSwap = Enable; + PKTHREAD Thread = KeGetCurrentThread(); + BOOLEAN PreviousState; + KIRQL OldIrql; + + /* Lock the Dispatcher Database */ + OldIrql = KeAcquireDispatcherDatabaseLock(); - /* Return Old State */ - return PreviousState; -} + /* Save Old State */ + PreviousState = Thread->EnableStackSwap; -VOID -KeInitializeThread(PKPROCESS Process, PKTHREAD Thread, BOOLEAN First) -/* - * FUNCTION: Initialize the microkernel state of the thread - */ -{ - 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; - } + /* Set New State */ + Thread->EnableStackSwap = Enable; - /* - * 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 - */ + /* No, Release Lock */ + KeReleaseDispatcherDatabaseLock(OldIrql); + + /* Return Old State */ + return PreviousState; } /* @@ -324,33 +437,33 @@ VOID STDCALL KeRevertToUserAffinityThread(VOID) { -#ifdef CONFIG_SMP - PKTHREAD CurrentThread; - KIRQL oldIrql; + PKTHREAD CurrentThread = KeGetCurrentThread(); + KIRQL OldIrql; - oldIrql = KeAcquireDispatcherDatabaseLock(); + ASSERT(CurrentThread->SystemAffinityActive != FALSE); + + /* Lock the Dispatcher Database */ + OldIrql = KeAcquireDispatcherDatabaseLock(); - CurrentThread = KeGetCurrentThread(); + /* Return to User Affinity */ + CurrentThread->Affinity = CurrentThread->UserAffinity; - 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 + /* 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); + } } /* @@ -358,20 +471,26 @@ KeRevertToUserAffinityThread(VOID) */ CCHAR STDCALL -KeSetIdealProcessorThread ( - IN PKTHREAD Thread, - IN CCHAR Processor) +KeSetIdealProcessorThread(IN PKTHREAD Thread, + IN CCHAR Processor) { - CCHAR PreviousIdealProcessor; + CCHAR PreviousIdealProcessor; + KIRQL OldIrql; + + /* Lock the Dispatcher Database */ + OldIrql = KeAcquireDispatcherDatabaseLock(); - /* Save Old Ideal Processor */ - PreviousIdealProcessor = Thread->IdealProcessor; - - /* Set New Ideal Processor */ - Thread->IdealProcessor = Processor; - - /* Return Old Ideal Processor */ - return PreviousIdealProcessor; + /* Save Old Ideal Processor */ + PreviousIdealProcessor = Thread->IdealProcessor; + + /* Set New Ideal Processor */ + Thread->IdealProcessor = Processor; + + /* Release Lock */ + KeReleaseDispatcherDatabaseLock(OldIrql); + + /* Return Old Ideal Processor */ + return PreviousIdealProcessor; } /* @@ -381,86 +500,237 @@ VOID STDCALL KeSetSystemAffinityThread(IN KAFFINITY Affinity) { -#ifdef CONFIG_SMP - PKTHREAD CurrentThread; - KIRQL oldIrql; + PKTHREAD CurrentThread = KeGetCurrentThread(); + KIRQL OldIrql; - oldIrql = KeAcquireDispatcherDatabaseLock(); + ASSERT(Affinity & ((1 << KeNumberProcessors) - 1)); + + /* Lock the Dispatcher Database */ + OldIrql = KeAcquireDispatcherDatabaseLock(); - CurrentThread = KeGetCurrentThread(); + /* Set the System Affinity Specified */ + CurrentThread->Affinity = Affinity; - 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 + /* 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); + } } /* * @implemented */ + /* The Increment Argument seems to be ignored by NT and always 0 when called */ VOID STDCALL KeTerminateThread(IN KPRIORITY Increment) { - /* The Increment Argument seems to be ignored by NT and always 0 when called */ - - /* Call our own internal routine */ - PsTerminateCurrentThread(0); + /* Call our own internal routine */ + PsTerminateCurrentThread(0); } +/* + * 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 + */ +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) +{ + 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; +} + +/* + * @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; - LARGE_INTEGER SafeInterval; + KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); + LARGE_INTEGER SafeInterval; + NTSTATUS Status; - PreviousMode = ExGetPreviousMode(); - - if(PreviousMode != KernelMode) - { - NTSTATUS Status = STATUS_SUCCESS; + /* Check if parameters are valid */ + if(PreviousMode != KernelMode) { - _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; - - if(!NT_SUCCESS(Status)) - { - return Status; - } + _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; } - return KeDelayExecutionThread(PreviousMode, - Alertable, - DelayInterval); + /* Call the Kernel Function */ + Status = KeDelayExecutionThread(PreviousMode, + Alertable, + &SafeInterval); + + /* Return Status */ + return Status; } diff --git a/reactos/ntoskrnl/ke/main.c b/reactos/ntoskrnl/ke/main.c index eef694b0bc7..71021dae392 100644 --- a/reactos/ntoskrnl/ke/main.c +++ b/reactos/ntoskrnl/ke/main.c @@ -1,37 +1,24 @@ -/* $Id$ - * +/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * FILE: ntoskrnl/ke/main.c * PURPOSE: Initalizes the kernel * - * PROGRAMMERS: David Welch (welch@cwcom.net) + * PROGRAMMERS: Alex Ionescu (cleaned up code, moved Executiv stuff to ex/init.c) + * 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); @@ -58,19 +45,17 @@ EXPORTED ULONG KiDmaIoCoherency = 0; /* RISC Architectures only */ EXPORTED ULONG InitSafeBootMode = 0; /* KB83764 */ #endif /* __GNUC__ */ -static LOADER_MODULE KeLoaderModules[64]; +LOADER_MODULE KeLoaderModules[64]; static CHAR KeLoaderModuleStrings[64][256]; static CHAR KeLoaderCommandLine[256]; -static ADDRESS_RANGE KeMemoryMap[64]; -static ULONG KeMemoryMapRangeCount; -static ULONG_PTR FirstKrnlPhysAddr; -static ULONG_PTR LastKrnlPhysAddr; -static ULONG_PTR LastKernelAddress; +ADDRESS_RANGE KeMemoryMap[64]; +ULONG KeMemoryMapRangeCount; +ULONG_PTR FirstKrnlPhysAddr; +ULONG_PTR LastKrnlPhysAddr; +ULONG_PTR LastKernelAddress; volatile BOOLEAN Initialized = FALSE; -extern ULONG MmCoreDumpType; -extern CHAR KiTimerSystemAuditing; -extern PVOID Ki386InitialStackArray[MAXIMUM_PROCESSORS]; +ULONG KeLargestCacheLine = 0x40; /* FIXME: Arch-specific */ /* We allocate 4 pages, but we only use 3. The 4th is to guarantee page alignment */ ULONG kernel_stack[4096]; @@ -82,793 +67,59 @@ 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); - } - } /* - * Tell ke/timer.c it's okay to run. + * @implemented */ - - KiTimerSystemAuditing = 1; - - ZwClose(ThreadHandle); - ZwClose(ProcessHandle); +ULONG +STDCALL +KeGetRecommendedSharedDataAlignment(VOID) +{ + return KeLargestCacheLine; } -VOID __attribute((noinline)) +VOID +__attribute((noinline)) KiSystemStartup(BOOLEAN BootProcessor) { - DPRINT1("KiSystemStartup(%d)\n", BootProcessor); - if (BootProcessor) - { - } - else - { - KeApplicationProcessorInit(); - } + DPRINT("KiSystemStartup(%d)\n", BootProcessor); + + /* Initialize the Application Processor */ + if (!BootProcessor) KeApplicationProcessorInit(); + + /* Initialize the Processor with HAL */ + HalInitializeProcessor(KeNumberProcessors, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock); - 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(;;); + /* 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(;;); } -VOID INIT_FUNCTION -_main (ULONG MultiBootMagic, PLOADER_PARAMETER_BLOCK _LoaderBlock) /* * FUNCTION: Called by the boot loader to start the kernel * ARGUMENTS: @@ -877,172 +128,158 @@ _main (ULONG MultiBootMagic, PLOADER_PARAMETER_BLOCK _LoaderBlock) * 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; + ULONG i; + ULONG size; + ULONG HalBase; + ULONG DriverBase; + ULONG DriverSize; + PIMAGE_NT_HEADERS NtHeader; + PIMAGE_OPTIONAL_HEADER OptHead; + CHAR* s; - /* 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; + /* 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; - /* - * 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; + /* 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; + /* Save the Base Address */ + MmSystemRangeStart = (PVOID)KeLoaderBlock.KernelBase; - /* - * 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; + /* Set the Command Line */ + strcpy(KeLoaderCommandLine, (PCHAR)_LoaderBlock->CommandLine); + KeLoaderBlock.CommandLine = (ULONG)KeLoaderCommandLine; - 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; + /* 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 */ KeLoaderModules[0].ModEnd = KeLoaderModules[0].ModStart + PAGE_ROUND_UP((ULONG)OptHead->SizeOfImage); - 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]; - } - - 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; + + /* 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); } - KeLoaderBlock.MmapLength = KeMemoryMapRangeCount * sizeof(ADDRESS_RANGE); - KeLoaderBlock.MmapAddr = (ULONG)KeMemoryMap; - } - else - { - KeLoaderBlock.MmapLength = 0; - KeLoaderBlock.MmapAddr = (ULONG)KeMemoryMap; + + /* 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]; } - KdInitSystem (0, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock); - HalInitSystem (0, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock); + /* Choose last module address as the final kernel address */ + LastKernelAddress = PAGE_ROUND_UP(KeLoaderModules[KeLoaderBlock.ModsCount - 1].ModEnd); - DPRINT1("_main (%x, %x)\n", MultiBootMagic, _LoaderBlock); + /* 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); - KiSystemStartup(1); + /* 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; + } + + /* Save data */ + KeLoaderBlock.MmapLength = KeMemoryMapRangeCount * sizeof(ADDRESS_RANGE); + KeLoaderBlock.MmapAddr = (ULONG)KeMemoryMap; + + } else { + + /* Nothing from BIOS */ + KeLoaderBlock.MmapLength = 0; + 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); } /* EOF */ diff --git a/reactos/ntoskrnl/ke/mutex.c b/reactos/ntoskrnl/ke/mutex.c index 3532781082c..992aa31c6cc 100644 --- a/reactos/ntoskrnl/ke/mutex.c +++ b/reactos/ntoskrnl/ke/mutex.c @@ -3,14 +3,19 @@ * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * FILE: ntoskrnl/ke/mutex.c - * PURPOSE: Implements mutex + * PURPOSE: Implements Mutexes and Mutants (that silly davec...) * - * PROGRAMMERS: David Welch (welch@mcmail.com) + * 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) */ /* INCLUDES *****************************************************************/ #include +#define NDEBUG #include /* FUNCTIONS *****************************************************************/ @@ -18,176 +23,212 @@ /* * @implemented */ -VOID STDCALL -KeInitializeMutex(IN PKMUTEX Mutex, - IN ULONG Level) -{ - 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 - */ -LONG STDCALL -KeReadStateMutex(IN PKMUTEX Mutex) -{ - return(Mutex->Header.SignalState); -} - -/* - * @implemented - */ -LONG STDCALL -KeReleaseMutex(IN PKMUTEX Mutex, - IN BOOLEAN Wait) -{ - 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 - */ -NTSTATUS STDCALL -KeWaitForMutexObject(IN PKMUTEX Mutex, - IN KWAIT_REASON WaitReason, - IN KPROCESSOR_MODE WaitMode, - IN BOOLEAN Alertable, - IN PLARGE_INTEGER Timeout) -{ - return(KeWaitForSingleObject(Mutex,WaitReason,WaitMode,Alertable,Timeout)); -} - - -/* - * @implemented - */ -VOID STDCALL +VOID +STDCALL KeInitializeMutant(IN PKMUTANT Mutant, - IN BOOLEAN InitialOwner) + IN BOOLEAN InitialOwner) { - if (InitialOwner == TRUE) - { - KeInitializeDispatcherHeader(&Mutant->Header, - InternalMutexType, - sizeof(KMUTANT) / sizeof(ULONG), - 0); - InsertTailList(&KeGetCurrentThread()->MutantListHead, - &Mutant->MutantListEntry); - Mutant->OwnerThread = KeGetCurrentThread(); + 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; } - else - { - KeInitializeDispatcherHeader(&Mutant->Header, - InternalMutexType, - sizeof(KMUTANT) / sizeof(ULONG), - 1); - Mutant->MutantListEntry.Flink = NULL; - Mutant->MutantListEntry.Blink = NULL; - Mutant->OwnerThread = NULL; - } - Mutant->Abandoned = FALSE; - Mutant->ApcDisable = 0; + + /* 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; } /* * @implemented */ -LONG STDCALL +VOID +STDCALL +KeInitializeMutex(IN PKMUTEX Mutex, + IN ULONG Level) +{ + 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); +} + +/* + * @implemented + */ +LONG +STDCALL KeReadStateMutant(IN PKMUTANT Mutant) { - return(Mutant->Header.SignalState); + /* Return the Signal State */ + return(Mutant->Header.SignalState); } /* * @implemented */ -LONG STDCALL -KeReleaseMutant(IN PKMUTANT Mutant, - IN KPRIORITY Increment, - IN BOOLEAN Abandon, - IN BOOLEAN Wait) +LONG +STDCALL +KeReadStateMutex(IN PKMUTEX Mutex) { - KIRQL OldIrql; + /* Return the Signal State */ + return(Mutex->Header.SignalState); +} - 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); +/* + * @implemented + */ +LONG +STDCALL +KeReleaseMutant(IN PKMUTANT Mutant, + IN KPRIORITY Increment, + IN BOOLEAN Abandon, + IN BOOLEAN Wait) +{ + 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; } - else - { - if (Mutant->OwnerThread != NULL) - { - 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 (Mutant->Header.SignalState == 1) - { - Mutant->OwnerThread = NULL; - if (Mutant->MutantListEntry.Flink && Mutant->MutantListEntry.Blink) - RemoveEntryList(&Mutant->MutantListEntry); - KiDispatcherObjectWake(&Mutant->Header, 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->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 PreviousState; +} - return(0); +/* + * @implemented + */ +LONG +STDCALL +KeReleaseMutex(IN PKMUTEX Mutex, + IN BOOLEAN Wait) +{ + + /* There's no difference at this level between the two */ + return KeReleaseMutant(Mutex, IO_NO_INCREMENT, FALSE, Wait); +} + +/* + * @implemented + */ +NTSTATUS +STDCALL +KeWaitForMutexObject(IN PKMUTEX Mutex, + IN KWAIT_REASON WaitReason, + IN KPROCESSOR_MODE WaitMode, + IN BOOLEAN Alertable, + IN PLARGE_INTEGER Timeout) +{ + /* This is a simple macro. Export the function here though */ + return KeWaitForSingleObject(Mutex, + WaitReason, + WaitMode, + Alertable, + Timeout); } /* EOF */ diff --git a/reactos/ntoskrnl/ke/queue.c b/reactos/ntoskrnl/ke/queue.c index 9c478709de8..6a3d63f2566 100644 --- a/reactos/ntoskrnl/ke/queue.c +++ b/reactos/ntoskrnl/ke/queue.c @@ -16,245 +16,482 @@ /* 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) { - 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; + 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; } - -/* - * @implemented - * - * Returns number of entries in the queue - */ -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 - ) -{ - ULONG InitialState; - - DPRINT("KiInsertQueue(Queue %x, Entry %x)\n", Queue, Entry); - - 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 +LONG +STDCALL KeInsertHeadQueue(IN PKQUEUE Queue, - IN PLIST_ENTRY Entry) + IN PLIST_ENTRY Entry) { - LONG Result; - KIRQL OldIrql; + 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); - OldIrql = KeAcquireDispatcherDatabaseLock(); - Result = KiInsertQueue(Queue,Entry,TRUE); - KeReleaseDispatcherDatabaseLock(OldIrql); - - return Result; + /* Return previous State */ + return PreviousState; } - /* * @implemented */ LONG STDCALL KeInsertQueue(IN PKQUEUE Queue, - IN PLIST_ENTRY Entry) + IN PLIST_ENTRY Entry) { - LONG Result; - KIRQL OldIrql; + 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); - OldIrql = KeAcquireDispatcherDatabaseLock(); - Result = KiInsertQueue(Queue,Entry,FALSE); - KeReleaseDispatcherDatabaseLock(OldIrql); - - return Result; + /* Return previous State */ + return PreviousState; } +/* + * @implemented + * + * Returns number of entries in the queue + */ +LONG +STDCALL +KeReadStateQueue(IN PKQUEUE Queue) +{ + /* Returns the Signal State */ + return(Queue->Header.SignalState); +} /* * @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; + PLIST_ENTRY ListEntry; + NTSTATUS Status; + PKTHREAD Thread = KeGetCurrentThread(); + KIRQL OldIrql; + PKQUEUE PreviousQueue; + PKWAIT_BLOCK WaitBlock; + PKWAIT_BLOCK TimerWaitBlock; + PKTIMER Timer; - OldIrql = KeAcquireDispatcherDatabaseLock (); + 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; + } - 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 - */ + /* This is needed so that we can set the new queue right here, before additional processing */ + PreviousQueue = Thread->Queue; + Thread->Queue = Queue; - //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); - } + /* 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); } - // register thread with this queue - InsertTailList(&Queue->ThreadListHead, &Thread->QueueListEntry); - Thread->Queue = Queue; - } - else /* if (Thread->Queue == Queue) */ - { - //dec. num running threads - Queue->CurrentCount--; - } + /* Insert in this new Queue */ + DPRINT("Inserting new Queue!\n"); + InsertTailList(&Queue->ThreadListHead, &Thread->QueueListEntry); - - - - 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; + } 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]; - Status = KeWaitForSingleObject(Queue, - WrQueue, - WaitMode, - TRUE, //bAlertable - Timeout); - - if (Status == STATUS_TIMEOUT || Status == STATUS_USER_APC) - { - return (PVOID)Status; - } - - OldIrql = KeAcquireDispatcherDatabaseLock (); - } - } + /* 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; } - /* * @implemented */ -PLIST_ENTRY STDCALL +PLIST_ENTRY +STDCALL KeRundownQueue(IN PKQUEUE Queue) { - PLIST_ENTRY EnumEntry; - PKTHREAD Thread; - KIRQL OldIrql; + PLIST_ENTRY EnumEntry; + PLIST_ENTRY FirstEntry; + PKTHREAD Thread; + KIRQL OldIrql; - DPRINT("KeRundownQueue(Queue %x)\n", Queue); + DPRINT("KeRundownQueue(Queue %x)\n", Queue); - /* I'm just guessing how this should work:-/ - * -Gunnar - */ - - OldIrql = KeAcquireDispatcherDatabaseLock (); + /* Get the Dispatcher Lock */ + OldIrql = KeAcquireDispatcherDatabaseLock(); - //no thread must wait on queue at rundown - ASSERT(IsListEmpty(&Queue->Header.WaitListHead)); + /* 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; - // unlink threads and clear their Thread->Queue - while (!IsListEmpty(&Queue->ThreadListHead)) - { - EnumEntry = RemoveHeadList(&Queue->ThreadListHead); - Thread = CONTAINING_RECORD(EnumEntry, KTHREAD, QueueListEntry); - Thread->Queue = 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; + } - if (IsListEmpty(&Queue->EntryListHead)) - { - EnumEntry = NULL; - } - else - { - EnumEntry = Queue->EntryListHead.Flink; - } + /* Release the lock and return */ + KeReleaseDispatcherDatabaseLock(OldIrql); + return FirstEntry; +} - KeReleaseDispatcherDatabaseLock (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); + } + } +} - return EnumEntry; +/* + * 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; + + /* 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; } /* EOF */ diff --git a/reactos/ntoskrnl/ke/sem.c b/reactos/ntoskrnl/ke/sem.c index 9408e66948c..f94990509fd 100644 --- a/reactos/ntoskrnl/ke/sem.c +++ b/reactos/ntoskrnl/ke/sem.c @@ -19,36 +19,39 @@ /* * @implemented */ -VOID STDCALL -KeInitializeSemaphore (PKSEMAPHORE Semaphore, - LONG Count, - LONG Limit) +VOID +STDCALL +KeInitializeSemaphore(PKSEMAPHORE Semaphore, + LONG Count, + LONG Limit) { - KeInitializeDispatcherHeader(&Semaphore->Header, - InternalSemaphoreType, - sizeof(KSEMAPHORE)/sizeof(ULONG), - Count); - Semaphore->Limit=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; } /* * @implemented */ -LONG STDCALL -KeReadStateSemaphore (PKSEMAPHORE Semaphore) +LONG +STDCALL +KeReadStateSemaphore(PKSEMAPHORE Semaphore) { - return(Semaphore->Header.SignalState); + /* Just return the Signal State */ + 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 @@ -68,40 +71,65 @@ KeReleaseSemaphore (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; + ULONG InitialState; + KIRQL OldIrql; + PKTHREAD CurrentThread; - 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); - OldIrql = KeAcquireDispatcherDatabaseLock(); + /* Lock the Dispatcher Database */ + OldIrql = KeAcquireDispatcherDatabaseLock(); - InitialState = Semaphore->Header.SignalState; - if (Semaphore->Limit < (LONG) InitialState + Adjustment || - InitialState > InitialState + Adjustment) - { - ExRaiseStatus(STATUS_SEMAPHORE_LIMIT_EXCEEDED); + /* 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); } - Semaphore->Header.SignalState += Adjustment; - if (InitialState == 0) - { - KiDispatcherObjectWake(&Semaphore->Header, SEMAPHORE_INCREMENT); + /* 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); } - if (Wait == FALSE) - { - KeReleaseDispatcherDatabaseLock(OldIrql); - } - else - { - KTHREAD *Thread = KeGetCurrentThread(); - Thread->WaitNext = TRUE; - Thread->WaitIrql = OldIrql; + /* 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; } - return(InitialState); + /* Return the previous state */ + return InitialState; } /* EOF */ diff --git a/reactos/ntoskrnl/ke/timer.c b/reactos/ntoskrnl/ke/timer.c index c46db9ddcff..de101af8b1c 100644 --- a/reactos/ntoskrnl/ke/timer.c +++ b/reactos/ntoskrnl/ke/timer.c @@ -107,12 +107,11 @@ KeInitializeTimerEx (PKTIMER Timer, /* Initialize the Dispatch Header */ KeInitializeDispatcherHeader(&Timer->Header, - InternalNotificationTimer + Type, + TimerNotificationObject + Type, sizeof(KTIMER) / sizeof(ULONG), FALSE); - /* Initalize the List Head and other data */ - InitializeListHead(&Timer->Header.WaitListHead); + /* Initalize the Other data */ Timer->DueTime.QuadPart = 0; Timer->Period = 0; } @@ -196,7 +195,6 @@ KeSetTimerEx (PKTIMER Timer, Timer->Dpc = Dpc; Timer->Period = Period; Timer->Header.SignalState = FALSE; - Timer->Header.Absolute = FALSE; /* Insert it */ if (!KiInsertTimer(Timer, DueTime)) { @@ -296,7 +294,7 @@ KiHandleExpiredTimer(PKTIMER Timer) /* Set it as Signaled */ DPRINT("Setting Timer as Signaled\n"); Timer->Header.SignalState = TRUE; - KiDispatcherObjectWake(&Timer->Header, 0); + KiWaitTest(&Timer->Header, 0); /* If the Timer is periodic, reinsert the timer with the new due time */ if (Timer->Period) { @@ -306,7 +304,7 @@ KiHandleExpiredTimer(PKTIMER Timer) if (!KiInsertTimer(Timer, DueTime)) { /* FIXME: I will think about how to handle this and fix it ASAP -- Alex */ - DPRINT1("CRITICAL UNHANDLED CASE: TIMER ALREADY EXPIRED!!!\n"); + DPRINT("CRITICAL UNHANDLED CASE: TIMER ALREADY EXPIRED!!!\n"); }; } @@ -338,8 +336,10 @@ KiInsertTimer(PKTIMER Timer, DPRINT("KiInsertTimer(Timer %x DueTime %I64d)\n", Timer, DueTime.QuadPart); - /* Set it as Inserted */ + /* Set default data */ 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 a6575e9bb88..7f65c81079b 100644 --- a/reactos/ntoskrnl/ke/wait.c +++ b/reactos/ntoskrnl/ke/wait.c @@ -1,16 +1,11 @@ -/* $Id$ - * +/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS project * FILE: ntoskrnl/ke/wait.c * PURPOSE: Manages non-busy waiting * - * PROGRAMMERS: David Welch (welch@mcmail.com) - * Phillip Susi - */ - -/* NOTES ******************************************************************** - * + * PROGRAMMERS: Alex Ionescu - Fixes and optimization. + * Gunnar Dalsnes - Implementation */ /* INCLUDES ******************************************************************/ @@ -24,387 +19,51 @@ static KSPIN_LOCK DispatcherDatabaseLock; -#define KeDispatcherObjectWakeOne(hdr, increment) KeDispatcherObjectWakeOneOrAll(hdr, increment, FALSE) -#define KeDispatcherObjectWakeAll(hdr, increment) KeDispatcherObjectWakeOneOrAll(hdr, increment, TRUE) +/* Tells us if the Timer or Event is a Syncronization or Notification Object */ +#define TIMER_OR_EVENT_TYPE 0x7L -extern POBJECT_TYPE EXPORTED ExMutantObjectType; -extern POBJECT_TYPE EXPORTED ExSemaphoreObjectType; -extern POBJECT_TYPE EXPORTED ExTimerType; +/* One of the Reserved Wait Blocks, this one is for the Thread's Timer */ +#define TIMER_WAIT_BLOCK 0x3L /* 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 -KeAcquireDispatcherDatabaseLockAtDpcLevel(VOID) -/* - * PURPOSE: Acquires the dispatcher database lock for the caller - */ +inline +FASTCALL +KiCheckAlertability(BOOLEAN Alertable, + PKTHREAD CurrentThread, + KPROCESSOR_MODE WaitMode, + PNTSTATUS Status) { - 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); + /* 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; + } } /* * @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: @@ -413,27 +72,102 @@ KeDelayExecutionThread (KPROCESSOR_MODE WaitMode, * Interval = Specifies the interval to wait * RETURNS: Status */ +NTSTATUS +STDCALL +KeDelayExecutionThread(KPROCESSOR_MODE WaitMode, + BOOLEAN Alertable, + PLARGE_INTEGER Interval) { - PKTHREAD Thread = KeGetCurrentThread(); + PKWAIT_BLOCK TimerWaitBlock; + PKTIMER ThreadTimer; + PKTHREAD CurrentThread = KeGetCurrentThread(); + NTSTATUS Status; - KeSetTimer(&Thread->Timer, *Interval, NULL); - return (KeWaitForSingleObject(&Thread->Timer, - (WaitMode == KernelMode) ? Executive : UserRequest, /* TMN: Was unconditionally Executive */ - WaitMode, /* TMN: Was UserMode */ - Alertable, - NULL)); + 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; } /* * @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: @@ -446,52 +180,174 @@ KeWaitForSingleObject(PVOID Object, * Timeout = Optional timeout value * RETURNS: Status */ +NTSTATUS +STDCALL +KeWaitForSingleObject(PVOID Object, + KWAIT_REASON WaitReason, + KPROCESSOR_MODE WaitMode, + BOOLEAN Alertable, + PLARGE_INTEGER Timeout) { - return KeWaitForMultipleObjects(1, - &Object, - WaitAny, - WaitReason, - WaitMode, - Alertable, - Timeout, - NULL); -} + PDISPATCHER_HEADER CurrentObject; + PKWAIT_BLOCK WaitBlock; + PKWAIT_BLOCK TimerWaitBlock; + PKTIMER ThreadTimer; + PKTHREAD CurrentThread = KeGetCurrentThread(); + NTSTATUS Status; + NTSTATUS WaitStatus; - -inline -PVOID -KiGetWaitableObjectFromObject(PVOID Object) -{ - //special case when waiting on file objects - if ( ((PDISPATCHER_HEADER)Object)->Type == InternalFileType) - { - return &((PFILE_OBJECT)Object)->Event; - } - - return Object; -} - - -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; + 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; + + /* 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)) { + + /* Return a timeout if we couldn't insert the timer for some reason */ + Status = STATUS_TIMEOUT; + goto WaitDone; + } + } + + /* 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; } /* @@ -507,558 +363,544 @@ KeWaitForMultipleObjects(ULONG Count, PLARGE_INTEGER Timeout, PKWAIT_BLOCK WaitBlockArray) { - DISPATCHER_HEADER *hdr; - PKWAIT_BLOCK blk; - PKTHREAD CurrentThread; - ULONG CountSignaled; - ULONG i; - NTSTATUS Status; - KIRQL OldIrql; - BOOLEAN Abandoned; - NTSTATUS WaitStatus; + 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\n", Count, Object, PsGetCurrentThread()); + DPRINT("Entering KeWaitForMultipleObjects(Count %lu Object[] %p) " + "PsGetCurrentThread() %x, Timeout %x\n", Count, Object, PsGetCurrentThread(), Timeout); - ASSERT(0 < Count && Count <= MAXIMUM_WAIT_OBJECTS); - - CurrentThread = KeGetCurrentThread(); - - /* - * 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); - } - } - - - - /* - * Set up the timeout if required - */ - if (Timeout != NULL && Timeout->QuadPart != 0) - { - KeSetTimer(&CurrentThread->Timer, *Timeout, NULL); - } - - do - { - if (CurrentThread->WaitNext) - { - CurrentThread->WaitNext = FALSE; - OldIrql = CurrentThread->WaitIrql; - } - else - { - OldIrql = KeAcquireDispatcherDatabaseLock (); - } - - /* Get the current Wait Status */ - WaitStatus = CurrentThread->WaitStatus; - - if (Alertable) { + /* Set the Current Thread */ + CurrentThread = KeGetCurrentThread(); - /* 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"); - WaitStatus = STATUS_ALERTED; - - /* If there are User APCs Pending, then we can't really be alertable */ - } else if ((!IsListEmpty(&CurrentThread->ApcState.ApcListHead[UserMode])) && - (WaitMode == UserMode)) { - - DPRINT1("APCs are Pending\n"); - CurrentThread->ApcState.UserApcPending = TRUE; - WaitStatus = STATUS_USER_APC; - } + /* Check if the lock is already held */ + if (CurrentThread->WaitNext) { - /* 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; + /* 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(); } - /* - * Check if the wait is (already) satisfied - */ - CountSignaled = 0; - Abandoned = FALSE; - for (i = 0; i < Count; i++) - { - hdr = (DISPATCHER_HEADER *) KiGetWaitableObjectFromObject(Object[i]); - - 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); - } - } - } - - 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; - } - - KeReleaseDispatcherDatabaseLock(OldIrql); - - if (Timeout != NULL && Timeout->QuadPart != 0) - { - KeCancelTimer(&CurrentThread->Timer); - } - - DPRINT("All objects are (already) signaled!\n"); - - if (Abandoned == TRUE) - { - return (STATUS_ABANDONED_WAIT_0); - } - - return (STATUS_WAIT_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; - } - - /* - * 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); - } - - /* 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 another thread - if (CurrentThread->Queue->CurrentCount < CurrentThread->Queue->MaximumCount && - !IsListEmpty(&CurrentThread->Queue->EntryListHead)) - { - KiDispatcherObjectWake(&CurrentThread->Queue->Header, IO_NO_INCREMENT); - } - } - - PsBlockThread(&Status, Alertable, WaitMode, TRUE, OldIrql, (UCHAR)WaitReason); - - //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); - - - if (Timeout != NULL) - { - KeCancelTimer(&CurrentThread->Timer); - } - - DPRINT("Returning from KeWaitForMultipleObjects()\n"); - return (Status); -} - -VOID KeInitializeDispatcher(VOID) -{ - KeInitializeSpinLock(&DispatcherDatabaseLock); -} - -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; + /* Make sure the Wait Count is valid for the Thread and Maximum Wait Objects */ + if (!WaitBlockArray) { - 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; - } - } + /* 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); + } - /* 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]); - } + /* 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; + } - return(Status); - } - } + /* 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; - Status = KeWaitForMultipleObjects(ObjectCount, - ObjectPtrArray, - WaitType, - UserRequest, - PreviousMode, - Alertable, - TimeOut, - WaitBlockArray); + /* 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); - /* dereference all objects */ - for (i = 0; i < ObjectCount; i++) - { - ObDereferenceObject(ObjectPtrArray[i]); - } + /* Insert the Timer into the Timer Lists and enable it */ + if (!KiInsertTimer(ThreadTimer, *Timeout)) { - return(Status); + /* 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; } +VOID +FASTCALL +KiSatisfyObjectWait(PDISPATCHER_HEADER Object, + PKTHREAD Thread) -/* - * @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; + /* Special case for Mutants */ + if (Object->Type == MutantObject) { - if(!NT_SUCCESS(Status)) - { - return Status; - } - } + /* 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; + + /* Check if it's abandoned */ + if (((PKMUTANT)Object)->Abandoned) { + + /* Unabandon it */ + ((PKMUTANT)Object)->Abandoned = FALSE; + + /* Return Status */ + Thread->WaitStatus = STATUS_ABANDONED; + } + + /* Insert it into the Mutant List */ + InsertHeadList(&Thread->MutantListHead, &((PKMUTANT)Object)->MutantListEntry); + } + + } 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) { - 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); + /* These ones can have multiple signalings, so we only decrease it */ + Object->SignalState--; + } } - -NTSTATUS STDCALL -NtSignalAndWaitForSingleObject(IN HANDLE ObjectHandleToSignal, - IN HANDLE WaitableObjectHandle, - IN BOOLEAN Alertable, - IN PLARGE_INTEGER TimeOut OPTIONAL) +VOID +FASTCALL +KiWaitTest(PDISPATCHER_HEADER Object, + KPRIORITY Increment) { - KPROCESSOR_MODE PreviousMode; - DISPATCHER_HEADER* hdr; - PVOID SignalObj; - PVOID WaitObj; - LARGE_INTEGER SafeTimeOut; - NTSTATUS Status = STATUS_SUCCESS; + 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; + } + + /* 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); - 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; - } +SkipUnwait: + /* Next entry */ + WaitEntry = WaitEntry->Flink; + } + + DPRINT("Done\n"); +} - Status = ObReferenceObjectByHandle(WaitableObjectHandle, - SYNCHRONIZE, - NULL, - PreviousMode, - &WaitObj, - NULL); - if (!NT_SUCCESS(Status)) - { - ObDereferenceObject(SignalObj); - return Status; - } +/* Must be called with the dispatcher lock held */ +VOID +FASTCALL +KiAbortWaitThread(PKTHREAD Thread, + NTSTATUS WaitStatus) +{ + PKWAIT_BLOCK WaitBlock; - hdr = (DISPATCHER_HEADER *)SignalObj; - switch (hdr->Type) - { - case InternalNotificationEvent: - case InternalSynchronizationEvent: - KeSetEvent(SignalObj, - EVENT_INCREMENT, - TRUE); - break; + /* 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)); - case InternalMutexType: - KeReleaseMutex(SignalObj, - TRUE); - break; + /* 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++; + } - 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; + /* Reschedule the Thread */ + DPRINT("Unblocking the Thread\n"); + PsUnblockThread((PETHREAD)Thread, &WaitStatus, 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); +} + +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; + } +} + +VOID +inline +FASTCALL +KiSatisifyMultipleObjectWaits(PKWAIT_BLOCK WaitBlock) +{ + PKTHREAD WaitThread = WaitBlock->Thread; + + /* Loop through all the Wait Blocks, and wake each Object */ + while (WaitBlock) { + + /* Wake the Object */ + KiSatisfyObjectWait(WaitBlock->Object, WaitThread); + WaitBlock = WaitBlock->NextWaitBlock; + } +} + +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)); +} + +KIRQL +inline +FASTCALL +KeAcquireDispatcherDatabaseLock(VOID) +{ + KIRQL OldIrql; + + KeAcquireSpinLock (&DispatcherDatabaseLock, &OldIrql); + return OldIrql; +} + +VOID +inline +FASTCALL +KeAcquireDispatcherDatabaseLockAtDpcLevel(VOID) +{ + KeAcquireSpinLockAtDpcLevel (&DispatcherDatabaseLock); +} + +VOID +inline +FASTCALL +KeInitializeDispatcher(VOID) +{ + /* Initialize the Dispatcher Lock */ + KeInitializeSpinLock(&DispatcherDatabaseLock); +} + +VOID +inline +FASTCALL +KeReleaseDispatcherDatabaseLock(KIRQL OldIrql) +{ + /* 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); + } +} + +VOID +inline +FASTCALL +KeReleaseDispatcherDatabaseLockFromDpcLevel(VOID) +{ + KeReleaseSpinLockFromDpcLevel(&DispatcherDatabaseLock); +} + +/* EOF */ diff --git a/reactos/ntoskrnl/ntoskrnl.def b/reactos/ntoskrnl/ntoskrnl.def index 461ebe6aa04..4063cc53e7b 100644 --- a/reactos/ntoskrnl/ntoskrnl.def +++ b/reactos/ntoskrnl/ntoskrnl.def @@ -122,7 +122,6 @@ ExIsResourceAcquiredExclusiveLite@4 ExIsResourceAcquiredSharedLite@4 ExLocalTimeToSystemTime@8 ExNotifyCallback@12 -ExPostSystemEvent@12 ExQueryPoolBlockSize@8 ExQueueWorkItem@8 ExRaiseAccessViolation@0 @@ -530,7 +529,7 @@ Ke386IoSetAccessProcess@8 Ke386QueryIoAccessMap@8 Ke386SetIoAccessMap@8 KeAcquireSpinLockAtDpcLevel@4 -KeAcquireDispatcherDatabaseLockAtDpcLevel +@KeAcquireDispatcherDatabaseLockAtDpcLevel@0 @KeAcquireInStackQueuedSpinLockAtDpcLevel@8 KeAcquireInterruptSpinLock@4 KeAddSystemServiceTable@20 @@ -611,7 +610,7 @@ KeReadStateSemaphore@4 KeReadStateTimer@4 KeRegisterBugCheckCallback@20 KeRegisterBugCheckReasonCallback@16 -KeReleaseDispatcherDatabaseLockFromDpcLevel +@KeReleaseDispatcherDatabaseLockFromDpcLevel@0 @KeReleaseInStackQueuedSpinLockFromDpcLevel@4 KeReleaseInterruptSpinLock@8 KeReleaseMutant@16 diff --git a/reactos/ntoskrnl/ntoskrnl.mc b/reactos/ntoskrnl/ntoskrnl.mc index 1458a0eca28..fafa73a6c3c 100644 --- a/reactos/ntoskrnl/ntoskrnl.mc +++ b/reactos/ntoskrnl/ntoskrnl.mc @@ -987,6 +987,22 @@ 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 new file mode 100644 index 00000000000..1b693c6ba6b --- /dev/null +++ b/reactos/ntoskrnl/ob/wait.c @@ -0,0 +1,300 @@ +/* + * 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 1837f096b5a..6344b7eb6d6 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; - KiDispatcherObjectWake(&CurrentThread->Tcb.DispatcherHeader, IO_NO_INCREMENT); + KiWaitTest(&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; - KiDispatcherObjectWake(&Process->Pcb.DispatcherHeader, IO_NO_INCREMENT); + KiWaitTest(&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 ac2f018c615..94d5f83e2df 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, - InternalProcessType, + ProcessObject, sizeof(EPROCESS), FALSE); KProcess = &PsInitialSystemProcess->Pcb; @@ -823,7 +823,7 @@ exitdereferenceobjects: } KeInitializeDispatcherHeader(&KProcess->DispatcherHeader, - InternalProcessType, + ProcessObject, sizeof(EPROCESS), FALSE); diff --git a/reactos/ntoskrnl/ps/thread.c b/reactos/ntoskrnl/ps/thread.c index ee9ad920917..4c21a919891 100644 --- a/reactos/ntoskrnl/ps/thread.c +++ b/reactos/ntoskrnl/ps/thread.c @@ -437,6 +437,7 @@ VOID PsDispatchThreadNoLock (ULONG NewThreadStatus) OldThread = CurrentThread; CurrentThread = Candidate; + IdleThread = KeGetCurrentKPCR()->PrcbData.IdleThread; if (&OldThread->Tcb == IdleThread) @@ -545,49 +546,46 @@ PsUnblockThread(PETHREAD Thread, PNTSTATUS WaitStatus, KPRIORITY Increment) } VOID -PsBlockThread(PNTSTATUS Status, UCHAR Alertable, ULONG WaitMode, - BOOLEAN DispatcherLock, KIRQL WaitIrql, UCHAR WaitReason) +STDCALL +PsBlockThread(PNTSTATUS Status, + UCHAR Alertable, + ULONG WaitMode, + UCHAR WaitReason) { - KIRQL oldIrql; - PKTHREAD KThread; - PETHREAD Thread; - PKWAIT_BLOCK WaitBlock; + PKTHREAD Thread = KeGetCurrentThread(); + PKWAIT_BLOCK WaitBlock; - if (!DispatcherLock) - { - oldIrql = KeAcquireDispatcherDatabaseLock(); + 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; } - - 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); + + DPRINT("Releasing Dispatcher Lock\n"); + KfLowerIrql(Thread->WaitIrql); } VOID @@ -1054,6 +1052,16 @@ 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 c56345c0f61..e7dfab08a70 100644 --- a/reactos/ntoskrnl/rtl/nls.c +++ b/reactos/ntoskrnl/rtl/nls.c @@ -36,7 +36,32 @@ 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 f52329eb239..7b76c796e9e 100644 --- a/reactos/tools/nci/sysfuncs.lst +++ b/reactos/tools/nci/sysfuncs.lst @@ -180,7 +180,6 @@ NtSetEaFile 4 NtSetEvent 2 NtSetHighEventPair 1 NtSetHighWaitLowEventPair 1 -NtSetHighWaitLowThread 0 NtSetInformationFile 5 NtSetInformationKey 4 NtSetInformationJobObject 4 @@ -192,7 +191,6 @@ NtSetIntervalProfile 2 NtSetLdtEntries 6 NtSetLowEventPair 1 NtSetLowWaitHighEventPair 1 -NtSetLowWaitHighThread 0 NtSetQuotaInformationFile 4 NtSetSecurityObject 3 NtSetSystemEnvironmentValue 2