Author Topic: Polling task goes to UTASKER_STOP  (Read 10829 times)

Offline aaronlawrence

  • Jr. Member
  • **
  • Posts: 66
    • View Profile
Polling task goes to UTASKER_STOP
« on: February 08, 2010, 03:30:36 AM »
I have set my application to run in polling mode. It is declared like this:

Code: [Select]
{ "app", fnApplication,  MEDIUM_QUE,  (DELAY_LIMIT)((0.10 * SEC) + (PHY_POWERUP_DELAY)),
0, UTASKER_STOP}, // Application - start after Ethernet to be sure we have Ethernet handle

but the application sets itself to polling mode during init:

Code: [Select]
extern void fnApplication(TTASKTABLE *ptrTaskTable)
{
...
if ( g_AppState == STATE_INIT )
{
InitialiseApplication();
// set ourselves to uTasker "polling" mode, that is continuous
uTaskerStateChange( TASK_APPLICATION, UTASKER_GO );
return;

Is this correct? Can I combine the startup delay with polling mode like this?
It seemed to work fine but now for some reason, the task has stopped running and is waiting for an event. How can that happen?

Offline aaronlawrence

  • Jr. Member
  • **
  • Posts: 66
    • View Profile
Re: Polling task goes to UTASKER_STOP
« Reply #1 on: February 08, 2010, 05:57:54 AM »
Well, it seems OK to me. I'm now looking at the code that sets UTASKER_ACTIVATE without checking, e.g.
fnWriteInternal()
 uTaskerStateChange(NewWakeTask, UTASKER_ACTIVATE);
if the task being sent to is a polling one, won't this cause it to stop polling??
I'm uncomfortable with the way polling tasks work, it seems like it shouldn't be dependent on a single fragile state variable that is used all over the place. ...

Offline aaronlawrence

  • Jr. Member
  • **
  • Posts: 66
    • View Profile
Re: Polling task goes to UTASKER_STOP
« Reply #2 on: February 08, 2010, 06:10:21 AM »
OK, so now I see the problem:

Code: [Select]
extern void fnRtmkSystemTick( void )
{
...
                ptTaskTable->ucTaskState = UTASKER_ACTIVATE;             // release task

This code unconditionally sets UTASKER_ACTIVATE... even though it is a polling task... though I suppose the bigger question is why does it think the timer is active? I suppose that really startup delay cannot be combined with polling mode at the moment :(


Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3234
    • View Profile
    • uTasker
Re: Polling task goes to UTASKER_STOP
« Reply #3 on: February 08, 2010, 01:05:05 PM »
Hi Aaron

Consider the following:

1) A task that is configured with timer resources, an input queue and a start-up delay of 1s

2) As long as no other task sends a message to this task, or changes the task's state before its start-up delay has expired, it will run for the first time after 1s

extern void fnTask(TTASKTABLE *ptrTaskTable)
{
...
    if (iState != STATE_READY) {
        iState = STATE_READY;
        uTaskerMonoTimer( OWN_TASK, (DELAY_LIMIT)(1*SEC), POLL_TERMINATE );
        uTaskerStateChange( OWN_TASK, UTASKER_GO );
    }

    while ( fnRead( PortIDInternal, ucInputMessage, HEADER_LENGTH )) {   // check input queue
      switch ( ucInputMessage[ MSG_SOURCE_TASK ] ) {
        case TIMER_EVENT:
            break;
...
}



3) When the task is scheduled for the first time it sets itself to polling mode (changes its own task state from UTASKER_STOP - the state that it will enter with when scheduled due to a timer event - to UTASKER_GO). It also starts a monostable timer to inform it after 1s that the event POLL_TERMINATE has occurred.

During the next 1s (as long as no other task changes the state or posts a message to it) it will be continuously scheduled (polled).
After 1s the timer will fire and set the task state to UTASKER_STOP when the timer event POLL_TERMINATE is put to its input queue. This will cause the 1s of polling to automatically terminate.

If during the 1s delay a message is posted to the task it will also cause it to return to the UTASKER_STOP state.

This is a characteristic of the wake-up operation (as you noted, the transitional state used to ensure that a post by a timer, event or other message, is UTASKER_ACTIVATE, which is a state which causes the task to be unconditionally scheduled once).

This means that if the task should continue polling (or return to polling) the task must set itself back to this state when it receives a message (timer event, interrupt event, etc.).

In your particular case, if the task stops polling it is presumably due to the fact that it has received something in its input queue (possibly a timer event from your details). If you would like this task to continue polling you will need to set it to the polling state again.

There should however be no problems involved with combining start-up delays with a polling task.



Notes:
A) The task's own state can be read with ptrTaskTable->ucTaskState, however beware that this state can be changed by an interrupt routine posting an event to the task, which includes also a monostable timer firing (it may not be the same value after being read). The combination of a task used in polling mode which can receive such events should generally be avoided - if it is required the method to be used to switch it to polling mode would be:

uDisable_Interrupt();                                        // protect the change from interrupts
if (ptrTaskTable->ucTaskState == UTASKER_STOP) {// don't change unless stopped because the task will be re-scheduled
    ptTaskTable->ucTaskState = UTASKER_GO;
}
uEnable_Interrupt();


B) It is not recommended to set a task to polling mode from another task due to the fact that this other task is not aware of the polling task's message handling. A simple task without timers and input queue can however be set to polling mode from another task (and stopped later if required) since it will never be disturbed.

C) There is presently a potential problem with the routine uTaskerStateChange(), making the technique in A) necessary to avoid a potential loss of event when setting a task to polling mode when the task is presently scheduled to be woken by an event (in the UTASKER_ACTIVATE state). This would cause the state to be changed to UTASKER_GO and the waiting timer event not to be posted to the task. I don't think that this is a big problem since I have never in fact encountered a project using a task in polling mode which is also handling interrupt based events, but I am considering making a change to the uTaskerStateChange() routine to automatically protect against this. In the meantime technique A) does the same thing (assuming being called from its own task) and is also more efficient since it doesn't have to first search for its own task.

