diff -r 578be2adaf3e -r 307f4279f433 Adaptation/GUID-B97BAC2E-04E3-4979-BACE-9C46BADE912E.dita --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Adaptation/GUID-B97BAC2E-04E3-4979-BACE-9C46BADE912E.dita Fri Oct 15 14:32:18 2010 +0100 @@ -0,0 +1,106 @@ + + + + + +Deferred Function CallsThis 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 the same time an asynchronous receive request and a transmit request +would create two DFCs, one each for receive and transmit.

There +are two main types of deferred function call:

    +
  • standard Deferred Function Call (DFC)

  • +
  • Immediate Deferred Function Call (IDFC).

  • +

A DFC is a kernel object that specifies a function to +be run in a thread, which is processing a DFC queue. A DFC is added +to a DFC queue that is associated with a given thread, where it is +cooperatively scheduled with other DFCs on that queue. Queued DFCs +are run in order of their priority, followed by the order they where +queued. When the DFC gets to run, the function is run kernel side, +and no other DFC in this queue will get to run until it completes. +A DFC can be queued from any context.

An IDFC is run as soon +as the scheduler is next run, which is:

+ + + +Scheduler +IDFC runs + + + + +queued from an Interrupt Service Routine (ISR) +during the IRQ postamble. + + +queued from an IDFC +when the currently-running IDFC completes. + + +queued from thread context +when the kernel is next unlocked. + + + +

Unlike a DFC, the IDFC is not run from a thread context, +and its execution time must be much smaller. For these reasons, IDFCs +are rarely used directly, but are used for implementation of the kernel +and RTOS personality layers. An important use of IDFCs is in the +implementation of queuing DFCs from an ISR context. IDFCs are run +with interrupts enabled but the kernel locked.

+
Creation

DFCs are created using TDfc objects.

The DFC is initialized 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; +/* RxDataDfc is a function pointer to a static function, "this" is passed as a parameter */ +iRxDfc(RxDataDfc,this,1); // This implements an DFC using the standard queue and priority 1. +iRxDfc(RxDataDfc,this,iDfcQ,1); // This implements an DFC on a user-specified queue with a priority of 1. +iRxDfc(RxDataDfc,this); // This implements an IDFC.DFCs are created with a priority which is 0 to (KNumDfcPriorities—1), which is typically 0..7. Using a higher priority value is an +error. IDFCs are created by not specifying a priority.
+
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(); +...
+
\ No newline at end of file