Binary semaphore reliability

alainm3 wrote on Wednesday, September 06, 2017:

Hi, a friend of mine with greater knowledge of RTOSes than myself is arguing about the reliability of this code:

  1. I have a binary semaphore created like this
    myMutex = xSemaphorCreateBinary();
  2. In my IRQHandler for serial input, I set a binary semaphore every time I get a new char and put it in the RX queue:
    xSemaphoreGiveFromISR(myMutex, …);
  3. I have a task waiting for that semaphore:
    xSemaphoreTake(myMutex, 10);
  4. Hardware is an CortexM0+ STM32F030, FreeRTOS version 7.6.0, compiler GCC

The argument is that there is a possibility of loosing a byte from my IRQ handler and that I should use a counting semaphore.
The question is: is it 100% safe to use a binary semaphore in this way (I got the example from the (payed) manual) or should I change to a counting semaphore as he says?

Thanks for making FreeRTOS and thanks for being here to help us,
Alain

rtel wrote on Wednesday, September 06, 2017:

The answer depends on how you have structured your code.

A binary semaphore will only tell you that something has happened, not
how many things have happened, so you must process ALL pending events
before going back to wait for the semaphore again, not just assume there
is only one event (character, in your case) pending.

See the code snippet on the following page, which shows a task
notification being used as a binary semaphore - the concept is the same

  • not do do while{} loop clearing all events before looking for a
    notification again:

http://www.freertos.org/ulTaskNotifyTake.html

alainm3 wrote on Thursday, September 07, 2017:

Yes, that is what I did but using binay semaphore. I do process all pending events before going back to taking the semaphore.

But the argument is that an ISR could happen “at some special moment” and cause the xSemaphoreTake() not to wake up. Is it guaranteed that this “special moment” does not exist?

And BTW, I have no mention to TaskNotify anywhere in Reference Manuas v2.0.0 for FreeRTOS v8.0.0
:frowning:

heinbali01 wrote on Thursday, September 07, 2017:

But the argument is that an ISR could happen “at some special moment” and
cause the xSemaphoreTake() not to wake up. Is it guaranteed that this
“special moment” does not exist?

That “special moment” do not exist in FreeRTOS. The FreeRTOS API’s take all necessary measurements to be atomic. In some cases interrupts are masked, in other cases the scheduler will be suspended temporarily. As a result you can Give and Take semaphores ( notifications ) at any moment you like, without worrying about congruency.

In most cases, the task receiving bytes will be sleeping in ulTaskNotifyTake() or xSemaphoreTake(). When the ISR comes at that moment, the function will unblock and return a non-zero value.

When the ISR comes at any other moment, the task is handling UART reception. It will read all bytes available and call the Take function again. That function will return immediately. And then there may, or there may not be RX bytes available. That depends on the actual sequence of events.

You won’t miss bytes using the “binary semaphore method”, unless there is a physical overflow, which may happen if the task does not get enough CPU time.

alainm3 wrote on Thursday, September 07, 2017:

Thanks very much for giving a definitive answer :slight_smile: