> 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.


Reply via email to