|
1 <?xml version="1.0" encoding="utf-8"?> |
|
2 <!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. --> |
|
3 <!-- This component and the accompanying materials are made available under the terms of the License |
|
4 "Eclipse Public License v1.0" which accompanies this distribution, |
|
5 and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". --> |
|
6 <!-- Initial Contributors: |
|
7 Nokia Corporation - initial contribution. |
|
8 Contributors: |
|
9 --> |
|
10 <!DOCTYPE concept |
|
11 PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd"> |
|
12 <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 |
|
13 used to implement asynchronous requests.</shortdesc><prolog><metadata><keywords/></metadata></prolog><conbody> |
|
14 <section id="GUID-1F20014A-5F1E-48B3-AEB8-ED1922452A84"><title>Deferred |
|
15 function calls</title> <p>Asynchronous request processing is normally |
|
16 done in a Deferred Function Call (DFC). The second stage of interrupt |
|
17 handling is deferred to run as a DFC, which runs in a non-critical |
|
18 context. </p> <p>Different asynchronous requests can be handled using |
|
19 a single or multiple DFCs. The number of DFCs to be created must be |
|
20 decided when the driver is designed. For example, a driver that handles |
|
21 at the same time an asynchronous receive request and a transmit request |
|
22 would create two DFCs, one each for receive and transmit. </p><p>There |
|
23 are two main types of deferred function call:<ul> |
|
24 <li><p>standard Deferred Function Call (DFC)</p></li> |
|
25 <li><p>Immediate Deferred Function Call (IDFC).</p></li> |
|
26 </ul></p><p>A DFC is a kernel object that specifies a function to |
|
27 be run in a thread, which is processing a DFC queue. A DFC is added |
|
28 to a DFC queue that is associated with a given thread, where it is |
|
29 cooperatively scheduled with other DFCs on that queue. Queued DFCs |
|
30 are run in order of their priority, followed by the order they where |
|
31 queued. When the DFC gets to run, the function is run kernel side, |
|
32 and no other DFC in this queue will get to run until it completes. |
|
33 A DFC can be queued from any context.</p><p>An IDFC is run as soon |
|
34 as the scheduler is next run, which is:</p><table id="GUID-CCA45A6C-BB16-41D1-B16C-E3491BEF8B7B"> |
|
35 <tgroup cols="2"><colspec colname="col1"/><colspec colname="col2"/> |
|
36 <thead> |
|
37 <row> |
|
38 <entry align="center" valign="top">Scheduler</entry> |
|
39 <entry align="center" valign="top">IDFC runs</entry> |
|
40 </row> |
|
41 </thead> |
|
42 <tbody> |
|
43 <row> |
|
44 <entry>queued from an Interrupt Service Routine (ISR)</entry> |
|
45 <entry>during the IRQ postamble.</entry> |
|
46 </row> |
|
47 <row> |
|
48 <entry>queued from an IDFC</entry> |
|
49 <entry>when the currently-running IDFC completes.</entry> |
|
50 </row> |
|
51 <row> |
|
52 <entry>queued from thread context</entry> |
|
53 <entry>when the kernel is next unlocked.</entry> |
|
54 </row> |
|
55 </tbody> |
|
56 </tgroup> |
|
57 </table><p>Unlike a DFC, the IDFC is not run from a thread context, |
|
58 and its execution time must be much smaller. For these reasons, IDFCs |
|
59 are rarely used directly, but are used for implementation of the kernel |
|
60 and RTOS personality layers. An important use of IDFCs is in the |
|
61 implementation of queuing DFCs from an ISR context. IDFCs are run |
|
62 with interrupts enabled but the kernel locked.</p></section> |
|
63 <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 |
|
64 an object to be passed to the callback function, and a priority. It |
|
65 can also provide the DFC queue to be used by this DFC at the time |
|
66 of construction. </p> <codeblock id="GUID-B3918CAB-F168-5992-BFA9-868648D07083" xml:space="preserve">TDfc iRxDfc; |
|
67 /* RxDataDfc is a function pointer to a static function, "this" is passed as a parameter */ |
|
68 iRxDfc(RxDataDfc,this,1); // This implements an DFC using the standard queue and priority 1. |
|
69 iRxDfc(RxDataDfc,this,iDfcQ,1); // This implements an DFC on a user-specified queue with a priority of 1. |
|
70 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 |
|
71 error. IDFCs are created by not specifying a priority. </note></section> |
|
72 <section id="GUID-886457DF-0DB5-4447-BC9B-EB43060A5C6B"><title>Queuing</title> <p>To initiate the process of DFC functionality, the DFC object |
|
73 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 |
|
74 associated with the queue (<xref href="GUID-24B2FEDB-9273-351F-A1C6-6F5F91BF83B7.dita"><apiname>TDfcQue</apiname></xref>) object. This |
|
75 can be either done at the time of construction, or can be set later, |
|
76 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">... |
|
77 // Associate the Tx and Rx DFCs with the same queue set to receive |
|
78 // the client messages for this driver. SetDfcQ() sets up the DFC |
|
79 // queue for the DFCs constructed for Tx and Rx |
|
80 // |
|
81 iRxDfc.SetDfcQ(iDfcQ); |
|
82 ...</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 |
|
83 // is the only way to queue an IDFC and is the only way to queue a |
|
84 // DFC from an ISR. To queue a DFC from an IDFC or a thread either |
|
85 // TDfc::Enque() or TDfc::DoEnque() should be used. This function |
|
86 // does nothing if the IDFC/DFC is already queued. |
|
87 // |
|
88 iRxDfc.Add(); |
|
89 </codeblock></section> |
|
90 <section id="GUID-E0B9073A-1554-4085-BE24-E27633B7EDF2"><title>Callback |
|
91 function</title> <p>The DFC callback function is a static function |
|
92 called when a DFC is executed. A pointer to this function is provided |
|
93 at the time of DFC object creation. This function implements the deferred |
|
94 functionality of an asynchronous request, such as reading or writing |
|
95 data from or to an I/O peripheral. It would then either complete the |
|
96 request or start another operation. </p> <codeblock id="GUID-5682EDE1-8397-592D-82CE-78DF11487512" xml:space="preserve">static void RxDataDfc(TAny* aPtr);</codeblock></section> |
|
97 <section id="GUID-A57C3C99-3032-48CD-A800-E9EE7DCDF4E3"><title>Cancellation</title> <p>A DFC function must be cancelled while cleaning up resources, |
|
98 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 |
|
99 is not queued. It must be called to avoid orphaned DFCs. </p> <codeblock id="GUID-CD926E3D-13E8-51C4-B224-8150FD4D70DB" xml:space="preserve">... |
|
100 // If it is a Transmit request, cancel the Transmit DFC. |
|
101 // TDfc::Cancel() cancels the DFC if it is already queued. It |
|
102 // does nothing if DFC is not queued. |
|
103 // |
|
104 iTxDfc.Cancel(); |
|
105 ...</codeblock></section> |
|
106 </conbody></concept> |