Confussion over Active Object and User::WaitForRequest

Login to reply to this topic.
Tue, 2005-01-04 15:46
Joined: 2005-01-03
Forum posts: 28
Hi,
   could some one tell me what is the difference between SetActive and calling User::WaitForRequest in a code given below. This is basically code for sending files via bluetooth. I want to know if SetActive will be required or not when I am doing User::WaitForRequest. while using SetActive can I put the last line i.e setting the variable to Null.

Code:
{...
   TRequestStatus status( KErrNone );
   iClient->Put(*iCurrObject, status);
   //SetActive();
   User::WaitForRequest(iStatus);
   iCurrObject=NULL;
..}

My requirement is the one that User::WaitForRequest does, i.e wait till sending is done and then go to next line.

Tue, 2005-01-04 17:20
Guest (not verified)
Forum posts: 2018
Re: Confussion over Active Object and User::WaitForRequest
If you are using an active object you MUST NOT call User::WaitForRequest() and MUST call SetActive().

If the code you have shown below is a function inside an active object then it is very wrong as you are also declaring a TRequestStatus.
Tue, 2005-01-04 17:41
Joined: 2004-12-03
Forum posts: 276
Confussion over Active Object and User::WaitForRequest
As far as I know whenever you are using active objects and you are requesting for any service from a service provider you have to set the state of the Active Object as Active which is done by SetActive()...

So if you want to wait till the request is finished then you use the function WaitForRequest().....

Dennis

Today is a gift by GOD, that's why it is called the present.

Tue, 2005-01-04 17:50
Joined: 2004-12-03
Forum posts: 276
Confussion over Active Object and User::WaitForRequest
Active objects are managed and controled by an Active Scheduler... So first thing you do in your code is to register your active objects with the Active Scheduler using the function CActiveScheduler::Add()....

Next thing you want to avail a functionality of a service provider, in your case the iClient [iClient->Put(*iCurrObject, status); ]. After requesting you have to tell the Active Scheduler that you are listening for some event.... you do this by changing your state to active by SetActive() function.....

After this you can do two things
* Do your usual stuff (Normal Scenario).... whenever your request is fulfilled you will be notified (RunL)

* You can wait till the request is finished..... using User::WaitForRequest()

Dennis

Today is a gift by GOD, that's why it is called the present.

Tue, 2005-01-04 18:06
Joined: 2005-01-03
Forum posts: 28
Confussion over Active Object and User::WaitForRequest
Thanks for the quick replies. I have much clear idea of things now. I think what I need to do is to change the code to remove this active schedular thing and make everything use User::WaitForRequest

Quote
After this you can do two things
* Do your usual stuff (Normal Scenario).... whenever your request is fulfilled you will be notified (RunL)

* You can wait till the request is finished..... using User::WaitForRequest()

As you mention here denis, when I try the second approach i.e calling the following code.

