> In his Confluence paper on "Signaling Semaphores and Priority
Inheritance”, Brennan Ashton’s analysis is both thorough and accurate; ...
Minor fix. I wrote the paper, Brennan converted the Confluence page
from an older DocuWiki page
> In any RTOS, priority inversion happens, and it’s OK, and a
well-designed RTOS can be configured to meet its timing constraints
given CPU performance is adequate for the application. Point: priority
inversion is not intrinsically a “bad thing,” it’s going to happen.
I read that priority inheritance does reduce the variability in response
times. I am not ready to defend that statement, but it is a common belief.
> It seems to me that “Signaling Semaphores” are only used within the
NuttX kernel (is this correct?). For intertask communication POSIX
pthread mechanisms could and should be used.
That is probably true. Application designers, of course, can do as they
wish and could use a counting semaphore for signaling between
processes. But I haven't seen that done.
> The solution Brennan suggests is to initialize semaphores used as
signaling events as follows:
> sem_init(&sem, 0, 0);
> sem_setprotocol(&sem, SEM_PRIO_NONE);
>
> this is, of course, correct, but retains the dual purpose of
sem_wait() and sem_post(). I believe this can be confusing and will
continue to be a source of subtle errors. I suggest going a step
further and isolate the two use cases. Let the current sem_init,
sem_wait, sem_post be used only for the resource locking use case.
>
> For the signaling use case, create a new API for event signaling
within the kernel: nxev_init, nxev_wait, nxev_post where: nxev_init is
simply:
> sem_init(&nxev, 0, 0);
> sem_setprotocol(&nxev, SEM_PRIO_NONE);
>
> and:
> #define nxev_wait sem_wait
> #define nxev_post sem_post
>
> In the case were PRIORITY_INHERITANCE is not configured,
sem_setprotocol() does nothing and the nxev_*() API is still used for
event notification.
>
> This may seem a trivial change, but having specific API function
names for the two specific use cases would, I believe, all but eliminate
future confusion; especially given that most people look to existing
drivers to use as a template. Finally, enabling or disabling
PRIORITY_INHERITANCE would not introduce the subtle error Brennan
documented.
Your suggestion would clarify the usage.
I was thinking out a conceptually simple solution that should also
resolve the risk in usage: Just change the default state to
SEM_PRIO_NONE for all semaphores. That would make the default protocol
for semaphore be no priority inheritance.
This would be a lot of work, however. All occurrences of sem_init()
would have to be examined:
For the signaling use case, you would do nothing. We would have to
remove all sem_setprotocol(&nxev, SEM_PRIO_NONE);
For the resource locking use case, you would have to add
sem_setprotocol(&nxev, SEM_PRIO_INHERIT); assuming priority inheritance
is enabled.
The eliminates the risk of inappropriately using priority inheritance on
a locking semaphore. The consequences of doing that are very bad:
https://nuttx.yahoogroups.narkive.com/3hggphCi/problem-related-semaphore-and-priority-inheritance
Then the only error that the user can make is to fail to select priority
inheritance when it would do good. That is a lesser error and, as you
note, usually OK.