[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: lib-ev vs. signal handling
- From: Sean Conner <sean@...>
- Date: Tue, 13 Apr 2010 04:15:46 -0400
It was thus said that the Great Alexander Gladysh once stated:
> Hi, Brian!
>
> I see that lib-ev has signal handling support in TODO section.
>
> What is the status of this feature? Is it hard to implement?
Signal handling is hard to do in general. I spent over a month [1]
tracking down a bug caused by a signal handler, and if you are attempting to
write code to work across multiple operating systems, the *only* thing you
can do safely in a signal handler is set a variable of type sig_atomic_t.
That's it.
*If* you can restrict yourself to Posix semantics, then the number of
things you can do goes up, but you *still* have to be very careful (it helps
to realize that once you start writing signal handlers, you're writing
multithreaded code).
I know in my syslog replacement [2], the code looks like (and sorry, this
part is in C):
volatile sig_atomic_t mf_sigint;
volatile sig_atomic_t mf_sigusr1;
volatile sig_atomic_t mf_sighup;
volatile sig_atomic_t mf_sigalarm;
void handle_signal(int sig)
{
switch(sig)
{
case SIGTERM: mf_sigint = 1; break;
case SIGINT: mf_sigint = 1; break;
case SIGUSR1: mf_sigusr1 = 1; break;
case SIGHUP: mf_sighup = 1; break;
case SIGALRM: mf_sigalarm = 1; break;
default: break;
}
}
/* ... */
set_signal_handler(SIGINT, handle_signal);
set_signal_handler(SIGUSR1,handle_signal);
set_signal_handler(SIGHUP ,handle_signal);
set_signal_handler(SIGALRM,handle_signal);
set_signal_handler(SIGTERM,handle_signal);
while(!mf_sigint)
{
assert(lua_gettop(g_L) == 0);
if (mf_sigusr1)
{
mf_sigusr1 = 0;
load_script();
}
if (mf_sighup)
{
mf_sighup = 0;
call_optional_luaf("reload_signal");
}
if (mf_sigalarm)
{
mf_sigalarm = 0;
call_optional_luaf("alarm_handler");
}
if (poll(events,g_maxsocket,-1) < 1)
continue; /* continue on errors and timeouts */
for (size_t i = 0 ; i < g_maxsocket; i++)
{
if ((events[i].revents & POLLIN))
event_read(&g_sockets[i]);
}
}
/*------------------------------------------------------------------------
; Per http://www.cons.org/cracauer/sigint.html, the only proper way to
; exit a program that has received a SIGINT (or SIGQUIT) is to actually
; use the default action of SIGINT (or SIGQUIT) so that the calling
; program can detect that the child process (in this case, us) actually
; received a signal. So that's why we set the default handler for SIGINT
; and kill ourselves, since the only way we get here is via SIGINT (or
; possibly SIGQUIT if/when I add logic for that).
; (I found this *just today!*)
;------------------------------------------------------------------------*/
set_signal_handler(SIGINT,SIG_DFL);
kill(getpid(),SIGINT);
If I need other signals, I'll add them in C, not in Lua. But, I also have
control over the Lua code, and I can make sure to avoid infinite loops in
the Lua code. And so far, this has been running solidly for months [3].
-spc (One of these days I'll get around to releasing the syslogd
replacement)
[1] http://boston.conman.org/2007/10/18.1
[2] http://boston.conman.org/2010/02/09.1
[3] Not to say there aren't issues---because of some of the code I'm
using when logging system messages (this is, after all, a
replacement for syslogd) causes problems on my home system when I
power up. It's an odd interaction between the network, iptables,
initlog [4] and a Lua script run by my syslogd replacement. I
haven't fully solved that issue yet.
[4] Yes, it's on a RedHat derived Linux distribution. Much hate, but
that's a post for another mailing list [5]
[5] Hates Software