First off, something a bit Off Topic. Why is it that all blog editors have to be so tiny. I have a maximized 1280x1024 window and the blog editor is about half of that. *sigh*
Anywho, todays topic: unix/linux signals. I had to introduce myself to them for a recent project at work where a wrote a threaded socket-ed server. I had used send and recv because they allowed for "MSG_NOSIGNAL" at least until I got home to my Mac OS X computer, which apparently doesn't have that flag (or if it does its not #defined the same way). At any rate its just as easy to handle the signal that is raised by a broken/disconnected socket, which is SIGPIPE (the broken pipe signal).
There are two (old) ways to handle such problems. The first way I learned was:
#include <sys/signal.h>
static void signalHandler() { //handle the signal somehow; }
int main()
{
// blah
signal(SIGPIPE,signalHandler);
//blah
}
This is a simple way to handle any signal and deal with it. The problem with this method is that if you are just ignoring the signal, you have to re register the signal handler every time it is used. One solution to the "only registered once" problem is to update our signal handler so it looks like this:
static void signalHandler()
{
//handle the signal somehow;
signal(SIGPIPE,signalHandler);
}
This is a good way to handle a reoccurring problem where you actually want to fix something and then handle it again. Obviously you don't have to do this for something you only want to handle once, such as say a SIGTERM, where you just want to close your sockets before exiting.
This is obviously much more than one might want to put in simply to ignore a signal however, which is why there is a function called:
sigignore(SIGPIPE);
This will ignore a signal to your program until the program quits.
I like this way of handling the SIGPIPE raised by a socket failure. Its not bad coding practice because sockets return either 0 or -1 on failure of a read/write, which is better anyway, because signal sending is only "supported" on a per application level. It might work and send it to the correct thread, but it is NOT guaranteed. Therefor you can only count on your main program to recieve the signals anyway. So by ignoring the signal (which would normally make your program take a crap) and checking the status of the socket on every send/recv (or read/write), your program has a good idea of what is going on.
Some common signals are:
Catchable:
SIGTERM = sent by kill among others
SIGPIPE = broken pipe, sent by dead sockets, pipes, etc.
SIGHUP = "hang up" sent by exiting the shell the process was running in etc.
SIGIO = configurable exception raised on sockets etc, when something is ready to happen (data recieved etc.)
SIGINT = "interrupt" sent by ctrl - c among other things.
Not able to be caught:
SIGKILL = sent by kill -9
There are more signals. Something like 22 I think, but those are the only ones I have run across so far, and I have only actually handled SIGTERM, SIGINT, and SIGPIPE. I like to handle SIGTERM and SIGINT so I can close my sockets before exiting
because it makes the program start quicker next time when it doesn't have to wait for previously bound sockets to time out before rebinding.
The last thing to note (sadly) is that this signal, sigignore, and all the other functions related in the man pages, are actually depricated. Thats not to say that they will be removed from any linux anytime soon. The new method is really overkill for anything I was doing, so I didn't bother to learn it. I hope that this method is never removed, because signal and sigignore are super easy ways to get things done. Im not disagreeing with "better" functionality, one of the features added in the new interface was ability to have a "previous" handler stored, which you could switch back to when you were done. Once again this is massive overkill for what I need to do, and in most cases, this will work just fine for years (I'm sure) to come.
Happy coding!
-Crusher4