Boost logo

Boost :

From: Niall Douglas (s_sourceforge_at_[hidden])
Date: 2020-05-19 13:22:01


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


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk