Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

520 lines
13 KiB

/*++
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_PTR HandleCount,
IN ULONG_PTR 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;
KGUARDED_MUTEX PopShutdownListMutex;
#ifdef ALLOC_DATA_PRAGMA
#pragma data_seg("PAGEDATA")
#endif
BOOLEAN PopShutdownListAvailable = FALSE;
//
// This list will contain a set of threads that we need to wait
// for when we're about to shutdown.
//
SINGLE_LIST_ENTRY PopShutdownThreadList;
//
// List containing a set of worker routines that
// we need to process before we can shutdown the
// machine.
//
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);
KeInitializeGuardedMutex(&PopShutdownListMutex);
PopShutdownListAvailable = TRUE;
return STATUS_SUCCESS;
}
NTSTATUS
PoRequestShutdownWait(
IN PETHREAD Thread
)
/*++
Routine Description:
This function will add the caller's thread onto an internal
list that we'll wait for before we shutdown.
Arguments:
Thread - Pointer to the caller's thread.
Return Value:
NTSTATUS.
--*/
{
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);
KeAcquireGuardedMutex(&PopShutdownListMutex);
if (! PopShutdownListAvailable) {
ObDereferenceObject(Thread);
ExFreePool(Entry);
KeReleaseGuardedMutex(&PopShutdownListMutex);
return STATUS_UNSUCCESSFUL;
}
PushEntryList(&PopShutdownThreadList,
&Entry->ShutdownThreadList);
KeReleaseGuardedMutex(&PopShutdownListMutex);
return STATUS_SUCCESS;
}
NTSTATUS
PoRequestShutdownEvent(
OUT PVOID *Event OPTIONAL
)
/*++
Routine Description:
This function will add the caller's thread onto an internal
list that we'll wait for before we shutdown.
Arguments:
Event - If the parameter exists, it will recieve a pointer
to our PopShutdownEvent.
Return Value:
NTSTATUS.
--*/
{
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
)
/*++
Routine Description:
This function appends WorkItem onto our internal list of things
to run down when we're about to shutdown. Subsystems can use this
as a mechanism to get notified whey we're going down so they can do
any last minute cleanup.
Arguments:
WorkItem - Pointer to work item to be added onto our
list which will be run down before we shutdown.
Return Value:
NTSTATUS.
--*/
{
NTSTATUS Status;
PAGED_CODE();
ASSERT(WorkItem);
ASSERT(WorkItem->WorkerRoutine);
KeAcquireGuardedMutex(&PopShutdownListMutex);
if (PopShutdownListAvailable) {
InsertTailList(&PopShutdownQueue,
&WorkItem->List);
Status = STATUS_SUCCESS;
} else {
Status = STATUS_SYSTEM_SHUTDOWN;
}
KeReleaseGuardedMutex(&PopShutdownListMutex);
return Status;
}
#if DBG
extern POBJECT_TYPE IoFileObjectType;
BOOLEAN
PopDumpFileObject(
IN PVOID Object,
IN PUNICODE_STRING ObjectName,
IN ULONG_PTR HandleCount,
IN ULONG_PTR 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;
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.
//
KeAcquireGuardedMutex(&PopShutdownListMutex);
PopShutdownListAvailable = FALSE;
KeReleaseGuardedMutex(&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 first-chance 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 ();
//
// Swap in the worker threads, to keep them from paging
//
ExShutdownSystem(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. The
// pagefile handles are closed, however the file objects backing them are
// still referenced. Paging can continue, but no pagefile handles will
// exist in the system handle table.
//
MmShutdownSystem (0);
//
// Flush the lazy writer cache
//
CcWaitForCurrentLazyWriterActivity();
//
// Send out last-chance shutdown IRPs, including shutdown IRPs to
// filesystems. This is for notifications only - the filesystems are
// still active and usable after this call. It is expected however that
// no subsequent writes will be cached.
//
// ISSUE - 2002/02/21 - ADRIAO: Shutdown messages incomplete for filesystems
// Ideally we'd have a message to tell filesystems that the FS is no
// longer in use. However, this needs to be done on a *per-device* basis
// and ordering!
// The FS shutdown IRPs cannot be used in this fashion as filesystems
// only register once against their control objects for this message. A
// future solution might be to forward the powers IRP to mounted filesystems
// with the expectation that the bottom of the FS stack will forward the
// IRP back to the underlying storage stack. This would be symmetric with
// how removals work in PnP.
//
IoShutdownSystem(1);
//
// Push any lazy writes that snuck in before we shutdown the filesystem
// to the hardware.
//
CcWaitForCurrentLazyWriterActivity();
//
// This prevents us from making any more calls out to GDI.
//
PopFullWake = 0;
ASSERT(PopAction.DevState);
PopAction.DevState->Thread = KeGetCurrentThread();
//
// 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.
//
PopSetDevicesSystemState(FALSE);
#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
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);
}
#ifdef ALLOC_DATA_PRAGMA
#pragma data_seg()
#endif