WaitForRequest with Timeout crashes

920 Views Asked by At

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

3

There are 3 best solutions below

6
On

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.

4
On

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.

2
On

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.