ef369b7d0aac27b02a4dc23d941bea765c97728d
[reactos.git] / ntoskrnl / io / shutdown.c
1 /* $Id$
2  *
3  * COPYRIGHT:       See COPYING in the top level directory
4  * PROJECT:         ReactOS kernel
5  * FILE:            ntoskrnl/io/shutdown.c
6  * PURPOSE:         Implements shutdown notification
7  * PROGRAMMER:      David Welch (welch@mcmail.com)
8  * UPDATE HISTORY:
9  *                  Created 22/05/98
10  */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <ddk/ntddk.h>
15 #include <internal/pool.h>
16
17 #define NDEBUG
18 #include <internal/debug.h>
19
20 /* LOCAL DATA ***************************************************************/
21
22 typedef struct _SHUTDOWN_ENTRY
23 {
24    LIST_ENTRY ShutdownList;
25    PDEVICE_OBJECT DeviceObject;
26 } SHUTDOWN_ENTRY, *PSHUTDOWN_ENTRY;
27
28 static LIST_ENTRY ShutdownListHead;
29 static KSPIN_LOCK ShutdownListLock;
30
31 #define TAG_SHUTDOWN_ENTRY    TAG('S', 'H', 'U', 'T')
32
33 /* FUNCTIONS *****************************************************************/
34
35 VOID IoInitShutdownNotification (VOID)
36 {
37    InitializeListHead(&ShutdownListHead);
38    KeInitializeSpinLock(&ShutdownListLock);
39 }
40
41 VOID IoShutdownRegisteredDevices(VOID)
42 {
43    PSHUTDOWN_ENTRY ShutdownEntry;
44    PLIST_ENTRY Entry;
45    IO_STATUS_BLOCK StatusBlock;
46    PIRP Irp;
47    KEVENT Event;
48    NTSTATUS Status;
49
50    Entry = ShutdownListHead.Flink;
51    while (Entry != &ShutdownListHead)
52      {
53         ShutdownEntry = CONTAINING_RECORD(Entry, SHUTDOWN_ENTRY, ShutdownList);
54
55         KeInitializeEvent (&Event,
56                            NotificationEvent,
57                            FALSE);
58
59         Irp = IoBuildSynchronousFsdRequest (IRP_MJ_SHUTDOWN,
60                                             ShutdownEntry->DeviceObject,
61                                             NULL,
62                                             0,
63                                             NULL,
64                                             &Event,
65                                             &StatusBlock);
66
67         Status = IoCallDriver (ShutdownEntry->DeviceObject,
68                                Irp);
69         if (Status == STATUS_PENDING)
70         {
71                 KeWaitForSingleObject (&Event,
72                                        Executive,
73                                        KernelMode,
74                                        FALSE,
75                                        NULL);
76         }
77
78         Entry = Entry->Flink;
79      }
80 }
81
82 NTSTATUS STDCALL IoRegisterShutdownNotification(PDEVICE_OBJECT DeviceObject)
83 {
84    PSHUTDOWN_ENTRY Entry;
85
86    Entry = ExAllocatePoolWithTag(NonPagedPool, sizeof(SHUTDOWN_ENTRY),
87                                  TAG_SHUTDOWN_ENTRY);
88    if (Entry == NULL)
89      return STATUS_INSUFFICIENT_RESOURCES;
90
91    Entry->DeviceObject = DeviceObject;
92
93    ExInterlockedInsertHeadList(&ShutdownListHead,
94                                &Entry->ShutdownList,
95                                &ShutdownListLock);
96
97    DeviceObject->Flags |= DO_SHUTDOWN_REGISTERED;
98
99    return STATUS_SUCCESS;
100 }
101
102 VOID STDCALL IoUnregisterShutdownNotification(PDEVICE_OBJECT DeviceObject)
103 {
104    PSHUTDOWN_ENTRY ShutdownEntry;
105    PLIST_ENTRY Entry;
106    KIRQL oldlvl;
107
108    Entry = ShutdownListHead.Flink;
109    while (Entry != &ShutdownListHead)
110      {
111         ShutdownEntry = CONTAINING_RECORD(Entry, SHUTDOWN_ENTRY, ShutdownList);
112         if (ShutdownEntry->DeviceObject == DeviceObject)
113           {
114             DeviceObject->Flags &= ~DO_SHUTDOWN_REGISTERED;
115
116             KeAcquireSpinLock(&ShutdownListLock,&oldlvl);
117             RemoveEntryList(Entry);
118             KeReleaseSpinLock(&ShutdownListLock,oldlvl);
119
120             ExFreePool(Entry);
121             return;
122           }
123
124         Entry = Entry->Flink;
125      }
126 }
127
128 /* EOF */