On Wed, Aug 30, 2017 at 12:57:31PM -0700, Brandon Williams wrote: > > And I think we're fine there even with a doubly-linked list. It's still > > the single update of the "next" pointer that controls that second > > traversal. > > I know it was mentioned earlier but if this is a critical section, and > it would be bad if it was interrupted, then couldn't we turn off > interrupts before attempting to remove an item from the list? If we have to, that's an option. I mostly didn't want to get into the portability headaches of signal-handling if we can avoid it. Right now sigchain uses plain old signal(). We do use sigaction() in a few places, but in a vanilla way. So the portability questions are: - can we rely on using more interesting bits of sigaction like sa_mask? Probably. - which flags should we be setting in sa_flags to get the same behavior we've been getting with signal()? Or alternatively, which behavior do we want? On Linux and BSD systems, at least, signal() defers repeat instances of the handled signal. So getting two quick SIGTERMs will not interrupt the handler to deliver the second. But getting SIGTERM followed by SIGINT would. We could extend that protection by having sigchain_push_common() set sa_mask to cover all of the related signals. On Linux and BSD the current code using signal() also implies SA_RESTART. We could add that to our flags, though I suspect in practice it doesn't matter. Whenever we establish a handler like this our intent is to never return from it. That just protects us from calling the _same_ handler from itself. But that's probably enough in practice, and means handlers don't have to worry about "critical sections". The other alternative is sigprocmask() to block signals entirely during a section. I'm not sure if there are portability questions there (it looks like we have a mingw wrapper there, but it's a complete noop). -Peff