[freertos - Open Discussion and Support] Bug or strange behaviour in TaskResume ?

112 views
Skip to first unread message

SourceForge.net

unread,
Nov 18, 2011, 5:48:02 AM11/18/11
to SourceForge.net

Read and respond to this message at:
https://sourceforge.net/projects/freertos/forums/forum/382005/topic/4826021
By: markuskrug

Hello,

First my Example Application. Both Tasks have the same priority. No other Tasks
are existing. The Task vTestTask1 gets started by the scheduler first. 'a' is
a global variable just to have a dummy job for the tasks.

static portTASK_FUNCTION( vTest1Task, pvParameters )
{
/* The parameters are not used. */
( void ) pvParameters;
for(;;) {

vTaskSuspend(NULL);
a++;
vTaskResume(xTest2_TaskHandle);
vTaskSuspend(NULL);
}
}

static portTASK_FUNCTION( vTest2Task, pvParameters )
{
/* The parameters are not used. */
( void ) pvParameters;

for(;;) {
vTaskResume(xTest1_TaskHandle);
vTaskSuspend(NULL);
a++;
}
}

The idea ist that the two tasks suspend themself just after resuming the other.
Therefore they should run somhow in a ping-pong matter and increment a. However
the application does not behave like this. I discovered that the call of
TaskResume(..) does not increase the value of xSuspendedTaskList.uxNumberOfItems.
Therefore after the second call of TaskSuspend(NULL) the number of suspended
Tasks is 2. Additionally does the value of pxReadyTasksLists[1].uxNumberOfItems
decrease by each call of TaskSuspend, but does not increase by calling
TaskResume().
Therefore my application ends in the idle Task very soon.
Can anyone explain my problem ? I read in this forum that there have been some
bugs with TaskSuspend in the past. Is this another one ?

Best Regards
Markus


_____________________________________________________________________________________
You are receiving this email because you elected to monitor this topic or entire forum.
To stop monitoring this topic visit:
https://sourceforge.net/projects/freertos/forums/forum/382005/topic/4826021/unmonitor
To stop monitoring this forum visit:
https://sourceforge.net/projects/freertos/forums/forum/382005/unmonitor

SourceForge.net

unread,
Nov 18, 2011, 6:10:27 AM11/18/11
to SourceForge.net

Read and respond to this message at:
https://sourceforge.net/projects/freertos/forums/forum/382005/topic/4826021
By: markuskrug

An additional information. I just upgraded to v7.0.2 without any change to my
described behaviour.

SourceForge.net

unread,
Nov 18, 2011, 6:11:41 AM11/18/11
to SourceForge.net
By: richardbarry

Scenario 1:

1) vTest2Task runs first, attempts to unsuspend vTest1Task (which is not suspended),
then suspends itself.
2) vTest1Task runs for the first time. It suspends itself.

Now both task are suspended.


Scenario 2:

1) vTest1Task runs first, and suspends itself.
2) vTest2Task runs. It resumes task 1.
3) vTest1Task runs and increments a, before suspending itself again.
4) vTest2Task runs again, the last line it executed was resuming vTestTask1,
the next line it executes it suspends itself.

Now both tasks are suspended.

There are probably more complex scenarios where this deadlock can occur too,
where preemptive context switches happen at various times, but basically I think
you have a test where the correct behaviour would be for both tasks to end up
in the suspended state.

Regards.

SourceForge.net

unread,
Nov 18, 2011, 6:32:06 AM11/18/11
to SourceForge.net
By: markuskrug

Hi Richard,

thanks for you quick response. The Scenario 2 is true due to the calling order
of TaskCreaste.
Step 1 and Step 2 I can confirm. However Step 3 is different. vTest1Task does
never start again although it is resumed (that's why I pointed out the
the xSuspendedTaskList.uxNumberOfItems is not changed after calling
TaskResume(task1)). I double checked this by looking at the varialble a that
is not incremented at all. The variable a is a global static variable. So it
is really allocated by the compiler in the memory. Step 4 I can obvious confirm.

Best Regards
Markus

SourceForge.net

unread,
Nov 18, 2011, 6:59:05 AM11/18/11
to SourceForge.net
By: richardbarry

[quote]However Step 3 is different. vTest1Task does never start again although
it is resumed[/quote]

How are you coming to that conclusion?

It is possible that, if you are stepping through the code in vTaskResume(),
and you step over the line portYIELD_WITHIN_API(), then the yield interrupt
and the other task have both executed without you knowing it before you break
on the next line in the debugger, as the next implied break point (the line
after portYIELD_WITHIN_API()) will get hit first by vTestTask2.

Regards.

SourceForge.net

unread,
Nov 18, 2011, 7:25:16 AM11/18/11
to SourceForge.net
By: markuskrug

Hi Richard,

I am aware that between brakepoints on succesive code-lines in multitasking
enviroment some other code can be executed. However, I come to that conclusion
because regardless if I step through the code or if I run it with full speed
and stop it after a while the variable a in the memory is never increased. By
the way it doesn't also make any difference if I use the Codewarrior Simulator
(I am using a HCS12 board) or the real hardware.

