And that’s exactly what it does: set some sort of flag.
However it does not pass control back to the scheduler. This could only be done by calling vTaskSuspend() which in turn would require a later call to vTaskResume(). So the call to taskYIELD() was of no benefit as it didn’t change anything with respect to task switching, right?
I believe your interpretation is wrong. “Set some flag” actually in general causes the context switch interrupt to execute at the next possible point of time (may be immediately but not necessarily) which will cause the scheduler to select the highest priority task for execution (note that if you have multiple priorities, the next task may be the same as the one that called the yield). vTaskSuspend(NULL) will remove the current task from the ready list and THEN in turn invoke the scheduler.
Also, using Suspend/Resume would imply that the tasks explicitly pass control back and forth between each other, which is not what cooperative multitasking is about; in cooperative multitasking, a task simply allos the OS ro give the CPU to another task without bothering which one.
Set some flag” actually in general causes the context switch interrupt to execute at the next possible point of time (may be immediately but not necessarily) which will cause the scheduler to select the highest priority task for execution
Yes. A task switch is a task switch, regardless of the underlying policy. The OS mustbe able to save a task context and restore another task’s context, that is what task switching (aka multitasking) is all about.
but that was implied by your statement that vTaskResume() would need to be called in cooperative musltitasking, and in order to resume a task, the caller (a task) would need to know which task to resume, so any implementation of multitasking using explicit suspend and resume would ask the involved tasks to deliberately pass the baton around, right? Such schmas exist (sometimes called co-routines), but that is a different approach.
Not necessarily. This scenario would happen if a running task would like to tell the OS ‘I still have things to do, but go ahead, server (possibly) other tasks and then resume me’. In other words something like a call to the none existing function taskPause(). Such a paused task would be resumed automatically by the scheduler not by any other task.
Again, I won’t argue about terminology. In the almoast 30 years I’ve worked as an embedded developer, I never came across a different understanding of the term “cooperative multitasking” from mine. You are welcome to use the terms differently, but from my understanding, you will have a hard time fitting it into existing systems.
The important thing to understand is that FreeRTOS is flexible enough to implement explicit scheduling between tasks, but the concept of a “task switch” is centryl to any form of multitasking. Without being able to save and restore task contexts, there simply is no switching back and forth between tasks, no matter what policy determines the scheduling sequence. Yield() effectively implements a task context switch, to come back to your original queastion, so it is indispendable to any form of multitasking.
No, in your first post you claimed that yield() was a no op.
Again, yield() is used both by the FreeRTOS scheduler and possibly by individual tasks to request a context switch - more precisely, to ask the OS to save the current task context and then select another task to obtyin the CPU. In a cooperatively working setup, yield() is EXCLUSIVELY (actually, this is a little simplified; ISRs may still force context switches depending on priorities, but that is going too much in detail) called from tasks to voluntarily release the CPU. In a preemptive setup, yield() can also be called in other scenarios, such as the expiration of a time slice.
I’ll stop this explanation now. I strongly recommend you study the scheduler code in tasks.c. It is very well written and straightforward to understand, and studying it will answer all questions you may have about multitasking.
PREEMPTIVE Multitasking, as soon as a higher task becomes ready, the system will switch to it. In particular, an ISR might do something to wake the task, and then the ISR will effectively return to that new task. In preemptive multitasking, code needs to be careful and may need to use critical sections when updating information shared between tasks.
COOPERATIVE Multitasking, The switch to a higher priority task doesn’t happen immediately, but is held off until the current task performs an operation that is defined to all a switch. This includes any FreeRTOS api call that might unblock some other task, or blocks the current task, or an explicit Yield, like with taskYield(). With cooperative multitasking you have less need to worry about updates to inter-task data structures (just don’t put one of the above API calls in the middle of it), but does make it harder to meet timing requirements, as the period of time that any task might spend between these preemption points needs to be added to the response time for the task, as well as the time needed by any higher (or same) priority task. With preemptive scheduling, you only need to worry about the latter.
Cooperative Multitasking makes HARD real time much harder, but can make soft real time system simpler.