rtel wrote on Sunday, June 23, 2019:
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.