How to block a task on demand?


First of all, allow me to apologize that, the answer to the question probably lies within a pdf obtained on this site somewhere, but it would requires extensive reading and in-depth understanding of FreeRTOS, a time I currently simply do not have.

I’m using a port for STM32WB55x series chip with Cortex M4F core.

I want to BLOCK, instead of UNBLOCK a task at my drop of the hat. I’m more inclined to use an interrupt which uses notifications to notify the task or the scheduler to block a task as soon as possible.

As you probably had guessed, notifications are typically used to UNBLOCK a task, the opposite of what I want. My task is a resident, almost perpetual running task.

FreeRTOS is multi-task-ish (duh) and scheduler pops tasks in and out of running state with context switches. I wish, ideally, that my task could be blocked on the most immediate context switch.

These are the plans that I came up with, please show me the way!!!

  1. Use a 1 slot queue or sempahore, use something to keep feeding into the queue/reseting the semaphore, and when that interrupt that I was talking about happened, the feeding behavior gets stopped, so my target task will be blocked.

  2. Polling. Get my perpetual running task to poll a flag or a static variable, and change the value of the variable/flag in the interrupt. If the value is “block me!” then the task kind of block itself.

Neither 1 is all that ideal. Could someone please help me ?

First, in general, stopping a task blindly wherever it is, tends to cause problems, so you tend to want to have the task stop on its own, like the patterns you are suggesting. One important question is once you block the task, what will unblock it in the future?

My first method for doing this sort of task is your second method. The task checks a flag, and if it is set, then the task blocks on whatever will wake it back up. You can also sort of do the first one, but having a semaphore that in the loop you have the task take, and then give, and to stop, have someone else take, which will stop the loop.

This is a somewhat unusual condition, as normally a task is doing some processing every time a new ‘work unit’ becomes available, so there is naturally something feeding a ‘go’ signal to the task, so it will naturally block when that is no longer there.

Now, a big question, WHY are you wanting to block this task? Is it you want to run some other task that has something more urgent to do? If so, you don’t need to have this task block, just let the other task have a higher priority, and unblock that task, then it will run. It the problem that this task is using resources that some other task needs to run? If so, just wrap the usage of that resource in a mutex (or semaphore), and have the other task take that mutex. When you task gets done with using that resource, it will give the mutex, and the new task takes it that will block this task from using it again until the other task is done with it.

Hello Richard, thank you for your reply!

“what will unblock it in the future?”

Here’s more detail:

By blocking it, idle task will be the only task that’s able to run. I’ve hooked the idle-task hook to a sleep function, which will put the system to sleep then have it wait for interrupt which according to official documents of my chip, would wake up the system immediately.

So to answer your question: a timer based interrupt will fire to block my “perpetually-running” task, and if the interrupt doesn’t happen, the task will not be blocked. So in a way, the task, as you suggested, using polling, will try to find out whether it should take the initiative and block itself. And it is fairly reasonable to unblock this task in the interrupt that wakes up the chip, BUT NOT the timer interrupt (just to clarify).

Actually after a lot of thought I think my #1 scheme seems to be more implement-able, I don’t seem to recall there’s a convenient way for a task to block itself.

"If so, you don’t need to have this task block, just let the other task have a higher priority, and unblock that task, then it will run. "

Well yea except this task I want to run is the idle task, and it is not exactly the wisest thing to change the idle task priority dynamically (if you could in the first place) and expect it to run right?

If your application is literally just one task, you don’t need an RTOS, and that is just making things more complicated.

I would be VERY hesitant to do as you describe and have the idle hook just automatically put the system into sleep, as that basically forces you into a non-RTOS structure of the task not EVER blocking except to cause the sleep, and generally most I/O should at least have the possibility of blocking the task to wait for completion instead of busy looping.

It is VERY easy for a task to ‘block’ itself, just do something like take a semaphore that isn’t ready or wait for a task notification, those will block the task until the condition is ready. In fact, you can’t really block another task, the closest you can do is suspend it, which is sort of similar, except that the only way out of a suspension is to use resume.

Oh no! My system has 3 tasks and counting. Using FreeRTOS has helped me circumvented a lot of steps regarding ISR which I had to code manually otherwise, increasing my workload. My project is all about BLE connectivity and the original example code was an operating system in its own right, I merely migrated the code and ported it to a more popular, mainstream platform, the FreeRTOS.

Well that’s the beauty of FreeRTOS: the idle task hook will take into effect only when no other tasks demand the processor time.

Rest assured I am most certainly not trying to use the blocking of this perpetual running task as the sole criteria for entering sleep mode.

I’ve done the blocking part, by giving itself semaphore and removing it. If the flag that got polled showed that the task should be blocked then the task remove the semaphore and gets blocked instantly. If it’s not the case, the task feed the semaphore once more.