[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: interrupting coroutines (was Re: Local Variables)
- From: William Ahern <william@...>
- Date: Mon, 11 Aug 2014 18:54:53 -0700
On Mon, Aug 11, 2014 at 06:38:31PM -0700, William Ahern wrote:
> On Mon, Aug 11, 2014 at 09:08:28PM -0400, Sean Conner wrote:
> <snip>
> > Not directly, but you can still gain control via a signal handler. Some
> > basic code:
> <snip>
> > volatile int ghookcount;
> > volatile int ghookmask;
> > volatile lua_Hook ghook;
> > volatile_sig_atomic_t gsig;
> <snip>
> > void signal_handler(int sig)
> > {
> > if (!gsig)
> > {
> > gsig = sig;
> > ghookcount = lua_gethookcount(gL);
> > ghookmask = lua_gethookmask(gL);
> > ghook = lua_gethook(gL);
> > lua_sethook(gL,luasigbackend,LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT,1);
> > }
> > }
>
> This can't be async-signal-safe unless all other signals are blocked during
> execution of the handler. So there should be the caveat that when installing
> the signal handler, sigfillset is used to initialize sa_mask.
It's also worth pointing out that this isn't async-signal-safe if two
signals come in back-to-back. If you get SIGCHLD followed by SIGHUP, you'll
lose the SIGCHLD and might never reap a zombie child. And that applies
regardless of whether you block other signals during delivery.
The only way to do make this safely is to have a static array of length
NSIG.[1] Then atomically set (using C11 atomics, platform-specific APIs, or
assembly) a flag indexed by the signal number.
sigtimedwait is definitely the way to go if you want to be both safe and
POSIX-compatible because no matter what you do you'll still have to poll for
your signals if you don't want to potentially lose a signal.
1. Technically you want an array of length (sizeof (sigset_t) * CHAR_BIT)
because systems like Solaris and FreeBSD will have signals higher than NSIG.
But there'll never be a user-visible signal higher than can fit in a
sigset_t object. sigset_t is de facto a bitfield because it must be
assignable, which means it cannot use dynamic memory. So its size provides a
fixed upper bound on the number of signals possible on a system. While NSIG
can change from kernel version to kernel version, it would be an ABI
catastrophe if a vendor changed the size of sigset_t.