sl@0
|
1 |
// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
|
sl@0
|
2 |
// All rights reserved.
|
sl@0
|
3 |
// This component and the accompanying materials are made available
|
sl@0
|
4 |
// under the terms of the License "Eclipse Public License v1.0"
|
sl@0
|
5 |
// which accompanies this distribution, and is available
|
sl@0
|
6 |
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
|
sl@0
|
7 |
//
|
sl@0
|
8 |
// Initial Contributors:
|
sl@0
|
9 |
// Nokia Corporation - initial contribution.
|
sl@0
|
10 |
//
|
sl@0
|
11 |
// Contributors:
|
sl@0
|
12 |
//
|
sl@0
|
13 |
// Description:
|
sl@0
|
14 |
// An agent plugin may have to service an asynchronous request, for example when
|
sl@0
|
15 |
// <code>ContentAccess::CAgentManager::NotifyStatusChange()</code> is called.
|
sl@0
|
16 |
// If the agent plugin must make an asynchronous SendReceive() call to service the request
|
sl@0
|
17 |
// then it must be careful to ensure that any memory that is passed as an argument
|
sl@0
|
18 |
// in the call is still valid when the agent server that receives the call processes
|
sl@0
|
19 |
// and uses the memory.
|
sl@0
|
20 |
// There are two ways that this can be achieved:
|
sl@0
|
21 |
// <hr>
|
sl@0
|
22 |
// If the agent plugin cannot guarantee that a variable to be passed in the asynchronous
|
sl@0
|
23 |
// SendReceive() call will still be in scope when the agent server comes to access and use
|
sl@0
|
24 |
// it then the agent plugin should store a local heap copy of the data and pass this
|
sl@0
|
25 |
// in the call instead. It is the responsibility of the agent plugin to maintain this heap
|
sl@0
|
26 |
// memory and delete it when appropriate. Depending on how and when the agent server uses
|
sl@0
|
27 |
// the memory, it may be safe to delete the memory after the asynchronous call has
|
sl@0
|
28 |
// been accepted, or not until the asynchronous request has completed.
|
sl@0
|
29 |
// For example, an agent plugin could implement the API <code>ContentAccess::CAgentManager::NotifyStatusChange()</code>
|
sl@0
|
30 |
// as illustrated below. Note that for this API the agent plugin can make no assumption about the
|
sl@0
|
31 |
// scope of the descriptor passed to aURI.
|
sl@0
|
32 |
// void CTestAgentManager::NotifyStatusChange(const TDesC& aURI, TEventMask aMask, TRequestStatus& aStatus)
|
sl@0
|
33 |
// HBufC* uri = aURI.Alloc();
|
sl@0
|
34 |
// if(uri)
|
sl@0
|
35 |
// // store the heap variable in a local array
|
sl@0
|
36 |
// iAsyncDataArray.Append(uri); // takes ownership of uri
|
sl@0
|
37 |
// SendReceive(EManagerNotifyStatusChange, TIpcArgs(uri,aMask),aStatus);
|
sl@0
|
38 |
// <hr>
|
sl@0
|
39 |
// Alternatively, the agent plugin can use the variables that are in scope at the time of the
|
sl@0
|
40 |
// asynchronous SendReceive() call if it makes a synchronous SendReceive() call afterwards,
|
sl@0
|
41 |
// within the same function scope, as illustrated below. The synchronous message can
|
sl@0
|
42 |
// be a 'no operation' in the agent server.
|
sl@0
|
43 |
// void CTestAgentManager::NotifyStatusChange(const TDesC& aURI, TEventMask aMask, TRequestStatus& aStatus)
|
sl@0
|
44 |
// SendReceive(EManagerNotifyStatusChange, TIpcArgs(&aURI,aMask),aStatus);
|
sl@0
|
45 |
// // this call doesn't have to be immediately after the asynchronous call, but within this function
|
sl@0
|
46 |
// SendReceive(ENoOp,TIpcArgs(NULL));
|
sl@0
|
47 |
// The synchronous call causes the message queue to be flushed into the agent server before the thread returns from the
|
sl@0
|
48 |
// function and unwinds the call stack. The intention is that the agent server will only complete the second (synchronous)
|
sl@0
|
49 |
// message after receiving and doing initial processing of the first (asynchronous) message, which may include, for
|
sl@0
|
50 |
// example, reading the uri descriptor.
|
sl@0
|
51 |
// However, an obvious disadvantage of this pattern is that it incurs a second IPC call, and so may degrade performance.<br>
|
sl@0
|
52 |
// Moreover, there are several caveats which must hold true in order for the pattern to work:
|
sl@0
|
53 |
// 1. The kernel delivers messages in the order that they are sent (this is currently true).<br>
|
sl@0
|
54 |
// 2. The agent server is guaranteed to finish processing the first message before completing the second message.<br>
|
sl@0
|
55 |
// This requires understanding of the agent server implementation.<br>
|
sl@0
|
56 |
// 3. After initial processing of the first (asynchronous) message the agent server does not need to
|
sl@0
|
57 |
// access the memory supplied in the message again. This requires understanding of the agent server implementation.<br>
|
sl@0
|
58 |
// 4. The synchronous call is a request that has no effect on the state of the agent server - a 'no operation'
|
sl@0
|
59 |
// may or may not be possible.
|
sl@0
|
60 |
// <b>
|
sl@0
|
61 |
// For these reasons, this pattern should only be used as a last resort - for example, if the agent plugin cannot store member data in its class for compatibility reasons.
|
sl@0
|
62 |
// <b>
|
sl@0
|
63 |
//
|
sl@0
|
64 |
//
|
sl@0
|
65 |
|
sl@0
|
66 |
/**
|
sl@0
|
67 |
@page CAFAsyncSendReceive Making an asynchronous SendReceive() call in an agent plugin
|
sl@0
|
68 |
- @ref StoreLocalCopy
|
sl@0
|
69 |
- @ref SyncSendReceive
|
sl@0
|
70 |
@section StoreLocalCopy Storing a local heap copy of transient data
|
sl@0
|
71 |
@code
|
sl@0
|
72 |
@endcode
|
sl@0
|
73 |
@section SyncSendReceive Following the asynchronous call with a synchronous call
|
sl@0
|
74 |
@code
|
sl@0
|
75 |
@endcode
|
sl@0
|
76 |
*/
|