Deferred Procedure Call

One feature available in the Windows kernel that I really like is the Deferred Procedure Call. It’s a mechanism that basically let’s you defer lower-priority tasks. This is because high-priority tasks such as interrupt handlers should complete as quickly as possible, but they may have other required tasks that are of lower-priority. DPC’s allow these tasks to be scheduled for later execution when the kernel drops to an IRQL (Interrupt Request Level) of Dispatch/DPC level. When the kernel is in this IRQL, it will execute DPC’s that have been queued.

In kernel mode, a DPC object is initialized with:

VOID KeInitializeDpc(

  __out     PRKDPC Dpc,

  __in      PKDEFERRED_ROUTINE DeferredRoutine,

  __in_opt  PVOID DeferredContext



This is the Custom DPC function prototype:



VOID CustomDpc(

  __in      struct _KDPC *Dpc,

  __in_opt  PVOID DeferredContext,

  __in_opt  PVOID SystemArgument1,

  __in_opt  PVOID SystemArgument2



You queue a DPC with:

BOOLEAN KeInsertQueueDpc(

  __inout   PRKDPC Dpc,

  __in_opt  PVOID SystemArgument1,

  __in_opt  PVOID SystemArgument2



I had a need for something like that in one of my .NET projects. However, I needed something deferred by time, rather than scheduling priority. This need is nothing new, of course. It’s commonly implemented with timers to basically delay the execution of code. Since I needed to do this kind of deferred procedure calls in a lot of places, I decided to write a nifty little class to do it for me instead of littering my code with a ton of timer creations and handlers.

And since I liked the Windows kernel’s DPC mechanism so much, I called it the same thing. The source can be downloaded here.

The class is DeferredProcedureCall. It can be built for Silverlight as well. Instantiating one instance for the lifetime of your class/app/program is enough. In fact, it is meant to be used this way. The function prototype for the DPC routine is as follows:

public delegate object DeferredRoutine(params object[] args);


This is in the same tradition as the kernel’s Custom DPC routine. However, the variable argument list in C#/.NET makes it all the more convenient. So, you may pass in any and any amount of parameters as you wish to suit your needs. The return type is also entirely up to you. It should be obvious that in callbacks of such traditions, you are responsible for the types being passed in and out.

The DPC class also has an event you can register a handler to which notifies you that a scheduled DPC has completed. Here’s how you register a handler, and the handler itself (from the sample source code):

      private DeferredProcedureCall _dpc = new DeferredProcedureCall();


      _dpc.DpcProcCompleted += new DeferredProcedureCall.DpcProcCompletedHandler(_dpc_DpcProcCompleted);


      void _dpc_DpcProcCompleted(object reference, DeferredProcedureCall.DeferredRoutine proc, object result)


            AddMessageProc(string.Format(“DPC Completed: [{0}] {1}”, proc.Method.Name, result.ToString()));



Here’s the method to schedule a DPC:

public object ScheduleDpc(double delayMs, DeferredRoutine proc, params object[] args)

Therefore, scheduling a DPC is merely so:

      _dpc.ScheduleDpc(1000, AddMessageProc, “First message”);


      _dpc.ScheduleDpc(4000, (x) => { lbStatus.Items.Add(x[0]); return true; }, “Second Message”);



As you can see, you could use Lambda Expressions to define callbacks as well. This can be convenient when you have fairly small and random functions you want to schedule. Do note of course that you don’t have to pass any parameters to the callback if there is no need for any.

This entry was posted in Uncategorized. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s