I am trying to port the SMP test multple_tasks_running for the existing MCU+SDK port of the SMP kernel. TLDR it spawns (number of cores - 1) number of tasks and checks if they are simultaneously running.
In the process as preemption is turned off the test either refuses to complete or fails. I have tested the following scenarios:
Test passes:
Preemption enabled
When only one ever running task is spawned(without pinning the main task to core 0)
Test fails:
Comment out the delay
Adding a delay to the ever running task
Changing the main task delay to 0
Changing the main task delay to 0 + prints → no outputs
Pinning the task to 0 and others to the respective core. Even with a high delay
Test exec doesn’t complete:
Default case
Main task delay is increased
Ever running tasks >1
Prints added to Ever running task → Prints a bunch of times(Random number: can be infinite(when in core 0) or stop at as less as 3 prints(other cores))
Main task has the same priority as the spawned tasks
Dissalowing multiple priority tasks from exec at the same time, configRUN_MULTIPLE_PRIORITIES 0
All tasks of equal priorities with time slicing
Adding core affinity prevents even 1 case from runninng
Pin the main task to 0 and pin no other task
Additionally it also seems like the idle tasks don’t seem to give up their core even when a ready task is present. Note this test turns of most config options allowing configRUN_MULTIPLE_PRIORITIES as the only one turned to 1 meaning no preemption or time slicing.
The (number of cores - 1) tasks are highest priority tasks, so they should run and hog all the cores except one which should be running the test runner task. This should not need preemption. Where did you get the port from?
If he is making the tasks after the kernel starts. he will need either preemption of the idle tasks need to yield. Maybe “not preemption” should force idle tasks to yield (if it doesn’t). I think the default is for them to yield, but if he explicitly turned that off, it could cause problem.
While debugging I noticed that the isr that increments the tick gets disabled after vtaskdelay is being called. This is then not enabled again meaning the tick count is not being incremented and the delayed task is never marked ready. Is this the right cause of this problem? If any ideas on why this behavior occurs?
This does not seem correct. The timer ISR should not remain blocked because that means time has essentially stopped from FreeRTOS perspective. Can you try to see why that is happening? And why does that not happen when preemption is enabled?
Solved by forcing idles to continuously yield without going to wfi. Thanks.
The freertos SMP kernel has four points where scheduling can take place:
(1) At tick ISR
(2) When a task voluntarily yields the core due to suspension, deletion or just a yield call.
(3) When a task is added to the ready list.
(4) When a task priority is changed.
In the case of cooperative scheduling when preemption is turned off (1),(3),(4) are not possible as they count as preemption.
Additionally no core can force a yield in another core again due to the same reason. This mean idle tasks can’t be preempted either, making task scheduling impossible.
This is because idle tasks yield once, and if configUSE_IDLE_HOOK and configUSE_PASSIVE_IDLE_HOOK are enabled, wait at the wfi instruction with each core expecting the same interrupt used by preemption.
This interrupt is not used when preemption is disabled, forcing idles to be forever stuck in wfi.
Refer:portTASK_FUNCTION in task.c
This can be prevented forcing the idle tasks to loop on yield, by enabling the wfi instruction only when preemption is turned on in vApplicationIdleHook and vApplicationPassiveIdleHook functions
Thank you for sharing your solution! Both the hooks are implemented in the application, so the change is in the application code, right? Just wanted to confirm that no change is needed in the FreeRTOs kernel.