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.

866 lines
19 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. pwork.c
  5. Abstract:
  6. Main work dispatcher in the power policy manager
  7. Author:
  8. Ken Reneris (kenr) 17-Jan-1997
  9. Revision History:
  10. --*/
  11. #include "pop.h"
  12. #ifdef ALLOC_PRAGMA
  13. #pragma alloc_text(PAGE, PopAcquirePolicyLock)
  14. #pragma alloc_text(PAGE, PopReleasePolicyLock)
  15. #pragma alloc_text(PAGE, PopPolicyWorkerMain)
  16. #pragma alloc_text(PAGE, PopPolicyWorkerNotify)
  17. #pragma alloc_text(PAGE, PopPolicyTimeChange)
  18. #pragma alloc_text(PAGE, PopDispatchCallout)
  19. #pragma alloc_text(PAGE, PopDispatchCallback)
  20. #pragma alloc_text(PAGE, PopDispatchDisplayRequired)
  21. #pragma alloc_text(PAGE, PopDispatchFullWake)
  22. #pragma alloc_text(PAGE, PopDispatchEventCodes)
  23. #pragma alloc_text(PAGE, PopDispatchAcDcCallback)
  24. #pragma alloc_text(PAGE, PopDispatchPolicyCallout)
  25. #pragma alloc_text(PAGE, PopDispatchSetStateFailure)
  26. #endif
  27. VOID
  28. PopAcquirePolicyLock(
  29. VOID
  30. )
  31. {
  32. PAGED_CODE();
  33. KeEnterCriticalRegion();
  34. ExAcquireResourceExclusiveLite (&PopPolicyLock, TRUE);
  35. //
  36. // Make sure we are not acquiring this recursively
  37. //
  38. ASSERT(PopPolicyLockThread == NULL);
  39. PopPolicyLockThread = KeGetCurrentThread();
  40. }
  41. VOID
  42. PopReleasePolicyLock(
  43. IN BOOLEAN CheckForWork
  44. )
  45. {
  46. PAGED_CODE();
  47. ASSERT (PopPolicyLockThread == KeGetCurrentThread());
  48. PopPolicyLockThread = NULL;
  49. ExReleaseResourceLite(&PopPolicyLock);
  50. //
  51. // If CheckForWork is set, then this thread is about ready
  52. // to leave the policy manager and it may have set a worker
  53. // pending bit.
  54. //
  55. // N.B. the WorkerPending test is not synchronized, but
  56. // since we're only concered with bits the current thread
  57. // may have set that's OK.
  58. //
  59. if (CheckForWork && (PopWorkerPending & PopWorkerStatus)) {
  60. //
  61. // Worker bit is unmasked and pending. Turn this thread
  62. // into a worker.
  63. //
  64. //
  65. // Handle any pending work
  66. //
  67. PopPolicyWorkerThread (NULL);
  68. }
  69. KeLeaveCriticalRegion ();
  70. }
  71. VOID
  72. PopGetPolicyWorker (
  73. IN ULONG WorkerType
  74. )
  75. /*++
  76. Routine Description:
  77. This function enqueus a worker thread for the particular WorkerType.
  78. At a maximum one worker thread per type may be dispatched, and typically
  79. fewer threads are actually dispatched as any given worker thread will
  80. call the new highest priority non-busy dispatch function until all
  81. pending work is completed before existing.
  82. Arguments:
  83. WorkerType - Which worker to enqueue for dispatching
  84. Return Value:
  85. None
  86. --*/
  87. {
  88. KIRQL OldIrql;
  89. KeAcquireSpinLock (&PopWorkerSpinLock, &OldIrql);
  90. //
  91. // Set pending to get worker to dispatch to handler
  92. //
  93. PopWorkerPending |= WorkerType;
  94. KeReleaseSpinLock (&PopWorkerSpinLock, OldIrql);
  95. }
  96. NTSTATUS
  97. PopCompletePolicyIrp (
  98. IN PDEVICE_OBJECT DeviceObject,
  99. IN PIRP Irp,
  100. IN PVOID Context
  101. )
  102. /*++
  103. Routine Description:
  104. This function handles the completion of a policy manager IRP.
  105. Policy manager IRPs have a stack location containing the irp
  106. handler function to dispatch too. In this function the irp is
  107. queue to the irp complete queue and a main worker is allocated
  108. if needed to run the queue.
  109. Arguments:
  110. DeviceObject -
  111. Irp - The irp which has completed
  112. Context -
  113. Return Value:
  114. STATUS_MORE_PROCESSING_REQUIRED
  115. --*/
  116. {
  117. KIRQL OldIrql;
  118. UNREFERENCED_PARAMETER (DeviceObject);
  119. UNREFERENCED_PARAMETER (Context);
  120. //
  121. // Put the irp on a queue for a worker thread
  122. //
  123. KeAcquireSpinLock (&PopWorkerSpinLock, &OldIrql);
  124. InsertTailList (&PopPolicyIrpQueue, &Irp->Tail.Overlay.ListEntry);
  125. //
  126. // Wait until base drivers are loaded before dispatching any policy irps
  127. //
  128. if (PopDispatchPolicyIrps) {
  129. //
  130. // Set pending to get worker to dispatch to handler
  131. //
  132. PopWorkerPending |= PO_WORKER_MAIN;
  133. //
  134. // If worker is not already running queue a thread
  135. //
  136. if ((PopWorkerStatus & (PO_WORKER_MAIN | PO_WORKER_STATUS)) ==
  137. (PO_WORKER_MAIN | PO_WORKER_STATUS) ) {
  138. PopWorkerStatus &= ~PO_WORKER_STATUS;
  139. ExQueueWorkItem (&PopPolicyWorker, DelayedWorkQueue);
  140. }
  141. }
  142. //
  143. // If this irp has been cancelled, then make sure to clear the cancel flag
  144. //
  145. if (Irp->IoStatus.Status == STATUS_CANCELLED) {
  146. Irp->Cancel = FALSE;
  147. }
  148. KeReleaseSpinLock (&PopWorkerSpinLock, OldIrql);
  149. return STATUS_MORE_PROCESSING_REQUIRED;
  150. }
  151. VOID
  152. PopCheckForWork (
  153. IN BOOLEAN GetWorker
  154. )
  155. /*++
  156. Routine Description:
  157. Checks for outstanding work and dispatches a worker if needed.
  158. Arguments:
  159. None
  160. Return Value:
  161. None
  162. --*/
  163. {
  164. KIRQL Irql;
  165. //
  166. // If pending work, handle it
  167. //
  168. if (PopWorkerPending & PopWorkerStatus) {
  169. //
  170. // If current thread already owns the policy lock,
  171. // then just return - we will handle the work when the
  172. // lock is released
  173. //
  174. if (PopPolicyLockThread == KeGetCurrentThread()) {
  175. return ;
  176. }
  177. //
  178. // Handle the work
  179. //
  180. Irql = KeGetCurrentIrql();
  181. if (!GetWorker && Irql < DISPATCH_LEVEL) {
  182. //
  183. // Use calling thread
  184. //
  185. KeEnterCriticalRegion ();
  186. PopPolicyWorkerThread (NULL);
  187. KeLeaveCriticalRegion ();
  188. } else {
  189. //
  190. // Get worker thread to handle it
  191. //
  192. KeAcquireSpinLock (&PopWorkerSpinLock, &Irql);
  193. if (PopWorkerStatus & PO_WORKER_STATUS) {
  194. PopWorkerStatus &= ~PO_WORKER_STATUS;
  195. ExQueueWorkItem (&PopPolicyWorker, DelayedWorkQueue);
  196. }
  197. KeReleaseSpinLock (&PopWorkerSpinLock, Irql);
  198. }
  199. }
  200. }
  201. VOID
  202. PopPolicyWorkerThread (
  203. PVOID Context
  204. )
  205. /*++
  206. Routine Description:
  207. Main policy manager worker thread dispatcher. Sends the
  208. worker thread to the highest pending priority handler which
  209. does not already have a worker thread. Loops until no
  210. handler can be dispatched too.
  211. Arguments:
  212. Return Value:
  213. None
  214. --*/
  215. {
  216. ULONG WorkerType;
  217. ULONG Mask;
  218. KIRQL OldIrql;
  219. ULONG i;
  220. ULONG DelayedWork;
  221. PAGED_CODE();
  222. try {
  223. //
  224. // Dispatch
  225. //
  226. KeAcquireSpinLock (&PopWorkerSpinLock, &OldIrql);
  227. PopWorkerStatus |= (ULONG) ((ULONG_PTR)Context);
  228. DelayedWork = 0;
  229. while (WorkerType = (PopWorkerPending & PopWorkerStatus)) {
  230. //
  231. // Get highest priority worker
  232. //
  233. i = KeFindFirstSetRightMember(WorkerType);
  234. Mask = 1 << i;
  235. //
  236. // Clear pending and indicate busy status
  237. //
  238. PopWorkerPending &= ~Mask;
  239. PopWorkerStatus &= ~Mask;
  240. KeReleaseSpinLock (&PopWorkerSpinLock, OldIrql);
  241. //
  242. // Dispatch to handler
  243. //
  244. DelayedWork |= PopWorkerTypes[i] ();
  245. //
  246. // No longer in progress
  247. //
  248. KeAcquireSpinLock (&PopWorkerSpinLock, &OldIrql);
  249. PopWorkerStatus |= Mask;
  250. }
  251. PopWorkerPending |= DelayedWork;
  252. KeReleaseSpinLock (&PopWorkerSpinLock, OldIrql);
  253. } except (PopExceptionFilter(GetExceptionInformation(), FALSE)) {
  254. }
  255. }
  256. ULONG
  257. PopPolicyWorkerMain (
  258. VOID
  259. )
  260. /*++
  261. Routine Description:
  262. Main policy worker thread. Dispatches any completed policy
  263. manager irps.
  264. Arguments:
  265. None
  266. Return Value:
  267. None
  268. --*/
  269. {
  270. IN PIRP Irp;
  271. PIO_STACK_LOCATION IrpSp;
  272. POP_IRP_HANDLER IrpHandler;
  273. PLIST_ENTRY Entry;
  274. PopAcquirePolicyLock ();
  275. //
  276. // Dispatch any policy irps which have completed
  277. //
  278. while (Entry = ExInterlockedRemoveHeadList (&PopPolicyIrpQueue, &PopWorkerSpinLock)) {
  279. Irp = CONTAINING_RECORD (Entry, IRP, Tail.Overlay.ListEntry);
  280. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  281. //
  282. // Dispatch irp to handler
  283. //
  284. IrpHandler = (POP_IRP_HANDLER) (ULONG_PTR) IrpSp->Parameters.Others.Argument3;
  285. IrpHandler ((PDEVICE_OBJECT) IrpSp->Parameters.Others.Argument1,
  286. Irp,
  287. (PVOID) IrpSp->Parameters.Others.Argument2);
  288. }
  289. PopReleasePolicyLock (FALSE);
  290. PopCheckForWork (TRUE);
  291. return 0;
  292. }
  293. VOID
  294. PopEventCalloutDispatch (
  295. IN PSPOWEREVENTTYPE EventNumber,
  296. IN ULONG_PTR Code
  297. )
  298. {
  299. WIN32_POWEREVENT_PARAMETERS Parms;
  300. ULONG Console;
  301. PVOID OpaqueSession;
  302. KAPC_STATE ApcState;
  303. NTSTATUS Status;
  304. Parms.EventNumber = EventNumber;
  305. Parms.Code = Code;
  306. ASSERT(MmIsSessionAddress((PVOID)PopEventCallout));
  307. if (EventNumber == PsW32GdiOn || EventNumber == PsW32GdiOff) {
  308. //
  309. // These events go to the console session only.
  310. // The ActiveConsoleId session is stored with the SharedUserData.
  311. //
  312. Console = SharedUserData->ActiveConsoleId;
  313. //
  314. // Unfortunately, it is not guaranteed to be valid during a console
  315. // session change, and there is no way to know when that is happening,
  316. // so if it's not valid, just default to session 0, which is always
  317. // there.
  318. //
  319. if (Console == ((ULONG)-1)) {
  320. Console = 0;
  321. }
  322. if ((PsGetCurrentProcess()->Flags & PS_PROCESS_FLAGS_IN_SESSION) &&
  323. (Console == PsGetCurrentProcessSessionId())) {
  324. //
  325. // If the caller is already in the specified session, call directly.
  326. //
  327. PopEventCallout(&Parms);
  328. } else {
  329. //
  330. // Attach to the console session and dispatch the event.
  331. //
  332. OpaqueSession = MmGetSessionById(Console);
  333. if (OpaqueSession) {
  334. Status = MmAttachSession(OpaqueSession, &ApcState);
  335. ASSERT(NT_SUCCESS(Status));
  336. if (NT_SUCCESS(Status)) {
  337. PopEventCallout(&Parms);
  338. Status = MmDetachSession(OpaqueSession, &ApcState);
  339. ASSERT(NT_SUCCESS(Status));
  340. }
  341. Status = MmQuitNextSession(OpaqueSession);
  342. ASSERT(NT_SUCCESS(Status));
  343. }
  344. }
  345. } else {
  346. //
  347. // All other events are broadcast to all sessions.
  348. //
  349. for (OpaqueSession = MmGetNextSession(NULL);
  350. OpaqueSession != NULL;
  351. OpaqueSession = MmGetNextSession(OpaqueSession)) {
  352. if ((PsGetCurrentProcess()->Flags & PS_PROCESS_FLAGS_IN_SESSION) &&
  353. (MmGetSessionId(OpaqueSession) == PsGetCurrentProcessSessionId())) {
  354. //
  355. // If the caller is already in the specified session, call directly.
  356. //
  357. PopEventCallout(&Parms);
  358. } else {
  359. //
  360. // Attach to the session and dispatch the event.
  361. //
  362. Status = MmAttachSession(OpaqueSession, &ApcState);
  363. ASSERT(NT_SUCCESS(Status));
  364. if (NT_SUCCESS(Status)) {
  365. PopEventCallout(&Parms);
  366. Status = MmDetachSession(OpaqueSession, &ApcState);
  367. ASSERT(NT_SUCCESS(Status));
  368. }
  369. }
  370. }
  371. }
  372. return;
  373. }
  374. ULONG
  375. PopPolicyTimeChange (
  376. VOID
  377. )
  378. {
  379. PopEventCalloutDispatch (PsW32SystemTime, 0);
  380. return 0;
  381. }
  382. VOID
  383. PopSetNotificationWork (
  384. IN ULONG Flags
  385. )
  386. /*++
  387. Routine Description:
  388. Sets notification flags for the USER notification worker thread.
  389. Each bit is a different type of outstanding notification that
  390. is to be processed.
  391. Arguments:
  392. Flags - The notifications to set
  393. Return Value:
  394. None
  395. --*/
  396. {
  397. //
  398. // Are the flags set
  399. //
  400. if ((PopNotifyEvents & Flags) != Flags) {
  401. PoPrint(PO_NOTIFY, ("PopSetNotificationWork: Queue notify of: %x\n", Flags));
  402. InterlockedOr (&PopNotifyEvents, Flags);
  403. PopGetPolicyWorker (PO_WORKER_NOTIFY);
  404. }
  405. }
  406. ULONG
  407. PopPolicyWorkerNotify (
  408. VOID
  409. )
  410. /*++
  411. Routine Description:
  412. USER notification worker. Processes each set bit in NotifyEvents.
  413. Arguments:
  414. None
  415. Return Value:
  416. None
  417. --*/
  418. {
  419. ULONG i;
  420. LONG Flags;
  421. ULONG Mask;
  422. const POP_NOTIFY_WORK* NotifyWork;
  423. //
  424. // If Win32 event callout is registered, then don't dispatch right now
  425. //
  426. if (!PopEventCallout) {
  427. return PO_WORKER_NOTIFY;
  428. }
  429. //
  430. // While events are pending collect them and dispatch them
  431. //
  432. while (Flags = InterlockedExchange (&PopNotifyEvents, 0)) {
  433. while (Flags) {
  434. //
  435. // Get change
  436. //
  437. i = KeFindFirstSetRightMember(Flags);
  438. Mask = 1 << i;
  439. Flags &= ~Mask;
  440. NotifyWork = PopNotifyWork + i;
  441. //
  442. // Dispatch it
  443. //
  444. NotifyWork->Function (NotifyWork->Arg);
  445. }
  446. }
  447. return 0;
  448. }
  449. VOID
  450. PopDispatchCallout (
  451. IN ULONG Arg
  452. )
  453. {
  454. PopEventCalloutDispatch (Arg, 0);
  455. }
  456. VOID
  457. PopDispatchCallback (
  458. IN ULONG Arg
  459. )
  460. {
  461. // Sundown: Arg is zero-extended
  462. ExNotifyCallback (ExCbPowerState, ULongToPtr(Arg), 0);
  463. }
  464. VOID
  465. PopDispatchDisplayRequired (
  466. IN ULONG Arg
  467. )
  468. /*++
  469. Routine Description:
  470. Notify user32 of the current "display required" setting. Zero, means
  471. the display may timeout. Non-zero, means the display is in use
  472. until told otherwise.
  473. --*/
  474. {
  475. ULONG i;
  476. UNREFERENCED_PARAMETER (Arg);
  477. i = PopAttributes[POP_DISPLAY_ATTRIBUTE].Count;
  478. PoPrint(PO_NOTIFY, ("PopNotify: DisplayRequired %x\n", i));
  479. //
  480. // If the display is in use but has not yet been turned on, then do so now
  481. //
  482. if (((PopFullWake & (PO_GDI_STATUS | PO_GDI_ON_PENDING)) == PO_GDI_ON_PENDING)) {
  483. PoPrint(PO_PACT, ("PopEventDispatch: gdi on\n"));
  484. InterlockedOr (&PopFullWake, PO_GDI_STATUS);
  485. PopEventCalloutDispatch (PsW32GdiOn, 0);
  486. }
  487. PopEventCalloutDispatch (PsW32DisplayState, i);
  488. }
  489. VOID
  490. PopDispatchFullWake (
  491. IN ULONG Arg
  492. )
  493. /*++
  494. Routine Description:
  495. Notify user32 that the system has fully awoken.
  496. Also reset the idle detection to the current policy
  497. --*/
  498. {
  499. //
  500. // If we're not in the middle setting the system state, then check the pending
  501. // flags.
  502. //
  503. UNREFERENCED_PARAMETER (Arg);
  504. if (PopAction.State != PO_ACT_SET_SYSTEM_STATE) {
  505. //
  506. // Notify user32 of the wake events
  507. //
  508. if ((PopFullWake & (PO_GDI_STATUS | PO_GDI_ON_PENDING)) == PO_GDI_ON_PENDING) {
  509. PoPrint(PO_PACT, ("PopEventDispatch: gdi on\n"));
  510. InterlockedOr (&PopFullWake, PO_GDI_STATUS);
  511. PopEventCalloutDispatch (PsW32GdiOn, 0);
  512. }
  513. if ((PopFullWake & (PO_FULL_WAKE_STATUS | PO_FULL_WAKE_PENDING)) == PO_FULL_WAKE_PENDING) {
  514. PoPrint(PO_PACT, ("PopEventDispatch: full wake\n"));
  515. InterlockedOr (&PopFullWake, PO_FULL_WAKE_STATUS);
  516. PopEventCalloutDispatch (PsW32FullWake, 0);
  517. //
  518. // Reset the idle detection policy
  519. //
  520. PopAcquirePolicyLock();
  521. PopInitSIdle ();
  522. PopReleasePolicyLock (FALSE);
  523. }
  524. }
  525. }
  526. VOID
  527. PopDispatchEventCodes (
  528. IN ULONG Arg
  529. )
  530. /*++
  531. Routine Description:
  532. Notify user32 of the queued event codes.
  533. --*/
  534. {
  535. ULONG i;
  536. ULONG Code;
  537. UNREFERENCED_PARAMETER (Arg);
  538. PopAcquirePolicyLock();
  539. for (i=0; i < POP_MAX_EVENT_CODES; i++) {
  540. if (PopEventCode[i]) {
  541. Code = PopEventCode[i];
  542. PopEventCode[i] = 0;
  543. PopReleasePolicyLock (FALSE);
  544. PoPrint(PO_NOTIFY, ("PopNotify: Event %x\n", Code));
  545. PopEventCalloutDispatch (PsW32EventCode, Code);
  546. PopAcquirePolicyLock ();
  547. }
  548. }
  549. PopResetSwitchTriggers();
  550. PopReleasePolicyLock(FALSE);
  551. }
  552. VOID
  553. PopDispatchAcDcCallback (
  554. IN ULONG Arg
  555. )
  556. /*++
  557. Routine Description:
  558. Notify the system callback of the current policy as either
  559. being AC or DC
  560. --*/
  561. {
  562. UNREFERENCED_PARAMETER (Arg);
  563. ExNotifyCallback (
  564. ExCbPowerState,
  565. UIntToPtr(PO_CB_AC_STATUS),
  566. UIntToPtr((PopPolicy == &PopAcPolicy))
  567. );
  568. }
  569. VOID
  570. PopDispatchPolicyCallout (
  571. IN ULONG Arg
  572. )
  573. /*++
  574. Routine Description:
  575. Notify user32 that the active policy has changed
  576. --*/
  577. {
  578. UNREFERENCED_PARAMETER (Arg);
  579. PoPrint(PO_NOTIFY, ("PopNotify: PolicyChanged\n"));
  580. PopEventCalloutDispatch (PsW32PowerPolicyChanged, PopPolicy->VideoTimeout);
  581. }
  582. VOID
  583. PopDispatchProcessorPolicyCallout (
  584. IN ULONG Arg
  585. )
  586. /*++
  587. Routine Description:
  588. Not used right now. But required so that we don't have a NULL entry
  589. in the PopNotifyWork array
  590. --*/
  591. {
  592. UNREFERENCED_PARAMETER (Arg);
  593. PoPrint(PO_NOTIFY, ("PopNotify: ProcessorPolicyChanges\n"));
  594. }
  595. VOID
  596. PopDispatchSetStateFailure (
  597. IN ULONG Arg
  598. )
  599. /*++
  600. Routine Description:
  601. Notify user32 that there was a failure during an async system state
  602. operation. E.g., no error code was returned to anyone, yet the operation
  603. failed
  604. --*/
  605. {
  606. PO_SET_STATE_FAILURE Failure;
  607. UNREFERENCED_PARAMETER (Arg);
  608. RtlZeroMemory (&Failure, sizeof(Failure));
  609. PopAcquirePolicyLock();
  610. //
  611. // If the action state is idle, check to see if we should notify
  612. // win32 of the failure
  613. //
  614. if (PopAction.State == PO_ACT_IDLE && !NT_SUCCESS(PopAction.Status) &&
  615. (PopAction.Flags & (POWER_ACTION_UI_ALLOWED | POWER_ACTION_CRITICAL)) ) {
  616. Failure.Status = PopAction.Status;
  617. Failure.PowerAction = PopAction.Action;
  618. Failure.MinState = PopAction.LightestState;
  619. Failure.Flags = PopAction.Flags;
  620. }
  621. //
  622. // Reset PopAction to the default. Otherwise, any power requests following
  623. // this failure will refer to PopAction, which contains data from this
  624. // failed request.
  625. //
  626. PopResetActionDefaults();
  627. PopReleasePolicyLock (FALSE);
  628. if (!NT_SUCCESS(Failure.Status)) {
  629. PoPrint(PO_NOTIFY, ("PopNotify: set state failed (code %x)\n", Failure.Status));
  630. PopEventCalloutDispatch (PsW32SetStateFailed, (ULONG_PTR) &Failure);
  631. }
  632. }