2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ke/dpc.c
5 * PURPOSE: Deferred Procedure Call (DPC) Support
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Philip Susi (phreak@iag.net)
11 /* INCLUDES ******************************************************************/
17 /* GLOBALS *******************************************************************/
19 ULONG KiMaximumDpcQueueDepth
= 4;
20 ULONG KiMinimumDpcRate
= 3;
21 ULONG KiAdjustDpcThreshold
= 20;
22 ULONG KiIdealDpcRate
= 20;
23 BOOLEAN KeThreadDpcEnable
;
24 FAST_MUTEX KiGenericCallDpcMutex
;
25 KDPC KiTimerExpireDpc
;
26 ULONG KiTimeLimitIsrMicroseconds
;
27 ULONG KiDPCTimeout
= 110;
29 /* PRIVATE FUNCTIONS *********************************************************/
33 KiCheckTimerTable(IN ULARGE_INTEGER CurrentTime
)
37 PLIST_ENTRY ListHead
, NextEntry
;
41 /* Raise IRQL to high and loop timers */
42 KeRaiseIrql(HIGH_LEVEL
, &OldIrql
);
45 /* Loop the current list */
46 ListHead
= &KiTimerTableListHead
[i
].Entry
;
47 NextEntry
= ListHead
->Flink
;
48 while (NextEntry
!= ListHead
)
50 /* Get the timer and move to the next one */
51 Timer
= CONTAINING_RECORD(NextEntry
, KTIMER
, TimerListEntry
);
52 NextEntry
= NextEntry
->Flink
;
54 /* Check if it expired */
55 if (Timer
->DueTime
.QuadPart
<= CurrentTime
.QuadPart
)
57 /* Check if the DPC was queued, but didn't run */
58 if (!(KeGetCurrentPrcb()->TimerRequest
) &&
59 !(*((volatile PULONG
*)(&KiTimerExpireDpc
.DpcData
))))
61 /* This is bad, breakpoint! */
62 DPRINT1("Invalid timer state!\n");
68 /* Move to the next timer */
70 } while(i
< TIMER_TABLE_SIZE
);
72 /* Lower IRQL and return */
79 KiTimerExpiration(IN PKDPC Dpc
,
80 IN PVOID DeferredContext
,
81 IN PVOID SystemArgument1
,
82 IN PVOID SystemArgument2
)
84 ULARGE_INTEGER SystemTime
, InterruptTime
;
85 LARGE_INTEGER Interval
;
87 ULONG Timers
, ActiveTimers
, DpcCalls
;
88 PLIST_ENTRY ListHead
, NextEntry
;
93 DPC_QUEUE_ENTRY DpcEntry
[MAX_TIMER_DPCS
];
94 PKSPIN_LOCK_QUEUE LockQueue
;
96 PKPRCB Prcb
= KeGetCurrentPrcb();
99 /* Disable interrupts */
102 /* Query system and interrupt time */
103 KeQuerySystemTime((PLARGE_INTEGER
)&SystemTime
);
104 InterruptTime
.QuadPart
= KeQueryInterruptTime();
105 Limit
= KeTickCount
.LowPart
;
107 /* Bring interrupts back */
110 /* Get the index of the timer and normalize it */
111 Index
= PtrToLong(SystemArgument1
);
112 if ((Limit
- Index
) >= TIMER_TABLE_SIZE
)
115 Limit
= Index
+ TIMER_TABLE_SIZE
- 1;
118 /* Setup index and actual limit */
120 Limit
&= (TIMER_TABLE_SIZE
- 1);
122 /* Setup accounting data */
127 /* Lock the Database and Raise IRQL */
128 OldIrql
= KiAcquireDispatcherLock();
130 /* Start expiration loop */
133 /* Get the current index */
134 Index
= (Index
+ 1) & (TIMER_TABLE_SIZE
- 1);
136 /* Get list pointers and loop the list */
137 ListHead
= &KiTimerTableListHead
[Index
].Entry
;
138 while (ListHead
!= ListHead
->Flink
)
140 /* Lock the timer and go to the next entry */
141 LockQueue
= KiAcquireTimerLock(Index
);
142 NextEntry
= ListHead
->Flink
;
144 /* Get the current timer and check its due time */
146 Timer
= CONTAINING_RECORD(NextEntry
, KTIMER
, TimerListEntry
);
147 if ((NextEntry
!= ListHead
) &&
148 (Timer
->DueTime
.QuadPart
<= InterruptTime
.QuadPart
))
150 /* It's expired, remove it */
152 KiRemoveEntryTimer(Timer
);
154 /* Make it non-inserted, unlock it, and signal it */
155 Timer
->Header
.Inserted
= FALSE
;
156 KiReleaseTimerLock(LockQueue
);
157 Timer
->Header
.SignalState
= 1;
159 /* Get the DPC and period */
160 TimerDpc
= Timer
->Dpc
;
161 Period
= Timer
->Period
;
163 /* Check if there's any waiters */
164 if (!IsListEmpty(&Timer
->Header
.WaitListHead
))
166 /* Check the type of event */
167 if (Timer
->Header
.Type
== TimerNotificationObject
)
169 /* Unwait the thread */
170 KxUnwaitThread(&Timer
->Header
, IO_NO_INCREMENT
);
174 /* Otherwise unwait the thread and signal the timer */
175 KxUnwaitThreadForEvent((PKEVENT
)Timer
, IO_NO_INCREMENT
);
179 /* Check if we have a period */
182 /* Calculate the interval and insert the timer */
183 Interval
.QuadPart
= Int32x32To64(Period
, -10000);
184 while (!KiInsertTreeTimer(Timer
, Interval
));
187 /* Check if we have a DPC */
192 * If the DPC is targeted to another processor,
193 * then insert it into that processor's DPC queue
194 * instead of delivering it now.
195 * If the DPC is a threaded DPC, and the current CPU
196 * has threaded DPCs enabled (KiExecuteDpc is actively parsing DPCs),
197 * then also insert it into the DPC queue for threaded delivery,
198 * instead of doing it here.
200 if (((TimerDpc
->Number
>= MAXIMUM_PROCESSORS
) &&
201 ((TimerDpc
->Number
- MAXIMUM_PROCESSORS
) != Prcb
->Number
)) ||
202 ((TimerDpc
->Type
== ThreadedDpcObject
) && (Prcb
->ThreadDpcEnable
)))
205 KeInsertQueueDpc(TimerDpc
,
206 UlongToPtr(SystemTime
.LowPart
),
207 UlongToPtr(SystemTime
.HighPart
));
212 /* Setup the DPC Entry */
213 DpcEntry
[DpcCalls
].Dpc
= TimerDpc
;
214 DpcEntry
[DpcCalls
].Routine
= TimerDpc
->DeferredRoutine
;
215 DpcEntry
[DpcCalls
].Context
= TimerDpc
->DeferredContext
;
217 ASSERT(DpcCalls
< MAX_TIMER_DPCS
);
221 /* Check if we're done processing */
222 if (!(ActiveTimers
) || !(Timers
))
224 /* Release the dispatcher while doing DPCs */
225 KiReleaseDispatcherLock(DISPATCH_LEVEL
);
227 /* Start looping all DPC Entries */
228 for (i
= 0; DpcCalls
; DpcCalls
--, i
++)
231 DpcEntry
[i
].Routine(DpcEntry
[i
].Dpc
,
233 UlongToPtr(SystemTime
.LowPart
),
234 UlongToPtr(SystemTime
.HighPart
));
237 /* Reset accounting */
241 /* Lock the dispatcher database */
242 KiAcquireDispatcherLock();
247 /* Check if the timer list is empty */
248 if (NextEntry
!= ListHead
)
251 ASSERT(KiTimerTableListHead
[Index
].Time
.QuadPart
<=
252 Timer
->DueTime
.QuadPart
);
254 /* Update the time */
256 KiTimerTableListHead
[Index
].Time
.QuadPart
=
257 Timer
->DueTime
.QuadPart
;
261 /* Release the lock */
262 KiReleaseTimerLock(LockQueue
);
264 /* Check if we've scanned all the timers we could */
267 /* Release the dispatcher while doing DPCs */
268 KiReleaseDispatcherLock(DISPATCH_LEVEL
);
270 /* Start looping all DPC Entries */
271 for (i
= 0; DpcCalls
; DpcCalls
--, i
++)
274 DpcEntry
[i
].Routine(DpcEntry
[i
].Dpc
,
276 UlongToPtr(SystemTime
.LowPart
),
277 UlongToPtr(SystemTime
.HighPart
));
280 /* Reset accounting */
284 /* Lock the dispatcher database */
285 KiAcquireDispatcherLock();
292 } while (Index
!= Limit
);
294 /* Verify the timer table, on debug builds */
295 if (KeNumberProcessors
== 1) KiCheckTimerTable(InterruptTime
);
297 /* Check if we still have DPC entries */
300 /* Release the dispatcher while doing DPCs */
301 KiReleaseDispatcherLock(DISPATCH_LEVEL
);
303 /* Start looping all DPC Entries */
304 for (i
= 0; DpcCalls
; DpcCalls
--, i
++)
307 DpcEntry
[i
].Routine(DpcEntry
[i
].Dpc
,
309 UlongToPtr(SystemTime
.LowPart
),
310 UlongToPtr(SystemTime
.HighPart
));
313 /* Lower IRQL if we need to */
314 if (OldIrql
!= DISPATCH_LEVEL
) KeLowerIrql(OldIrql
);
318 /* Unlock the dispatcher */
319 KiReleaseDispatcherLock(OldIrql
);
325 KiTimerListExpire(IN PLIST_ENTRY ExpiredListHead
,
328 ULARGE_INTEGER SystemTime
;
329 LARGE_INTEGER Interval
;
335 DPC_QUEUE_ENTRY DpcEntry
[MAX_TIMER_DPCS
];
337 PKPRCB Prcb
= KeGetCurrentPrcb();
341 KeQuerySystemTime((PLARGE_INTEGER
)&SystemTime
);
343 /* Loop expired list */
344 while (ExpiredListHead
->Flink
!= ExpiredListHead
)
346 /* Get the current timer */
347 Timer
= CONTAINING_RECORD(ExpiredListHead
->Flink
, KTIMER
, TimerListEntry
);
350 RemoveEntryList(&Timer
->TimerListEntry
);
353 Timer
->Header
.Inserted
= FALSE
;
356 Timer
->Header
.SignalState
= 1;
358 /* Get the DPC and period */
359 TimerDpc
= Timer
->Dpc
;
360 Period
= Timer
->Period
;
362 /* Check if there's any waiters */
363 if (!IsListEmpty(&Timer
->Header
.WaitListHead
))
365 /* Check the type of event */
366 if (Timer
->Header
.Type
== TimerNotificationObject
)
368 /* Unwait the thread */
369 KxUnwaitThread(&Timer
->Header
, IO_NO_INCREMENT
);
373 /* Otherwise unwait the thread and signal the timer */
374 KxUnwaitThreadForEvent((PKEVENT
)Timer
, IO_NO_INCREMENT
);
378 /* Check if we have a period */
381 /* Calculate the interval and insert the timer */
382 Interval
.QuadPart
= Int32x32To64(Period
, -10000);
383 while (!KiInsertTreeTimer(Timer
, Interval
));
386 /* Check if we have a DPC */
391 * If the DPC is targeted to another processor,
392 * then insert it into that processor's DPC queue
393 * instead of delivering it now.
394 * If the DPC is a threaded DPC, and the current CPU
395 * has threaded DPCs enabled (KiExecuteDpc is actively parsing DPCs),
396 * then also insert it into the DPC queue for threaded delivery,
397 * instead of doing it here.
399 if (((TimerDpc
->Number
>= MAXIMUM_PROCESSORS
) &&
400 ((TimerDpc
->Number
- MAXIMUM_PROCESSORS
) != Prcb
->Number
)) ||
401 ((TimerDpc
->Type
== ThreadedDpcObject
) && (Prcb
->ThreadDpcEnable
)))
404 KeInsertQueueDpc(TimerDpc
,
405 UlongToPtr(SystemTime
.LowPart
),
406 UlongToPtr(SystemTime
.HighPart
));
411 /* Setup the DPC Entry */
412 DpcEntry
[DpcCalls
].Dpc
= TimerDpc
;
413 DpcEntry
[DpcCalls
].Routine
= TimerDpc
->DeferredRoutine
;
414 DpcEntry
[DpcCalls
].Context
= TimerDpc
->DeferredContext
;
416 ASSERT(DpcCalls
< MAX_TIMER_DPCS
);
421 /* Check if we still have DPC entries */
424 /* Release the dispatcher while doing DPCs */
425 KiReleaseDispatcherLock(DISPATCH_LEVEL
);
427 /* Start looping all DPC Entries */
428 for (i
= 0; DpcCalls
; DpcCalls
--, i
++)
431 DpcEntry
[i
].Routine(DpcEntry
[i
].Dpc
,
433 UlongToPtr(SystemTime
.LowPart
),
434 UlongToPtr(SystemTime
.HighPart
));
438 KeLowerIrql(OldIrql
);
442 /* Unlock the dispatcher */
443 KiReleaseDispatcherLock(OldIrql
);
451 PKPRCB Prcb
= KeGetCurrentPrcb();
452 PKTHREAD NextThread
, Thread
= Prcb
->CurrentThread
;
454 /* Check if a DPC Event was requested to be signaled */
455 if (InterlockedExchange(&Prcb
->DpcSetEventRequest
, 0))
458 KeSetEvent(&Prcb
->DpcEvent
, 0, 0);
461 /* Raise to synchronization level and lock the PRCB and thread */
462 KeRaiseIrqlToSynchLevel();
463 KiAcquireThreadLock(Thread
);
464 KiAcquirePrcbLock(Prcb
);
466 /* Check if Quantum expired */
467 if (Thread
->Quantum
<= 0)
469 /* Check if we're real-time and with quantums disabled */
470 if ((Thread
->Priority
>= LOW_REALTIME_PRIORITY
) &&
471 (Thread
->ApcState
.Process
->DisableQuantum
))
473 /* Otherwise, set maximum quantum */
474 Thread
->Quantum
= MAX_QUANTUM
;
478 /* Reset the new Quantum */
479 Thread
->Quantum
= Thread
->QuantumReset
;
481 /* Calculate new priority */
482 Thread
->Priority
= KiComputeNewPriority(Thread
, 1);
484 /* Check if a new thread is scheduled */
485 if (!Prcb
->NextThread
)
487 /* Get a new ready thread */
488 NextThread
= KiSelectReadyThread(Thread
->Priority
, Prcb
);
491 /* Found one, set it on standby */
492 NextThread
->State
= Standby
;
493 Prcb
->NextThread
= NextThread
;
498 /* Otherwise, make sure that this thread doesn't get preempted */
499 Thread
->Preempted
= FALSE
;
504 /* Release the thread lock */
505 KiReleaseThreadLock(Thread
);
507 /* Check if there's no thread scheduled */
508 if (!Prcb
->NextThread
)
511 KiReleasePrcbLock(Prcb
);
512 KeLowerIrql(DISPATCH_LEVEL
);
516 /* Get the next thread now */
517 NextThread
= Prcb
->NextThread
;
519 /* Set current thread's swap busy to true */
520 KiSetThreadSwapBusy(Thread
);
522 /* Switch threads in PRCB */
523 Prcb
->NextThread
= NULL
;
524 Prcb
->CurrentThread
= NextThread
;
526 /* Set thread to running and the switch reason to Quantum End */
527 NextThread
->State
= Running
;
528 Thread
->WaitReason
= WrQuantumEnd
;
530 /* Queue it on the ready lists */
531 KxQueueReadyThread(Thread
, Prcb
);
533 /* Set wait IRQL to APC_LEVEL */
534 Thread
->WaitIrql
= APC_LEVEL
;
537 KiSwapContext(APC_LEVEL
, Thread
);
539 /* Lower IRQL back to DISPATCH_LEVEL */
540 KeLowerIrql(DISPATCH_LEVEL
);
545 KiRetireDpcList(IN PKPRCB Prcb
)
548 PLIST_ENTRY ListHead
, DpcEntry
;
550 PKDEFERRED_ROUTINE DeferredRoutine
;
551 PVOID DeferredContext
, SystemArgument1
, SystemArgument2
;
557 /* Get data and list variables before starting anything else */
558 DpcData
= &Prcb
->DpcData
[DPC_NORMAL
];
559 ListHead
= &DpcData
->DpcListHead
;
561 /* Main outer loop */
564 /* Set us as active */
565 Prcb
->DpcRoutineActive
= TRUE
;
567 /* Check if this is a timer expiration request */
568 if (Prcb
->TimerRequest
)
570 /* It is, get the timer hand and disable timer request */
571 TimerHand
= Prcb
->TimerHand
;
572 Prcb
->TimerRequest
= 0;
574 /* Expire timers with interrups enabled */
576 KiTimerExpiration(NULL
, NULL
, (PVOID
)TimerHand
, NULL
);
580 /* Loop while we have entries in the queue */
581 while (DpcData
->DpcQueueDepth
!= 0)
583 /* Lock the DPC data and get the DPC entry*/
584 KeAcquireSpinLockAtDpcLevel(&DpcData
->DpcLock
);
585 DpcEntry
= ListHead
->Flink
;
587 /* Make sure we have an entry */
588 if (DpcEntry
!= ListHead
)
590 /* Remove the DPC from the list */
591 RemoveEntryList(DpcEntry
);
592 Dpc
= CONTAINING_RECORD(DpcEntry
, KDPC
, DpcListEntry
);
594 /* Clear its DPC data and save its parameters */
596 DeferredRoutine
= Dpc
->DeferredRoutine
;
597 DeferredContext
= Dpc
->DeferredContext
;
598 SystemArgument1
= Dpc
->SystemArgument1
;
599 SystemArgument2
= Dpc
->SystemArgument2
;
601 /* Decrease the queue depth */
602 DpcData
->DpcQueueDepth
--;
605 Prcb
->DebugDpcTime
= 0;
607 /* Release the lock */
608 KeReleaseSpinLockFromDpcLevel(&DpcData
->DpcLock
);
610 /* Re-enable interrupts */
618 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
620 /* Disable interrupts and keep looping */
625 /* The queue should be flushed now */
626 ASSERT(DpcData
->DpcQueueDepth
== 0);
628 /* Release DPC Lock */
629 KeReleaseSpinLockFromDpcLevel(&DpcData
->DpcLock
);
633 /* Clear DPC Flags */
634 Prcb
->DpcRoutineActive
= FALSE
;
635 Prcb
->DpcInterruptRequested
= FALSE
;
638 /* Check if we have deferred threads */
639 if (Prcb
->DeferredReadyListHead
.Next
)
642 /* Re-enable interrupts and raise to synch */
644 OldIrql
= KeRaiseIrqlToSynchLevel();
646 /* Process deferred threads */
647 KiProcessDeferredReadyList(Prcb
);
649 /* Lower IRQL back and disable interrupts */
650 KeLowerIrql(OldIrql
);
654 } while (DpcData
->DpcQueueDepth
!= 0);
659 KiInitializeDpc(IN PKDPC Dpc
,
660 IN PKDEFERRED_ROUTINE DeferredRoutine
,
661 IN PVOID DeferredContext
,
664 /* Setup the DPC Object */
667 Dpc
->Importance
= MediumImportance
;
668 Dpc
->DeferredRoutine
= DeferredRoutine
;
669 Dpc
->DeferredContext
= DeferredContext
;
673 /* PUBLIC FUNCTIONS **********************************************************/
680 KeInitializeThreadedDpc(IN PKDPC Dpc
,
681 IN PKDEFERRED_ROUTINE DeferredRoutine
,
682 IN PVOID DeferredContext
)
684 /* Call the internal routine */
685 KiInitializeDpc(Dpc
, DeferredRoutine
, DeferredContext
, ThreadedDpcObject
);
693 KeInitializeDpc(IN PKDPC Dpc
,
694 IN PKDEFERRED_ROUTINE DeferredRoutine
,
695 IN PVOID DeferredContext
)
697 /* Call the internal routine */
698 KiInitializeDpc(Dpc
, DeferredRoutine
, DeferredContext
, DpcObject
);
706 KeInsertQueueDpc(IN PKDPC Dpc
,
707 IN PVOID SystemArgument1
,
708 IN PVOID SystemArgument2
)
711 PKPRCB Prcb
, CurrentPrcb
;
714 BOOLEAN DpcConfigured
= FALSE
, DpcInserted
= FALSE
;
717 /* Check IRQL and Raise it to HIGH_LEVEL */
718 KeRaiseIrql(HIGH_LEVEL
, &OldIrql
);
719 CurrentPrcb
= KeGetCurrentPrcb();
721 /* Check if the DPC has more then the maximum number of CPUs */
722 if (Dpc
->Number
>= MAXIMUM_PROCESSORS
)
724 /* Then substract the maximum and get that PRCB. */
725 Cpu
= Dpc
->Number
- MAXIMUM_PROCESSORS
;
726 Prcb
= KiProcessorBlock
[Cpu
];
730 /* Use the current one */
735 /* ROS Sanity Check */
736 ASSERT(Prcb
== CurrentPrcb
);
738 /* Check if this is a threaded DPC and threaded DPCs are enabled */
739 if ((Dpc
->Type
== ThreadedDpcObject
) && (Prcb
->ThreadDpcEnable
))
741 /* Then use the threaded data */
742 DpcData
= &Prcb
->DpcData
[DPC_THREADED
];
746 /* Otherwise, use the regular data */
747 DpcData
= &Prcb
->DpcData
[DPC_NORMAL
];
750 /* Acquire the DPC lock */
751 KiAcquireSpinLock(&DpcData
->DpcLock
);
753 /* Get the DPC Data */
754 if (!InterlockedCompareExchangePointer(&Dpc
->DpcData
, DpcData
, NULL
))
756 /* Now we can play with the DPC safely */
757 Dpc
->SystemArgument1
= SystemArgument1
;
758 Dpc
->SystemArgument2
= SystemArgument2
;
759 DpcData
->DpcQueueDepth
++;
761 DpcConfigured
= TRUE
;
763 /* Check if this is a high importance DPC */
764 if (Dpc
->Importance
== HighImportance
)
766 /* Pre-empty other DPCs */
767 InsertHeadList(&DpcData
->DpcListHead
, &Dpc
->DpcListEntry
);
771 /* Add it at the end */
772 InsertTailList(&DpcData
->DpcListHead
, &Dpc
->DpcListEntry
);
775 /* Check if this is the DPC on the threaded list */
776 if (&Prcb
->DpcData
[DPC_THREADED
] == DpcData
)
778 /* Make sure a threaded DPC isn't already active */
779 if (!(Prcb
->DpcThreadActive
) && !(Prcb
->DpcThreadRequested
))
781 /* FIXME: Setup Threaded DPC */
782 UNIMPLEMENTED_FATAL("Threaded DPC not supported\n");
787 /* Make sure a DPC isn't executing already */
788 if (!(Prcb
->DpcRoutineActive
) && !(Prcb
->DpcInterruptRequested
))
790 /* Check if this is the same CPU */
791 if (Prcb
!= CurrentPrcb
)
794 * Check if the DPC is of high importance or above the
795 * maximum depth. If it is, then make sure that the CPU
796 * isn't idle, or that it's sleeping.
798 if (((Dpc
->Importance
== HighImportance
) ||
799 (DpcData
->DpcQueueDepth
>=
800 Prcb
->MaximumDpcQueueDepth
)) &&
801 (!(AFFINITY_MASK(Cpu
) & KiIdleSummary
) ||
804 /* Set interrupt requested */
805 Prcb
->DpcInterruptRequested
= TRUE
;
807 /* Set DPC inserted */
813 /* Check if the DPC is of anything but low importance */
814 if ((Dpc
->Importance
!= LowImportance
) ||
815 (DpcData
->DpcQueueDepth
>=
816 Prcb
->MaximumDpcQueueDepth
) ||
817 (Prcb
->DpcRequestRate
< Prcb
->MinimumDpcRate
))
819 /* Set interrupt requested */
820 Prcb
->DpcInterruptRequested
= TRUE
;
822 /* Set DPC inserted */
830 /* Release the lock */
831 KiReleaseSpinLock(&DpcData
->DpcLock
);
833 /* Check if the DPC was inserted */
836 /* Check if this was SMP */
837 if (Prcb
!= CurrentPrcb
)
839 /* It was, request and IPI */
840 KiIpiSend(AFFINITY_MASK(Cpu
), IPI_DPC
);
844 /* It wasn't, request an interrupt from HAL */
845 HalRequestSoftwareInterrupt(DISPATCH_LEVEL
);
850 KeLowerIrql(OldIrql
);
851 return DpcConfigured
;
859 KeRemoveQueueDpc(IN PKDPC Dpc
)
865 /* Disable interrupts */
866 Enable
= KeDisableInterrupts();
869 DpcData
= Dpc
->DpcData
;
872 /* Acquire the DPC lock */
873 KiAcquireSpinLock(&DpcData
->DpcLock
);
875 /* Make sure that the data didn't change */
876 if (DpcData
== Dpc
->DpcData
)
879 DpcData
->DpcQueueDepth
--;
880 RemoveEntryList(&Dpc
->DpcListEntry
);
884 /* Release the lock */
885 KiReleaseSpinLock(&DpcData
->DpcLock
);
888 /* Re-enable interrupts */
889 if (Enable
) _enable();
891 /* Return if the DPC was in the queue or not */
892 return DpcData
? TRUE
: FALSE
;
900 KeFlushQueuedDpcs(VOID
)
902 PKPRCB CurrentPrcb
= KeGetCurrentPrcb();
905 /* Check if this is an UP machine */
906 if (KeActiveProcessors
== 1)
908 /* Check if there are DPCs on either queues */
909 if ((CurrentPrcb
->DpcData
[DPC_NORMAL
].DpcQueueDepth
> 0) ||
910 (CurrentPrcb
->DpcData
[DPC_THREADED
].DpcQueueDepth
> 0))
912 /* Request an interrupt */
913 HalRequestSoftwareInterrupt(DISPATCH_LEVEL
);
918 /* FIXME: SMP support required */
928 KeIsExecutingDpc(VOID
)
930 /* Return if the Dpc Routine is active */
931 return KeGetCurrentPrcb()->DpcRoutineActive
;
939 KeSetImportanceDpc (IN PKDPC Dpc
,
940 IN KDPC_IMPORTANCE Importance
)
942 /* Set the DPC Importance */
944 Dpc
->Importance
= Importance
;
952 KeSetTargetProcessorDpc(IN PKDPC Dpc
,
955 /* Set a target CPU */
957 Dpc
->Number
= Number
+ MAXIMUM_PROCESSORS
;
965 KeGenericCallDpc(IN PKDEFERRED_ROUTINE Routine
,
968 ULONG Barrier
= KeNumberProcessors
;
970 DEFERRED_REVERSE_BARRIER ReverseBarrier
;
971 ASSERT(KeGetCurrentIrql () < DISPATCH_LEVEL
);
974 // The barrier is the number of processors, each processor will decrement it
975 // by one, so when all processors have run the DPC, the barrier reaches zero
977 ReverseBarrier
.Barrier
= Barrier
;
978 ReverseBarrier
.TotalProcessors
= Barrier
;
981 // But we don't need the barrier on UP, since we can simply call the routine
982 // directly while at DISPATCH_LEVEL and not worry about anything else
984 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
985 Routine(&KeGetCurrentPrcb()->CallDpc
, Context
, &Barrier
, &ReverseBarrier
);
986 KeLowerIrql(OldIrql
);
994 KeSignalCallDpcDone(IN PVOID SystemArgument1
)
997 // Decrement the barrier, which is actually the processor count
999 InterlockedDecrement((PLONG
)SystemArgument1
);
1007 KeSignalCallDpcSynchronize(IN PVOID SystemArgument2
)
1010 // There is nothing to do on UP systems -- the processor calling this wins
1012 UNREFERENCED_PARAMETER(SystemArgument2
);