Passing Stack Or Temporary Variables to an Asynchronous Service

This document describes porting problems related to asynchronous services.

The client-server framework used on Symbian platform assumes that a client thread stops running after passing an asynchronous request to a server and does not resume until the server has finished handling the request. In SMP there is no guarantee that this will happen, and consequently there is an impact on the way in which you pass variables between client and server threads.

Passing variables to an asynchronous service in an SMP safe way

On a single core system it is common for client code to assume that the client thread will be pre-empted by the server thread since the server thread has higher priority. On SMP this is not so, as the two threads may be running on separate cores. It is therefore quite possible for a client thread to continue running while an asynchronous request is being serviced and might unwind its own stack before the server has written to that stack in response to the request.

One way round this problem is to force the client thread to wait until the request has been serviced, but then the request is no longer asynchronous.

On SMP a client thread should not pass stack variables to a server thread when making an asynchronous request. Instead, the data should be held in class members of the client class, since member variables are stored on the heap. This principle applies to all temporary variables in a client thread.

The following code examples illustrate the problem.

Example 1:

108 inline TInt RWlanLogicalChannel::ManagementCommand(
109     const TDesC8& aInBuffer, 
110     TDes8* aOutBuffer, 
111     TRequestStatus* aStatus)
112     {
…
114	SOidMsgStrorage* pdu( new SOidMsgStrorage );
116	SOutputBuffer output = { NULL, 0 }; 
…
141             // Execute command asynchronously
142             DoRequest(EWlanCommand, *aStatus, pdu, 
143                 (output.iData ? &output : NULL) 
144                 );
…
146	ret = KErrNone;
...
149         // always remember to deallocate
150         
151         }
154     }
…

Example 2:

108 inline TInt RWlanLogicalChannel::ManagementCommand(
109     const TDesC8& aInBuffer, 
110     TDes8* aOutBuffer, 
111     TRequestStatus* aStatus)
112     {
…
147	iAsyncOidCommandMsg = *pdu;
148	iAsyncOidCommandOutput = output;
149       DoRequest(
150           EWlanCommand, 
151           *aStatus, 
152           &iAsyncOidCommandMsg, 
153           (output.iData ? &iAsyncOidCommandOutput : NULL) );
146	ret = KErrNone;
...
149         // always remember to deallocate
150         
151         }
154     }
	
…

In the first example, the variables pdu and output are stack variables declared within the function ManagementCommand() and there is a danger that the stack will have been unwound before the server tries to write to those variables. In the second example, pdu and output have the same function as before but are class members of RWlanLogicalChannel. They are therefore stored on the heap and will persist until the request is completed regardless of the state of the stack.

Related concepts
SMP Developer Tips