|
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-2648B61C-6EBD-4668-AACD-EA4B2C435BB2" xml:lang="en"><title>Message |
|
13 Handling</title><shortdesc>This document describes message queues and message handling.</shortdesc><prolog><metadata><keywords/></metadata></prolog><conbody> |
|
14 <section id="GUID-AE9A6778-85AE-4D1D-BF61-EE06339549D9"><title>Message queues</title> <p>The |
|
15 request handling kernel side DFC is managed by a message queue object of the <xref href="GUID-F10B7D2F-D546-3997-A020-37A0D894F1CD.dita"><apiname>TMessageQueue</apiname></xref> type. |
|
16 The message queue consists of a DFC and a doubly linked list of received messages. |
|
17 The messages are represented by <xref href="GUID-D43CB8FA-C212-3B56-AD16-9F1D69DA7551.dita"><apiname>TThreadMessage</apiname></xref> objects |
|
18 and are owned by each user thread. Requests are queued as message objects |
|
19 on the message queue. </p> <p>The driver framework requires that the driver |
|
20 sets a DFC queue to use with the message queue. This is done by calling <xref href="GUID-A3CC1D95-4681-3349-A67C-F113A614041D.dita#GUID-A3CC1D95-4681-3349-A67C-F113A614041D/GUID-EB160A2E-39A9-3739-ABDE-C91E2A28D26D"><apiname>DLogicalChannel::SetDfcQ()</apiname></xref>. |
|
21 The message queue must also be enabled to receive incoming messages by calling <xref href="GUID-382DD935-E9D7-3E00-88B2-B28A89CAD4FB.dita#GUID-382DD935-E9D7-3E00-88B2-B28A89CAD4FB/GUID-EF06556E-9EC6-3D1C-AEE9-0CDDF6B42A24"><apiname>TMessageQue::Receive()</apiname></xref>. </p> <codeblock id="GUID-A995A927-113D-5CB6-B813-DF88DC02D0C1" xml:space="preserve">// Logical Channel Second stage constructor |
|
22 TInt DExDriverLogicalChannel::DoCreate(TInt /*aUnit*/, const TDesC8* |
|
23 /*anInfo*/, const TVersion& aVer) |
|
24 { |
|
25 ... |
|
26 // Set up the DFC queue for this driver. Here, the DFC |
|
27 // queue is created by the PDD dedicated for this driver. |
|
28 SetDfcQ(Pdd()->DfcQ()); |
|
29 |
|
30 // Start receiving the incoming requests on the message queue |
|
31 iMsgQ.Receive(); |
|
32 ... |
|
33 }</codeblock> <p>The Kernel provides a standard DFC queue, which runs |
|
34 on a dedicated kernel thread called <codeph>DFCThread0</codeph>, for general |
|
35 use by drivers. However, it is recommended that the driver creates its own |
|
36 DFC thread to process its requests. The following example shows how a PDD |
|
37 can implement the <codeph>DfcQ()</codeph> function to return a newly created |
|
38 DFC thread: </p> <codeblock id="GUID-4753E5B1-8B8F-5589-8547-C94B48B7D66A" xml:space="preserve">// DfcQ - Creates a DFC queue dedicated for the tutorial driver |
|
39 TDynamicDfcQue* DExUartPhysicalChannelH4::DfcQ() |
|
40 { |
|
41 // Create a DFC queue dedicated to the driver with a specified |
|
42 // priority |
|
43 TInt r = Kern::DynamicDfcQCreate(pDfcQ,KExUartDfcPriority, |
|
44 KExUartDfcName); |
|
45 if (r!=KErrNone) |
|
46 { |
|
47 // DfcQ failed, return NULL |
|
48 return NULL; |
|
49 } |
|
50 return iDfcQueue; |
|
51 }</codeblock> <p>The DFC thread that is created for the driver must be |
|
52 destroyed after use. To do this, the driver can create an Exit or Kill DFC |
|
53 request and queue it to the thread to be destroyed in the logical channel |
|
54 destructor. This exit DFC function cancels any other requests pending using <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> and |
|
55 calls <xref href="GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D.dita#GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D/GUID-808B3622-BDC4-376D-96E9-16281BA28AF8"><apiname>Kern::Exit()</apiname></xref> to terminate the thread. </p> <p>The <xref href="GUID-D9111A26-FAA3-3D8E-AB41-5B1263FABB6A.dita"><apiname>TDynamicDfcQue</apiname></xref> has |
|
56 a destroy method that can be run on the channel destructor. The destroy method |
|
57 destroys the DFC queue, kills the DFC thread and deletes the <xref href="GUID-D9111A26-FAA3-3D8E-AB41-5B1263FABB6A.dita"><apiname>TDynamicDfcQue</apiname></xref> object |
|
58 itself. This avoids the possibilities of memory leaks in the DFC. </p></section> |
|
59 <section id="GUID-2463763E-1838-4D7D-80F2-D77420B49D09"><title>Message handling</title> <p>All |
|
60 synchronous and asynchronous requests are passed to the <xref href="GUID-621F4531-996F-33BB-8081-4B2067CC262A.dita"><apiname>HandleMsg()</apiname></xref> function |
|
61 by the framework, with the message as an argument. A driver should implement |
|
62 the function to identify the message type and handle the messages accordingly. </p> <p>The |
|
63 client thread is blocked until the message is completed, as the request uses |
|
64 the thread's message object. If the client thread was left free, it would |
|
65 corrupt the message if another request was issued. </p> <p>When the driver |
|
66 has completed handling the message, it notifies the framework by calling <xref href="GUID-D43CB8FA-C212-3B56-AD16-9F1D69DA7551.dita#GUID-D43CB8FA-C212-3B56-AD16-9F1D69DA7551/GUID-20CFC972-7C07-36D8-BAC8-BB63AA4612B6"><apiname>TThreadMessage::Complete()</apiname></xref>. |
|
67 The client thread is then unblocked, and can either block on the thread semaphore |
|
68 or issue further requests before blocking. </p> <p>For synchronous requests, |
|
69 the message is not completed until the request itself is complete, and the |
|
70 driver calls the <codeph>TThreadMessage::Complete()</codeph> function after |
|
71 the actual completion of the request. However, for asynchronous requests, |
|
72 the message is completed after the driver has accepted the request, but not |
|
73 necessarily after the actual completion of the request, which can happen later. |
|
74 This means that the driver calls <codeph>TThreadMessage::Complete()</codeph> as |
|
75 soon as it has received the message and initiated the required processing |
|
76 to complete the request. </p> <codeblock id="GUID-C178DFFA-2321-5396-AED6-5244BBF98388" xml:space="preserve">void DExDriverLogicalChannel::HandleMsg(TMessageBase* aMsg) |
|
77 { |
|
78 TThreadMessage& m = *(TThreadMessage*)aMsg; |
|
79 // obtain the function id value to determine the request nature |
|
80 TInt id = m.iValue; |
|
81 ... |
|
82 if (id>=0) // Synchronous messages |
|
83 { |
|
84 // call synchronous message handler function, DoControl() |
|
85 TInt r = DoControl(id,m.Ptr0(),m.Ptr1()); |
|
86 m.Complete(r,ETrue); |
|
87 return; |
|
88 } |
|
89 }</codeblock></section> |
|
90 </conbody></concept> |