Well, you aren't 100% clear on what you expect from an answer but I'll try to cover the general idea.
First of all, what you could call a 'debugging' signals are (and when to expect them):
SIGILL
, SIGFPE
— if program tries to run an illegal instruction, usually can appear with wrong CFLAGS
and/or own assembly (or serious random breakages);
SIGABRT
— caused by the abort()
call, for example in assert()
. It can also come from libraries, so you usually should handle it;
SIGSEGV
— invalid memory access, you probably know all about it already;
SIGBUS
— can happen when doing I/O with mmap()
and trying to read/write unaccessible memory; it also happened to me when mmap()
-based I/O ran out-of-space;
SIGPIPE
— when doing I/O on pipes, and the pipe gets disconnected from the other side;
- POSIX also specifies
SIGSYS
for invalid system calls and you probably want to catch that as well (though I never managed to see one).
I would say you need to handle those signals if you are using the relevant operations. They're all in POSIX but I'm not sure if all systems implement them so you may want to use #ifdef
s for them anyway (SIG*
are guaranteed to be macros and thus suitable for #ifdef
).
Other signals you may encounter through the runtime of your program are:
SIGALRM
— when using alarm()
,
SIGPOLL
— when using polling,
SIGCHLD
— when spawning processes…
And these are basically signals which you are handling anyway when using the relevant operations and though they terminate by default, you should have other handlers for them anyway.
And finally, if you expect to handle signals sent by user, that's a harsh case — because user can practically send every signal. Thus, if you want to handle it all gracefully, you need to catch every signal from man signal
which defaults to termination or abort actions.
If you want to just catch a common subset of signals which you could expect, these would be:
SIGHUP
when the terminal with the program (or some other parent if relevant) dies,
SIGINT
for ^c key,
SIGQUIT
for ^\ key,
SIGTERM
for the termination request (sent by the kill
program by default and other similar tools),
SIGUSR1
and SIGUSR2
are user-defined signals and usually are used to perform program-specific actions. They are sent by user, and — for some reason — default to killing the program.
There's also SIGKILL
but the standard doesn't allow catching it.
I hope I covered the most important signals. Note that I'm a Linux user, and other *nixes may have a few specific signals you also may want to catch.
It usually all depends on what you want to achieve. Although preventing the software from being interrupted by random signals is a good idea, it's usually not worth it to prevent it from being killed by all of them, and especially those which are only sent directly by user.
If user wants to kill the app, he can achieve it anyway, and it should be enough to just handle the common ones — SIGINT
and SIGTERM
. I would personally expect SIGQUIT
(^\ key) to kill the application without letting it finish even critical tasks (like SIGKILL
does).
Edit. And as a rationale for the last sentence, think about the following: I've just made something stupid, like removed some important data. Or simply noticed there's something wrong with the cleanup-on-exit procedure. I really want to terminate the program ensuring my signal won't be caught but cause it to return immediately. Even if it would result in broken data, sometimes I would really prefer to have broken data (hoping I would be able to recover what I need) than no data.
SIGBUS
can also be an alignment error, I think. – Sebastian