Confussion over Active Object and User::WaitForRequest
| Tue, 2005-01-04 15:46 | |
|
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. |
|






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.
Forum posts: 276
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.
Forum posts: 276
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.
Forum posts: 28
* 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.
{
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.
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.
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.
Forum posts: 276
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.
Forum posts: 364
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.
Forum posts: 28
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.
#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;
}
Forum posts: 276
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.
Forum posts: 28
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?
There are ways of making asynchronous calls appear synchronous but more complex than simply using WaitForRequest.
Forum posts: 364
Forum posts: 28
As suggest yesterday, I converted the class to a non active class replacing all the SetActive() with something like
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
{
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).
Forum posts: 364
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.