windows-nt/Source/XPSP1/NT/base/ntos/po/poshtdwn.c
2020-09-26 16:20:57 +08:00

430 lines
10 KiB
C

/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
poshtdwn.c
Abstract:
Shutdown-related routines and structures
Author:
Rob Earhart (earhart) 01-Feb-2000
Revision History:
--*/
#include "pop.h"
#if DBG
BOOLEAN
PopDumpFileObject(
IN PVOID Object,
IN PUNICODE_STRING ObjectName,
IN ULONG HandleCount,
IN ULONG PointerCount,
IN PVOID Parameter
);
#endif
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, PopInitShutdownList)
#pragma alloc_text(PAGE, PoRequestShutdownEvent)
#pragma alloc_text(PAGE, PoRequestShutdownWait)
#pragma alloc_text(PAGE, PoQueueShutdownWorkItem)
#pragma alloc_text(PAGELK, PopGracefulShutdown)
#if DBG
#pragma alloc_text(PAGELK, PopDumpFileObject)
#endif
#endif
KEVENT PopShutdownEvent;
FAST_MUTEX PopShutdownListMutex;
#ifdef ALLOC_DATA_PRAGMA
#pragma data_seg("PAGEDATA")
#endif
BOOLEAN PopShutdownListAvailable = FALSE;
SINGLE_LIST_ENTRY PopShutdownThreadList;
LIST_ENTRY PopShutdownQueue;
typedef struct _PoShutdownThreadListEntry {
SINGLE_LIST_ENTRY ShutdownThreadList;
PETHREAD Thread;
} POSHUTDOWNLISTENTRY, *PPOSHUTDOWNLISTENTRY;
NTSTATUS
PopInitShutdownList(
VOID
)
{
PAGED_CODE();
KeInitializeEvent(&PopShutdownEvent,
NotificationEvent,
FALSE);
PopShutdownThreadList.Next = NULL;
InitializeListHead(&PopShutdownQueue);
ExInitializeFastMutex(&PopShutdownListMutex);
PopShutdownListAvailable = TRUE;
return STATUS_SUCCESS;
}
NTSTATUS
PoRequestShutdownWait(
IN PETHREAD Thread
)
{
PPOSHUTDOWNLISTENTRY Entry;
PAGED_CODE();
Entry = (PPOSHUTDOWNLISTENTRY)
ExAllocatePoolWithTag(PagedPool|POOL_COLD_ALLOCATION,
sizeof(POSHUTDOWNLISTENTRY),
'LSoP');
if (! Entry) {
return STATUS_NO_MEMORY;
}
Entry->Thread = Thread;
ObReferenceObject(Thread);
ExAcquireFastMutex(&PopShutdownListMutex);
if (! PopShutdownListAvailable) {
ObDereferenceObject(Thread);
ExFreePool(Entry);
ExReleaseFastMutex(&PopShutdownListMutex);
return STATUS_UNSUCCESSFUL;
}
PushEntryList(&PopShutdownThreadList,
&Entry->ShutdownThreadList);
ExReleaseFastMutex(&PopShutdownListMutex);
return STATUS_SUCCESS;
}
NTSTATUS
PoRequestShutdownEvent(
OUT PVOID *Event
)
{
NTSTATUS Status;
PAGED_CODE();
if (Event != NULL) {
*Event = NULL;
}
Status = PoRequestShutdownWait(PsGetCurrentThread());
if (!NT_SUCCESS(Status)) {
return Status;
}
if (Event != NULL) {
*Event = &PopShutdownEvent;
}
return STATUS_SUCCESS;
}
NTKERNELAPI
NTSTATUS
PoQueueShutdownWorkItem(
IN PWORK_QUEUE_ITEM WorkItem
)
{
NTSTATUS Status;
PAGED_CODE();
ExAcquireFastMutex(&PopShutdownListMutex);
if (PopShutdownListAvailable) {
InsertTailList(&PopShutdownQueue,
&WorkItem->List);
Status = STATUS_SUCCESS;
} else {
Status = STATUS_SYSTEM_SHUTDOWN;
}
ExReleaseFastMutex(&PopShutdownListMutex);
return Status;
}
#if DBG
extern POBJECT_TYPE IoFileObjectType;
BOOLEAN
PopDumpFileObject(
IN PVOID Object,
IN PUNICODE_STRING ObjectName,
IN ULONG HandleCount,
IN ULONG PointerCount,
IN PVOID Parameter
)
{
PFILE_OBJECT File;
PULONG NumberOfFilesFound;
UNREFERENCED_PARAMETER(ObjectName);
ASSERT(Object);
ASSERT(Parameter);
File = (PFILE_OBJECT) Object;
NumberOfFilesFound = (PULONG) Parameter;
++*NumberOfFilesFound;
DbgPrint("\t0x%0p : HC %d, PC %d, Name %.*ls\n",
Object, HandleCount, PointerCount,
File->FileName.Length,
File->FileName.Buffer);
return TRUE;
}
#endif // DBG
VOID
PopGracefulShutdown (
IN PVOID WorkItemParameter
)
/*++
Routine Description:
This function is only called as a HyperCritical work queue item.
It's responsible for gracefully shutting down the system.
Return Value:
This function never returns.
--*/
{
PVOID Context;
LARGE_INTEGER Timeout;
HANDLE ShutdownReqThreadHandle;
NTSTATUS Status;
UNREFERENCED_PARAMETER(WorkItemParameter);
//
// Shutdown executive components (there's no turning back after this).
//
PERFINFO_SHUTDOWN_LOG_LAST_MEMORY_SNAPSHOT();
if (!PopAction.ShutdownBugCode) {
HalEndOfBoot();
}
if (PoCleanShutdownEnabled()) {
//
// Terminate all processes. This will close all the handles and delete
// all the address spaces. Note the system process is kept alive.
//
PsShutdownSystem ();
//
// Notify every system thread that we're shutting things
// down...
//
KeSetEvent(&PopShutdownEvent, 0, FALSE);
//
// ... and give all threads which requested notification a
// chance to clean up and exit.
//
ExAcquireFastMutex(&PopShutdownListMutex);
PopShutdownListAvailable = FALSE;
ExReleaseFastMutex(&PopShutdownListMutex);
{
PLIST_ENTRY Next;
PWORK_QUEUE_ITEM WorkItem;
while (PopShutdownQueue.Flink != &PopShutdownQueue) {
Next = RemoveHeadList(&PopShutdownQueue);
WorkItem = CONTAINING_RECORD(Next,
WORK_QUEUE_ITEM,
List);
WorkItem->WorkerRoutine(WorkItem->Parameter);
}
}
{
PSINGLE_LIST_ENTRY Next;
PPOSHUTDOWNLISTENTRY ShutdownEntry;
while (TRUE) {
Next = PopEntryList(&PopShutdownThreadList);
if (! Next) {
break;
}
ShutdownEntry = CONTAINING_RECORD(Next,
POSHUTDOWNLISTENTRY,
ShutdownThreadList);
KeWaitForSingleObject(ShutdownEntry->Thread,
Executive,
KernelMode,
FALSE,
NULL);
ObDereferenceObject(ShutdownEntry->Thread);
ExFreePool(ShutdownEntry);
}
}
}
//
// Terminate Plug-N-Play.
//
PpShutdownSystem (TRUE, 0, &Context);
ExShutdownSystem (0);
//
// Send shutdown IRPs to all drivers that asked for it.
//
IoShutdownSystem (0);
if (PoCleanShutdownEnabled()) {
//
// Wait for all the user mode processes to exit.
//
PsWaitForAllProcesses ();
}
//
// Scrub the object directories
//
if (PoCleanShutdownEnabled() & PO_CLEAN_SHUTDOWN_OB) {
ObShutdownSystem (0);
}
//
// Close the registry and the associated handles/file objects.
//
CmShutdownSystem ();
//
// Check for open handles
//
if (PoCleanShutdownEnabled() & PO_CLEAN_SHUTDOWN_OB) {
ObShutdownSystem (1);
}
//
// This call to MmShutdownSystem will flush all the mapped data and empty
// the cache. This gets the data out and dereferences all the file objects
// so the drivers (ie: the network stack) can be cleanly unloaded.
// Note that the drivers in the paging path will (and must) remain as the
// pagefile handle has not yet been closed.
//
MmShutdownSystem (0);
//
// Inform drivers of the system shutdown state.
// This will finish shutting down Io and Mm.
// After this is complete,
// NO MORE REFERENCES TO PAGABLE CODE OR DATA MAY BE MADE.
//
// ISSUE-2000/03/14-earhart: shutdown filesystems in dev shutdown
IoConfigureCrashDump(CrashDumpDisable);
CcWaitForCurrentLazyWriterActivity();
ExShutdownSystem(1);
IoShutdownSystem(1);
MmShutdownSystem(1);
#if DBG
if (PoCleanShutdownEnabled()) {
ULONG NumberOfFilesFoundAtShutdown = 0;
// As of this time, no files should be open.
DbgPrint("Looking for open files...\n");
ObEnumerateObjectsByType(IoFileObjectType,
&PopDumpFileObject,
&NumberOfFilesFoundAtShutdown);
DbgPrint("Found %d open files.\n", NumberOfFilesFoundAtShutdown);
ASSERT(NumberOfFilesFoundAtShutdown == 0);
}
#endif
// This prevents us from making any more calls out to GDI.
PopFullWake = 0;
ASSERT(PopAction.DevState);
PopAction.DevState->Thread = KeGetCurrentThread();
PopSetDevicesSystemState(FALSE);
IoFreePoDeviceNotifyList(&PopAction.DevState->Order);
//
// Disable any wake alarms.
//
HalSetWakeEnable(FALSE);
//
// If this is a controlled shutdown bugcheck sequence, issue the
// bugcheck now
// ISSUE-2000/01/30-earhart Placement of ShutdownBugCode BugCheck
// I dislike the fact that we're doing this controlled shutdown
// bugcheck so late in the shutdown process; at this stage, too
// much state has been torn down for this to be really useful.
// Maybe if there's a debugger attached, we could shut down
// sooner...
if (PopAction.ShutdownBugCode) {
KeBugCheckEx (PopAction.ShutdownBugCode->Code,
PopAction.ShutdownBugCode->Parameter1,
PopAction.ShutdownBugCode->Parameter2,
PopAction.ShutdownBugCode->Parameter3,
PopAction.ShutdownBugCode->Parameter4);
}
PERFINFO_SHUTDOWN_DUMP_PERF_BUFFER();
PpShutdownSystem (TRUE, 1, &Context);
ExShutdownSystem (2);
if (PoCleanShutdownEnabled() & PO_CLEAN_SHUTDOWN_OB) {
ObShutdownSystem (2);
}
//
// Any allocated pool left at this point is a leak.
//
MmShutdownSystem (2);
//
// Implement shutdown style action -
// N.B. does not return (will bugcheck in preference to returning).
//
PopShutdownSystem(PopAction.Action);
}