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

Reply via email to