ReactOS  0.4.13-dev-73-gcfe54aa
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 
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 */
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 */
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 */
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 */
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,
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();
663 
664  /* Process deferred threads */
666 
667  /* Lower IRQL back and disable interrupts */
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 */
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 */
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 */
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 */
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  //
1003  Routine(&KeGetCurrentPrcb()->CallDpc, Context, &Barrier, &ReverseBarrier);
1005 }
1006 
1007 /*
1008  * @implemented
1009  */
1010 VOID
1011 NTAPI
1013 {
1014  //
1015  // Decrement the barrier, which is actually the processor count
1016  //
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  //
1031  return TRUE;
1032 }
1033 
1034 /* 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:244
ULONG KiAdjustDpcThreshold
Definition: dpc.c:21
ULONG KiIdealDpcRate
Definition: dpc.c:22
ULONG LowPart
Definition: ketypes.h:910
#define IN
Definition: typedefs.h:38
#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
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
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:323
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:84
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
_In_ ULONGLONG _In_ ULONGLONG _In_ BOOLEAN Enable
Definition: ntddpcm.h:140
FORCEINLINE struct _KPRCB * KeGetCurrentPrcb(VOID)
Definition: ketypes.h:1062
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
#define LOW_REALTIME_PRIORITY
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:155
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
void DbgBreakPoint()
Definition: mach.c:558
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:946
struct _KTHREAD * NextThread
Definition: ketypes.h:567
_Must_inspect_result_ FORCEINLINE BOOLEAN IsListEmpty(_In_ const LIST_ENTRY *ListHead)
Definition: rtlfuncs.h:57
#define PAGED_CODE()
Definition: video.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:63
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
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
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
VOID FASTCALL KiReleaseSpinLock(IN PKSPIN_LOCK SpinLock)
Definition: ntoskrnl.c:39
long LONG
Definition: pedump.c:60
#define InterlockedCompareExchangePointer
Definition: interlocked.h:129
struct _KTHREAD * CurrentThread
Definition: ketypes.h:566
unsigned char BOOLEAN
FORCEINLINE VOID KiAcquirePrcbLock(IN PKPRCB Prcb)
Definition: ke_x.h:214
smooth NULL
Definition: ftsmooth.c:416
#define MAX_TIMER_DPCS
Definition: ke.h:64
VOID FASTCALL KiTimerListExpire(IN PLIST_ENTRY ExpiredListHead, IN KIRQL OldIrql)
Definition: dpc.c:338
FORCEINLINE BOOLEAN KeDisableInterrupts(VOID)
Definition: ke.h:176
BOOLEAN KeThreadDpcEnable
Definition: dpc.c:23
#define IPI_DPC
Definition: ketypes.h:233
Definition: ke.h:66
PKDPC Dpc
Definition: ke.h:68
ULONG DpcCount
Definition: ketypes.h:748
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:667
DWORD Interval
Definition: netstat.c:30
KEVENT DpcEvent
Definition: ketypes.h:706
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:234
enum _KDPC_IMPORTANCE KDPC_IMPORTANCE
struct _LIST_ENTRY * Flink
Definition: typedefs.h:119
KDPC KiTimerExpireDpc
Definition: dpc.c:25
_In_ LARGE_INTEGER _In_opt_ PKDPC Dpc
Definition: kefuncs.h:524
#define TIMER_TABLE_SIZE
Definition: ketypes.h:836
LIST_ENTRY Entry
Definition: ketypes.h:666
char CCHAR
Definition: typedefs.h:50
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
static const UCHAR Index[8]
Definition: usbohci.c:18
_In_opt_ PFILE_OBJECT _In_opt_ PETHREAD Thread
Definition: fltkernel.h:2653
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
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:687
KDEFERRED_ROUTINE * PKDEFERRED_ROUTINE
Definition: ketypes.h:678
UCHAR DpcInterruptRequested
Definition: ketypes.h:686
ULONG LowPart
Definition: typedefs.h:104
Definition: typedefs.h:117
ULONG_PTR KiIdleSummary
Definition: thrdschd.c:25
VOID FASTCALL KiIpiSend(KAFFINITY TargetSet, ULONG IpiRequest)
ULONG TotalProcessors
Definition: ke.h:49
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: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: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:69
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:70
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:244
volatile UCHAR State
Definition: ketypes.h:1679
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
volatile USHORT Number
Definition: ketypes.h:690
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: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: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:105
#define Int32x32To64(a, b)
FORCEINLINE VOID KiReleaseTimerLock(IN PKSPIN_LOCK_QUEUE LockQueue)
Definition: ke_x.h:291
LONGLONG QuadPart
Definition: typedefs.h:112
BOOLEAN NTAPI KeSignalCallDpcSynchronize(IN PVOID SystemArgument2)
Definition: dpc.c:1025
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