Source code of Windows XP (NT5)
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.

140 lines
3.6 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. dpcplt.c
  5. Abstract:
  6. This module implements platform specific code to support Deferred
  7. Procedure Calls (DPCs).
  8. Author:
  9. David N. Cutler (davec) 30-Aug-2000
  10. Environment:
  11. Kernel mode only.
  12. Revision History:
  13. --*/
  14. #include "ki.h"
  15. VOID
  16. KiRetireDpcList (
  17. PKPRCB Prcb
  18. )
  19. /*++
  20. Routine Description:
  21. This function processes the DPC list for the specified processor.
  22. N.B. This function is entered with interrupts disabled and exits with
  23. interrupts disabled.
  24. Arguments:
  25. Prcb - Supplies the address of the processor block.
  26. Return Value:
  27. None.
  28. --*/
  29. {
  30. PKDPC Dpc;
  31. PVOID DeferredContext;
  32. PKDEFERRED_ROUTINE DeferredRoutine;
  33. PLIST_ENTRY Entry;
  34. PLIST_ENTRY ListHead;
  35. PVOID SystemArgument1;
  36. PVOID SystemArgument2;
  37. ULONG TimerHand;
  38. //
  39. // Loop processing DPC list entries until the specified DPC list is empty.
  40. //
  41. // N.B. This following code appears to have a redundant loop, but it does
  42. // not. The point of this code is to avoid as many dispatch interrupts
  43. // as possible.
  44. //
  45. ListHead = &Prcb->DpcListHead;
  46. do {
  47. Prcb->DpcRoutineActive = TRUE;
  48. //
  49. // If the timer hand value is nonzero, then process expired timers.
  50. //
  51. if ((TimerHand = Prcb->TimerHand) != 0) {
  52. Prcb->TimerHand = 0;
  53. _enable();
  54. KiTimerExpiration(NULL, NULL, UlongToHandle(TimerHand - 1), NULL);
  55. _disable();
  56. }
  57. //
  58. // If the DPC list is not empty, then process the DPC list.
  59. //
  60. if (Prcb->DpcQueueDepth != 0) {
  61. //
  62. // Acquire the DPC lock for the current processor and check if
  63. // the DPC list is empty. If the DPC list is not empty, then
  64. // remove the first entry from the DPC list, capture the DPC
  65. // parameters, set the DPC inserted state false, decrement the
  66. // DPC queue depth, release the DPC lock, enable interrupts, and
  67. // call the specified DPC routine. Otherwise, release the DPC
  68. // lock and enable interrupts.
  69. //
  70. do {
  71. KeAcquireSpinLockAtDpcLevel(&Prcb->DpcLock);
  72. Entry = Prcb->DpcListHead.Flink;
  73. if (Entry != ListHead) {
  74. RemoveEntryList(Entry);
  75. Dpc = CONTAINING_RECORD(Entry, KDPC, DpcListEntry);
  76. DeferredRoutine = Dpc->DeferredRoutine;
  77. DeferredContext = Dpc->DeferredContext;
  78. SystemArgument1 = Dpc->SystemArgument1;
  79. SystemArgument2 = Dpc->SystemArgument2;
  80. Dpc->Lock = NULL;
  81. Prcb->DpcQueueDepth -= 1;
  82. KeReleaseSpinLockFromDpcLevel(&Prcb->DpcLock);
  83. _enable();
  84. (DeferredRoutine)(Dpc,
  85. DeferredContext,
  86. SystemArgument1,
  87. SystemArgument2);
  88. ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
  89. _disable();
  90. } else {
  91. ASSERT(Prcb->DpcQueueDepth == 0);
  92. KeReleaseSpinLockFromDpcLevel(&Prcb->DpcLock);
  93. }
  94. } while (ListHead != *((PLIST_ENTRY volatile *)&ListHead->Flink));
  95. }
  96. Prcb->DpcRoutineActive = FALSE;
  97. Prcb->DpcInterruptRequested = FALSE;
  98. } while (ListHead != *((PLIST_ENTRY volatile *)&ListHead->Flink));
  99. return;
  100. }