when can we not use task notificatin as binary semaphore

Hello, I recently came to know about the task notification. It is a very nice feature. However it confuses me with the binary semaphore. What is different in binary semaphore that the task notification can not do? If none, why do we even have binary semaphore if we have a mechanism (task notification)which is 45% faster? If they are same, why we implemented a new mechanism (task notification)? instead we could have changed the binary semaphore implementation with the task notification implementation to make binary semaphore 45% faster. Is there any difference between these two, use case wise? I do not understand. Please advice. Thanks in advance

when can we not use task notificatin as binary semaphore

Richard Barry would ( and maybe will ) give you a more accurate answer, but here is my short answer: when you use a binary semaphore just to wake-up a task, it is definitely more efficient to use task notification in stead. Only one task can wait for its notification, and that makes it simpler. When semaphores are used like mutexes, they can not be replaced by task notification. Many tasks can wait for the same semaphore, and only the highest-priority task will get it. When the priorities of two tasks are equal, the semaphore will be taken by the task that has waited the longest.

when can we not use task notificatin as binary semaphore

One key difference is that any task can wait for an take a binary semaphore, but only the specific task can wait for a specific notification, so a direct to task notification can’t replace a semaphore if you don’t know what task is going to want to wait for it, or perhaps you need to publish somewhere what task is waiting for the event. A second difference is that the direct to task notification can only a single counting semaphore or a limited number of binary semaphores (and the programmer needs to keep careful track of which bit represents which notification). You can have an effectively unlimted number of semaphores, (the only limit is memory space). Direct to Task notification came significantly later in the development of FreeRTOS, for the cases where it does work, it likely does work better (task/interrupt A wants to let task B proceed from its wait) and probably should be used in new code (it may not be worth it to change existing working code). There are still a number of cases where you still need the semaphore, or the semaphore is ‘better’.

when can we not use task notificatin as binary semaphore

Yes to the above, and to elaborate. If you look at the evolution of FreeRTOS, from its roots 15 years ago, the original design was intended to be as small as possible. As such semaphores were originally implemented as macros on top of queues, so the functionality was achieved without adding any code size – but at the expense of semaphores being somewhat larger than many people expect. This became a problem when folks started writing FreeRTOS specific peripheral drivers and wanted to use semaphores per driver port (serial, IO or whatever) as a blocking/signalling mechanism. At that time we considered, and even prototyped specific semaphore objects. However, when looking at data on how people were using semaphores it became apparent that the majority of use cases always had the same sender and the same receiver – so rather than implement a new generic semaphore object that (like the FreeRTOS semaphores) contained logic that enabled multiple senders and multiple receivers, we implemented a primitive we called task notifications that was optimised for the most common use case. Therefore task notifications are smaller as they don’t need to worry about prioritiesed lists of senders or receivers. Task notifications are faster as there is no separate storage object – unlike semaphores that write to an object then have another task read from that object the write is directly to the receiving task (as an aside, as code size is less important now, the queue primitive can be updated to do the same thing if there is already a task waiting to receive when data is written to a queue). Now you have a choice of a fully features primitive with lots of flexibility, or smaller and faster primitives with a use case that is restricted to the most common use case. Peripheral drivers now don’t need to contain a semaphore object, but instead just remember the handle of the task they must send a notification to when the driver wants to unblock a task.

when can we not use task notificatin as binary semaphore

Thanks everyone. It really helped.