Code:
void CObjectExchangeClient::SendMessageL()
   {
   if (iState != EWaitingToSend)
       {
       User::Leave(KErrDisconnected);
       }
   /*
   else if (IsActive())
       {
       User::Leave(KErrInUse);
       }
   TRequestStatus status( KErrNone );
   iClient->Put(*iCurrObject, status);
   SetActive();
   User::WaitForRequest(status);
   iCurrObject=NULL;
   }

The code program hangs. Otherwise when I comment the SetActive(), then also the program hangs. Correct me if I am wrong but from all the discussion here and the codes performance I can only understand that if I extend CActive then I cannot use WaitForRequest.
Tue, 2005-01-04 18:51
Anonymous (not verified)
Forum posts: 2018
Confussion over Active Object and User::WaitForRequest
>> * You can wait till the request is finished..... using User::WaitForRequest()

No that is totally wrong. You do not call User::WaitForRequest in an active object. That is done for you by the active scheduler.

If CObjectExchangeClient is an active object you must get rid of the TRequestStatus status( KErrNone ) as it already has one defined and you must get rid of the User::WaitForRequest.
Tue, 2005-01-04 18:53
Anonymous (not verified)
Forum posts: 2018
Confussion over Active Object and User::WaitForRequest
Quote from: Anonymous
>> * You can wait till the request is finished..... using User::WaitForRequest()

No that is totally wrong. You do not call User::WaitForRequest in an active object. That is done for you by the active scheduler.

If you do this there's absolutley no point in using an active object.
Tue, 2005-01-04 18:59
Joined: 2004-12-03
Forum posts: 276
Confussion over Active Object and User::WaitForRequest
As I already said... I am not quite sure but the document says.....

Quote
static void WaitForRequest(TRequestStatus& aStatus);
Description
Waits for a specific asynchronous request to complete. The current thread waits on its request semaphore.

So it says the current thread waits ..... Moreover Active Scheduler uses WaitForAnyRequest not WaitForRequest....

Please correct me if I am wrong

Dennis

Today is a gift by GOD, that's why it is called the present.

Tue, 2005-01-04 19:09
Joined: 2004-07-10
Forum posts: 364
Confussion over Active Object and User::WaitForRequest
Yes the active scheduler uses WaitForAnyRequest but if you are using an active object you should not put any calls in to this nor to WaitForRequest in your active object code. Nor should you be declaring any additional TRequestStatus.

Varhdman, I presume CObjectExchangeClient must be an active object as you have a SetActive() call in there.
You should not be declaring that TRequestStatus and you should not be calling User::WaitForRequest.

You should pass the active object's iStatus to iClient->Put() and call SetActive() and your active object's RunL() should then get called.
If you don't want RunL to get called there's no point in CobjectExchangeClient being an active object.

Declaring your own TRequestStatus and calling WaitForRequest() would be ok if CObjectExchangeClient wasn't an active object but then your code could lock up, hence that's the advantage of using active objects.


User::WaitForRequest() and User::WaitForAnyRequest() are used when you are not using active objects.
Tue, 2005-01-04 19:15
Joined: 2005-01-03
Forum posts: 28
Confussion over Active Object and User::WaitForRequest
Hi Dennis,

After reading a big pdf from symbian.com regarding Active Objects and Schedulars I came to realize that Guest is saying correct.
What actually happens is that when SetActive is called the IStatus variable that is internal to Active Object is set to KRequestPending and then after doing the processing the iStatus variable is changed accordingly and RunL is invoked and soon..

Hi Guest, thanks for all that information, kindly give me some advice on whether this is workable, I change the class and not derive it using Active Object and then after issuing a Put i simply call User::WaifForRequest as the question of calling setActive doesn't arise.

It would be great if you can see the code once and tell me if that will work.

Code:
/* Copyright (c) 2002, Nokia Mobile Phones. All rights reserved */
#include<aknnotewrappers.h>
#include "ObjectExchangeClient.h"
#include "ObjectExchangeServiceSearcher.h"
#include "BTObjectExchange.pan"

CObjectExchangeClient* CObjectExchangeClient::NewL()
   {
   CObjectExchangeClient* self = NewLC();
   CleanupStack::Pop(self);
   return self;
   }

CObjectExchangeClient* CObjectExchangeClient::NewLC()
{
   CObjectExchangeClient* self = new (ELeave) CObjectExchangeClient();
   CleanupStack::PushL(self);
   self->ConstructL();
   return self;
   }

CObjectExchangeClient::CObjectExchangeClient()
: CActive(CActive::EPriorityStandard),
 iState(EWaitingToGetDevice),
 filename()
   {
   CActiveScheduler::Add(this);
   }

void CObjectExchangeClient::ConstructL()
   {
   iServiceSearcher = CObjectExchangeServiceSearcher::NewL();
   }

void CObjectExchangeClient::SetFileName(const TDesC& fullFileName,const TDesC& filename1){
     iCurrObject =  CObexFileObject::NewL();
    iCurrObject->SetNameL(_L("HelloWorld.bmp"));
    filename.Set(fullFileName);
   }

void CObjectExchangeClient::MakePacket(){
    iCurrObject->InitFromFileL(filename);
}

CObjectExchangeClient::~CObjectExchangeClient()
   {
   Cancel();

   if (iState != EWaitingToGetDevice && iClient)
       {
       iClient->Abort();
       }

   delete iCurrObject;
   iCurrObject = NULL;

   delete iServiceSearcher;
   iServiceSearcher = NULL;

   delete iClient;
   iClient = NULL;
   }

void CObjectExchangeClient::DoCancel()
   {
   }


void CObjectExchangeClient::RunL()
   {
   if (iStatus != KErrNone)
       {
       switch (iState)
           {
           case EGettingDevice:
               if (iStatus = KErrCancel)
                   {
                   }
               break;
           case EGettingService:
           case EGettingConnection:
           case EDisconnecting:
               iState = EWaitingToGetDevice;
               break;
           case EWaitingToSend:
               iState = EWaitingToGetDevice;
               break;
           default:
               Panic(EBTObjectExchangeUnexpectedLogicState);
               break;
           }
       }
   else
       {
       switch (iState)
           {
           case EGettingDevice:
               // found a device now search for a suitable service
             
               iState = EGettingService;
               iStatus = KRequestPending;
// this means that the RunL can not be called until
     // this program does something to iStatus
               iServiceSearcher->FindServiceL(iStatus);
               SetActive();
               break;

           case EGettingService:
               iState = EGettingConnection;
               ConnectToServerL();
               break;

           case EGettingConnection:
               iState = EWaitingToSend;
               break;

           case EWaitingToSend:
               break;

           case EDisconnecting:
               iState = EWaitingToGetDevice;
               break;

           default:
               Panic(EBTObjectExchangeSdpRecordDelete);
               break;
           };
       }
   }


void CObjectExchangeClient::ConnectL()
   {
   if (iState == EWaitingToGetDevice && !IsActive())
       {
       iServiceSearcher->SelectDeviceByDiscoveryL(iStatus);
       iState = EGettingDevice;
       SetActive();
       }
   else
       {
       User::Leave(KErrInUse);
       }
   }

void CObjectExchangeClient::ConnectToServerL()
   {
   TObexBluetoothProtocolInfo protocolInfo;

   protocolInfo.iTransport.Copy(KServerTransportName);
   protocolInfo.iAddr.SetBTAddr(iServiceSearcher->BTDevAddr());
   protocolInfo.iAddr.SetPort(iServiceSearcher->Port());

   if (iClient)
       {
       delete iClient;
       iClient = NULL;
       }
   iClient = CObexClient::NewL(protocolInfo);

   iClient->Connect(iStatus);
   SetActive();
   }

void CObjectExchangeClient::SendMessageL()
   {
   if (iState != EWaitingToSend)
       {
       User::Leave(KErrDisconnected);
       }
   /*
   else if (IsActive())
       {
       User::Leave(KErrInUse);
       }
     */
   iClient->Put(*iCurrObject, status);
   SetActive();
   iCurrObject=NULL;
   }

void CObjectExchangeClient::StopL()
   {
   if (iClient && iClient->IsConnected())
       {
       iClient->Abort();
       iState = EWaitingToGetDevice;
       }
   }

void CObjectExchangeClient::DisconnectL()
   {
   if (iState == EWaitingToGetDevice)
       {
       return;
       }
   if (iState == EWaitingToSend)
       {
       //iLog.LogL(_L("Disconnecting"));
       iState = EDisconnecting;
       iClient->Disconnect(iStatus);
       SetActive();
       }
   else
       {
       User::Leave(KErrInUse);
       }
   }

TBool CObjectExchangeClient::IsBusy()
   {
   return IsActive();
   }

TBool CObjectExchangeClient::IsConnected()
   {
   return iState == EWaitingToSend;
   }
Tue, 2005-01-04 19:22
Joined: 2004-12-03
Forum posts: 276
Confussion over Active Object and User::WaitForRequest
Hi mungbeans and Guest,

I think you are right..... I was slightly messed with the concept..... thanks for clearing the dark area.....

Dennis

Today is a gift by GOD, that's why it is called the present.

Tue, 2005-01-04 20:02
Joined: 2005-01-03
Forum posts: 28
Confussion over Active Object and User::WaitForRequest
hi mungbeans

Thanks for the information. What I needed was to implement a function whose call returns only when the sending stuff(Put) which is asynchronus is completed, with Active Objects that is not AFAIK easy to do because all the function returns and then RunL get invoked later etc. So I will make a non Active Object class for my purpose and use WaitForRequest at those places where setActive was being called, will that work?
Tue, 2005-01-04 23:11
Anonymous (not verified)
Forum posts: 2018
Confussion over Active Object and User::WaitForRequest
Hi, yes that would work but bear in mind that if WaitForRequest takes a long time to be signalled your code, depending upon how it is architected, could hang i.e. if there's a UI it could be unresponsive.

There are ways of making asynchronous calls appear synchronous but more complex than simply using WaitForRequest.
Tue, 2005-01-04 23:12
Joined: 2004-07-10
Forum posts: 364
Confussion over Active Object and User::WaitForRequest
P.S. Guest above==mungbeans
Wed, 2005-01-05 07:28
Joined: 2005-01-03
Forum posts: 28
problem continues...
hi mungbeans

As suggest yesterday, I converted the class to a non active class replacing all the SetActive() with something like
Code:
TRequestStatus temp(KErrNone);
   iClient->Connect(temp);//asynchronus calls
   User::WaitForRequest(temp);
   if(temp.Int() != KErrNone)
          User::Leave(temp.Int());

I am not able to understand where the error comes up, as I can't debug bluetooth application on pc due to lack of hardware, but on phone I get the error
App Closed
CamTimerBT
where CamTimerBT is my application name. I have no idea how to remove this error and where it comes from, can you give some idea as to what might cause such kind of problems.
Here is the main code segment that on invokation causes all the problem

Code:
void CObjectExchangeClient::ConnectL()
   {
   if (iState == EWaitingToGetDevice )
       {

       iStatus=TRequestStatus(KErrNone);

       iServiceSearcher->SelectDeviceByDiscoveryL(iStatus);
       iState = EGettingDevice;
       User::WaitForRequest(iStatus);
       iState=EWaitingToSend;
       if(iStatus.Int() != KErrNone)
          User::Leave(iStatus.Int());

       iStatus=TRequestStatus(KErrNone);
       iServiceSearcher->FindServiceL(iStatus);
       User::WaitForRequest(iStatus);
        iState = EGettingConnection;
         if(iStatus.Int() != KErrNone)
          User::Leave(iStatus.Int());
   //     return;
        ConnectToServerL();
        iState = EWaitingToSend;
         if(iStatus.Int() != KErrNone)
          User::Leave(iStatus.Int());

       }
   else
       {
       User::Leave(KErrInUse);
       }
   }

void CObjectExchangeClient::ConnectToServerL()
   {
   TObexBluetoothProtocolInfo protocolInfo;

   protocolInfo.iTransport.Copy(KServerTransportName);
   protocolInfo.iAddr.SetBTAddr(iServiceSearcher->BTDevAddr());
   protocolInfo.iAddr.SetPort(iServiceSearcher->Port());

   if (iClient)
       {
       delete iClient;
       iClient = NULL;
       }
   iClient = CObexClient::NewL(protocolInfo);
   TRequestStatus temp(KErrNone);
   //iStatus=TRequestStatus(KErrNone);
   iClient->Connect(temp);
   User::WaitForRequest(temp);
      if(temp.Int() != KErrNone)
          User::Leave(temp.Int());
   CAknInformationNote* informationNote = new (ELeave) CAknInformationNote;
   informationNote->ExecuteLD(KTEMP);
  }

problem is in ConnectToServerL() function most probably, the Popupdoesn't pop if put at current position but pops if put b4 if (iClient).
Sun, 2005-01-09 23:02
Joined: 2004-07-10
Forum posts: 364
Re: problem continues...
Hi

The code snippet as shown looks ok in isolation but when using asynchronous functionality one can't always be sure if its ok or not without being aware of the bigger design, similarly its difficult to comment on if an active or non active object should be used.

You could put some debugging statments into your code in an attempt to identify where any problem might be originating from. If you have codewarrior there is also the possiblity to debug it on hardware.
  • Login to reply to this topic.