Best Regards
Markus

SourceForge.net

unread,
Nov 18, 2011, 7:30:00 AM11/18/11
to SourceForge.net
By: richardbarry

I will have to set up the exact same scenario to see what I observe. I will
report back when this is done, but it won't be immediately.

Regards.

SourceForge.net

unread,
Nov 18, 2011, 7:46:59 AM11/18/11
to SourceForge.net
By: markuskrug

Hi Richard,

thanks for offering you help.
I played around a little bit around by adding a third task to have a better
insight what happens during calling TaskSuspend and TaskResume. The third task
will never be suspended, has low priority and is just calling TaskResume for
the previous suspended Task1+Task2.
For me it comes down to the following thing I am observing. Calling TaskSuspend
updates in the different parts of the Kernel data structures comprehensible
by decreasing the counters of the ready task and increasing the counters for
the suspended tasks. However if I call TaskResume no changes to this counters
seems to happen. Is this a correct behaviour ?


Best Regards
Markus

SourceForge.net

unread,
Nov 18, 2011, 11:40:01 AM11/18/11
to SourceForge.net
By: richardbarry

Ok, I have run this and looked at it in detail, and cannot see anything wrong
with the kernel, but can with your test code.

Before showing you the scenario I observed, an explanation on the behaviour:
When a task is removed from the suspended list, it is added to the end of the
ready list for tasks of that priority. This is so it is the last task, of that
priority, that is selected to run. It has to be this way to prevent a task
from continuously being selected to run. That means, the scenario 2 I described
above was not quite correct. When there are only two tasks of a given priority,
and a start condition that has one task in the Running state and one task in
the Suspended state, then the running task resuming the suspended task will
not result in the resumed task running immediately. When it is resumed, it
is added to the [b]end[/b] of what was a list of 1 task, and the following yield
therefore re-selects the task that was already Running. Below is the corrected
scenario 2, which is what I observed, and at all times the number of items in
each list was shown as I would expect:


1) Task 1 runs and suspends itself.

2) Task 2 runs and resumed Task 1. It continues running though, and suspends
itself.

3) Task 1 is now the only task that can run, so runs, resumes task 2, carries
on running, and suspends itself.

4) Task 2 is now the only task that can run, so runs, resumes task 1, carries
on running, and suspends itself.

5) Task 1 runs, once again, loops back to the top of its for( ;; ) loop, and
suspends itself without ever resuming Task 2.

Now both tasks are in the suspended state, although 'a' has been incremented
(once by each task I think).

I think this is quite simply an error in the logic of your code.

Regards.










When I set this up, if I create task 1 followed by task 2 and have both tasks
at the same priority (above the idle priority), then task 2 runs and suspends
itself, then task 1 runs and suspends itself. This is my scenario 1 from a
few posts above.

If I switch the order in which the tasks are created, then:

+ Task 1 runs first and suspends itself. The suspended task list shows one
item.

+ Task 2 runs immediately that Task 2 is suspended. It resumes task 1 (the
suspended task list is now showing 0 items), then yields.

+ The yield handler chooses Task 1 to run again. This is because Task 2 was
inserted into the end of the ready list, and as the list contains just two task,
Task 1 gets re-selected.

+ Task 2 continues running with Task 1 in the ready list, and suspends itself.
The suspended task list once again shows that it contains 1 task.

+ Task 2 entering the suspended list causes another context switch, so Task
1 is chosen to run. It increments 'a', then resumes task 2.

+ Task 2 is removed from the suspended list, and the suspended list once again
shows it is empty. For the reason mentioned above, Task 2 does not run yet,
and task 1 returns from its call to vTaskResume(xTest2_TaskHandle) to immediately
suspend itself.

+ Task 1 being suspended again allows Task 2 to run again. It increments 'a',
then calls vTaskResume(xTest1_TaskHandle) again. Task 2 then continues and
suspends itself, allowing Task 1 to run again,

From this it looks like it might

SourceForge.net

unread,
Nov 18, 2011, 11:40:53 AM11/18/11
to SourceForge.net

_____________________________________________________________________________________

SourceForge.net

unread,
Nov 18, 2011, 11:29:16 AM11/18/11
to SourceForge.net
By: richard_damon

Part of the problem is that the definition of Resume is to be a hop if the task
is already running, so a suspend-resume is different than a resume-suspend (if
the task is currently Ready. This means that your program has a race condition
is the suspend and resume for a task are coming from different tasks, and they
don't have anything to make sure that they happen in the right order.

Better to use a semaphore given by one task and taken by the other to do the
suspension, as it doesn't matter if the give happens before of after the take,
you just one proceed from the take until both happen.

Even better (unless this is just a learning exercise) if you have two operations
at the same priority, that are to alternate operations, just put them in one
task.and save resources.

Reply all
Reply to author
Forward
0 new messages