sl@0: // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // An agent plugin may have to service an asynchronous request, for example when sl@0: // ContentAccess::CAgentManager::NotifyStatusChange() is called. sl@0: // If the agent plugin must make an asynchronous SendReceive() call to service the request sl@0: // then it must be careful to ensure that any memory that is passed as an argument sl@0: // in the call is still valid when the agent server that receives the call processes sl@0: // and uses the memory. sl@0: // There are two ways that this can be achieved: sl@0: //
sl@0: // If the agent plugin cannot guarantee that a variable to be passed in the asynchronous sl@0: // SendReceive() call will still be in scope when the agent server comes to access and use sl@0: // it then the agent plugin should store a local heap copy of the data and pass this sl@0: // in the call instead. It is the responsibility of the agent plugin to maintain this heap sl@0: // memory and delete it when appropriate. Depending on how and when the agent server uses sl@0: // the memory, it may be safe to delete the memory after the asynchronous call has sl@0: // been accepted, or not until the asynchronous request has completed. sl@0: // For example, an agent plugin could implement the API ContentAccess::CAgentManager::NotifyStatusChange() sl@0: // as illustrated below. Note that for this API the agent plugin can make no assumption about the sl@0: // scope of the descriptor passed to aURI. sl@0: // void CTestAgentManager::NotifyStatusChange(const TDesC& aURI, TEventMask aMask, TRequestStatus& aStatus) sl@0: // HBufC* uri = aURI.Alloc(); sl@0: // if(uri) sl@0: // // store the heap variable in a local array sl@0: // iAsyncDataArray.Append(uri); // takes ownership of uri sl@0: // SendReceive(EManagerNotifyStatusChange, TIpcArgs(uri,aMask),aStatus); sl@0: //
sl@0: // Alternatively, the agent plugin can use the variables that are in scope at the time of the sl@0: // asynchronous SendReceive() call if it makes a synchronous SendReceive() call afterwards, sl@0: // within the same function scope, as illustrated below. The synchronous message can sl@0: // be a 'no operation' in the agent server. sl@0: // void CTestAgentManager::NotifyStatusChange(const TDesC& aURI, TEventMask aMask, TRequestStatus& aStatus) sl@0: // SendReceive(EManagerNotifyStatusChange, TIpcArgs(&aURI,aMask),aStatus); sl@0: // // this call doesn't have to be immediately after the asynchronous call, but within this function sl@0: // SendReceive(ENoOp,TIpcArgs(NULL)); sl@0: // The synchronous call causes the message queue to be flushed into the agent server before the thread returns from the sl@0: // function and unwinds the call stack. The intention is that the agent server will only complete the second (synchronous) sl@0: // message after receiving and doing initial processing of the first (asynchronous) message, which may include, for sl@0: // example, reading the uri descriptor. sl@0: // However, an obvious disadvantage of this pattern is that it incurs a second IPC call, and so may degrade performance.
sl@0: // Moreover, there are several caveats which must hold true in order for the pattern to work: sl@0: // 1. The kernel delivers messages in the order that they are sent (this is currently true).
sl@0: // 2. The agent server is guaranteed to finish processing the first message before completing the second message.
sl@0: // This requires understanding of the agent server implementation.
sl@0: // 3. After initial processing of the first (asynchronous) message the agent server does not need to sl@0: // access the memory supplied in the message again. This requires understanding of the agent server implementation.
sl@0: // 4. The synchronous call is a request that has no effect on the state of the agent server - a 'no operation' sl@0: // may or may not be possible. sl@0: // sl@0: // 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: // sl@0: // sl@0: // sl@0: sl@0: /** sl@0: @page CAFAsyncSendReceive Making an asynchronous SendReceive() call in an agent plugin sl@0: - @ref StoreLocalCopy sl@0: - @ref SyncSendReceive sl@0: @section StoreLocalCopy Storing a local heap copy of transient data sl@0: @code sl@0: @endcode sl@0: @section SyncSendReceive Following the asynchronous call with a synchronous call sl@0: @code sl@0: @endcode sl@0: */