lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


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.