rakshasa/rtorrent — pull request #127 by blaenk (2013-04-08 03:16:43+00:00)
Title: replace signal() call with sigaction() for better portability

I came across issue #51 in which Solaris users encounter crashes upon receipt of `SIGUSR1` and I have a feeling I know what's happening. I don't think the problem is Solaris' implementation of [`pthread_kill`](http://docs.oracle.com/cd/E26502_01/html/E29034/pthread-kill-3c.html) as that is defined by the POSIX standards and Solaris is apparently [fully POSIX-complaint](http://en.wikipedia.org/wiki/POSIX#Fully_POSIX-compliant), more than can be said of Linux, and yet those of us on Linux don't experience this problem.

Rather, `signal()` is known to have portability problems (the POSIX standard allows it presumably due to historical reasons). Some systems such as old Unix systems and System V employ a behavior in which the signal disposition is reset to `SIG_DFL` (default) upon invocation of a signal handler by the delivery of a signal.

> The only portable use of signal() is to set a signal's disposition to
> SIG_DFL or SIG_IGN. The semantics when using signal() to establish a
> signal handler vary across systems (and POSIX.1 explicitly permits this
> variation); do not use it for this purpose.

From: http://man7.org/linux/man-pages/man2/signal.2.html

Solaris is a system which employs the SIG_DFL reset behavior even in
version 11.1.

See http://docs.oracle.com/cd/E26502_01/html/E29034/signal-3c.html

> If `signal()` is used, disp is the address of a signal handler, and sig is not SIGILL,
> SIGTRAP, or SIGPWR, the system first sets the signal's disposition to SIG_DFL before
> executing the signal handler.

On Solaris the default signal disposition for `SIGUSR1` is to exit the application.

See http://docs.oracle.com/cd/E26502_01/html/E29033/signal.h-3head.html

If I'm correct in assuming this is the problem Solaris users are encountering, the solution to this (and likely any other portability issues that may arise) is to use `sigaction()` which has explicitly defined behavior as per the POSIX standards.

As you can see, it's a pretty drop-in solution. In fact, on some systems such as Linux, glibc defines `signal()` as a wrapper around `sigaction()` to use BSD semantics (i.e. not the behavior detailed above), which is likely why few others have experienced these problems.

See http://man7.org/linux/man-pages/man2/signal.2.html

I really hope this helps you guys out with Solaris (and maybe other systems which employ this behavior). I don't have Solaris myself so I can't test it, but it's a drop-in replacement of `signal()` so it should have no effect on other systems and hopefully fix the problem on Solaris. All I could do on my Linux machine was add a torrent and force a re-hash, which I believe is what fires `SIGUSR1` (or so I inferred from the talk on the issue). The re-hash went through just fine.