Adaptation/GUID-B97BAC2E-04E3-4979-BACE-9C46BADE912E.dita
author Graeme Price <GRAEME.PRICE@NOKIA.COM>
Fri, 15 Oct 2010 14:32:18 +0100
changeset 15 307f4279f433
permissions -rw-r--r--
Initial contribution of the Adaptation Documentation.

<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. -->
<!-- This component and the accompanying materials are made available under the terms of the License 
"Eclipse Public License v1.0" which accompanies this distribution, 
and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". -->
<!-- Initial Contributors:
    Nokia Corporation - initial contribution.
Contributors: 
-->
<!DOCTYPE concept
  PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd">
<concept id="GUID-B97BAC2E-04E3-4979-BACE-9C46BADE912E" xml:lang="en"><title>Deferred Function Calls</title><shortdesc>This document describes how Deferred Function Calls are
used to implement asynchronous requests.</shortdesc><prolog><metadata><keywords/></metadata></prolog><conbody>
<section id="GUID-1F20014A-5F1E-48B3-AEB8-ED1922452A84"><title>Deferred
function calls</title> <p>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. </p> <p>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. </p><p>There
are two main types of deferred function call:<ul>
<li><p>standard Deferred Function Call (DFC)</p></li>
<li><p>Immediate Deferred Function Call (IDFC).</p></li>
</ul></p><p>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.</p><p>An IDFC is run as soon
as the scheduler is next run, which is:</p><table id="GUID-CCA45A6C-BB16-41D1-B16C-E3491BEF8B7B">
<tgroup cols="2"><colspec colname="col1"/><colspec colname="col2"/>
<thead>
<row>
<entry align="center" valign="top">Scheduler</entry>
<entry align="center" valign="top">IDFC runs</entry>
</row>
</thead>
<tbody>
<row>
<entry>queued from an Interrupt Service Routine (ISR)</entry>
<entry>during the IRQ postamble.</entry>
</row>
<row>
<entry>queued from an IDFC</entry>
<entry>when the currently-running IDFC completes.</entry>
</row>
<row>
<entry>queued from thread context</entry>
<entry>when the kernel is next unlocked.</entry>
</row>
</tbody>
</tgroup>
</table><p>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.</p></section>
<section id="GUID-5439E26D-754A-46F3-B607-D229BF5B8A8C"><title>Creation</title> <p>DFCs are created using <xref href="GUID-A14562A5-3E91-3113-AB3C-71DBEA9D58EB.dita"><apiname>TDfc</apiname></xref> objects. </p> <p>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. </p> <codeblock id="GUID-B3918CAB-F168-5992-BFA9-868648D07083" xml:space="preserve">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.</codeblock><note>DFCs are created with a priority which is 0 to (<xref href="GUID-483DF06F-0236-36C0-8F59-475BB38344E5.dita"><apiname>KNumDfcPriorities</apiname></xref>—1), which is typically 0..7. Using a higher priority value is an
error. IDFCs are created by not specifying a priority. </note></section>
<section id="GUID-886457DF-0DB5-4447-BC9B-EB43060A5C6B"><title>Queuing</title> <p>To initiate the process of DFC functionality, the DFC object
must be queued to the DFC queue associated with the Kernel thread. </p> <p>Before adding the DFC to a DFC queue of the thread, it must be
associated with the queue (<xref href="GUID-24B2FEDB-9273-351F-A1C6-6F5F91BF83B7.dita"><apiname>TDfcQue</apiname></xref>) object. This
can be either done at the time of construction, or can be set later,
by calling <xref href="GUID-A14562A5-3E91-3113-AB3C-71DBEA9D58EB.dita#GUID-A14562A5-3E91-3113-AB3C-71DBEA9D58EB/GUID-E3458CD4-7A1C-3FBD-A7FB-488A9C92AE42"><apiname>TDfc::SetDfcQ()</apiname></xref>. </p> <codeblock id="GUID-B57B1C37-A1A5-5C85-AED8-FDD8DBE84280" xml:space="preserve">...
// 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);
...</codeblock> <p> <xref href="GUID-A14562A5-3E91-3113-AB3C-71DBEA9D58EB.dita#GUID-A14562A5-3E91-3113-AB3C-71DBEA9D58EB/GUID-18073EBB-D91B-3AC8-87A2-424AEDD4D7A4"><apiname> TDfc::Add()</apiname></xref> or <xref href="GUID-A14562A5-3E91-3113-AB3C-71DBEA9D58EB.dita#GUID-A14562A5-3E91-3113-AB3C-71DBEA9D58EB/GUID-F6F0C858-8EB2-387B-AE1A-F04B51CE4CED"><apiname>TDfc::Enque()</apiname></xref> is used to add the DFC object to the DFC queue. From an ISR, <xref href="GUID-A14562A5-3E91-3113-AB3C-71DBEA9D58EB.dita#GUID-A14562A5-3E91-3113-AB3C-71DBEA9D58EB/GUID-18073EBB-D91B-3AC8-87A2-424AEDD4D7A4"><apiname>TDfc::Add()</apiname></xref> is used. From a thread, <xref href="GUID-A14562A5-3E91-3113-AB3C-71DBEA9D58EB.dita#GUID-A14562A5-3E91-3113-AB3C-71DBEA9D58EB/GUID-F6F0C858-8EB2-387B-AE1A-F04B51CE4CED"><apiname>TDfc::Enque()</apiname></xref> is used. If preemption is disabled, <codeph>TDfc::Add()</codeph> could also be used. </p> <codeblock id="GUID-9FBB6881-4BA9-534E-86C7-3A0167E9159C" xml:space="preserve">// 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();
</codeblock></section>
<section id="GUID-E0B9073A-1554-4085-BE24-E27633B7EDF2"><title>Callback
function</title> <p>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. </p> <codeblock id="GUID-5682EDE1-8397-592D-82CE-78DF11487512" xml:space="preserve">static void RxDataDfc(TAny* aPtr);</codeblock></section>
<section id="GUID-A57C3C99-3032-48CD-A800-E9EE7DCDF4E3"><title>Cancellation</title> <p>A DFC function must be cancelled while cleaning up resources,
for example, when closing the channel. The function <xref href="GUID-A14562A5-3E91-3113-AB3C-71DBEA9D58EB.dita#GUID-A14562A5-3E91-3113-AB3C-71DBEA9D58EB/GUID-9851B90B-8D05-3C86-B083-44C4564AC140"><apiname>TDfc::Cancel()</apiname></xref> 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. </p> <codeblock id="GUID-CD926E3D-13E8-51C4-B224-8150FD4D70DB" xml:space="preserve">...
// 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();
...</codeblock></section>
</conbody></concept>