On 19/05/2020 11:32, Phil Endecott via Boost wrote:
Niall Douglas wrote:
The latest revision of the "modern signals" paper can be found at https://wg21.link/P2069.
Thanks Niall, that's interesting.
I note that your signal_guard takes a callable. That's not easy to combine with a scoped lock_guard, i.e. if I want to make something that's exactly like std::lock_guard but also blocks SIGINT. Is there any way around that?
You can install guards for the current thread. That takes a callable which is to be protected, as you noticed. The callable based design is unavoidable here, for Win32 SEH compatibility. You can also install handlers globally. I'd suggest a global handler which examines thread_local state would suit you best.
To block SIGINT for the short time that a lock is held, I was imagining calls to pthread_sigmask() when locking and unlocking - but I guess this is an actual system call, so it could take much longer than the mutex lock and unlock, which are just atomics typically.
Correct.
If I understand correctly, your proposal
avoids this by installing a signal handler once at startup, and then just changing some state at the start and end of the guard.
Correct. We install sigaction() handlers at the start of process, and globally enable signals. Those are slow operations. We then "reimplement" signal handling locally, all of which avoids the kernel.
So if I want only to block a signal rather than ignoring or handling it, with your proposal I would need to track pending signals and raise them at the end of the guard. Is that right?
Under P2069, all globally installed handlers are *filtering* handlers. You'll get called when the signal raises, you can do your thing, and handlers installed after you get called in turn by default. So for your situation, you need to do nothing.
I'm unclear what happens in a multi-threaded program; if one thread is in a critical section with SIGINT blocked, can the signal be delivered to a different thread and cause the whole process to be terminated, defeating the purpose of blocking it? Does your proposal change this behaviour, compared to pthread_sigmask() ?
We don't touch the thread local signal mask at all. We globally enable signals for the process. Thus, whichever thread receives a signal is the thread which runs "modern signals". And that varies per POSIX implementation. In terms of general thread safety, "modern signals" is always thread and reentrant safe i.e. you can modify installed signals at any time from any thread. One caveat, which is documented, is that modifying the global signal install from within a global signal handle of the same signal number can cause an endless loop, so don't do that if you can avoid it. If you can't, it can be worked around, with effort. BTW, I assume you realise that your proposed scheme won't be watertight right? I mean that Windows doesn't send you a signal on process termination, and there are ways of terminating a POSIX process without it ever receiving a signal either. The biggest source of that on Linux is OOM, which is very irritating of it. Niall