S60 Open C
Open C Tips and Tricks

Open C Tips and Tricks

Table of Contents

Calling Symbian asynchronous APIs in an Open C application

 


Calling Symbian asynchronous APIs in an Open C application

When porting an Open C or C++ application on top of Symbian C++ or Open C, the developer may need to make use of Symbian asynchronous APIs. If asynchronous APIs are made use of in an Open C application, the application needs to wait for the completion of the asynchronous API. This can be done in two ways:

  • Wait for the asynchronous request to complete. This can be achieved by making use of User::WaitForRequest(iStatus); where iStatus is the TRequestSemaphore used by the asynchronous API.
  • Call the asynchronous API in an active object, run an active scheduler, and let the active scheduler wait for the asynchronous operation to complete.

The problems with these approaches are:

The open source application would get blocked till the asynchronous operation completes in the first approach. In the second approach, the active scheduler would be running in a wait loop, checking for asynchronous API completion. Even in this case, the Open C application would not be able to perform any other operations outside the active scheduler framework.

The asynchronous APIs could be called in a separate process, and the Open C application could communicate with this process by making use of the client/server framework of Symbian or by making use of other Open C IPC mechanisms. However, making a different process for calling asynchronous APIs might pose a performance hit.

One of the ways to solve these problems is to call the asynchronous APIs in a separate thread.

An example class which implements the same is given below:

class CActiveThread:  public CActive
{
public: 

    enum TState
    {
    EInitialized = 0x0,
    EDoFirst = 0x1,
    EDoSecond = 0x2,
    EDoThird = 0x4,
    ECompleted = 0x8
    };
 
     // thread startup routine
    static int StartMyThread(void* thisptr);
    // leaving variant of the thread startup routine
    static int StartMyThreadL(void* thisptr);
    // Helper function to start the thread
    void StartThread();    
    // Do Function
    void DoFunction(TState aState );      
              
    // CActive Functions
    void RunL();
    void DoCancel();
    		
    // Constructors and destructor      
    static CActiveThread* NewL(); 
    CActiveThread ();
    void ConstructL();
    ~ CActiveThread();      
           
private:    
  
    // Active Scheduler
    CActiveSchedulerWait *iWait;          
    // Command/State
    TInt iState;        	    
    TRequestStatus iThreadExitWait;	    
    // my thread handle
    RThread iActiveThread;    	    
    sem_t iSem;
};

The StartThread member function of CActiveThread creates the thread which runs the active scheduler. StartMyThread is the entry point function for the new thread that starts an active scheduler and sets up the clean up stack. To call an asynchronous function, DoFunction needs to be called with the corresponding state. The parent thread signals the child thread using the child thread’s thread request semaphore. When the thread request semaphore is signaled, the child thread wakes up, calls the corresponding asynchronous API in RunL based on the iState and again goes back to the active scheduler wait loop.

To synchronize between the parent thread and the child thread, a semaphore can be used as shown in the following code snippet.

CActiveThread* CActiveThread::NewL()
{
CActiveThread* self = new (ELeave) CActiveThread();
self->ConstructL();
return self;
}
     
CActiveThread::CActiveThread():CActive(EPriorityStandard),iState(EInitialized)
{       
}

void CActiveThread::ConstructL()
{  
// semaphore for Synching
sem_init(&iSem,0,0);  
}
     
void CActiveThread::StartThread()
{       
//Create Thread 
TInt err = iActiveThread.Create( KThreadName(),&CActiveThread::StartMyThread,
     KDefaultStackSize, NULL, (TAny*)this );         
iActiveThread.Logon( iThreadExitWait );
iActiveThread.Resume();
sem_wait( &iSem );    
}
 
int CActiveThread::StartMyThread( void* ptr )
{
CActiveScheduler* scheduler = new (ELeave) CActiveScheduler();
CActiveScheduler::Install(scheduler);     
CTrapCleanup* pCleanup = CTrapCleanup::New();
TRAPD(err, StartMyThreadL(ptr));        
}
 
int CActiveThread::StartMyThreadL( void* ptr )
{        
CActiveThread *thisptr = (CActiveThread*)ptr;    
CActiveScheduler::Add(thisptr);
thisptr->iWait = new (ELeave) CActiveSchedulerWait();	    
thisptr->iState = EInitialized;
thisptr->iStatus = KRequestPending;
thisptr->SetActive();
sem_post( &(thisptr->iSem ));    
thisptr->iWait->Start();   
}

 void CActiveThread::RunL()
 {
 switch ( iState )
     {
     case  EDoFirst:
     // Call 1st asynchronous function
     break;
     
     case EDoSecond:
     // Call 2nd asynchronous function
     break;
      
     case EDoThird:
     // Call 3rd asynchronous function
     break;
     
     case ECompleted:
     iWait->AsyncStop();    
     return;			
     }
	
iStatus = KRequestPending;
SetActive();
// wake up the waiting thread
sem_post( &iSem );
}

void CActiveThread::DoCancel()
{    
}

void CActiveThread::DoFunction(TState aState )
{
iState = aState;
TRequestStatus *reqPtr = &iStatus	;
iActiveThread.RequestComplete( reqPtr, KErrNone );
sem_wait(&iSem);
}    
 
CActiveThread::~CActiveThread()
{  
if ( iState != EInitialized )
    {
    iState = ECompleted;
    TRequestStatus *reqPtr = &iStatus	
    iActiveThread.RequestComplete( reqPtr, KErrNone ); 
    User::WaitForRequest( iThreadExitWait);
    }    
sem_destroy(&iSem);
}

Using CActiveThread:

iMyAsyncIf = CActiveThread::NewL();   
iMyAsyncIf->StartThread();    
iMyAsyncIf->DoFunction(EDoFirst);

Limitations:

In this approach, only the parent thread communicates with the child thread. There is no way for the child thread to communicate with the parent thread.

Give feedback of this section


©Nokia 2007

Back to top


This material, including documentation and any related computer programs, is protected by copyright controlled by Nokia. All rights are reserved. Copying, including reproducing, storing, adapting or translating, any or all of this material requires the prior written consent of Nokia. This material also contains confidential information, which may not be disclosed to others without the prior written consent of Nokia.

Nokia is a registered trademark of Nokia Corporation. S60 and logo is a trademark of Nokia Corporation. Java and all Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. Other company and product names mentioned herein may be trademarks or tradenames of their respective owners.