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

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. poshtdwn.c
  5. Abstract:
  6. Shutdown-related routines and structures
  7. Author:
  8. Rob Earhart (earhart) 01-Feb-2000
  9. Revision History:
  10. --*/
  11. #include "pop.h"
  12. #if DBG
  13. BOOLEAN
  14. PopDumpFileObject(
  15. IN PVOID Object,
  16. IN PUNICODE_STRING ObjectName,
  17. IN ULONG_PTR HandleCount,
  18. IN ULONG_PTR PointerCount,
  19. IN PVOID Parameter
  20. );
  21. #endif
  22. #ifdef ALLOC_PRAGMA
  23. #pragma alloc_text(INIT, PopInitShutdownList)
  24. #pragma alloc_text(PAGE, PoRequestShutdownEvent)
  25. #pragma alloc_text(PAGE, PoRequestShutdownWait)
  26. #pragma alloc_text(PAGE, PoQueueShutdownWorkItem)
  27. #pragma alloc_text(PAGELK, PopGracefulShutdown)
  28. #if DBG
  29. #pragma alloc_text(PAGELK, PopDumpFileObject)
  30. #endif
  31. #endif
  32. KEVENT PopShutdownEvent;
  33. KGUARDED_MUTEX PopShutdownListMutex;
  34. #ifdef ALLOC_DATA_PRAGMA
  35. #pragma data_seg("PAGEDATA")
  36. #endif
  37. BOOLEAN PopShutdownListAvailable = FALSE;
  38. //
  39. // This list will contain a set of threads that we need to wait
  40. // for when we're about to shutdown.
  41. //
  42. SINGLE_LIST_ENTRY PopShutdownThreadList;
  43. //
  44. // List containing a set of worker routines that
  45. // we need to process before we can shutdown the
  46. // machine.
  47. //
  48. LIST_ENTRY PopShutdownQueue;
  49. typedef struct _PoShutdownThreadListEntry {
  50. SINGLE_LIST_ENTRY ShutdownThreadList;
  51. PETHREAD Thread;
  52. } POSHUTDOWNLISTENTRY, *PPOSHUTDOWNLISTENTRY;
  53. NTSTATUS
  54. PopInitShutdownList(
  55. VOID
  56. )
  57. {
  58. PAGED_CODE();
  59. KeInitializeEvent(&PopShutdownEvent,
  60. NotificationEvent,
  61. FALSE);
  62. PopShutdownThreadList.Next = NULL;
  63. InitializeListHead(&PopShutdownQueue);
  64. KeInitializeGuardedMutex(&PopShutdownListMutex);
  65. PopShutdownListAvailable = TRUE;
  66. return STATUS_SUCCESS;
  67. }
  68. NTSTATUS
  69. PoRequestShutdownWait(
  70. IN PETHREAD Thread
  71. )
  72. /*++
  73. Routine Description:
  74. This function will add the caller's thread onto an internal
  75. list that we'll wait for before we shutdown.
  76. Arguments:
  77. Thread - Pointer to the caller's thread.
  78. Return Value:
  79. NTSTATUS.
  80. --*/
  81. {
  82. PPOSHUTDOWNLISTENTRY Entry;
  83. PAGED_CODE();
  84. Entry = (PPOSHUTDOWNLISTENTRY)
  85. ExAllocatePoolWithTag(PagedPool|POOL_COLD_ALLOCATION,
  86. sizeof(POSHUTDOWNLISTENTRY),
  87. 'LSoP');
  88. if (! Entry) {
  89. return STATUS_NO_MEMORY;
  90. }
  91. Entry->Thread = Thread;
  92. ObReferenceObject(Thread);
  93. KeAcquireGuardedMutex(&PopShutdownListMutex);
  94. if (! PopShutdownListAvailable) {
  95. ObDereferenceObject(Thread);
  96. ExFreePool(Entry);
  97. KeReleaseGuardedMutex(&PopShutdownListMutex);
  98. return STATUS_UNSUCCESSFUL;
  99. }
  100. PushEntryList(&PopShutdownThreadList,
  101. &Entry->ShutdownThreadList);
  102. KeReleaseGuardedMutex(&PopShutdownListMutex);
  103. return STATUS_SUCCESS;
  104. }
  105. NTSTATUS
  106. PoRequestShutdownEvent(
  107. OUT PVOID *Event OPTIONAL
  108. )
  109. /*++
  110. Routine Description:
  111. This function will add the caller's thread onto an internal
  112. list that we'll wait for before we shutdown.
  113. Arguments:
  114. Event - If the parameter exists, it will recieve a pointer
  115. to our PopShutdownEvent.
  116. Return Value:
  117. NTSTATUS.
  118. --*/
  119. {
  120. NTSTATUS Status;
  121. PAGED_CODE();
  122. if (Event != NULL) {
  123. *Event = NULL;
  124. }
  125. Status = PoRequestShutdownWait(PsGetCurrentThread());
  126. if (!NT_SUCCESS(Status)) {
  127. return Status;
  128. }
  129. if (Event != NULL) {
  130. *Event = &PopShutdownEvent;
  131. }
  132. return STATUS_SUCCESS;
  133. }
  134. NTKERNELAPI
  135. NTSTATUS
  136. PoQueueShutdownWorkItem(
  137. IN PWORK_QUEUE_ITEM WorkItem
  138. )
  139. /*++
  140. Routine Description:
  141. This function appends WorkItem onto our internal list of things
  142. to run down when we're about to shutdown. Subsystems can use this
  143. as a mechanism to get notified whey we're going down so they can do
  144. any last minute cleanup.
  145. Arguments:
  146. WorkItem - Pointer to work item to be added onto our
  147. list which will be run down before we shutdown.
  148. Return Value:
  149. NTSTATUS.
  150. --*/
  151. {
  152. NTSTATUS Status;
  153. PAGED_CODE();
  154. ASSERT(WorkItem);
  155. ASSERT(WorkItem->WorkerRoutine);
  156. KeAcquireGuardedMutex(&PopShutdownListMutex);
  157. if (PopShutdownListAvailable) {
  158. InsertTailList(&PopShutdownQueue,
  159. &WorkItem->List);
  160. Status = STATUS_SUCCESS;
  161. } else {
  162. Status = STATUS_SYSTEM_SHUTDOWN;
  163. }
  164. KeReleaseGuardedMutex(&PopShutdownListMutex);
  165. return Status;
  166. }
  167. #if DBG
  168. extern POBJECT_TYPE IoFileObjectType;
  169. BOOLEAN
  170. PopDumpFileObject(
  171. IN PVOID Object,
  172. IN PUNICODE_STRING ObjectName,
  173. IN ULONG_PTR HandleCount,
  174. IN ULONG_PTR PointerCount,
  175. IN PVOID Parameter
  176. )
  177. {
  178. PFILE_OBJECT File;
  179. PULONG NumberOfFilesFound;
  180. UNREFERENCED_PARAMETER(ObjectName);
  181. ASSERT(Object);
  182. ASSERT(Parameter);
  183. File = (PFILE_OBJECT) Object;
  184. NumberOfFilesFound = (PULONG) Parameter;
  185. ++*NumberOfFilesFound;
  186. DbgPrint("\t0x%0p : HC %d, PC %d, Name %.*ls\n",
  187. Object, HandleCount, PointerCount,
  188. File->FileName.Length,
  189. File->FileName.Buffer);
  190. return TRUE;
  191. }
  192. #endif // DBG
  193. VOID
  194. PopGracefulShutdown (
  195. IN PVOID WorkItemParameter
  196. )
  197. /*++
  198. Routine Description:
  199. This function is only called as a HyperCritical work queue item.
  200. It's responsible for gracefully shutting down the system.
  201. Return Value:
  202. This function never returns.
  203. --*/
  204. {
  205. PVOID Context;
  206. UNREFERENCED_PARAMETER(WorkItemParameter);
  207. //
  208. // Shutdown executive components (there's no turning back after this).
  209. //
  210. PERFINFO_SHUTDOWN_LOG_LAST_MEMORY_SNAPSHOT();
  211. if (!PopAction.ShutdownBugCode) {
  212. HalEndOfBoot();
  213. }
  214. if (PoCleanShutdownEnabled()) {
  215. //
  216. // Terminate all processes. This will close all the handles and delete
  217. // all the address spaces. Note the system process is kept alive.
  218. //
  219. PsShutdownSystem ();
  220. //
  221. // Notify every system thread that we're shutting things
  222. // down...
  223. //
  224. KeSetEvent(&PopShutdownEvent, 0, FALSE);
  225. //
  226. // ... and give all threads which requested notification a
  227. // chance to clean up and exit.
  228. //
  229. KeAcquireGuardedMutex(&PopShutdownListMutex);
  230. PopShutdownListAvailable = FALSE;
  231. KeReleaseGuardedMutex(&PopShutdownListMutex);
  232. {
  233. PLIST_ENTRY Next;
  234. PWORK_QUEUE_ITEM WorkItem;
  235. while (PopShutdownQueue.Flink != &PopShutdownQueue) {
  236. Next = RemoveHeadList(&PopShutdownQueue);
  237. WorkItem = CONTAINING_RECORD(Next,
  238. WORK_QUEUE_ITEM,
  239. List);
  240. WorkItem->WorkerRoutine(WorkItem->Parameter);
  241. }
  242. }
  243. {
  244. PSINGLE_LIST_ENTRY Next;
  245. PPOSHUTDOWNLISTENTRY ShutdownEntry;
  246. while (TRUE) {
  247. Next = PopEntryList(&PopShutdownThreadList);
  248. if (! Next) {
  249. break;
  250. }
  251. ShutdownEntry = CONTAINING_RECORD(Next,
  252. POSHUTDOWNLISTENTRY,
  253. ShutdownThreadList);
  254. KeWaitForSingleObject(ShutdownEntry->Thread,
  255. Executive,
  256. KernelMode,
  257. FALSE,
  258. NULL);
  259. ObDereferenceObject(ShutdownEntry->Thread);
  260. ExFreePool(ShutdownEntry);
  261. }
  262. }
  263. }
  264. //
  265. // Terminate Plug-N-Play.
  266. //
  267. PpShutdownSystem (TRUE, 0, &Context);
  268. ExShutdownSystem (0);
  269. //
  270. // Send first-chance shutdown IRPs to all drivers that asked for it.
  271. //
  272. IoShutdownSystem (0);
  273. if (PoCleanShutdownEnabled()) {
  274. //
  275. // Wait for all the user mode processes to exit.
  276. //
  277. PsWaitForAllProcesses ();
  278. }
  279. //
  280. // Scrub the object directories
  281. //
  282. if (PoCleanShutdownEnabled() & PO_CLEAN_SHUTDOWN_OB) {
  283. ObShutdownSystem (0);
  284. }
  285. //
  286. // Close the registry and the associated handles/file objects.
  287. //
  288. CmShutdownSystem ();
  289. //
  290. // Swap in the worker threads, to keep them from paging
  291. //
  292. ExShutdownSystem(1);
  293. //
  294. // This call to MmShutdownSystem will flush all the mapped data and empty
  295. // the cache. This gets the data out and dereferences all the file objects
  296. // so the drivers (ie: the network stack) can be cleanly unloaded. The
  297. // pagefile handles are closed, however the file objects backing them are
  298. // still referenced. Paging can continue, but no pagefile handles will
  299. // exist in the system handle table.
  300. //
  301. MmShutdownSystem (0);
  302. //
  303. // Flush the lazy writer cache
  304. //
  305. CcWaitForCurrentLazyWriterActivity();
  306. //
  307. // Send out last-chance shutdown IRPs, including shutdown IRPs to
  308. // filesystems. This is for notifications only - the filesystems are
  309. // still active and usable after this call. It is expected however that
  310. // no subsequent writes will be cached.
  311. //
  312. // ISSUE - 2002/02/21 - ADRIAO: Shutdown messages incomplete for filesystems
  313. // Ideally we'd have a message to tell filesystems that the FS is no
  314. // longer in use. However, this needs to be done on a *per-device* basis
  315. // and ordering!
  316. // The FS shutdown IRPs cannot be used in this fashion as filesystems
  317. // only register once against their control objects for this message. A
  318. // future solution might be to forward the powers IRP to mounted filesystems
  319. // with the expectation that the bottom of the FS stack will forward the
  320. // IRP back to the underlying storage stack. This would be symmetric with
  321. // how removals work in PnP.
  322. //
  323. IoShutdownSystem(1);
  324. //
  325. // Push any lazy writes that snuck in before we shutdown the filesystem
  326. // to the hardware.
  327. //
  328. CcWaitForCurrentLazyWriterActivity();
  329. //
  330. // This prevents us from making any more calls out to GDI.
  331. //
  332. PopFullWake = 0;
  333. ASSERT(PopAction.DevState);
  334. PopAction.DevState->Thread = KeGetCurrentThread();
  335. //
  336. // Inform drivers of the system shutdown state.
  337. // This will finish shutting down Io and Mm.
  338. // After this is complete,
  339. // NO MORE REFERENCES TO PAGABLE CODE OR DATA MAY BE MADE.
  340. //
  341. PopSetDevicesSystemState(FALSE);
  342. #if DBG
  343. if (PoCleanShutdownEnabled()) {
  344. ULONG NumberOfFilesFoundAtShutdown = 0;
  345. // As of this time, no files should be open.
  346. DbgPrint("Looking for open files...\n");
  347. ObEnumerateObjectsByType(IoFileObjectType,
  348. &PopDumpFileObject,
  349. &NumberOfFilesFoundAtShutdown);
  350. DbgPrint("Found %d open files.\n", NumberOfFilesFoundAtShutdown);
  351. ASSERT(NumberOfFilesFoundAtShutdown == 0);
  352. }
  353. #endif
  354. IoFreePoDeviceNotifyList(&PopAction.DevState->Order);
  355. //
  356. // Disable any wake alarms.
  357. //
  358. HalSetWakeEnable(FALSE);
  359. //
  360. // If this is a controlled shutdown bugcheck sequence, issue the
  361. // bugcheck now
  362. // ISSUE-2000/01/30-earhart Placement of ShutdownBugCode BugCheck
  363. // I dislike the fact that we're doing this controlled shutdown
  364. // bugcheck so late in the shutdown process; at this stage, too
  365. // much state has been torn down for this to be really useful.
  366. // Maybe if there's a debugger attached, we could shut down
  367. // sooner...
  368. if (PopAction.ShutdownBugCode) {
  369. KeBugCheckEx (PopAction.ShutdownBugCode->Code,
  370. PopAction.ShutdownBugCode->Parameter1,
  371. PopAction.ShutdownBugCode->Parameter2,
  372. PopAction.ShutdownBugCode->Parameter3,
  373. PopAction.ShutdownBugCode->Parameter4);
  374. }
  375. PERFINFO_SHUTDOWN_DUMP_PERF_BUFFER();
  376. PpShutdownSystem (TRUE, 1, &Context);
  377. ExShutdownSystem (2);
  378. if (PoCleanShutdownEnabled() & PO_CLEAN_SHUTDOWN_OB) {
  379. ObShutdownSystem (2);
  380. }
  381. //
  382. // Any allocated pool left at this point is a leak.
  383. //
  384. MmShutdownSystem (2);
  385. //
  386. // Implement shutdown style action -
  387. // N.B. does not return (will bugcheck in preference to returning).
  388. //
  389. PopShutdownSystem(PopAction.Action);
  390. }
  391. #ifdef ALLOC_DATA_PRAGMA
  392. #pragma data_seg()
  393. #endif