All about Linux signals - Linux Programming Blog
linuxprogrammingblog.com
linuxprogrammingblog.com
Seriously, use it. And OP: please update the blog post to at least point people at it. There's no excuse on a modern linux system for trying to use anything else.
> First we must block the signals we want to handle with signalfd(2) using sigprocmask(2). This function will be described later. Then we call signalfd(2) to create a file descriptor...
http://www.linuxprogrammingblog.com/all-about-linux-signals?...
http://www.linuxprogrammingblog.com/code-examples/signalfd
I just wish freebsd and linux folks agree on a standard instead of dealing with multiple ways to handle async events via different poller implementations and hacks.
Having ported my fair share of code from open source projects that only ran on Linux to FreeBSD I feel like too much emphasis is put on using Linux only stuff making it difficult or extremely hard to port code in a clean manner.
It's not particularly hard to emulate (most of) signalfd()'s behavior by writing a byte to a pipe and checking for it in your main loop.
Yes, signalfd() is wonderful and nice, but it makes it a pain in the behind to port your software. If you need to use signals and do it in an event loop of some sort take a look at libev which abstracts away the OS and handles it in the best way possible depending on the system it is run on.
Not only that, but libev will make use of epoll/kqueue/select/poll as required on the OS it is running on, so you get easier portability with the various different event mechanisms that do exist across systems.
Why limit your audience to one single operating system?
(I haven't finished reading the guide yet... apologies if it's in there... but I'd say I'm pretty familiar with signals.)
Since your code could have been anywhere in the execution path you can only do very limited amount of things within the signal handler that won't cause catastrophic issues otherwise.
I'm pretty familiar with signals, but I don't really know what the problem is here. Why would you rely on signals to interrupt system calls? Maybe if I know why you would do that, I will see why it's a problem if the signal comes before the syscall happens.
So we have to rely upon SIGALRM (via setitimer()) to interrupt the fcntl() call so we don't hang indefinitely.
For example, lets say you want Ctrl + C to quit the program (bare with me, very simple example), and you have a select() call. So you set up your signal handlers, and then start filling the required structures for the select() call, before select() is called though you receive a SIGINT, your signal handler simply sets a global flag that is checked when select() returns (with errno == EINTR). So now the flag is set, the handler has done its job, and select() gets called and your program now starts waiting on file descriptors.
What you really wanted to happen is that the program would see the flag, clean up nicely and quit. Now the user has to send a second Ctrl + C to interrupt the select() syscall and to have the code executed that checks for errno == EINTR and the global flag that was set in the signal handler.
This is but a simple example of a race condition that can exist. The SIGALRM example given by the other HN user is also an excellent example of when things can go awry when not intentioned, and unless you program your signal handlers with that in mind you may get results you weren't expecting.
That example doesn't live up to the hype that was mentioned by a previous poster and that had me worried. However, that hype was probably overstated.
For example, "there are certain race conditions if you rely on signals to interrupt system calls and the interrupt happens before the syscall is called" -> seems to imply there are race conditions inherent to the situation, not race conditions that can be introduced by programmer mistake (which is pretty obvious, IMO).
Also "since your code could have been anywhere in the execution path you can only do very limited amount of things within the signal handler that won't cause catastrophic issues otherwise" -> I just don't believe that; you can do lots of things in the signal handler if you know what you're doing.
As a rule of thumb I generally prefer to use signal handlers to set a small amount of global data and nothing else, and have the main interrupt loop notice and deal with the condition. It's possible to use weird siglongjmp things to get to the main loop if you are not there already, but (like longjmp in general) it is kind of weird and bizarre.
When in the signal handler itself, the list of libc functions it is safe to call is small; the Single UNIX specification only guarantees less than 120 functions.
I don't think this is precisely accurate. I think it's safe to call libc functions anywhere, but the point is that you have to ensure that non-reentrant functions are not called simultaneously by the same thread.
One way to do that is to never call those functions in a signal handler, but if you really know what you're doing (i.e., you know the signal hanlder is not interrupting the function you want to call), you can call it in the signal handler.
Does this sound right? I'm not being pedantic; I'm actually trying to make sure I have it right in my head.
For example, take the classic case of printf() - sure, you might be able to guarantee that your signal handler can never interrupt an ongoing printf() call elsewhere, but what if printf() calls malloc() internally, and your signal handler has interrupted a malloc()?
That's why there's a (short) list of async-signal-safe functions in POSIX (see http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2...)
Your main loop can then notice that the other end of the pipe is readable (the main loop is normally watching file descriptors for activity anyway).
I'd really like to see a list of syscalls that are not restarted no matter the flags. And the macros that (implicitly) turn on SysV behavior of signal() ...
Another interesting thing that I had to read in the Linux source code to be sure is that non-fatal signals can't interrupt a write(2) against the filesystem (and you can't have a short write count returned because of a signal). This is an assumption many programs rely on.