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?
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();
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.
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).
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?
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?
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.
Forum posts: 1379
Triggering it youself is easy:
TRequestStatus* s = &iStatus;
User::RequestComplete(s, KErrNone);
SetActive();
And you will be RunL-ed.
didster
Forum posts: 75
-Slava
Forum posts: 1379
TRequestStatus* s = &iStatusInOtherThread;
RThread aOtherThread(idOfOtherThread);
aOtherThread.RequestComplete(s, KErrNone);
didster
Forum posts: 75
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
Forum posts: 723
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/
Forum posts: 135
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?
Forum posts: 723
tOtE
Gabor Torok
Software architect, Agil Eight (http://www.agileight.com/)
Blog: http://mobile-thoughts.blogspot.com/
Forum posts: 349
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:
Lets take the sockets (CSocketsEngine, CSocketsReader, CSocketsWriter, ...) example in the Series60Ex folder. Is then
User::RequestComplete(s, KErrNone);
SetActive();
called from within the RSocket class to notify CSocketsReader that data has arrived?
SetActive code:
{
__ASSERT_ALWAYS(!IsActive(), User::Panic(KPanicSocketsEngineRead, ESocketsBadState));
iSocket.RecvOneOrMore(iBuffer_tmp, 0, iStatus, iDummyLength);
SetActive();
}
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.