diff --git a/reactos/ntoskrnl/include/internal/po.h b/reactos/ntoskrnl/include/internal/po.h index 11891202787..aa9a3c7d075 100644 --- a/reactos/ntoskrnl/include/internal/po.h +++ b/reactos/ntoskrnl/include/internal/po.h @@ -240,7 +240,7 @@ typedef struct _POWER_CHANNEL_SUMMARY ULONG D0Count; LIST_ENTRY NotifyList; } POWER_CHANNEL_SUMMARY, *PPOWER_CHANNEL_SUMMARY; - + typedef struct _DEVICE_OBJECT_POWER_EXTENSION { ULONG IdleCount; @@ -255,6 +255,12 @@ typedef struct _DEVICE_OBJECT_POWER_EXTENSION LIST_ENTRY Volume; } DEVICE_OBJECT_POWER_EXTENSION, *PDEVICE_OBJECT_POWER_EXTENSION; +typedef struct _POP_SHUTDOWN_WAIT_ENTRY +{ + struct _POP_SHUTDOWN_WAIT_ENTRY *NextEntry; + PETHREAD Thread; +} POP_SHUTDOWN_WAIT_ENTRY, *PPOP_SHUTDOWN_WAIT_ENTRY; + // // Initialization routines // @@ -270,6 +276,12 @@ PoInitializePrcb( IN PKPRCB Prcb ); +VOID +NTAPI +PopInitShutdownList( + VOID +); + // // I/O Routines // diff --git a/reactos/ntoskrnl/po/poshtdwn.c b/reactos/ntoskrnl/po/poshtdwn.c index 589779a5973..ea2557b7092 100644 --- a/reactos/ntoskrnl/po/poshtdwn.c +++ b/reactos/ntoskrnl/po/poshtdwn.c @@ -18,16 +18,137 @@ /* GLOBALS *******************************************************************/ ULONG PopShutdownPowerOffPolicy; +KEVENT PopShutdownEvent; +PPOP_SHUTDOWN_WAIT_ENTRY PopShutdownThreadList; +LIST_ENTRY PopShutdownQueue; +KGUARDED_MUTEX PopShutdownListMutex; +BOOLEAN PopShutdownListAvailable; + /* PRIVATE FUNCTIONS *********************************************************/ +VOID +NTAPI +PopInitShutdownList(VOID) +{ + PAGED_CODE(); + + /* Initialize the global shutdown event */ + KeInitializeEvent(&PopShutdownEvent, NotificationEvent, FALSE); + + /* Initialize the shutdown lists */ + PopShutdownThreadList = NULL; + InitializeListHead(&PopShutdownQueue); + + /* Initialize the shutdown list lock */ + KeInitializeGuardedMutex(&PopShutdownListMutex); + + /* The list is available now */ + PopShutdownListAvailable = TRUE; +} + +NTSTATUS +NTAPI +PoRequestShutdownWait( + _In_ PETHREAD Thread) +{ + PPOP_SHUTDOWN_WAIT_ENTRY ShutDownWaitEntry; + NTSTATUS Status; + PAGED_CODE(); + + /* Allocate a new shutdown wait entry */ + ShutDownWaitEntry = ExAllocatePoolWithTag(PagedPool, 8u, 'LSoP'); + if (ShutDownWaitEntry == NULL) + { + return STATUS_NO_MEMORY; + } + + /* Reference the thread and save it in the wait entry */ + ObReferenceObject(Thread); + ShutDownWaitEntry->Thread = Thread; + + /* Acquire the shutdown list lock */ + KeAcquireGuardedMutex(&PopShutdownListMutex); + + /* Check if the list is still available */ + if (PopShutdownListAvailable) + { + /* Insert the item in the list */ + ShutDownWaitEntry->NextEntry = PopShutdownThreadList; + PopShutdownThreadList = ShutDownWaitEntry; + + /* We are successful */ + Status = STATUS_SUCCESS; + } + else + { + /* We cannot proceed, cleanup and return failure */ + ObDereferenceObject(Thread); + ExFreePoolWithTag(ShutDownWaitEntry, 0); + Status = STATUS_UNSUCCESSFUL; + } + + /* Release the list lock */ + KeReleaseGuardedMutex(&PopShutdownListMutex); + + /* Return the status */ + return Status; +} + +VOID +NTAPI +PopProcessShutDownLists(VOID) +{ + PPOP_SHUTDOWN_WAIT_ENTRY ShutDownWaitEntry; + PWORK_QUEUE_ITEM WorkItem; + PLIST_ENTRY ListEntry; + + /* First signal the shutdown event */ + KeSetEvent(&PopShutdownEvent, IO_NO_INCREMENT, FALSE); + + /* Acquire the shutdown list lock */ + KeAcquireGuardedMutex(&PopShutdownListMutex); + + /* Block any further attempts to register a shutdown event */ + PopShutdownListAvailable = FALSE; + + /* Release the list lock, since we are exclusively using the lists now */ + KeReleaseGuardedMutex(&PopShutdownListMutex); + + /* Process the shutdown queue */ + while (!IsListEmpty(&PopShutdownQueue)) + { + /* Get the head entry */ + ListEntry = RemoveHeadList(&PopShutdownQueue); + WorkItem = CONTAINING_RECORD(ListEntry, WORK_QUEUE_ITEM, List); + + /* Call the shutdown worker routine */ + WorkItem->WorkerRoutine(WorkItem->Parameter); + } + + /* Now process the shutdown thread list */ + while (PopShutdownThreadList != NULL) + { + /* Get the top entry and remove it from the list */ + ShutDownWaitEntry = PopShutdownThreadList; + PopShutdownThreadList = PopShutdownThreadList->NextEntry; + + /* Wait for the thread to finish and dereference it */ + KeWaitForSingleObject(ShutDownWaitEntry->Thread, 0, 0, 0, 0); + ObfDereferenceObject(ShutDownWaitEntry->Thread); + + /* Finally free the entry */ + ExFreePoolWithTag(ShutDownWaitEntry, 0); + } +} + VOID NTAPI PopShutdownHandler(VOID) { PUCHAR Logo1, Logo2; ULONG i; - + /* Stop all interrupts */ KeRaiseIrqlToDpcLevel(); _disable(); @@ -72,7 +193,7 @@ PopShutdownSystem(IN POWER_ACTION SystemAction) /* Unload symbols */ DPRINT1("It's the final countdown...%lx\n", SystemAction); DbgUnLoadImageSymbols(NULL, (PVOID)-1, 0); - + /* Run the thread on the boot processor */ KeSetSystemAffinityThread(1); @@ -101,7 +222,7 @@ PopShutdownSystem(IN POWER_ACTION SystemAction) /* Call shutdown handler */ //PopInvokeSystemStateHandler(PowerStateShutdownOff, NULL); - + /* ReactOS Hack */ PopSetSystemPowerState(PowerSystemShutdown, SystemAction); PopShutdownHandler(); @@ -124,6 +245,9 @@ PopGracefulShutdown(IN PVOID Context) { PEPROCESS Process = NULL; + /* Process the registered waits and work items */ + PopProcessShutDownLists(); + /* Loop every process */ Process = PsGetNextProcess(Process); while (Process) @@ -144,13 +268,13 @@ PopGracefulShutdown(IN PVOID Context) HalEndOfBoot(); /* In this step, the I/O manager does first-chance shutdown notification */ - DPRINT1("I/O manager shutting down in phase 0\n"); + DPRINT1("I/O manager shutting down in phase 0\n"); IoShutdownSystem(0); - + /* In this step, all workers are killed and hives are flushed */ DPRINT1("Configuration Manager shutting down\n"); CmShutdownSystem(); - + /* Note that modified pages should be written here (MiShutdownSystem) */ #ifdef NEWCC /* Flush all user files before we start shutting down IO */ @@ -159,7 +283,7 @@ PopGracefulShutdown(IN PVOID Context) #endif /* In this step, the I/O manager does last-chance shutdown notification */ - DPRINT1("I/O manager shutting down in phase 1\n"); + DPRINT1("I/O manager shutting down in phase 1\n"); IoShutdownSystem(1); CcWaitForCurrentLazyWriterActivity(); @@ -168,7 +292,7 @@ PopGracefulShutdown(IN PVOID Context) /* In this step, the HAL disables any wake timers */ DPRINT1("Disabling wake timers\n"); HalSetWakeEnable(FALSE); - + /* And finally the power request is sent */ DPRINT1("Taking the system down\n"); PopShutdownSystem(PopAction.Action); @@ -185,7 +309,7 @@ PopReadShutdownPolicy(VOID) ULONG Length; UCHAR Buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG)]; PKEY_VALUE_PARTIAL_INFORMATION Info = (PVOID)Buffer; - + /* Setup object attributes */ RtlInitUnicodeString(&KeyString, L"\\Registry\\Machine\\Software\\Policies\\Microsoft\\Windows NT"); @@ -220,3 +344,60 @@ PopReadShutdownPolicy(VOID) /* PUBLIC FUNCTIONS **********************************************************/ +/* + * @unimplemented + */ +NTSTATUS +NTAPI +PoQueueShutdownWorkItem( + _In_ PWORK_QUEUE_ITEM WorkItem) +{ + NTSTATUS Status; + + /* Acquire the shutdown list lock */ + KeAcquireGuardedMutex(&PopShutdownListMutex); + + /* Check if the list is (already/still) available */ + if (PopShutdownListAvailable) + { + /* Insert the item into the list */ + InsertTailList(&PopShutdownQueue, &WorkItem->List); + Status = STATUS_SUCCESS; + } + else + { + /* We are already in shutdown */ + Status = STATUS_SYSTEM_SHUTDOWN; + } + + /* Release the list lock */ + KeReleaseGuardedMutex(&PopShutdownListMutex); + + return Status; +} + +/* + * @implemented + */ +NTSTATUS +NTAPI +PoRequestShutdownEvent(OUT PVOID *Event) +{ + NTSTATUS Status; + PAGED_CODE(); + + /* Initialize to NULL */ + if (Event) *Event = NULL; + + /* Request a shutdown wait */ + Status = PoRequestShutdownWait(PsGetCurrentThread()); + if (!NT_SUCCESS(Status)) + { + return Status; + } + + /* Return the global shutdown event */ + if (Event) *Event = &PopShutdownEvent; + return STATUS_SUCCESS; +} + diff --git a/reactos/ntoskrnl/po/power.c b/reactos/ntoskrnl/po/power.c index 88df5846a98..3b9e58c41c3 100644 --- a/reactos/ntoskrnl/po/power.c +++ b/reactos/ntoskrnl/po/power.c @@ -344,6 +344,10 @@ PoInitSystem(IN ULONG BootPhase) /* Initialize support for dope */ KeInitializeSpinLock(&PopDopeGlobalLock); + + /* Initialize support for shutdown waits and work-items */ + PopInitShutdownList(); + return TRUE; } @@ -445,17 +449,6 @@ PoShutdownBugCheck(IN BOOLEAN LogError, BugCheckParameter4); } -/* - * @unimplemented - */ -NTSTATUS -NTAPI -PoRequestShutdownEvent(OUT PVOID *Event) -{ - UNIMPLEMENTED; - return STATUS_NOT_IMPLEMENTED; -} - /* * @unimplemented */ @@ -637,19 +630,6 @@ PoUnregisterSystemState(IN PVOID StateHandle) UNIMPLEMENTED; } -/* - * @unimplemented - */ -NTSTATUS -NTAPI -PoQueueShutdownWorkItem(IN PWORK_QUEUE_ITEM WorkItem) -{ - PAGED_CODE(); - - UNIMPLEMENTED; - return STATUS_NOT_IMPLEMENTED; -} - /* * @unimplemented */