ReactOS 0.4.15-dev-7953-g1f49173
dpc.c
Go to the documentation of this file.
1/*
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)
8 * Eric Kohl
9 */
10
11/* INCLUDES ******************************************************************/
12
13#include <ntoskrnl.h>
14#define NDEBUG
15#include <debug.h>
16
17/* GLOBALS *******************************************************************/
18
28
29/* PRIVATE FUNCTIONS *********************************************************/
30
31VOID
34{
35#if DBG
36 ULONG i = 0;
37 PLIST_ENTRY ListHead, NextEntry;
40
41 /* Raise IRQL to high and loop timers */
43 do
44 {
45 /* Loop the current list */
46 ListHead = &KiTimerTableListHead[i].Entry;
47 NextEntry = ListHead->Flink;
48 while (NextEntry != ListHead)
49 {
50 /* Get the timer and move to the next one */
51 Timer = CONTAINING_RECORD(NextEntry, KTIMER, TimerListEntry);
52 NextEntry = NextEntry->Flink;
53
54 /* Check if it expired */
55 if (Timer->DueTime.QuadPart <= CurrentTime.QuadPart)
56 {
57 /* Check if the DPC was queued, but didn't run */
58 if (!(KeGetCurrentPrcb()->TimerRequest) &&
59 !(*((volatile PULONG*)(&KiTimerExpireDpc.DpcData))))
60 {
61 /* This is bad, breakpoint! */
62 DPRINT1("Invalid timer state!\n");
64 }
65 }
66 }
67
68 /* Move to the next timer */
69 i++;
70 } while(i < TIMER_TABLE_SIZE);
71
72 /* Lower IRQL and return */
74#endif
75}
76
77VOID
83{
84 ULARGE_INTEGER SystemTime, InterruptTime;
86 LONG Limit, Index, i;
87 ULONG Timers, ActiveTimers, DpcCalls;
88 PLIST_ENTRY ListHead, NextEntry;
91 PKDPC TimerDpc;
94 PKSPIN_LOCK_QUEUE LockQueue;
95 PKPRCB Prcb = KeGetCurrentPrcb();
96
97 /* Disable interrupts */
98 _disable();
99
100 /* Query system and interrupt time */
101 KeQuerySystemTime((PLARGE_INTEGER)&SystemTime);
102 InterruptTime.QuadPart = KeQueryInterruptTime();
104
105 /* Bring interrupts back */
106 _enable();
107
108 /* Get the index of the timer and normalize it */
110 if ((Limit - Index) >= TIMER_TABLE_SIZE)
111 {
112 /* Normalize it */
114 }
115
116 /* Setup index and actual limit */
117 Index--;
118 Limit &= (TIMER_TABLE_SIZE - 1);
119
120 /* Setup accounting data */
121 DpcCalls = 0;
122 Timers = 24;
123 ActiveTimers = 4;
124
125 /* Lock the Database and Raise IRQL */
127
128 /* Start expiration loop */
129 do
130 {
131 /* Get the current index */
132 Index = (Index + 1) & (TIMER_TABLE_SIZE - 1);
133
134 /* Get list pointers and loop the list */
135 ListHead = &KiTimerTableListHead[Index].Entry;
136 while (ListHead != ListHead->Flink)
137 {
138 /* Lock the timer and go to the next entry */
139 LockQueue = KiAcquireTimerLock(Index);
140 NextEntry = ListHead->Flink;
141
142 /* Get the current timer and check its due time */
143 Timers--;
144 Timer = CONTAINING_RECORD(NextEntry, KTIMER, TimerListEntry);
145 if ((NextEntry != ListHead) &&
146 (Timer->DueTime.QuadPart <= InterruptTime.QuadPart))
147 {
148 /* It's expired, remove it */
149 ActiveTimers--;
151
152 /* Make it non-inserted, unlock it, and signal it */
153 Timer->Header.Inserted = FALSE;
154 KiReleaseTimerLock(LockQueue);
155 Timer->Header.SignalState = 1;
156
157 /* Get the DPC and period */
158 TimerDpc = Timer->Dpc;
159 Period = Timer->Period;
160
161 /* Check if there's any waiters */
162 if (!IsListEmpty(&Timer->Header.WaitListHead))
163 {
164 /* Check the type of event */
165 if (Timer->Header.Type == TimerNotificationObject)
166 {
167 /* Unwait the thread */
169 }
170 else
171 {
172 /* Otherwise unwait the thread and signal the timer */
174 }
175 }
176
177 /* Check if we have a period */
178 if (Period)
179 {
180 /* Calculate the interval and insert the timer */
181 Interval.QuadPart = Int32x32To64(Period, -10000);
183 }
184
185 /* Check if we have a DPC */
186 if (TimerDpc)
187 {
188#ifdef CONFIG_SMP
189 /*
190 * If the DPC is targeted to another processor,
191 * then insert it into that processor's DPC queue
192 * instead of delivering it now.
193 * If the DPC is a threaded DPC, and the current CPU
194 * has threaded DPCs enabled (KiExecuteDpc is actively parsing DPCs),
195 * then also insert it into the DPC queue for threaded delivery,
196 * instead of doing it here.
197 */
198 if (((TimerDpc->Number >= MAXIMUM_PROCESSORS) &&
199 ((TimerDpc->Number - MAXIMUM_PROCESSORS) != Prcb->Number)) ||
200 ((TimerDpc->Type == ThreadedDpcObject) && (Prcb->ThreadDpcEnable)))
201 {
202 /* Queue it */
203 KeInsertQueueDpc(TimerDpc,
204 UlongToPtr(SystemTime.LowPart),
205 UlongToPtr(SystemTime.HighPart));
206 }
207 else
208#endif
209 {
210 /* Setup the DPC Entry */
211 DpcEntry[DpcCalls].Dpc = TimerDpc;
212 DpcEntry[DpcCalls].Routine = TimerDpc->DeferredRoutine;
213 DpcEntry[DpcCalls].Context = TimerDpc->DeferredContext;
214 DpcCalls++;
215 ASSERT(DpcCalls < MAX_TIMER_DPCS);
216 }
217 }
218
219 /* Check if we're done processing */
220 if (!(ActiveTimers) || !(Timers))
221 {
222 /* Release the dispatcher while doing DPCs */
224
225 /* Start looping all DPC Entries */
226 for (i = 0; DpcCalls; DpcCalls--, i++)
227 {
228#if DBG
229 /* Clear DPC Time */
230 Prcb->DebugDpcTime = 0;
231#endif
232
233 /* Call the DPC */
234 DpcEntry[i].Routine(DpcEntry[i].Dpc,
235 DpcEntry[i].Context,
236 UlongToPtr(SystemTime.LowPart),
237 UlongToPtr(SystemTime.HighPart));
238 }
239
240 /* Reset accounting */
241 Timers = 24;
242 ActiveTimers = 4;
243
244 /* Lock the dispatcher database */
246 }
247 }
248 else
249 {
250 /* Check if the timer list is empty */
251 if (NextEntry != ListHead)
252 {
253 /* Sanity check */
255 Timer->DueTime.QuadPart);
256
257 /* Update the time */
258 _disable();
260 Timer->DueTime.QuadPart;
261 _enable();
262 }
263
264 /* Release the lock */
265 KiReleaseTimerLock(LockQueue);
266
267 /* Check if we've scanned all the timers we could */
268 if (!Timers)
269 {
270 /* Release the dispatcher while doing DPCs */
272
273 /* Start looping all DPC Entries */
274 for (i = 0; DpcCalls; DpcCalls--, i++)
275 {
276#if DBG
277 /* Clear DPC Time */
278 Prcb->DebugDpcTime = 0;
279#endif
280
281 /* Call the DPC */
282 DpcEntry[i].Routine(DpcEntry[i].Dpc,
283 DpcEntry[i].Context,
284 UlongToPtr(SystemTime.LowPart),
285 UlongToPtr(SystemTime.HighPart));
286 }
287
288 /* Reset accounting */
289 Timers = 24;
290 ActiveTimers = 4;
291
292 /* Lock the dispatcher database */
294 }
295
296 /* Done looping */
297 break;
298 }
299 }
300 } while (Index != Limit);
301
302 /* Verify the timer table, on debug builds */
303 if (KeNumberProcessors == 1) KiCheckTimerTable(InterruptTime);
304
305 /* Check if we still have DPC entries */
306 if (DpcCalls)
307 {
308 /* Release the dispatcher while doing DPCs */
310
311 /* Start looping all DPC Entries */
312 for (i = 0; DpcCalls; DpcCalls--, i++)
313 {
314#if DBG
315 /* Clear DPC Time */
316 Prcb->DebugDpcTime = 0;
317#endif
318
319 /* Call the DPC */
320 DpcEntry[i].Routine(DpcEntry[i].Dpc,
321 DpcEntry[i].Context,
322 UlongToPtr(SystemTime.LowPart),
323 UlongToPtr(SystemTime.HighPart));
324 }
325
326 /* Lower IRQL if we need to */
328 }
329 else
330 {
331 /* Unlock the dispatcher */
333 }
334}
335
336VOID
340{
341 ULARGE_INTEGER SystemTime;
343 LONG i;
344 ULONG DpcCalls = 0;
346 PKDPC TimerDpc;
349 PKPRCB Prcb = KeGetCurrentPrcb();
350
351 /* Query system */
352 KeQuerySystemTime((PLARGE_INTEGER)&SystemTime);
353
354 /* Loop expired list */
355 while (ExpiredListHead->Flink != ExpiredListHead)
356 {
357 /* Get the current timer */
358 Timer = CONTAINING_RECORD(ExpiredListHead->Flink, KTIMER, TimerListEntry);
359
360 /* Remove it */
361 RemoveEntryList(&Timer->TimerListEntry);
362
363 /* Not inserted */
364 Timer->Header.Inserted = FALSE;
365
366 /* Signal it */
367 Timer->Header.SignalState = 1;
368
369 /* Get the DPC and period */
370 TimerDpc = Timer->Dpc;
371 Period = Timer->Period;
372
373 /* Check if there's any waiters */
374 if (!IsListEmpty(&Timer->Header.WaitListHead))
375 {
376 /* Check the type of event */
377 if (Timer->Header.Type == TimerNotificationObject)
378 {
379 /* Unwait the thread */
381 }
382 else
383 {
384 /* Otherwise unwait the thread and signal the timer */
386 }
387 }
388
389 /* Check if we have a period */
390 if (Period)
391 {
392 /* Calculate the interval and insert the timer */
393 Interval.QuadPart = Int32x32To64(Period, -10000);
395 }
396
397 /* Check if we have a DPC */
398 if (TimerDpc)
399 {
400#ifdef CONFIG_SMP
401 /*
402 * If the DPC is targeted to another processor,
403 * then insert it into that processor's DPC queue
404 * instead of delivering it now.
405 * If the DPC is a threaded DPC, and the current CPU
406 * has threaded DPCs enabled (KiExecuteDpc is actively parsing DPCs),
407 * then also insert it into the DPC queue for threaded delivery,
408 * instead of doing it here.
409 */
410 if (((TimerDpc->Number >= MAXIMUM_PROCESSORS) &&
411 ((TimerDpc->Number - MAXIMUM_PROCESSORS) != Prcb->Number)) ||
412 ((TimerDpc->Type == ThreadedDpcObject) && (Prcb->ThreadDpcEnable)))
413 {
414 /* Queue it */
415 KeInsertQueueDpc(TimerDpc,
416 UlongToPtr(SystemTime.LowPart),
417 UlongToPtr(SystemTime.HighPart));
418 }
419 else
420#endif
421 {
422 /* Setup the DPC Entry */
423 DpcEntry[DpcCalls].Dpc = TimerDpc;
424 DpcEntry[DpcCalls].Routine = TimerDpc->DeferredRoutine;
425 DpcEntry[DpcCalls].Context = TimerDpc->DeferredContext;
426 DpcCalls++;
427 ASSERT(DpcCalls < MAX_TIMER_DPCS);
428 }
429 }
430 }
431
432 /* Check if we still have DPC entries */
433 if (DpcCalls)
434 {
435 /* Release the dispatcher while doing DPCs */
437
438 /* Start looping all DPC Entries */
439 for (i = 0; DpcCalls; DpcCalls--, i++)
440 {
441#if DBG
442 /* Clear DPC Time */
443 Prcb->DebugDpcTime = 0;
444#endif
445
446 /* Call the DPC */
447 DpcEntry[i].Routine(DpcEntry[i].Dpc,
448 DpcEntry[i].Context,
449 UlongToPtr(SystemTime.LowPart),
450 UlongToPtr(SystemTime.HighPart));
451 }
452
453 /* Lower IRQL */
455 }
456 else
457 {
458 /* Unlock the dispatcher */
460 }
461}
462
464VOID
465NTAPI
467{
468 PKPRCB Prcb = KeGetCurrentPrcb();
469 PKTHREAD NextThread, Thread = Prcb->CurrentThread;
470
471 /* Check if a DPC Event was requested to be signaled */
473 {
474 /* Signal it */
475 KeSetEvent(&Prcb->DpcEvent, 0, 0);
476 }
477
478 /* Raise to synchronization level and lock the PRCB and thread */
481 KiAcquirePrcbLock(Prcb);
482
483 /* Check if Quantum expired */
484 if (Thread->Quantum <= 0)
485 {
486 /* Check if we're real-time and with quantums disabled */
487 if ((Thread->Priority >= LOW_REALTIME_PRIORITY) &&
488 (Thread->ApcState.Process->DisableQuantum))
489 {
490 /* Otherwise, set maximum quantum */
491 Thread->Quantum = MAX_QUANTUM;
492 }
493 else
494 {
495 /* Reset the new Quantum */
496 Thread->Quantum = Thread->QuantumReset;
497
498 /* Calculate new priority */
499 Thread->Priority = KiComputeNewPriority(Thread, 1);
500
501 /* Check if a new thread is scheduled */
502 if (!Prcb->NextThread)
503 {
504 /* Get a new ready thread */
505 NextThread = KiSelectReadyThread(Thread->Priority, Prcb);
506 if (NextThread)
507 {
508 /* Found one, set it on standby */
509 NextThread->State = Standby;
510 Prcb->NextThread = NextThread;
511 }
512 }
513 else
514 {
515 /* Otherwise, make sure that this thread doesn't get preempted */
516 Thread->Preempted = FALSE;
517 }
518 }
519 }
520
521 /* Release the thread lock */
523
524 /* Check if there's no thread scheduled */
525 if (!Prcb->NextThread)
526 {
527 /* Just leave now */
528 KiReleasePrcbLock(Prcb);
530 return;
531 }
532
533 /* Get the next thread now */
534 NextThread = Prcb->NextThread;
535
536 /* Set current thread's swap busy to true */
538
539 /* Switch threads in PRCB */
540 Prcb->NextThread = NULL;
541 Prcb->CurrentThread = NextThread;
542
543 /* Set thread to running and the switch reason to Quantum End */
544 NextThread->State = Running;
545 Thread->WaitReason = WrQuantumEnd;
546
547 /* Queue it on the ready lists */
548 KxQueueReadyThread(Thread, Prcb);
549
550 /* Set wait IRQL to APC_LEVEL */
551 Thread->WaitIrql = APC_LEVEL;
552
553 /* Swap threads */
555
556 /* Lower IRQL back to DISPATCH_LEVEL */
558}
559
560VOID
563{
564 PKDPC_DATA DpcData;
565 PLIST_ENTRY ListHead, DpcEntry;
566 PKDPC Dpc;
567 PKDEFERRED_ROUTINE DeferredRoutine;
569 ULONG_PTR TimerHand;
570#ifdef CONFIG_SMP
572#endif
573
574 /* Get data and list variables before starting anything else */
575 DpcData = &Prcb->DpcData[DPC_NORMAL];
576 ListHead = &DpcData->DpcListHead;
577
578 /* Main outer loop */
579 do
580 {
581 /* Set us as active */
582 Prcb->DpcRoutineActive = TRUE;
583
584 /* Check if this is a timer expiration request */
585 if (Prcb->TimerRequest)
586 {
587 /* It is, get the timer hand and disable timer request */
588 TimerHand = Prcb->TimerHand;
589 Prcb->TimerRequest = 0;
590
591 /* Expire timers with interrupts enabled */
592 _enable();
593 KiTimerExpiration(NULL, NULL, (PVOID)TimerHand, NULL);
594 _disable();
595 }
596
597 /* Loop while we have entries in the queue */
598 while (DpcData->DpcQueueDepth != 0)
599 {
600 /* Lock the DPC data and get the DPC entry*/
602 DpcEntry = ListHead->Flink;
603
604 /* Make sure we have an entry */
605 if (DpcEntry != ListHead)
606 {
607 /* Remove the DPC from the list */
608 RemoveEntryList(DpcEntry);
609 Dpc = CONTAINING_RECORD(DpcEntry, KDPC, DpcListEntry);
610
611 /* Clear its DPC data and save its parameters */
612 Dpc->DpcData = NULL;
613 DeferredRoutine = Dpc->DeferredRoutine;
614 DeferredContext = Dpc->DeferredContext;
615 SystemArgument1 = Dpc->SystemArgument1;
616 SystemArgument2 = Dpc->SystemArgument2;
617
618 /* Decrease the queue depth */
619 DpcData->DpcQueueDepth--;
620
621#if DBG
622 /* Clear DPC Time */
623 Prcb->DebugDpcTime = 0;
624#endif
625
626 /* Release the lock */
628
629 /* Re-enable interrupts */
630 _enable();
631
632 /* Call the DPC */
633 DeferredRoutine(Dpc,
638
639 /* Disable interrupts and keep looping */
640 _disable();
641 }
642 else
643 {
644 /* The queue should be flushed now */
645 ASSERT(DpcData->DpcQueueDepth == 0);
646
647 /* Release DPC Lock */
649 }
650 }
651
652 /* Clear DPC Flags */
653 Prcb->DpcRoutineActive = FALSE;
654 Prcb->DpcInterruptRequested = FALSE;
655
656#ifdef CONFIG_SMP
657 /* Check if we have deferred threads */
658 if (Prcb->DeferredReadyListHead.Next)
659 {
660
661 /* Re-enable interrupts and raise to synch */
662 _enable();
664
665 /* Process deferred threads */
667
668 /* Lower IRQL back and disable interrupts */
670 _disable();
671 }
672#endif
673 } while (DpcData->DpcQueueDepth != 0);
674}
675
676VOID
677NTAPI
679 IN PKDEFERRED_ROUTINE DeferredRoutine,
682{
683 /* Setup the DPC Object */
684 Dpc->Type = Type;
685 Dpc->Number = 0;
686 Dpc->Importance= MediumImportance;
687 Dpc->DeferredRoutine = DeferredRoutine;
688 Dpc->DeferredContext = DeferredContext;
689 Dpc->DpcData = NULL;
690}
691
692/* PUBLIC FUNCTIONS **********************************************************/
693
694/*
695 * @implemented
696 */
697VOID
698NTAPI
700 IN PKDEFERRED_ROUTINE DeferredRoutine,
702{
703 /* Call the internal routine */
705}
706
707/*
708 * @implemented
709 */
710VOID
711NTAPI
713 IN PKDEFERRED_ROUTINE DeferredRoutine,
715{
716 /* Call the internal routine */
717 KiInitializeDpc(Dpc, DeferredRoutine, DeferredContext, DpcObject);
718}
719
720/*
721 * @implemented
722 */
724NTAPI
728{
730 PKPRCB Prcb, CurrentPrcb;
731 ULONG Cpu;
732 PKDPC_DATA DpcData;
733 BOOLEAN DpcConfigured = FALSE, DpcInserted = FALSE;
735
736 /* Check IRQL and Raise it to HIGH_LEVEL */
738 CurrentPrcb = KeGetCurrentPrcb();
739
740 /* Check if the DPC has more then the maximum number of CPUs */
741 if (Dpc->Number >= MAXIMUM_PROCESSORS)
742 {
743 /* Then substract the maximum and get that PRCB. */
744 Cpu = Dpc->Number - MAXIMUM_PROCESSORS;
745 Prcb = KiProcessorBlock[Cpu];
746 }
747 else
748 {
749 /* Use the current one */
750 Prcb = CurrentPrcb;
751 Cpu = Prcb->Number;
752 }
753
754 /* ROS Sanity Check */
755 ASSERT(Prcb == CurrentPrcb);
756
757 /* Check if this is a threaded DPC and threaded DPCs are enabled */
758 if ((Dpc->Type == ThreadedDpcObject) && (Prcb->ThreadDpcEnable))
759 {
760 /* Then use the threaded data */
761 DpcData = &Prcb->DpcData[DPC_THREADED];
762 }
763 else
764 {
765 /* Otherwise, use the regular data */
766 DpcData = &Prcb->DpcData[DPC_NORMAL];
767 }
768
769 /* Acquire the DPC lock */
770 KiAcquireSpinLock(&DpcData->DpcLock);
771
772 /* Get the DPC Data */
773 if (!InterlockedCompareExchangePointer(&Dpc->DpcData, DpcData, NULL))
774 {
775 /* Now we can play with the DPC safely */
776 Dpc->SystemArgument1 = SystemArgument1;
777 Dpc->SystemArgument2 = SystemArgument2;
778 DpcData->DpcQueueDepth++;
779 DpcData->DpcCount++;
780 DpcConfigured = TRUE;
781
782 /* Check if this is a high importance DPC */
783 if (Dpc->Importance == HighImportance)
784 {
785 /* Pre-empty other DPCs */
786 InsertHeadList(&DpcData->DpcListHead, &Dpc->DpcListEntry);
787 }
788 else
789 {
790 /* Add it at the end */
791 InsertTailList(&DpcData->DpcListHead, &Dpc->DpcListEntry);
792 }
793
794 /* Check if this is the DPC on the threaded list */
795 if (&Prcb->DpcData[DPC_THREADED] == DpcData)
796 {
797 /* Make sure a threaded DPC isn't already active */
798 if (!(Prcb->DpcThreadActive) && !(Prcb->DpcThreadRequested))
799 {
800 /* FIXME: Setup Threaded DPC */
801 UNIMPLEMENTED_FATAL("Threaded DPC not supported\n");
802 }
803 }
804 else
805 {
806 /* Make sure a DPC isn't executing already */
807 if (!(Prcb->DpcRoutineActive) && !(Prcb->DpcInterruptRequested))
808 {
809 /* Check if this is the same CPU */
810 if (Prcb != CurrentPrcb)
811 {
812 /*
813 * Check if the DPC is of high importance or above the
814 * maximum depth. If it is, then make sure that the CPU
815 * isn't idle, or that it's sleeping.
816 */
817 if (((Dpc->Importance == HighImportance) ||
818 (DpcData->DpcQueueDepth >=
819 Prcb->MaximumDpcQueueDepth)) &&
820 (!(AFFINITY_MASK(Cpu) & KiIdleSummary) ||
821 (Prcb->Sleeping)))
822 {
823 /* Set interrupt requested */
825
826 /* Set DPC inserted */
827 DpcInserted = TRUE;
828 }
829 }
830 else
831 {
832 /* Check if the DPC is of anything but low importance */
833 if ((Dpc->Importance != LowImportance) ||
834 (DpcData->DpcQueueDepth >=
835 Prcb->MaximumDpcQueueDepth) ||
836 (Prcb->DpcRequestRate < Prcb->MinimumDpcRate))
837 {
838 /* Set interrupt requested */
840
841 /* Set DPC inserted */
842 DpcInserted = TRUE;
843 }
844 }
845 }
846 }
847 }
848
849 /* Release the lock */
850 KiReleaseSpinLock(&DpcData->DpcLock);
851
852 /* Check if the DPC was inserted */
853 if (DpcInserted)
854 {
855 /* Check if this was SMP */
856 if (Prcb != CurrentPrcb)
857 {
858 /* It was, request and IPI */
860 }
861 else
862 {
863 /* It wasn't, request an interrupt from HAL */
865 }
866 }
867
868 /* Lower IRQL */
870 return DpcConfigured;
871}
872
873/*
874 * @implemented
875 */
877NTAPI
879{
880 PKDPC_DATA DpcData;
883
884 /* Disable interrupts */
886
887 /* Get DPC data */
888 DpcData = Dpc->DpcData;
889 if (DpcData)
890 {
891 /* Acquire the DPC lock */
892 KiAcquireSpinLock(&DpcData->DpcLock);
893
894 /* Make sure that the data didn't change */
895 if (DpcData == Dpc->DpcData)
896 {
897 /* Remove the DPC */
898 DpcData->DpcQueueDepth--;
899 RemoveEntryList(&Dpc->DpcListEntry);
900 Dpc->DpcData = NULL;
901 }
902
903 /* Release the lock */
904 KiReleaseSpinLock(&DpcData->DpcLock);
905 }
906
907 /* Re-enable interrupts */
908 if (Enable) _enable();
909
910 /* Return if the DPC was in the queue or not */
911 return DpcData ? TRUE : FALSE;
912}
913
914/*
915 * @implemented
916 */
917VOID
918NTAPI
920{
921 PKPRCB CurrentPrcb = KeGetCurrentPrcb();
922 PAGED_CODE();
923
924 /* Check if this is an UP machine */
925 if (KeActiveProcessors == 1)
926 {
927 /* Check if there are DPCs on either queues */
928 if ((CurrentPrcb->DpcData[DPC_NORMAL].DpcQueueDepth > 0) ||
929 (CurrentPrcb->DpcData[DPC_THREADED].DpcQueueDepth > 0))
930 {
931 /* Request an interrupt */
933 }
934 }
935 else
936 {
937 /* FIXME: SMP support required */
938 ASSERT(FALSE);
939 }
940}
941
942/*
943 * @implemented
944 */
946NTAPI
948{
949 /* Return if the Dpc Routine is active */
950 return KeGetCurrentPrcb()->DpcRoutineActive;
951}
952
953/*
954 * @implemented
955 */
956VOID
957NTAPI
960{
961 /* Set the DPC Importance */
963 Dpc->Importance = Importance;
964}
965
966/*
967 * @implemented
968 */
969VOID
970NTAPI
973{
974 /* Set a target CPU */
976 Dpc->Number = Number + MAXIMUM_PROCESSORS;
977}
978
979/*
980 * @implemented
981 */
982VOID
983NTAPI
986{
987 ULONG Barrier = KeNumberProcessors;
989 DEFERRED_REVERSE_BARRIER ReverseBarrier;
991
992 //
993 // The barrier is the number of processors, each processor will decrement it
994 // by one, so when all processors have run the DPC, the barrier reaches zero
995 //
996 ReverseBarrier.Barrier = Barrier;
997 ReverseBarrier.TotalProcessors = Barrier;
998
999 //
1000 // But we don't need the barrier on UP, since we can simply call the routine
1001 // directly while at DISPATCH_LEVEL and not worry about anything else
1002 //
1004 Routine(&KeGetCurrentPrcb()->CallDpc, Context, &Barrier, &ReverseBarrier);
1006}
1007
1008/*
1009 * @implemented
1010 */
1011VOID
1012NTAPI
1014{
1015 //
1016 // Decrement the barrier, which is actually the processor count
1017 //
1019}
1020
1021/*
1022 * @implemented
1023 */
1024BOOLEAN
1025NTAPI
1027{
1028 //
1029 // There is nothing to do on UP systems -- the processor calling this wins
1030 //
1032 return TRUE;
1033}
1034
1035/* EOF */
#define PAGED_CODE()
unsigned char BOOLEAN
Type
Definition: Type.h:7
#define InterlockedExchange
Definition: armddk.h:54
#define InterlockedDecrement
Definition: armddk.h:52
#define DPRINT1
Definition: precomp.h:8
#define PtrToLong(p)
Definition: basetsd.h:84
#define _Requires_lock_not_held_(lock)
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
VOID NTAPI KeGenericCallDpc(IN PKDEFERRED_ROUTINE Routine, IN PVOID Context)
Definition: dpc.c:984
BOOLEAN NTAPI KeInsertQueueDpc(IN PKDPC Dpc, IN PVOID SystemArgument1, IN PVOID SystemArgument2)
Definition: dpc.c:725
FAST_MUTEX KiGenericCallDpcMutex
Definition: dpc.c:24
ULONG KiAdjustDpcThreshold
Definition: dpc.c:21
ULONG KiTimeLimitIsrMicroseconds
Definition: dpc.c:26
ULONG KiMaximumDpcQueueDepth
Definition: dpc.c:19
BOOLEAN KeThreadDpcEnable
Definition: dpc.c:23
VOID NTAPI KeInitializeDpc(IN PKDPC Dpc, IN PKDEFERRED_ROUTINE DeferredRoutine, IN PVOID DeferredContext)
Definition: dpc.c:712
VOID NTAPI KeSetTargetProcessorDpc(IN PKDPC Dpc, IN CCHAR Number)
Definition: dpc.c:971
KDPC KiTimerExpireDpc
Definition: dpc.c:25
VOID FASTCALL KiTimerListExpire(IN PLIST_ENTRY ExpiredListHead, IN KIRQL OldIrql)
Definition: dpc.c:338
ULONG KiMinimumDpcRate
Definition: dpc.c:20
BOOLEAN NTAPI KeRemoveQueueDpc(IN PKDPC Dpc)
Definition: dpc.c:878
BOOLEAN NTAPI KeSignalCallDpcSynchronize(IN PVOID SystemArgument2)
Definition: dpc.c:1026
ULONG KiDPCTimeout
Definition: dpc.c:27
VOID NTAPI KeFlushQueuedDpcs(VOID)
Definition: dpc.c:919
VOID NTAPI KeInitializeThreadedDpc(IN PKDPC Dpc, IN PKDEFERRED_ROUTINE DeferredRoutine, IN PVOID DeferredContext)
Definition: dpc.c:699
ULONG KiIdealDpcRate
Definition: dpc.c:22
VOID NTAPI KiCheckTimerTable(IN ULARGE_INTEGER CurrentTime)
Definition: dpc.c:33
VOID NTAPI KiInitializeDpc(IN PKDPC Dpc, IN PKDEFERRED_ROUTINE DeferredRoutine, IN PVOID DeferredContext, IN KOBJECTS Type)
Definition: dpc.c:678
VOID NTAPI KeSignalCallDpcDone(IN PVOID SystemArgument1)
Definition: dpc.c:1013
BOOLEAN NTAPI KeIsExecutingDpc(VOID)
Definition: dpc.c:947
VOID NTAPI KiTimerExpiration(IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2)
Definition: dpc.c:79
VOID NTAPI KeSetImportanceDpc(IN PKDPC Dpc, IN KDPC_IMPORTANCE Importance)
Definition: dpc.c:958
VOID FASTCALL KiRetireDpcList(IN PKPRCB Prcb)
Definition: dpc.c:562
#define UlongToPtr(u)
Definition: config.h:106
#define RemoveEntryList(Entry)
Definition: env_spec_w32.h:986
#define InsertTailList(ListHead, Entry)
#define InsertHeadList(ListHead, Entry)
#define IsListEmpty(ListHead)
Definition: env_spec_w32.h:954
UCHAR KIRQL
Definition: env_spec_w32.h:591
#define KeRaiseIrql(irql, oldIrql)
Definition: env_spec_w32.h:597
#define HIGH_LEVEL
Definition: env_spec_w32.h:703
#define APC_LEVEL
Definition: env_spec_w32.h:695
#define KeLowerIrql(oldIrql)
Definition: env_spec_w32.h:602
#define KeSetEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:476
#define KeQuerySystemTime(t)
Definition: env_spec_w32.h:570
#define KeGetCurrentIrql()
Definition: env_spec_w32.h:706
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
#define MAXIMUM_PROCESSORS
Definition: rwlock.h:5
_In_opt_ PFILE_OBJECT _In_opt_ PETHREAD Thread
Definition: fltkernel.h:2653
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
VOID FASTCALL HalRequestSoftwareInterrupt(IN KIRQL Irql)
Definition: pic.c:271
KIRQL NTAPI KeRaiseIrqlToSynchLevel(VOID)
Definition: pic.c:156
NTSYSAPI void WINAPI DbgBreakPoint(void)
#define LOW_REALTIME_PRIORITY
#define InterlockedCompareExchangePointer
Definition: interlocked.h:129
void __cdecl _disable(void)
Definition: intrin_arm.h:365
void __cdecl _enable(void)
Definition: intrin_arm.h:373
FORCEINLINE VOID KiReleaseDispatcherLock(IN KIRQL OldIrql)
Definition: ke_x.h:157
FORCEINLINE PKTHREAD KiSelectReadyThread(IN KPRIORITY Priority, IN PKPRCB Prcb)
Definition: ke_x.h:1422
FORCEINLINE VOID KiSetThreadSwapBusy(IN PKTHREAD Thread)
Definition: ke_x.h:210
FORCEINLINE VOID KiRemoveEntryTimer(IN PKTIMER Timer)
Definition: ke_x.h:892
FORCEINLINE VOID KiReleaseTimerLock(IN PKSPIN_LOCK_QUEUE LockQueue)
Definition: ke_x.h:297
FORCEINLINE VOID KiReleasePrcbLock(IN PKPRCB Prcb)
Definition: ke_x.h:230
FORCEINLINE VOID KiAcquireThreadLock(IN PKTHREAD Thread)
Definition: ke_x.h:240
FORCEINLINE VOID KxUnwaitThread(IN DISPATCHER_HEADER *Object, IN KPRIORITY Increment)
Definition: ke_x.h:1259
FORCEINLINE PKSPIN_LOCK_QUEUE KiAcquireTimerLock(IN ULONG Hand)
Definition: ke_x.h:286
FORCEINLINE VOID KiReleaseThreadLock(IN PKTHREAD Thread)
Definition: ke_x.h:250
FORCEINLINE VOID KiAcquirePrcbLock(IN PKPRCB Prcb)
Definition: ke_x.h:220
FORCEINLINE KIRQL KiAcquireDispatcherLock(VOID)
Definition: ke_x.h:149
FORCEINLINE SCHAR KiComputeNewPriority(IN PKTHREAD Thread, IN SCHAR Adjustment)
Definition: ke_x.h:1472
FORCEINLINE VOID KxUnwaitThreadForEvent(IN PKEVENT Event, IN KPRIORITY Increment)
Definition: ke_x.h:1304
CCHAR KeNumberProcessors
Definition: krnlinit.c:35
#define ASSERT(a)
Definition: mode.c:44
static PLARGE_INTEGER Time
Definition: time.c:105
FORCEINLINE struct _KPRCB * KeGetCurrentPrcb(VOID)
Definition: ketypes.h:1161
#define IPI_DPC
Definition: ketypes.h:298
FORCEINLINE KAFFINITY AFFINITY_MASK(ULONG Index)
Definition: kefuncs.h:39
@ TimerNotificationObject
Definition: ketypes.h:414
@ DpcObject
Definition: ketypes.h:425
@ ThreadedDpcObject
Definition: ketypes.h:430
@ Running
Definition: ketypes.h:390
@ Standby
Definition: ketypes.h:391
enum _KOBJECTS KOBJECTS
#define MAX_QUANTUM
Definition: ketypes.h:136
DWORD Interval
Definition: netstat.c:30
#define FASTCALL
Definition: nt_native.h:50
#define Int32x32To64(a, b)
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:317
_In_ ULONGLONG _In_ ULONGLONG _In_ BOOLEAN Enable
Definition: ntddpcm.h:142
FORCEINLINE BOOLEAN KeDisableInterrupts(VOID)
Definition: ke.h:239
NTKERNELAPI volatile KSYSTEM_TIME KeTickCount
Definition: clock.c:19
KTIMER_TABLE_ENTRY KiTimerTableListHead[TIMER_TABLE_SIZE]
Definition: timerobj.c:17
PKPRCB KiProcessorBlock[]
Definition: krnlinit.c:32
BOOLEAN FASTCALL KiSwapContext(IN KIRQL WaitIrql, IN PKTHREAD CurrentThread)
KAFFINITY KiIdleSummary
Definition: thrdschd.c:25
KAFFINITY KeActiveProcessors
Definition: krnlinit.c:23
VOID FASTCALL KiProcessDeferredReadyList(IN PKPRCB Prcb)
Definition: thrdschd.c:41
VOID FASTCALL KiIpiSend(KAFFINITY TargetSet, ULONG IpiRequest)
VOID NTAPI KiQuantumEnd(VOID)
BOOLEAN FASTCALL KiInsertTreeTimer(IN PKTIMER Timer, IN LARGE_INTEGER Interval)
Definition: timerobj.c:26
#define MAX_TIMER_DPCS
Definition: ke.h:69
VOID FASTCALL KiAcquireSpinLock(IN PKSPIN_LOCK SpinLock)
Definition: spinlock.c:287
VOID FASTCALL KiReleaseSpinLock(IN PKSPIN_LOCK SpinLock)
Definition: spinlock.c:298
_In_opt_ PENTER_STATE_SYSTEM_HANDLER _In_opt_ PVOID _In_ LONG _In_opt_ LONG volatile * Number
Definition: ntpoapi.h:207
long LONG
Definition: pedump.c:60
#define UNIMPLEMENTED_FATAL(...)
Definition: debug.h:244
#define KeQueryInterruptTime()
Definition: ke.h:37
#define KeAcquireSpinLockAtDpcLevel(SpinLock)
Definition: ke.h:125
#define KeReleaseSpinLockFromDpcLevel(SpinLock)
Definition: ke.h:135
ULONG TotalProcessors
Definition: ke.h:54
Definition: ke.h:72
PVOID Context
Definition: ke.h:75
PKDEFERRED_ROUTINE Routine
Definition: ke.h:74
PKDPC Dpc
Definition: ke.h:73
ULONG DpcCount
Definition: ketypes.h:860
ULONG_PTR DpcLock
Definition: ketypes.h:854
volatile ULONG DpcQueueDepth
Definition: ketypes.h:858
Definition: ketypes.h:699
UCHAR Type
Definition: ketypes.h:700
PKDEFERRED_ROUTINE DeferredRoutine
Definition: ketypes.h:704
volatile PVOID DpcData
Definition: ketypes.h:708
volatile USHORT Number
Definition: ketypes.h:702
PVOID DeferredContext
Definition: ketypes.h:705
UCHAR DpcThreadActive
Definition: ketypes.h:773
UCHAR DpcInterruptRequested
Definition: ketypes.h:770
UCHAR DpcRoutineActive
Definition: ketypes.h:772
LONG Sleeping
Definition: ketypes.h:846
KDPC_DATA DpcData[2]
Definition: ketypes.h:760
ULONG DebugDpcTime
Definition: ketypes.h:572
LONG MaximumDpcQueueDepth
Definition: ketypes.h:767
ULONG MinimumDpcRate
Definition: ketypes.h:769
UCHAR ThreadDpcEnable
Definition: ketypes.h:779
struct _KTHREAD * CurrentThread
Definition: ketypes.h:650
struct _KTHREAD * NextThread
Definition: ketypes.h:651
UCHAR DpcThreadRequested
Definition: ketypes.h:771
LONG DpcSetEventRequest
Definition: ketypes.h:783
USHORT Number
Definition: ketypes.h:643
KEVENT DpcEvent
Definition: ketypes.h:790
ULONG DpcRequestRate
Definition: ketypes.h:768
ULONG LowPart
Definition: ketypes.h:929
volatile UCHAR State
Definition: ketypes.h:1789
ULARGE_INTEGER Time
Definition: ketypes.h:779
LIST_ENTRY Entry
Definition: ketypes.h:778
Definition: typedefs.h:120
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
$ULONG LowPart
Definition: ntbasedef.h:569
ULONGLONG QuadPart
Definition: ms-dtyp.idl:185
$ULONG HighPart
Definition: ntbasedef.h:570
static LIST_ENTRY Timers
Definition: clock.c:40
uint32_t * PULONG
Definition: typedefs.h:59
#define NTAPI
Definition: typedefs.h:36
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define IN
Definition: typedefs.h:39
int32_t * PLONG
Definition: typedefs.h:58
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
uint32_t ULONG
Definition: typedefs.h:59
char CCHAR
Definition: typedefs.h:51
LONGLONG QuadPart
Definition: typedefs.h:114
_In_ WDFCOLLECTION _In_ ULONG Index
_Must_inspect_result_ _In_ PWDF_DPC_CONFIG _In_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFDPC * Dpc
Definition: wdfdpc.h:112
FAST_MUTEX
Definition: extypes.h:17
#define IO_NO_INCREMENT
Definition: iotypes.h:598
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:778
_In_ KDPC_IMPORTANCE Importance
Definition: kefuncs.h:82
_In_ LARGE_INTEGER _In_ ULONG Period
Definition: kefuncs.h:1313
_In_ LONG _In_ LONG Limit
Definition: kefuncs.h:304
@ HighImportance
Definition: ketypes.h:695
@ LowImportance
Definition: ketypes.h:693
@ MediumImportance
Definition: ketypes.h:694
@ WrQuantumEnd
Definition: ketypes.h:445
#define DPC_NORMAL
enum _KDPC_IMPORTANCE KDPC_IMPORTANCE
#define ASSERT_DPC(Object)
_In_opt_ PVOID _In_opt_ PVOID SystemArgument1
Definition: ketypes.h:688
_In_opt_ PVOID DeferredContext
Definition: ketypes.h:687
#define TIMER_TABLE_SIZE
Definition: ketypes.h:848
_In_opt_ PVOID _In_opt_ PVOID _In_opt_ PVOID SystemArgument2
Definition: ketypes.h:689
#define DPC_THREADED
KDEFERRED_ROUTINE * PKDEFERRED_ROUTINE
Definition: ketypes.h:690