ReactOS  r75636
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 */
42  KeRaiseIrql(HIGH_LEVEL, &OldIrql);
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 */
73  KeLowerIrql(OldIrql);
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();
103  Limit = KeTickCount.LowPart;
104 
105  /* Bring interrupts back */
106  _enable();
107 
108  /* Get the index of the timer and normalize it */
109  Index = PtrToLong(SystemArgument1);
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 */
126  OldIrql = KiAcquireDispatcherLock();
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--;
150  KiRemoveEntryTimer(Timer);
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 */
327  if (OldIrql != DISPATCH_LEVEL) KeLowerIrql(OldIrql);
328  }
329  else
330  {
331  /* Unlock the dispatcher */
332  KiReleaseDispatcherLock(OldIrql);
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 */
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 */
454  KeLowerIrql(OldIrql);
455  }
456  else
457  {
458  /* Unlock the dispatcher */
459  KiReleaseDispatcherLock(OldIrql);
460  }
461 }
462 
463 VOID
464 NTAPI
466 {
467  PKPRCB Prcb = KeGetCurrentPrcb();
468  PKTHREAD NextThread, Thread = Prcb->CurrentThread;
469 
470  /* Check if a DPC Event was requested to be signaled */
472  {
473  /* Signal it */
474  KeSetEvent(&Prcb->DpcEvent, 0, 0);
475  }
476 
477  /* Raise to synchronization level and lock the PRCB and thread */
479  KiAcquireThreadLock(Thread);
480  KiAcquirePrcbLock(Prcb);
481 
482  /* Check if Quantum expired */
483  if (Thread->Quantum <= 0)
484  {
485  /* Check if we're real-time and with quantums disabled */
486  if ((Thread->Priority >= LOW_REALTIME_PRIORITY) &&
487  (Thread->ApcState.Process->DisableQuantum))
488  {
489  /* Otherwise, set maximum quantum */
490  Thread->Quantum = MAX_QUANTUM;
491  }
492  else
493  {
494  /* Reset the new Quantum */
495  Thread->Quantum = Thread->QuantumReset;
496 
497  /* Calculate new priority */
498  Thread->Priority = KiComputeNewPriority(Thread, 1);
499 
500  /* Check if a new thread is scheduled */
501  if (!Prcb->NextThread)
502  {
503  /* Get a new ready thread */
504  NextThread = KiSelectReadyThread(Thread->Priority, Prcb);
505  if (NextThread)
506  {
507  /* Found one, set it on standby */
508  NextThread->State = Standby;
509  Prcb->NextThread = NextThread;
510  }
511  }
512  else
513  {
514  /* Otherwise, make sure that this thread doesn't get preempted */
515  Thread->Preempted = FALSE;
516  }
517  }
518  }
519 
520  /* Release the thread lock */
521  KiReleaseThreadLock(Thread);
522 
523  /* Check if there's no thread scheduled */
524  if (!Prcb->NextThread)
525  {
526  /* Just leave now */
527  KiReleasePrcbLock(Prcb);
529  return;
530  }
531 
532  /* Get the next thread now */
533  NextThread = Prcb->NextThread;
534 
535  /* Set current thread's swap busy to true */
536  KiSetThreadSwapBusy(Thread);
537 
538  /* Switch threads in PRCB */
539  Prcb->NextThread = NULL;
540  Prcb->CurrentThread = NextThread;
541 
542  /* Set thread to running and the switch reason to Quantum End */
543  NextThread->State = Running;
544  Thread->WaitReason = WrQuantumEnd;
545 
546  /* Queue it on the ready lists */
547  KxQueueReadyThread(Thread, Prcb);
548 
549  /* Set wait IRQL to APC_LEVEL */
550  Thread->WaitIrql = APC_LEVEL;
551 
552  /* Swap threads */
553  KiSwapContext(APC_LEVEL, Thread);
554 
555  /* Lower IRQL back to DISPATCH_LEVEL */
557 }
558 
559 VOID
560 FASTCALL
562 {
563  PKDPC_DATA DpcData;
564  PLIST_ENTRY ListHead, DpcEntry;
565  PKDPC Dpc;
566  PKDEFERRED_ROUTINE DeferredRoutine;
568  ULONG_PTR TimerHand;
569 #ifdef CONFIG_SMP
570  KIRQL OldIrql;
571 #endif
572 
573  /* Get data and list variables before starting anything else */
574  DpcData = &Prcb->DpcData[DPC_NORMAL];
575  ListHead = &DpcData->DpcListHead;
576 
577  /* Main outer loop */
578  do
579  {
580  /* Set us as active */
581  Prcb->DpcRoutineActive = TRUE;
582 
583  /* Check if this is a timer expiration request */
584  if (Prcb->TimerRequest)
585  {
586  /* It is, get the timer hand and disable timer request */
587  TimerHand = Prcb->TimerHand;
588  Prcb->TimerRequest = 0;
589 
590  /* Expire timers with interrups enabled */
591  _enable();
592  KiTimerExpiration(NULL, NULL, (PVOID)TimerHand, NULL);
593  _disable();
594  }
595 
596  /* Loop while we have entries in the queue */
597  while (DpcData->DpcQueueDepth != 0)
598  {
599  /* Lock the DPC data and get the DPC entry*/
601  DpcEntry = ListHead->Flink;
602 
603  /* Make sure we have an entry */
604  if (DpcEntry != ListHead)
605  {
606  /* Remove the DPC from the list */
607  RemoveEntryList(DpcEntry);
608  Dpc = CONTAINING_RECORD(DpcEntry, KDPC, DpcListEntry);
609 
610  /* Clear its DPC data and save its parameters */
611  Dpc->DpcData = NULL;
612  DeferredRoutine = Dpc->DeferredRoutine;
613  DeferredContext = Dpc->DeferredContext;
614  SystemArgument1 = Dpc->SystemArgument1;
615  SystemArgument2 = Dpc->SystemArgument2;
616 
617  /* Decrease the queue depth */
618  DpcData->DpcQueueDepth--;
619 
620 #if DBG
621  /* Clear DPC Time */
622  Prcb->DebugDpcTime = 0;
623 #endif
624 
625  /* Release the lock */
627 
628  /* Re-enable interrupts */
629  _enable();
630 
631  /* Call the DPC */
632  DeferredRoutine(Dpc,
633  DeferredContext,
634  SystemArgument1,
635  SystemArgument2);
637 
638  /* Disable interrupts and keep looping */
639  _disable();
640  }
641  else
642  {
643  /* The queue should be flushed now */
644  ASSERT(DpcData->DpcQueueDepth == 0);
645 
646  /* Release DPC Lock */
648  }
649  }
650 
651  /* Clear DPC Flags */
652  Prcb->DpcRoutineActive = FALSE;
653  Prcb->DpcInterruptRequested = FALSE;
654 
655 #ifdef CONFIG_SMP
656  /* Check if we have deferred threads */
657  if (Prcb->DeferredReadyListHead.Next)
658  {
659 
660  /* Re-enable interrupts and raise to synch */
661  _enable();
662  OldIrql = KeRaiseIrqlToSynchLevel();
663 
664  /* Process deferred threads */
666 
667  /* Lower IRQL back and disable interrupts */
668  KeLowerIrql(OldIrql);
669  _disable();
670  }
671 #endif
672  } while (DpcData->DpcQueueDepth != 0);
673 }
674 
675 VOID
676 NTAPI
678  IN PKDEFERRED_ROUTINE DeferredRoutine,
680  IN KOBJECTS Type)
681 {
682  /* Setup the DPC Object */
683  Dpc->Type = Type;
684  Dpc->Number = 0;
685  Dpc->Importance= MediumImportance;
686  Dpc->DeferredRoutine = DeferredRoutine;
687  Dpc->DeferredContext = DeferredContext;
688  Dpc->DpcData = NULL;
689 }
690 
691 /* PUBLIC FUNCTIONS **********************************************************/
692 
693 /*
694  * @implemented
695  */
696 VOID
697 NTAPI
699  IN PKDEFERRED_ROUTINE DeferredRoutine,
701 {
702  /* Call the internal routine */
703  KiInitializeDpc(Dpc, DeferredRoutine, DeferredContext, ThreadedDpcObject);
704 }
705 
706 /*
707  * @implemented
708  */
709 VOID
710 NTAPI
712  IN PKDEFERRED_ROUTINE DeferredRoutine,
714 {
715  /* Call the internal routine */
716  KiInitializeDpc(Dpc, DeferredRoutine, DeferredContext, DpcObject);
717 }
718 
719 /*
720  * @implemented
721  */
722 BOOLEAN
723 NTAPI
727 {
728  KIRQL OldIrql;
729  PKPRCB Prcb, CurrentPrcb;
730  ULONG Cpu;
731  PKDPC_DATA DpcData;
732  BOOLEAN DpcConfigured = FALSE, DpcInserted = FALSE;
733  ASSERT_DPC(Dpc);
734 
735  /* Check IRQL and Raise it to HIGH_LEVEL */
736  KeRaiseIrql(HIGH_LEVEL, &OldIrql);
737  CurrentPrcb = KeGetCurrentPrcb();
738 
739  /* Check if the DPC has more then the maximum number of CPUs */
740  if (Dpc->Number >= MAXIMUM_PROCESSORS)
741  {
742  /* Then substract the maximum and get that PRCB. */
743  Cpu = Dpc->Number - MAXIMUM_PROCESSORS;
744  Prcb = KiProcessorBlock[Cpu];
745  }
746  else
747  {
748  /* Use the current one */
749  Prcb = CurrentPrcb;
750  Cpu = Prcb->Number;
751  }
752 
753  /* ROS Sanity Check */
754  ASSERT(Prcb == CurrentPrcb);
755 
756  /* Check if this is a threaded DPC and threaded DPCs are enabled */
757  if ((Dpc->Type == ThreadedDpcObject) && (Prcb->ThreadDpcEnable))
758  {
759  /* Then use the threaded data */
760  DpcData = &Prcb->DpcData[DPC_THREADED];
761  }
762  else
763  {
764  /* Otherwise, use the regular data */
765  DpcData = &Prcb->DpcData[DPC_NORMAL];
766  }
767 
768  /* Acquire the DPC lock */
769  KiAcquireSpinLock(&DpcData->DpcLock);
770 
771  /* Get the DPC Data */
772  if (!InterlockedCompareExchangePointer(&Dpc->DpcData, DpcData, NULL))
773  {
774  /* Now we can play with the DPC safely */
775  Dpc->SystemArgument1 = SystemArgument1;
776  Dpc->SystemArgument2 = SystemArgument2;
777  DpcData->DpcQueueDepth++;
778  DpcData->DpcCount++;
779  DpcConfigured = TRUE;
780 
781  /* Check if this is a high importance DPC */
782  if (Dpc->Importance == HighImportance)
783  {
784  /* Pre-empty other DPCs */
785  InsertHeadList(&DpcData->DpcListHead, &Dpc->DpcListEntry);
786  }
787  else
788  {
789  /* Add it at the end */
790  InsertTailList(&DpcData->DpcListHead, &Dpc->DpcListEntry);
791  }
792 
793  /* Check if this is the DPC on the threaded list */
794  if (&Prcb->DpcData[DPC_THREADED] == DpcData)
795  {
796  /* Make sure a threaded DPC isn't already active */
797  if (!(Prcb->DpcThreadActive) && !(Prcb->DpcThreadRequested))
798  {
799  /* FIXME: Setup Threaded DPC */
800  UNIMPLEMENTED_FATAL("Threaded DPC not supported\n");
801  }
802  }
803  else
804  {
805  /* Make sure a DPC isn't executing already */
806  if (!(Prcb->DpcRoutineActive) && !(Prcb->DpcInterruptRequested))
807  {
808  /* Check if this is the same CPU */
809  if (Prcb != CurrentPrcb)
810  {
811  /*
812  * Check if the DPC is of high importance or above the
813  * maximum depth. If it is, then make sure that the CPU
814  * isn't idle, or that it's sleeping.
815  */
816  if (((Dpc->Importance == HighImportance) ||
817  (DpcData->DpcQueueDepth >=
818  Prcb->MaximumDpcQueueDepth)) &&
819  (!(AFFINITY_MASK(Cpu) & KiIdleSummary) ||
820  (Prcb->Sleeping)))
821  {
822  /* Set interrupt requested */
823  Prcb->DpcInterruptRequested = TRUE;
824 
825  /* Set DPC inserted */
826  DpcInserted = TRUE;
827  }
828  }
829  else
830  {
831  /* Check if the DPC is of anything but low importance */
832  if ((Dpc->Importance != LowImportance) ||
833  (DpcData->DpcQueueDepth >=
834  Prcb->MaximumDpcQueueDepth) ||
835  (Prcb->DpcRequestRate < Prcb->MinimumDpcRate))
836  {
837  /* Set interrupt requested */
838  Prcb->DpcInterruptRequested = TRUE;
839 
840  /* Set DPC inserted */
841  DpcInserted = TRUE;
842  }
843  }
844  }
845  }
846  }
847 
848  /* Release the lock */
849  KiReleaseSpinLock(&DpcData->DpcLock);
850 
851  /* Check if the DPC was inserted */
852  if (DpcInserted)
853  {
854  /* Check if this was SMP */
855  if (Prcb != CurrentPrcb)
856  {
857  /* It was, request and IPI */
859  }
860  else
861  {
862  /* It wasn't, request an interrupt from HAL */
864  }
865  }
866 
867  /* Lower IRQL */
868  KeLowerIrql(OldIrql);
869  return DpcConfigured;
870 }
871 
872 /*
873  * @implemented
874  */
875 BOOLEAN
876 NTAPI
878 {
879  PKDPC_DATA DpcData;
880  BOOLEAN Enable;
881  ASSERT_DPC(Dpc);
882 
883  /* Disable interrupts */
884  Enable = KeDisableInterrupts();
885 
886  /* Get DPC data */
887  DpcData = Dpc->DpcData;
888  if (DpcData)
889  {
890  /* Acquire the DPC lock */
891  KiAcquireSpinLock(&DpcData->DpcLock);
892 
893  /* Make sure that the data didn't change */
894  if (DpcData == Dpc->DpcData)
895  {
896  /* Remove the DPC */
897  DpcData->DpcQueueDepth--;
898  RemoveEntryList(&Dpc->DpcListEntry);
899  Dpc->DpcData = NULL;
900  }
901 
902  /* Release the lock */
903  KiReleaseSpinLock(&DpcData->DpcLock);
904  }
905 
906  /* Re-enable interrupts */
907  if (Enable) _enable();
908 
909  /* Return if the DPC was in the queue or not */
910  return DpcData ? TRUE : FALSE;
911 }
912 
913 /*
914  * @implemented
915  */
916 VOID
917 NTAPI
919 {
920  PKPRCB CurrentPrcb = KeGetCurrentPrcb();
921  PAGED_CODE();
922 
923  /* Check if this is an UP machine */
924  if (KeActiveProcessors == 1)
925  {
926  /* Check if there are DPCs on either queues */
927  if ((CurrentPrcb->DpcData[DPC_NORMAL].DpcQueueDepth > 0) ||
928  (CurrentPrcb->DpcData[DPC_THREADED].DpcQueueDepth > 0))
929  {
930  /* Request an interrupt */
932  }
933  }
934  else
935  {
936  /* FIXME: SMP support required */
937  ASSERT(FALSE);
938  }
939 }
940 
941 /*
942  * @implemented
943  */
944 BOOLEAN
945 NTAPI
947 {
948  /* Return if the Dpc Routine is active */
949  return KeGetCurrentPrcb()->DpcRoutineActive;
950 }
951 
952 /*
953  * @implemented
954  */
955 VOID
956 NTAPI
959 {
960  /* Set the DPC Importance */
961  ASSERT_DPC(Dpc);
962  Dpc->Importance = Importance;
963 }
964 
965 /*
966  * @implemented
967  */
968 VOID
969 NTAPI
971  IN CCHAR Number)
972 {
973  /* Set a target CPU */
974  ASSERT_DPC(Dpc);
975  Dpc->Number = Number + MAXIMUM_PROCESSORS;
976 }
977 
978 /*
979  * @implemented
980  */
981 VOID
982 NTAPI
984  IN PVOID Context)
985 {
986  ULONG Barrier = KeNumberProcessors;
987  KIRQL OldIrql;
988  DEFERRED_REVERSE_BARRIER ReverseBarrier;
990 
991  //
992  // The barrier is the number of processors, each processor will decrement it
993  // by one, so when all processors have run the DPC, the barrier reaches zero
994  //
995  ReverseBarrier.Barrier = Barrier;
996  ReverseBarrier.TotalProcessors = Barrier;
997 
998  //
999  // But we don't need the barrier on UP, since we can simply call the routine
1000  // directly while at DISPATCH_LEVEL and not worry about anything else
1001  //
1002  KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
1003  Routine(&KeGetCurrentPrcb()->CallDpc, Context, &Barrier, &ReverseBarrier);
1004  KeLowerIrql(OldIrql);
1005 }
1006 
1007 /*
1008  * @implemented
1009  */
1010 VOID
1011 NTAPI
1013 {
1014  //
1015  // Decrement the barrier, which is actually the processor count
1016  //
1017  InterlockedDecrement((PLONG)SystemArgument1);
1018 }
1019 
1020 /*
1021  * @implemented
1022  */
1023 BOOLEAN
1024 NTAPI
1026 {
1027  //
1028  // There is nothing to do on UP systems -- the processor calling this wins
1029  //
1030  UNREFERENCED_PARAMETER(SystemArgument2);
1031  return TRUE;
1032 }
1033 
1034 /* EOF */
#define KeQuerySystemTime(t)
Definition: env_spec_w32.h:570
DWORD *typedef PVOID
Definition: winlogon.h:52
#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:244
ULONG KiAdjustDpcThreshold
Definition: dpc.c:21
ULONG KiIdealDpcRate
Definition: dpc.c:22
ULONG LowPart
Definition: ketypes.h:895
#define IN
Definition: typedefs.h:39
#define KeRaiseIrql(irql, oldIrql)
Definition: env_spec_w32.h:597
#define TRUE
Definition: types.h:120
ULONG MinimumDpcRate
Definition: ketypes.h:685
#define KeLowerIrql(oldIrql)
Definition: env_spec_w32.h:602
Type
Definition: Type.h:6
FORCEINLINE VOID KiReleasePrcbLock(IN PKPRCB Prcb)
Definition: ke_x.h:224
enum _KOBJECTS KOBJECTS
BOOLEAN Enable
Definition: acefiex.h:245
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:687
KDPC_DATA DpcData[2]
Definition: ketypes.h:676
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel)?(CompletionRoutine!=NULL):TRUE)
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:315
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:1295
void __cdecl _enable(void)
Definition: intrin_arm.h:373
FORCEINLINE PKSPIN_LOCK_QUEUE KiAcquireTimerLock(IN ULONG Hand)
Definition: ke_x.h:280
#define PtrToLong(p)
Definition: basetsd.h:83
VOID NTAPI KeAcquireSpinLockAtDpcLevel(IN PKSPIN_LOCK SpinLock)
Definition: spinlock.c:192
BOOLEAN NTAPI KeInsertQueueDpc(IN PKDPC Dpc, IN PVOID SystemArgument1, IN PVOID SystemArgument2)
Definition: dpc.c:724
FORCEINLINE VOID KiSetThreadSwapBusy(IN PKTHREAD Thread)
Definition: ke_x.h:204
FORCEINLINE struct _KPRCB * KeGetCurrentPrcb(VOID)
Definition: ketypes.h:1054
SCHAR Priority
Definition: ketypes.h:974
VOID NTAPI KeSetImportanceDpc(IN PKDPC Dpc, IN KDPC_IMPORTANCE Importance)
Definition: dpc.c:957
BOOLEAN NTAPI KeRemoveQueueDpc(IN PKDPC Dpc)
Definition: dpc.c:877
_In_ LARGE_INTEGER _In_ ULONG Period
Definition: kefuncs.h:1268
LIST_ENTRY TimerListEntry
Definition: ketypes.h:827
VOID NTAPI KiInitializeDpc(IN PKDPC Dpc, IN PKDEFERRED_ROUTINE DeferredRoutine, IN PVOID DeferredContext, IN KOBJECTS Type)
Definition: dpc.c:677
#define AFFINITY_MASK(Id)
Definition: ke.h:148
ULONG KiMinimumDpcRate
Definition: dpc.c:20
_Must_inspect_result_ _In_ ULONG Index
Definition: fltkernel.h:1824
#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
#define LOW_REALTIME_PRIORITY
void DbgBreakPoint()
Definition: mach.c:558
LONG NTAPI KeSetEvent(IN PKEVENT Event, IN KPRIORITY Increment, IN BOOLEAN Wait)
Definition: eventobj.c:159
ULONG Period
Definition: ketypes.h:832
#define FASTCALL
Definition: nt_native.h:50
BOOLEAN Preempted
Definition: ketypes.h:1212
BOOLEAN NTAPI KeIsExecutingDpc(VOID)
Definition: dpc.c:946
struct _KTHREAD * NextThread
Definition: ketypes.h:567
_Must_inspect_result_ FORCEINLINE BOOLEAN IsListEmpty(_In_ const LIST_ENTRY *ListHead)
Definition: rtlfuncs.h:57
ULONG DebugDpcTime
Definition: ketypes.h:516
ULONG_PTR DpcLock
Definition: ketypes.h:742
static LIST_ENTRY Timers
Definition: clock.c:40
uint32_t ULONG_PTR
Definition: typedefs.h:64
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:698
FORCEINLINE SCHAR KiComputeNewPriority(IN PKTHREAD Thread, IN SCHAR Adjustment)
Definition: ke_x.h:1458
UCHAR KIRQL
Definition: env_spec_w32.h:591
FORCEINLINE VOID KxQueueReadyThread(IN PKTHREAD Thread, IN PKPRCB Prcb)
Definition: ke_x.h:1343
GLenum GLclampf GLint i
Definition: glfuncs.h:14
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 FASTCALL KiReleaseSpinLock(IN PKSPIN_LOCK SpinLock)
Definition: ntoskrnl.c:39
long LONG
Definition: pedump.c:60
DISPATCHER_HEADER Header
Definition: ketypes.h:825
KAPC_STATE ApcState
Definition: ketypes.h:969
#define InterlockedCompareExchangePointer
Definition: interlocked.h:129
struct _KTHREAD * CurrentThread
Definition: ketypes.h:566
FORCEINLINE VOID KiAcquirePrcbLock(IN PKPRCB Prcb)
Definition: ke_x.h:214
smooth NULL
Definition: ftsmooth.c:513
#define MAX_TIMER_DPCS
Definition: ke.h:57
VOID FASTCALL KiTimerListExpire(IN PLIST_ENTRY ExpiredListHead, IN KIRQL OldIrql)
Definition: dpc.c:338
FORCEINLINE BOOLEAN KeDisableInterrupts(VOID)
Definition: ke.h:152
BOOLEAN KeThreadDpcEnable
Definition: dpc.c:23
#define IPI_DPC
Definition: ketypes.h:233
Definition: ke.h:59
PKDPC Dpc
Definition: ke.h:61
ULONG DpcCount
Definition: ketypes.h:748
UCHAR WaitReason
Definition: ketypes.h:1249
ULARGE_INTEGER Time
Definition: ketypes.h:667
DWORD Interval
Definition: netstat.c:30
KEVENT DpcEvent
Definition: ketypes.h:706
UCHAR Type
Definition: ketypes.h:673
FAST_MUTEX
Definition: extypes.h:17
_In_opt_ PVOID _In_opt_ PVOID SystemArgument1
Definition: ketypes.h:660
FORCEINLINE VOID KiAcquireThreadLock(IN PKTHREAD Thread)
Definition: ke_x.h:234
enum _KDPC_IMPORTANCE KDPC_IMPORTANCE
struct _LIST_ENTRY * Flink
Definition: typedefs.h:120
KDPC KiTimerExpireDpc
Definition: dpc.c:25
unsigned char BOOLEAN
struct _KDPC * Dpc
Definition: ketypes.h:828
#define UlongToPtr(ul)
Definition: basetsd.h:97
_In_ LARGE_INTEGER _In_opt_ PKDPC Dpc
Definition: kefuncs.h:524
#define TIMER_TABLE_SIZE
Definition: ketypes.h:821
LIST_ENTRY Entry
Definition: ketypes.h:666
char CCHAR
Definition: typedefs.h:51
BOOLEAN FASTCALL KiInsertTreeTimer(IN PKTIMER Timer, IN LARGE_INTEGER Interval)
Definition: timerobj.c:26
VOID NTAPI KeReleaseSpinLockFromDpcLevel(IN PKSPIN_LOCK SpinLock)
Definition: spinlock.c:215
_In_opt_ PFILE_OBJECT _In_opt_ PETHREAD Thread
Definition: fltkernel.h:2653
#define PAGED_CODE()
Definition: video.h:57
ULARGE_INTEGER DueTime
Definition: ketypes.h:826
KTIMER_TABLE_ENTRY KiTimerTableListHead[TIMER_TABLE_SIZE]
Definition: timerobj.c:17
UCHAR DpcRoutineActive
Definition: ketypes.h:688
#define InterlockedDecrement
Definition: armddk.h:52
NTKERNELAPI volatile KSYSTEM_TIME KeTickCount
Definition: clock.c:19
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:803
Definition: ketypes.h:672
KDEFERRED_ROUTINE * PKDEFERRED_ROUTINE
Definition: ketypes.h:663
UCHAR DpcInterruptRequested
Definition: ketypes.h:686
ULONG LowPart
Definition: typedefs.h:105
PVOID SystemArgument1
Definition: ketypes.h:679
Definition: typedefs.h:118
ULONG_PTR KiIdleSummary
Definition: thrdschd.c:25
VOID FASTCALL KiIpiSend(KAFFINITY TargetSet, ULONG IpiRequest)
ULONG TotalProcessors
Definition: ke.h:42
UCHAR ThreadDpcEnable
Definition: ketypes.h:695
_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
CCHAR KeNumberProcessors
Definition: krnlinit.c:35
VOID NTAPI KiQuantumEnd(VOID)
Definition: dpc.c:465
_In_opt_ PVOID _In_opt_ PVOID _In_opt_ PVOID SystemArgument2
Definition: ketypes.h:660
PVOID SystemArgument2
Definition: ketypes.h:680
UCHAR QuantumReset
Definition: ketypes.h:1300
#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:746
#define HIGH_LEVEL
Definition: env_spec_w32.h:703
UINT Timer
Definition: capclock.c:11
FORCEINLINE VOID KiReleaseDispatcherLock(IN KIRQL OldIrql)
Definition: ke_x.h:152
FORCEINLINE PKTHREAD KiSelectReadyThread(IN KPRIORITY Priority, IN PKPRCB Prcb)
Definition: ke_x.h:1408
VOID NTAPI KeSignalCallDpcDone(IN PVOID SystemArgument1)
Definition: dpc.c:1012
VOID FASTCALL KiRetireDpcList(IN PKPRCB Prcb)
Definition: dpc.c:561
FORCEINLINE KIRQL KiAcquireDispatcherLock(VOID)
Definition: ke_x.h:144
#define DPC_THREADED
PKDEFERRED_ROUTINE Routine
Definition: ke.h:62
VOID NTAPI KeGenericCallDpc(IN PKDEFERRED_ROUTINE Routine, IN PVOID Context)
Definition: dpc.c:983
LONG Sleeping
Definition: ketypes.h:762
PKPRCB KiProcessorBlock[]
Definition: krnlinit.c:32
PVOID Context
Definition: ke.h:63
LONG DpcSetEventRequest
Definition: ketypes.h:699
VOID FASTCALL KiAcquireSpinLock(IN PKSPIN_LOCK SpinLock)
Definition: ntoskrnl.c:32
unsigned int * PULONG
Definition: retypes.h:1
FORCEINLINE VOID KiRemoveEntryTimer(IN PKTIMER Timer)
Definition: ke_x.h:884
ULONG KiMaximumDpcQueueDepth
Definition: dpc.c:19
UCHAR DpcThreadActive
Definition: ketypes.h:689
#define DPRINT1
Definition: precomp.h:8
_In_ KDPC_IMPORTANCE Importance
Definition: kefuncs.h:93
VOID NTAPI KeSetTargetProcessorDpc(IN PKDPC Dpc, IN CCHAR Number)
Definition: dpc.c:970
#define UNIMPLEMENTED_FATAL(...)
Definition: debug.h:243
volatile UCHAR State
Definition: ketypes.h:997
USHORT Number
Definition: ketypes.h:559
void __cdecl _disable(void)
Definition: intrin_arm.h:365
unsigned int ULONG
Definition: retypes.h:1
#define IO_NO_INCREMENT
Definition: iotypes.h:565
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
LIST_ENTRY WaitListHead
Definition: ketypes.h:781
volatile USHORT Number
Definition: ketypes.h:675
FORCEINLINE VOID KxUnwaitThread(IN DISPATCHER_HEADER *Object, IN KPRIORITY Increment)
Definition: ke_x.h:1250
ULONG DpcRequestRate
Definition: ketypes.h:684
VOID NTAPI KeInitializeDpc(IN PKDPC Dpc, IN PKDEFERRED_ROUTINE DeferredRoutine, IN PVOID DeferredContext)
Definition: dpc.c:711
LONG MaximumDpcQueueDepth
Definition: ketypes.h:683
volatile PVOID DpcData
Definition: ketypes.h:681
PKDEFERRED_ROUTINE DeferredRoutine
Definition: ketypes.h:677
PVOID DeferredContext
Definition: ketypes.h:678
signed int * PLONG
Definition: retypes.h:5
#define APC_LEVEL
Definition: env_spec_w32.h:695
VOID NTAPI KeFlushQueuedDpcs(VOID)
Definition: dpc.c:918
_In_ LONG _In_ LONG Limit
Definition: kefuncs.h:328
ULONGLONG NTAPI KeQueryInterruptTime(VOID)
Definition: clock.c:203
static PLARGE_INTEGER Time
Definition: time.c:28
#define Int32x32To64(a, b)
FORCEINLINE VOID KiReleaseTimerLock(IN PKSPIN_LOCK_QUEUE LockQueue)
Definition: ke_x.h:291
LONGLONG QuadPart
Definition: typedefs.h:113
BOOLEAN NTAPI KeSignalCallDpcSynchronize(IN PVOID SystemArgument2)
Definition: dpc.c:1025
KIRQL WaitIrql
Definition: ketypes.h:999
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:660