Active objects: How to trigger RunL programmatically

Login to reply to this topic.
Thu, 2004-11-11 11:46
Joined: 2004-09-06
Forum posts: 349
I have read quite a few pages on active objects, but I still don't know how the RunL method is triggered. I know that the RunL method IS triggered, but not HOW or if it I can programmatically trigger the function. Can I do that, and if I can - how?

Thu, 2004-11-11 13:08
Joined: 2004-07-28
Forum posts: 1379
Active objects: How to trigger RunL programmatically
RunL is triggered when the threads request semapore is set - and the active object is both active and has iStatus set to something other than KRequestPending.

Triggering it youself is easy:

TRequestStatus* s = &iStatus;
User::RequestComplete(s, KErrNone);
SetActive();

And you will be RunL-ed.

didster

Fri, 2004-11-12 23:26
Joined: 2004-09-25
Forum posts: 75
Active objects: How to trigger RunL programmatically
Keep in mind that it's a bit more complicated if you are doing it from another thread (not the one that owns the CActive object)

-Slava
Mon, 2004-11-15 09:09
Joined: 2004-07-28
Forum posts: 1379
Active objects: How to trigger RunL programmatically
Not that much more though:

TRequestStatus* s = &iStatusInOtherThread;
RThread aOtherThread(idOfOtherThread);
aOtherThread.RequestComplete(s, KErrNone);

didster

Mon, 2004-11-15 11:55
Joined: 2004-09-25
Forum posts: 75
Active objects: How to trigger RunL programmatically
Quote from: didster
Not that much more though:

TRequestStatus* s = &iStatusInOtherThread;
RThread aOtherThread(idOfOtherThread);
aOtherThread.RequestComplete(s, KErrNone);

That would work most of the time. However, there appears to be a race condition between the scheduler loop in the target thread and the thread that completes the request. Unless you take appropriate precausions, you will be getting either E32USER-CBase 42 ("already active") or E32USER-CBase 46 ("stray signal") panic from time to time. That's what makes it a bit more complicated.

-Slava
Mon, 2004-11-15 13:40
Forum Nokia Champion
Joined: 2003-10-01
Forum posts: 723
Active objects: How to trigger RunL programmatically
Quote from: didster
RunL is triggered when the threads request semapore is set - and the active object is both active and has iStatus set to something other than KRequestPending.

Triggering it youself is easy:

TRequestStatus* s = &iStatus;
User::RequestComplete(s, KErrNone);
SetActive();

And you will be RunL-ed.

Yes, and something additional...

The Active Scheduler (AS) keeps track of its Active Objects (AO) in a queue. Whenever the thread's request semaphore is set, the AS knows that an AO is ready to be RunL-ed. Then the AS starts checking its AOs to see, which one is ready to be called. If it finds the AO, then the AS calls AO::RunL. This RunL may leave, thus the AS TRAPs it: when RunL leaves, the AS will call AO::RunError to give the AO the chance to handle the error. If the AO still returns an error code, other than KErrNone, then CActiveScheduler panics, CBaActiveScheduler swallows this and does nothing. That is, different AS-es handle AOs' error differently, note that you may write your own AS.
When the AS did not find any AO to call (i.e. there was no AO ready), then it's a stray signal and result in a panic.
Note that after the AO handled the request (i.e. RunL returned), the AS sets the queue index back to zero. That is, next time the AS will start checking the AOs in the queue from the 0th item again. This may be dangerous, because if you have an AO, which is often ready to be called, then this AO may not let other AOs process their requests (e.g. your incoming socket (AO#1) always has at least one byte to be read, then your outgoing socket (AO#2) may not have the change to send anything).

Cheers,

tOtE

Gabor Torok
Software architect, Agil Eight (http://www.agileight.com/)
Blog: http://mobile-thoughts.blogspot.com/

Mon, 2004-11-15 14:38
Joined: 2003-05-08
Forum posts: 135
Active objects: How to trigger RunL programmatically
tote, just a small error in your explanation.

When the AS sorts the signals, it is sorted according to the priority assigned in the AO.  It then calls the AO with the highest priority.  Thus, to prevent a condition were your calls influence the UI, just set the priority low enough.

Chris

The box said 'Windows 98 or better'. Why is it not working on Linux?

Mon, 2004-11-15 15:36
Forum Nokia Champion
Joined: 2003-10-01
Forum posts: 723
Active objects: How to trigger RunL programmatically
Yes, you're right, I missed that. Thank you!

tOtE

Gabor Torok
Software architect, Agil Eight (http://www.agileight.com/)
Blog: http://mobile-thoughts.blogspot.com/

Tue, 2005-01-04 12:38
Joined: 2004-09-06
Forum posts: 349
Active objects: How to trigger RunL programmatically
Quote from: didster
RunL is triggered when the threads request semapore is set - and the active object is both active and has iStatus set to something other than KRequestPending.

Triggering it youself is easy:

TRequestStatus* s = &iStatus;
User::RequestComplete(s, KErrNone);
SetActive();

And you will be RunL-ed.


From the documentation on CActives's SetActive() function:

Quote
Indicates that the active object has issued a request and that it is now outstanding. Derived classes must call this function after issuing a request.

Lets take the sockets (CSocketsEngine, CSocketsReader, CSocketsWriter, ...) example in the Series60Ex folder. Is then

Quote
TRequestStatus* s = &iStatus;
User::RequestComplete(s, KErrNone);
SetActive();

called from within the RSocket class to notify CSocketsReader that data has arrived?

SetActive code:
Code:
void CSocketsReader::IssueRead()
{
   __ASSERT_ALWAYS(!IsActive(), User::Panic(KPanicSocketsEngineRead, ESocketsBadState));
iSocket.RecvOneOrMore(iBuffer_tmp, 0, iStatus, iDummyLength);
SetActive();
}
Tue, 2005-01-04 17:32
Guest (not verified)
Forum posts: 2018
Active objects: How to trigger RunL programmatically
No

Code like

TRequestStatus* s = &iStatus;
User::RequestComplete(s, KErrNone);
SetActive();

Is used when you want to trigger your active object's RunL yourself (if you are using an active object to break a long calculation into a series of steps for example).

If your active object is asking another class/function/server etc. for something then it is that other class/function that triggers the RunL for you. This will involve a call to User::RequestComplet() but the other class won't declare a TRequestStatus (as it will use the one you passed to it), and it won't call SetActive() as that's a function on CActive and you must call that yourself.

I don't have the example code you refer to but in

void CSocketsReader::IssueRead()
{
   __ASSERT_ALWAYS(!IsActive(), User::Panic(KPanicSocketsEngineRead, ESocketsBadState));
  iSocket.RecvOneOrMore(iBuffer_tmp, 0, iStatus, iDummyLength);
  SetActive();
}

iSocket will call User::RequestComplete when there is data.
  • Login to reply to this topic.