ReactOS  0.4.15-dev-3187-ge372f2b
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 
31 VOID
32 NTAPI
34 {
35 #if DBG
36  ULONG i = 0;
37  PLIST_ENTRY ListHead, NextEntry;
38  KIRQL OldIrql;
39  PKTIMER Timer;
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");
63  DbgBreakPoint();
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 
77 VOID
78 NTAPI
83 {
84  ULARGE_INTEGER SystemTime, InterruptTime;
86  LONG Limit, Index, i;
87  ULONG Timers, ActiveTimers, DpcCalls;
88  PLIST_ENTRY ListHead, NextEntry;
89  KIRQL OldIrql;
90  PKTIMER Timer;
91  PKDPC TimerDpc;
92  ULONG Period;
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 */
113  Limit = Index + TIMER_TABLE_SIZE - 1;
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);
182  while (!KiInsertTreeTimer(Timer, Interval));
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 
336 VOID
337 FASTCALL
339  IN KIRQL OldIrql)
340 {
341  ULARGE_INTEGER SystemTime;
343  LONG i;
344  ULONG DpcCalls = 0;
345  PKTIMER Timer;
346  PKDPC TimerDpc;
347  ULONG Period;
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);
394  while (!KiInsertTreeTimer(Timer, Interval));
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 
464 VOID
465 NTAPI
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 
560 VOID
561 FASTCALL
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
571  KIRQL OldIrql;
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 interrups 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 
676 VOID
677 NTAPI
679  IN PKDEFERRED_ROUTINE DeferredRoutine,
681  IN KOBJECTS Type)
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  */
697 VOID
698 NTAPI
700  IN PKDEFERRED_ROUTINE DeferredRoutine,
702 {
703  /* Call the internal routine */
705 }
706 
707 /*
708  * @implemented
709  */
710 VOID
711 NTAPI
713  IN PKDEFERRED_ROUTINE DeferredRoutine,
715 {
716  /* Call the internal routine */
717  KiInitializeDpc(Dpc, DeferredRoutine, DeferredContext, DpcObject);
718 }
719 
720 /*
721  * @implemented
722  */
723 BOOLEAN
724 NTAPI
728 {
729  KIRQL OldIrql;
730  PKPRCB Prcb, CurrentPrcb;
731  ULONG Cpu;
732  PKDPC_DATA DpcData;
733  BOOLEAN DpcConfigured = FALSE, DpcInserted = FALSE;
734  ASSERT_DPC(Dpc);
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 */
824  Prcb->DpcInterruptRequested = TRUE;
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 */
839  Prcb->DpcInterruptRequested = TRUE;
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  */
876 BOOLEAN
877 NTAPI
879 {
880  PKDPC_DATA DpcData;
881  BOOLEAN Enable;
882  ASSERT_DPC(Dpc);
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  */
917 VOID
918 NTAPI
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  */
945 BOOLEAN
946 NTAPI
948 {
949  /* Return if the Dpc Routine is active */
950  return KeGetCurrentPrcb()->DpcRoutineActive;
951 }
952 
953 /*
954  * @implemented
955  */
956 VOID
957 NTAPI
960 {
961  /* Set the DPC Importance */
962  ASSERT_DPC(Dpc);
963  Dpc->Importance = Importance;
964 }
965 
966 /*
967  * @implemented
968  */
969 VOID
970 NTAPI
972  IN CCHAR Number)
973 {
974  /* Set a target CPU */
975  ASSERT_DPC(Dpc);
976  Dpc->Number = Number + MAXIMUM_PROCESSORS;
977 }
978 
979 /*
980  * @implemented
981  */
982 VOID
983 NTAPI
985  IN PVOID Context)
986 {
987  ULONG Barrier = KeNumberProcessors;
988  KIRQL OldIrql;
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  */
1011 VOID
1012 NTAPI
1014 {
1015  //
1016  // Decrement the barrier, which is actually the processor count
1017  //
1019 }
1020 
1021 /*
1022  * @implemented
1023  */
1024 BOOLEAN
1025 NTAPI
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 KeQuerySystemTime(t)
Definition: env_spec_w32.h:570
#define KeGetCurrentIrql()
Definition: env_spec_w32.h:706
#define MAXIMUM_PROCESSORS
Definition: rwlock.h:5
FORCEINLINE VOID KiReleaseThreadLock(IN PKTHREAD Thread)
Definition: ke_x.h:250
ULONG KiAdjustDpcThreshold
Definition: dpc.c:21
ULONG KiIdealDpcRate
Definition: dpc.c:22
ULONG LowPart
Definition: ketypes.h:917
#define IN
Definition: typedefs.h:39
ULONG MinimumDpcRate
Definition: ketypes.h:689
_Must_inspect_result_ _In_ PWDF_DPC_CONFIG _In_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFDPC * Dpc
Definition: wdfdpc.h:107
FORCEINLINE VOID KiReleasePrcbLock(IN PKPRCB Prcb)
Definition: ke_x.h:230
enum _KOBJECTS KOBJECTS
VOID NTAPI KiTimerExpiration(IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2)
Definition: dpc.c:79
#define DPC_NORMAL
UCHAR DpcThreadRequested
Definition: ketypes.h:691
KDPC_DATA DpcData[2]
Definition: ketypes.h:680
#define TRUE
Definition: types.h:120
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:317
FORCEINLINE VOID InsertHeadList(_Inout_ PLIST_ENTRY ListHead, _Inout_ __drv_aliasesMem PLIST_ENTRY Entry)
Definition: rtlfuncs.h:201
FORCEINLINE VOID KxUnwaitThreadForEvent(IN PKEVENT Event, IN KPRIORITY Increment)
Definition: ke_x.h:1304
void __cdecl _enable(void)
Definition: intrin_arm.h:373
FORCEINLINE PKSPIN_LOCK_QUEUE KiAcquireTimerLock(IN ULONG Hand)
Definition: ke_x.h:286
#define PtrToLong(p)
Definition: basetsd.h:84
VOID NTAPI KeAcquireSpinLockAtDpcLevel(IN PKSPIN_LOCK SpinLock)
Definition: spinlock.c:198
BOOLEAN NTAPI KeInsertQueueDpc(IN PKDPC Dpc, IN PVOID SystemArgument1, IN PVOID SystemArgument2)
Definition: dpc.c:725
FORCEINLINE VOID KiSetThreadSwapBusy(IN PKTHREAD Thread)
Definition: ke_x.h:210
_In_ ULONGLONG _In_ ULONGLONG _In_ BOOLEAN Enable
Definition: ntddpcm.h:140
FORCEINLINE struct _KPRCB * KeGetCurrentPrcb(VOID)
Definition: ketypes.h:1079
VOID NTAPI KeSetImportanceDpc(IN PKDPC Dpc, IN KDPC_IMPORTANCE Importance)
Definition: dpc.c:958
BOOLEAN NTAPI KeRemoveQueueDpc(IN PKDPC Dpc)
Definition: dpc.c:878
_In_ LARGE_INTEGER _In_ ULONG Period
Definition: kefuncs.h:1324
#define LOW_REALTIME_PRIORITY
VOID NTAPI KiQuantumEnd(VOID)
VOID NTAPI KiInitializeDpc(IN PKDPC Dpc, IN PKDEFERRED_ROUTINE DeferredRoutine, IN PVOID DeferredContext, IN KOBJECTS Type)
Definition: dpc.c:678
#define AFFINITY_MASK(Id)
Definition: ke.h:159
ULONG KiMinimumDpcRate
Definition: dpc.c:20
#define InsertTailList(ListHead, Entry)
ULONG KiTimeLimitIsrMicroseconds
Definition: dpc.c:26
#define ASSERT_DPC(Object)
VOID NTAPI KiCheckTimerTable(IN ULARGE_INTEGER CurrentTime)
Definition: dpc.c:33
ULONG KiDPCTimeout
Definition: dpc.c:27
#define MAX_QUANTUM
Definition: ketypes.h:136
LONG NTAPI KeSetEvent(IN PKEVENT Event, IN KPRIORITY Increment, IN BOOLEAN Wait)
Definition: eventobj.c:159
#define FASTCALL
Definition: nt_native.h:50
BOOLEAN NTAPI KeIsExecutingDpc(VOID)
Definition: dpc.c:947
struct _KTHREAD * NextThread
Definition: ketypes.h:571
_Must_inspect_result_ FORCEINLINE BOOLEAN IsListEmpty(_In_ const LIST_ENTRY *ListHead)
Definition: rtlfuncs.h:57
ULONG DebugDpcTime
Definition: ketypes.h:518
ULONG_PTR DpcLock
Definition: ketypes.h:784
static LIST_ENTRY Timers
Definition: clock.c:40
uint32_t ULONG_PTR
Definition: typedefs.h:65
BOOLEAN FASTCALL KiSwapContext(IN KIRQL WaitIrql, IN PKTHREAD CurrentThread)
FORCEINLINE BOOLEAN RemoveEntryList(_In_ PLIST_ENTRY Entry)
Definition: rtlfuncs.h:105
VOID NTAPI KeInitializeThreadedDpc(IN PKDPC Dpc, IN PKDEFERRED_ROUTINE DeferredRoutine, IN PVOID DeferredContext)
Definition: dpc.c:699
FORCEINLINE SCHAR KiComputeNewPriority(IN PKTHREAD Thread, IN SCHAR Adjustment)
Definition: ke_x.h:1469
UCHAR KIRQL
Definition: env_spec_w32.h:591
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
FAST_MUTEX KiGenericCallDpcMutex
Definition: dpc.c:24
ULONGLONG QuadPart
Definition: ms-dtyp.idl:185
#define FALSE
Definition: types.h:117
VOID NTAPI DbgBreakPoint(VOID)
long LONG
Definition: pedump.c:60
#define InterlockedCompareExchangePointer
Definition: interlocked.h:129
struct _KTHREAD * CurrentThread
Definition: ketypes.h:570
unsigned char BOOLEAN
FORCEINLINE VOID KiAcquirePrcbLock(IN PKPRCB Prcb)
Definition: ke_x.h:220
#define MAX_TIMER_DPCS
Definition: ke.h:69
VOID FASTCALL KiTimerListExpire(IN PLIST_ENTRY ExpiredListHead, IN KIRQL OldIrql)
Definition: dpc.c:338
FORCEINLINE BOOLEAN KeDisableInterrupts(VOID)
Definition: ke.h:235
BOOLEAN KeThreadDpcEnable
Definition: dpc.c:23
#define IPI_DPC
Definition: ketypes.h:237
Definition: ke.h:71
PKDPC Dpc
Definition: ke.h:73
ULONG DpcCount
Definition: ketypes.h:790
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
#define UlongToPtr(u)
Definition: config.h:106
ULARGE_INTEGER Time
Definition: ketypes.h:709
KIRQL OldIrql
Definition: mm.h:1502
DWORD Interval
Definition: netstat.c:33
KEVENT DpcEvent
Definition: ketypes.h:710
UCHAR Type
Definition: ketypes.h:688
FAST_MUTEX
Definition: extypes.h:17
_In_opt_ PVOID _In_opt_ PVOID SystemArgument1
Definition: ketypes.h:675
FORCEINLINE VOID KiAcquireThreadLock(IN PKTHREAD Thread)
Definition: ke_x.h:240
enum _KDPC_IMPORTANCE KDPC_IMPORTANCE
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
KDPC KiTimerExpireDpc
Definition: dpc.c:25
#define TIMER_TABLE_SIZE
Definition: ketypes.h:836
LIST_ENTRY Entry
Definition: ketypes.h:708
#define ASSERT(a)
Definition: mode.c:44
char CCHAR
Definition: typedefs.h:51
_In_ WDFCOLLECTION _In_ ULONG Index
BOOLEAN FASTCALL KiInsertTreeTimer(IN PKTIMER Timer, IN LARGE_INTEGER Interval)
Definition: timerobj.c:26
VOID NTAPI KeReleaseSpinLockFromDpcLevel(IN PKSPIN_LOCK SpinLock)
Definition: spinlock.c:221
Type
Definition: Type.h:6
_In_opt_ PFILE_OBJECT _In_opt_ PETHREAD Thread
Definition: fltkernel.h:2652
KTIMER_TABLE_ENTRY KiTimerTableListHead[TIMER_TABLE_SIZE]
Definition: timerobj.c:17
UCHAR DpcRoutineActive
Definition: ketypes.h:692
#define InterlockedDecrement
Definition: armddk.h:52
NTKERNELAPI volatile KSYSTEM_TIME KeTickCount
Definition: clock.c:19
Definition: ketypes.h:687
KDEFERRED_ROUTINE * PKDEFERRED_ROUTINE
Definition: ketypes.h:678
UCHAR DpcInterruptRequested
Definition: ketypes.h:690
ULONG LowPart
Definition: typedefs.h:106
Definition: typedefs.h:119
ULONG_PTR KiIdleSummary
Definition: thrdschd.c:25
VOID FASTCALL KiIpiSend(KAFFINITY TargetSet, ULONG IpiRequest)
ULONG TotalProcessors
Definition: ke.h:54
UCHAR ThreadDpcEnable
Definition: ketypes.h:699
_In_opt_ PENTER_STATE_SYSTEM_HANDLER _In_opt_ PVOID _In_ LONG _In_opt_ LONG volatile * Number
Definition: ntpoapi.h:204
KAFFINITY KeActiveProcessors
Definition: krnlinit.c:23
#define InterlockedExchange
Definition: armddk.h:54
_Must_inspect_result_ _In_ PWDF_TIMER_CONFIG _In_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFTIMER * Timer
Definition: wdftimer.h:153
CCHAR KeNumberProcessors
Definition: krnlinit.c:35
_In_opt_ PVOID _In_opt_ PVOID _In_opt_ PVOID SystemArgument2
Definition: ketypes.h:675
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
VOID FASTCALL HalRequestSoftwareInterrupt(IN KIRQL Irql)
Definition: pic.c:271
volatile ULONG DpcQueueDepth
Definition: ketypes.h:788
#define HIGH_LEVEL
Definition: env_spec_w32.h:703
VOID FASTCALL KiReleaseSpinLock(IN PKSPIN_LOCK SpinLock)
Definition: spinlock.c:298
FORCEINLINE VOID KiReleaseDispatcherLock(IN KIRQL OldIrql)
Definition: ke_x.h:157
FORCEINLINE PKTHREAD KiSelectReadyThread(IN KPRIORITY Priority, IN PKPRCB Prcb)
Definition: ke_x.h:1419
VOID NTAPI KeSignalCallDpcDone(IN PVOID SystemArgument1)
Definition: dpc.c:1013
VOID FASTCALL KiRetireDpcList(IN PKPRCB Prcb)
Definition: dpc.c:562
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
FORCEINLINE KIRQL KiAcquireDispatcherLock(VOID)
Definition: ke_x.h:149
#define DPC_THREADED
PKDEFERRED_ROUTINE Routine
Definition: ke.h:74
VOID NTAPI KeGenericCallDpc(IN PKDEFERRED_ROUTINE Routine, IN PVOID Context)
Definition: dpc.c:984
LONG Sleeping
Definition: ketypes.h:766
PKPRCB KiProcessorBlock[]
Definition: krnlinit.c:32
PVOID Context
Definition: ke.h:75
LONG DpcSetEventRequest
Definition: ketypes.h:703
unsigned int * PULONG
Definition: retypes.h:1
#define NULL
Definition: types.h:112
VOID FASTCALL KiAcquireSpinLock(IN PKSPIN_LOCK SpinLock)
Definition: spinlock.c:287
FORCEINLINE VOID KiRemoveEntryTimer(IN PKTIMER Timer)
Definition: ke_x.h:892
VOID NTAPI KeRaiseIrql(KIRQL NewIrql, PKIRQL OldIrql)
Definition: spinlock.c:27
ULONG KiMaximumDpcQueueDepth
Definition: dpc.c:19
UCHAR DpcThreadActive
Definition: ketypes.h:693
_Requires_lock_not_held_(Prcb->PrcbLock) VOID NTAPI KiQuantumEnd(VOID)
Definition: dpc.c:463
#define DPRINT1
Definition: precomp.h:8
_In_ KDPC_IMPORTANCE Importance
Definition: kefuncs.h:80
VOID NTAPI KeSetTargetProcessorDpc(IN PKDPC Dpc, IN CCHAR Number)
Definition: dpc.c:971
#define UNIMPLEMENTED_FATAL(...)
Definition: debug.h:244
volatile UCHAR State
Definition: ketypes.h:1721
USHORT Number
Definition: ketypes.h:563
void __cdecl _disable(void)
Definition: intrin_arm.h:365
unsigned int ULONG
Definition: retypes.h:1
#define IO_NO_INCREMENT
Definition: iotypes.h:598
volatile USHORT Number
Definition: ketypes.h:690
FORCEINLINE VOID KxUnwaitThread(IN DISPATCHER_HEADER *Object, IN KPRIORITY Increment)
Definition: ke_x.h:1259
ULONG DpcRequestRate
Definition: ketypes.h:688
VOID NTAPI KeLowerIrql(KIRQL NewIrql)
Definition: spinlock.c:39
VOID NTAPI KeInitializeDpc(IN PKDPC Dpc, IN PKDEFERRED_ROUTINE DeferredRoutine, IN PVOID DeferredContext)
Definition: dpc.c:712
LONG MaximumDpcQueueDepth
Definition: ketypes.h:687
volatile PVOID DpcData
Definition: ketypes.h:696
PKDEFERRED_ROUTINE DeferredRoutine
Definition: ketypes.h:692
PVOID DeferredContext
Definition: ketypes.h:693
signed int * PLONG
Definition: retypes.h:5
#define APC_LEVEL
Definition: env_spec_w32.h:695
VOID NTAPI KeFlushQueuedDpcs(VOID)
Definition: dpc.c:919
_In_ LONG _In_ LONG Limit
Definition: kefuncs.h:315
ULONGLONG NTAPI KeQueryInterruptTime(VOID)
Definition: clock.c:203
static PLARGE_INTEGER Time
Definition: time.c:105
#define Int32x32To64(a, b)
FORCEINLINE VOID KiReleaseTimerLock(IN PKSPIN_LOCK_QUEUE LockQueue)
Definition: ke_x.h:297
LONGLONG QuadPart
Definition: typedefs.h:114
BOOLEAN NTAPI KeSignalCallDpcSynchronize(IN PVOID SystemArgument2)
Definition: dpc.c:1026
#define PAGED_CODE()
KIRQL NTAPI KeRaiseIrqlToSynchLevel(VOID)
Definition: pic.c:156
VOID FASTCALL KiProcessDeferredReadyList(IN PKPRCB Prcb)
Definition: thrdschd.c:41
_In_opt_ PVOID DeferredContext
Definition: ketypes.h:675