|
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-B7B7F611-BCA0-498F-BEC1-16B276F680D5" xml:lang="en"><title>Calling |
|
13 Symbian Asynchronous APIs in Applications</title><shortdesc/><prolog><metadata><keywords/></metadata></prolog><conbody> |
|
14 <p>When porting an P.I.P.S.-based C or C++ application on top of Symbian C++, |
|
15 the developer may need to make use of Symbian asynchronous APIs. If asynchronous |
|
16 APIs are made use of in an P.I.P.S. application, the application needs to |
|
17 wait for the completion of the asynchronous API. This can be done in two ways: |
|
18 <ul> |
|
19 <li><p>Wait for the asynchronous request to complete. This can be achieved |
|
20 by making use of <codeph>User::WaitForRequest(iStatus)</codeph>; where <codeph>iStatus</codeph> is |
|
21 the <codeph>TRequestSemaphore</codeph> used by the asynchronous API. </p></li> |
|
22 <li><p>Call the asynchronous API in an active object, run an active scheduler, |
|
23 and let the active scheduler wait for the asynchronous operation to complete. </p></li> |
|
24 </ul></p> |
|
25 <p><b>The problems with these approaches are: </b></p> |
|
26 <p>The open source application would get blocked till the asynchronous operation |
|
27 completes in the first approach. In the second approach, the active scheduler |
|
28 would be running in a wait loop, checking for asynchronous API completion. |
|
29 Even in this case, the P.I.P.S. application would not be able to perform any |
|
30 other operations outside the active scheduler framework.</p> |
|
31 <p>The asynchronous APIs could be called in a separate process, and the P.I.P.S. |
|
32 application could communicate with this process by making use of the client/server |
|
33 framework of Symbian or by making use of other P.I.P.S. IPC mechanisms. However, |
|
34 making a different process for calling asynchronous APIs might pose a performance |
|
35 hit.</p> |
|
36 <p>One of the ways to solve these problems is to call the asynchronous APIs |
|
37 in a separate thread.</p> |
|
38 <p><b>Example:</b></p> |
|
39 <codeblock xml:space="preserve">class CActiveThread: public CActive |
|
40 { |
|
41 public: |
|
42 |
|
43 enum TState |
|
44 { |
|
45 EInitialized = 0x0, |
|
46 EDoFirst = 0x1, |
|
47 EDoSecond = 0x2, |
|
48 EDoThird = 0x4, |
|
49 ECompleted = 0x8 |
|
50 }; |
|
51 |
|
52 // thread startup routine |
|
53 static int StartMyThread(void* thisptr); |
|
54 // leaving variant of the thread startup routine |
|
55 static int StartMyThreadL(void* thisptr); |
|
56 // Helper function to start the thread |
|
57 void StartThread(); |
|
58 // Do Function |
|
59 void DoFunction(TState aState ); |
|
60 |
|
61 // CActive Functions |
|
62 void RunL(); |
|
63 void DoCancel(); |
|
64 |
|
65 // Constructors and destructor |
|
66 static CActiveThread* NewL(); |
|
67 CActiveThread (); |
|
68 void ConstructL(); |
|
69 ~ CActiveThread(); |
|
70 |
|
71 private: |
|
72 |
|
73 // Active Scheduler |
|
74 CActiveSchedulerWait *iWait; |
|
75 // Command/State |
|
76 TInt iState; |
|
77 TRequestStatus iThreadExitWait; |
|
78 // my thread handle |
|
79 RThread iActiveThread; |
|
80 sem_t iSem; |
|
81 }; |
|
82 </codeblock> |
|
83 <p>The <codeph>StartThread</codeph> member function of <xref href="GUID-7968C6B4-3247-335A-845B-3D196E2EB14C.dita"><apiname>CActiveThread</apiname></xref> creates |
|
84 the thread which runs the active scheduler. <codeph>StartMyThread</codeph> is |
|
85 the entry point function for the new thread that starts an active scheduler |
|
86 and sets up the clean up stack. To call an asynchronous function, <codeph>DoFunction()</codeph> needs |
|
87 to be called with the corresponding state. The parent thread signals the child |
|
88 thread using the child thread’s thread request semaphore. When the thread |
|
89 request semaphore is signaled, the child thread wakes up, calls the corresponding |
|
90 asynchronous API in <codeph>RunL()</codeph> based on the <codeph>iState</codeph> and |
|
91 again goes back to the active scheduler wait loop. </p> |
|
92 <p>To synchronize between the parent thread and the child thread, a semaphore |
|
93 can be used as shown in the following code snippet. </p> |
|
94 <codeblock xml:space="preserve">CActiveThread* CActiveThread::NewL() |
|
95 { |
|
96 CActiveThread* self = new (ELeave) CActiveThread(); |
|
97 self->ConstructL(); |
|
98 return self; |
|
99 } |
|
100 |
|
101 CActiveThread::CActiveThread():CActive(EPriorityStandard),iState(EInitialized) |
|
102 { |
|
103 } |
|
104 |
|
105 void CActiveThread::ConstructL() |
|
106 { |
|
107 // semaphore for Synching |
|
108 sem_init(&iSem,0,0); |
|
109 } |
|
110 |
|
111 void CActiveThread::StartThread() |
|
112 { |
|
113 //Create Thread |
|
114 TInt err = iActiveThread.Create( KThreadName(),&CActiveThread::StartMyThread, KDefaultStackSize, NULL, (TAny*)this ); |
|
115 iActiveThread.Logon( iThreadExitWait ); |
|
116 iActiveThread.Resume(); |
|
117 sem_wait(&iSem ); |
|
118 } |
|
119 |
|
120 int CActiveThread::StartMyThread( void* ptr ) |
|
121 { |
|
122 CActiveScheduler* scheduler = new (ELeave) CActiveScheduler(); |
|
123 CActiveScheduler::Install(scheduler); |
|
124 CTrapCleanup* pCleanup = CTrapCleanup::New(); |
|
125 TRAPD(err, StartMyThreadL(ptr)); |
|
126 } |
|
127 |
|
128 int CActiveThread::StartMyThreadL( void* ptr ) |
|
129 { |
|
130 CActiveThread *thisptr = (CActiveThread*)ptr; |
|
131 CActiveScheduler::Add(thisptr); |
|
132 thisptr->iWait = new (ELeave) CActiveSchedulerWait(); |
|
133 thisptr->iState = EInitialized; |
|
134 thisptr->iStatus = KRequestPending; |
|
135 thisptr->SetActive(); |
|
136 sem_post( &(thisptr->iSem )); |
|
137 thisptr->iWait->Start(); |
|
138 } |
|
139 |
|
140 void CActiveThread::RunL() |
|
141 { |
|
142 switch ( iState ) |
|
143 { |
|
144 case EDoFirst: |
|
145 // Call 1st asynchronous function |
|
146 break; |
|
147 |
|
148 case EDoSecond: |
|
149 // Call 2nd asynchronous function |
|
150 break; |
|
151 |
|
152 case EDoThird: |
|
153 // Call 3rd asynchronous function |
|
154 break; |
|
155 |
|
156 case ECompleted: |
|
157 iWait->AsyncStop(); |
|
158 return; |
|
159 } |
|
160 |
|
161 iStatus = KRequestPending; |
|
162 SetActive(); |
|
163 // wake up the waiting thread |
|
164 sem_post(&iSem); |
|
165 } |
|
166 |
|
167 void CActiveThread::DoCancel() |
|
168 { |
|
169 } |
|
170 |
|
171 void CActiveThread::DoFunction(TState aState ) |
|
172 { |
|
173 iState = aState; |
|
174 TRequestStatus *reqPtr = &iStatus; |
|
175 iActiveThread.RequestComplete( reqPtr, KErrNone ); |
|
176 sem_wait(&iSem); |
|
177 } |
|
178 |
|
179 CActiveThread::~CActiveThread() |
|
180 { |
|
181 if ( iState != EInitialized ) |
|
182 { |
|
183 iState = ECompleted; |
|
184 TRequestStatus *reqPtr = &iStatus; |
|
185 iActiveThread.RequestComplete( reqPtr, KErrNone ); |
|
186 User::WaitForRequest( iThreadExitWait); |
|
187 } |
|
188 sem_destroy(&iSem); |
|
189 } |
|
190 </codeblock> |
|
191 <p><b>Using <xref href="GUID-7968C6B4-3247-335A-845B-3D196E2EB14C.dita"><apiname>CActiveThread</apiname></xref>:</b></p> |
|
192 <codeblock xml:space="preserve">iMyAsyncIf = CActiveThread::NewL(); |
|
193 iMyAsyncIf->StartThread(); |
|
194 iMyAsyncIf->DoFunction(EDoFirst); |
|
195 </codeblock> |
|
196 <p><b>Limitations: </b></p> |
|
197 <p>In this approach, only the parent thread communicates with the child thread. |
|
198 There is no way for the child thread to communicate with the parent thread. |
|
199 </p> |
|
200 </conbody></concept> |