Does this help solve your problem?

Regards

Mark



Offline aaronlawrence

  • Jr. Member
  • **
  • Posts: 66
    • View Profile
Re: Polling task goes to UTASKER_STOP
« Reply #4 on: February 17, 2010, 08:49:57 AM »
Mark,

Thanks for the tips. I understand how to solve the problem, but I find this to be a big bunch of hacks for something that is really claimed to be supported out of the box (polling mode).

I think if you are going to claim there is a polling mode, it should be something you can enable or disable independently, and not depend on a large number of caveats.

As it stands I think polling mode is too fragile to rely on.

I might try and implement a proper polling mode myself in the uTasker loop ie. a separate flag in the task table. I'm kind of committed to this approach now and need something to rely on.

Offline aaronlawrence

  • Jr. Member
  • **
  • Posts: 66
    • View Profile
Re: Polling task goes to UTASKER_STOP
« Reply #5 on: February 19, 2010, 01:29:30 PM »
Oh well ... I did the check in fnApplication to set itself back to polling mode... hope I got all cases.
Thanks.

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3234
    • View Profile
    • uTasker
Re: Polling task goes to UTASKER_STOP
« Reply #6 on: February 19, 2010, 02:10:55 PM »
Hi Aaron

I realise that this is not the most comfortable solution but it should work well.

The polling mode was originally intended for tasks which don't have queues but over the time it has been used more and more in combination with more flexible tasks and that is where the potential danger has been recognised - I don't actually know of any cases of problems though; the danger is restricted to configurations which are probably very rare.

However I don't actually see why it shouldn't be possible to allow polling mode, timers and interrupt event to operate together without needing to resort to workarounds. Shortly I will be actively working on a project that can benefit from this and so I will also be working on analysing the situation plus possibly making some adjustments to improve it.

At the same time is is important to point out that the analysis is very important since any modification to the scheduler is fundamental to all existing uses and so backward compatibility and the avoidance of risk is critical in this area.

I will inform as soon as details are available ;-)

Regards

Mark