views:

367

answers:

3

Hi,

EDIT: I have now edited my code a bit to have a rough idea of "all" the code. Maybe this might be helpful to identify the problem ;)

I have integrated the following simple code fragement which either cancels the timer if data is read from the TCP socket or otherwise it cancels the data read from the socket

// file tcp.cpp
void CheckTCPSocket()
{
TRequestStatus iStatus;
TSockXfrLength len;

int timeout = 1000;
RTimer timer;
TRequestStatus timerstatus;

TPtr8 buff;
iSocket.RecvOneOrMore( buff, 0, iStatus, len );

timer.CreateLocal();

timer.After(timerstatus, timeout);
// Wait for two requests – if timer completes first, we have a
// timeout.
User::WaitForRequest(iStatus, timerstatus);

if(timerstatus.Int() != KRequestPending)
{
  iSocket.CancelRead();
}
else
{
  timer.Cancel();
}
timer.Close();
}

// file main.cpp
void TestActiveObject::RunL()
{
  TUint Data;
  MQueue.ReceiveBlocking(Data);
  CheckTCPSocket();
  SetActive();
}

This part is executed within active Object and since integrating the code piece above I always get the kernel panic: E32User-CBase 46: This panic is raised by an active scheduler, a CActiveScheduler. It is caused by a stray signal.

I never had any problem with my code until now this piece of code is executed; code executes fine as data is read from the socket and then the timer is canceled and closed. I do not understand how the timer object has here any influence on the AO.

Would be great if someone could point me to the right direction.

Thanks

+1  A: 

This could be a problem with another active object completing (not one of these two), or SetActive() not being called. See Forum Nokia. Hard to say without seeing all your code!

BTW User::WaitForRequest() is nearly always a bad idea. See why here.

KevinD
Thanks for your answer. The thing is, I am having a request/response protocol to follow which means that I need to wait for the incoming response before I can preced with the next request; hence the WaitForRequest() inclusion!
You don't need WaitForRequest to achieve that. An Active Object state machine will surely do the trick. WaitForRequest should be avoided at all costs (in 10 years of Symbian OS programming I've never had to use it :-)
KevinD
Chees Kevin, but I am writing code for testing purposes, so it must not be absolutley efficient. It is just important getting something to run quickly and hopefully there is a quick fix for my problem. Do not wanna rewrite the whole implementation ;)
KevinD
Also, you can potentially be calling SetActive() without a request pending (if the timer completes, you cancel the socket read, yet still call SetActive()) - this will cause a CBase 46 panic.Where do you see the CBase 46 - in the WaitForRequest() call, or SetActive()
KevinD
The waitforRequest works fine, i can cancel the timer but when i returns then to the AO it crashes then. Might this be a helpful behaviour to narrow down the problem?
A: 

Never mix active objects and User::WaitForRequest().

(Well, almost never. When you know exactly what you are doing it can be ok, but the code you posted suggests you still have some learning to do.)

You get the stray signal panic when the thread request semaphore is signalled with RThread::RequestComplete() by the asynchronous service provider and the active scheduler that was waiting on the semaphore with User::WaitForAnyRequest() tries to look for an active object that was completed so that its RunL() could be called, but cannot find any in its list of active objects.

In this case you have two ongoing requests, neither of which is controlled by the active scheduler (for example, not using CActive::iStatus as the TRequestStatus; issuing SetActive() on an object where CActive::iStatus is not involved in an async request is another error in your code but not the reason for stray signal). You wait for either one of them to complete with WaitForRequest() but don't wait for the other to complete at all. The other request's completion signal will go to the active scheduler's WaitForAnyRequest(), resulting in stray signal. If you cancel a request, you will still need to wait on the thread request semaphore.

The best solution is to make the timeout timer an active object as well. Have a look at the CTimer class.

Another solution is just to add another WaitForRequest on the request not yet completed.

laalto
The weird thing is that I never had a problem when I just had the User::WaitForRequest(iStatus) statement in the code and left out the timer. Now, as I am using RTimer and User::WaitForRequest(iStatus, timerstatus) I suddenly get this problem. Shouldn't I had this problem already in the first place, or does this only occur when I am having multiple requests pending?
I've updated the answer to further clarify your issue.
laalto
Thanks laalto and yes I agree I am far from being an expert in Symbian! Alright, this behaviour surprises me I have to admit. I thought when I cancel a request that I do not need to consider it at later stages. In other words, I need to add another WaitForRequest in the path where the timer is canceled, is that correct? In doing so, I make sure that I handle the RequestComplete() of the Timer and I do not get the error in the Active Object.
Basically, instead of timer.cancel in my code I wait for the request complete with User::WaitForRequest(timerstatus) as the timeout signal always occurs and needs to be handled. The story for the data read from the socket is different as it can be that here I NEVER get any data back. Here i cancel then just the request as in the original code
Yes, if you have n requests, you'll get n completions that satisfy n `WaitForRequest`s. Requests can either complete normally or by cancellation. Practically it's easiest to learn to use active objects properly and let the active scheduler do the waiting for you.
laalto
A: 

You are calling TestActiveObject::SetActive() but there is no call to any method that sets TestActiveObject::iStatus to KRequestPending. This will create the stray signal panic.

The only iStatus variable in your code is local to the CheckTCPSocket() method.

QuickRecipesOnSymbianOS
This applies only to debug builds of euser, e.g. winscw udeb emulator, not target devices running release euser.
laalto
(Also assuming that the object has been Add()ed to the active scheduler.)
laalto