Deferred Function Calls

This document describes how Deferred Function Calls are used to implement asynchronous requests.

Deferred function calls

Asynchronous request processing is normally done in a Deferred Function Call (DFC). The second stage of interrupt handling is deferred to run as a DFC, which runs in a non-critical context.

Different asynchronous requests can be handled using a single or multiple DFCs. The number of DFCs to be created must be decided when the driver is designed. For example, a driver that handles at a time an asynchronous receive request and a transmit request would create two DFCs each for receive and transmit.

Creation

DFCs are created using TDfc objects.

The DFC is initialised with a DFC callback function, a pointer to an object to be passed to the callback function, and a priority. It can also provide the DFC queue to be used by this DFC at the time of construction.

TDfc iRxDfc;
iRxDfc(RxDataDfc,this,1); 
    or
iRxDfc(RxDataDfc,this,iDfcQ,1);

Queuing

To initiate the process of DFC functionality, the DFC object must be queued to the DFC queue associated with the Kernel thread.

Before adding the DFC to a DFC queue of the thread, it must be associated with the queue (TDfcQue) object. This can be either done at the time of construction, or can be set later, by calling TDfc::SetDfcQ().

...
// Associate the Tx and Rx DFCs with the same queue set to receive 
// the client messages for this driver. SetDfcQ() sets up the DFC 
// queue for the DFCs constructed for Tx and Rx
//
iRxDfc.SetDfcQ(iDfcQ);
...

TDfc::Add() or TDfc::Enque() is used to add the DFC object to the DFC queue. From an ISR, TDfc::Add() is used. From a thread, TDfc::Enque() is used. If preemption is disabled, TDfc::Add() could also be used.

// TDfc::Add() will queue an IDFC or a DFC from an ISR. This function 
// is the only way to queue an IDFC and is the only way to queue a 
// DFC from an ISR. To queue a DFC from an IDFC or a thread either 
// TDfc::Enque() or TDfc::DoEnque() should be used. This function 
// does nothing if the IDFC/DFC is already queued.
//
iRxDfc.Add();

Callback function

The DFC callback function is a static function called when a DFC is executed. A pointer to this function is provided at the time of DFC object creation. This function implements the deferred functionality of an asynchronous request, such as reading or writing data from or to an I/O peripheral. It would then either complete the request or start another operation.

static void RxDataDfc(TAny* aPtr);

Cancellation

A DFC function must be cancelled while cleaning up resources, for example, when closing the channel. The function TDfc::Cancel() cancels the DFC if it is already queued. It does nothing if a DFC is not queued. It must be called to avoid orphaned DFCs.

...
// If it is a Transmit request, cancel the Transmit DFC. 
// TDfc::Cancel() cancels the DFC if it is already queued. It 
// does nothing if DFC is not queued.
//
iTxDfc.Cancel();
...