All, In his Confluence paper on "Signaling Semaphores and Priority Inheritance”, Brennan Ashton’s analysis is both thorough and accurate; and his conclusion that There should then be no priority inheritance operations on this semaphore that is used for signalling. is unassailable.
It’s important to understand a few points here: 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. Point: The “bad thing” about priority inversion happens when it becomes unbounded. There are plenty of papers on this, but summarily, unbounded priority inversion happens when a thread blocks on a resource held by another thread of a lower priority (so far this is normal priority inversion); and then a third, unrelated thread, with an intermediate priority becomes ready (imagine it decides to calculate pi). Now we have unbounded priority inversion (UPI) and we no longer have a deterministic realtime system. There are a number of solutions to the problem of UPI. In the case of NuttX, a fixed-priority preemptive RTOS, one solution that both solves the problem and minimizes performance penalty is priority inheritance. Point: priority inheritance is a solution to the problem of unbounded priority inversion. In the use case described by Brennan as “Signaling Semaphores”, the semaphore is used as a signal to indicate some event has just occurred, i.e a serial driver signaling an incoming character or keystroke. Since it’s not used to protect a shared resource, there is no contention for a shared resource and “priority inversion” is meaningless in this case (how would you boost the priority of the device or person typing on the far end of a serial cable?). Point: in the use case of a signaling semaphore, unbounded priority inversion doesn’t happen because there’s no priority inversion to begin with. Final Point: priority inheritance, in the case of Signaling Semaphores, is the application of a solution to a problem that doesn’t exist; and in fact becomes the problem. My thoughts: 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. 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. Cheers, -david > On Mar 30, 2023, at 6:49 AM, Gregory Nutt <spudan...@gmail.com> wrote: > > >>> 3. Move priority inheritance from nxsem to nxmutex, and optimize the >>> performance of priority inheritance; >> >> That will break every a lot of people's code. There is probably a lot of >> application logic that depends on priority inheritance working on counting >> semaphores. Removing that will problems for a lot of people. >> >> This is, however, consistent with how Linux works. > > AFAIK there is nothing that prohibits semaphores from supporting priority > inheritance -- other than the fact that there is no "owner" of a semaphore as > there is for a mutex. Priority inheritance is very important for the correct > behavior of some real time systems so we were able to use priority > inheritance with counting semaphores by adding some non-standard interfaces > to control whether a semaphore supports priority inheritance or not by its > usage: > https://cwiki.apache.org/confluence/display/NUTTX/Signaling+Semaphores+and+Priority+Inheritance > > I have mixed feelings myself and hope that we get some consensus through > dialog. One one hand, it is important to stay faithful to documented > standard and undocumented conventions for the use the a POSIX/Unix systems. > But on the other hand, unlike other OSs that strive toward standard > conformance, we are an RTOS and must satisfy certain requirements for > deterministic, real time behavior. > > What do you all think? >