Signal handling in Linux

Table of contents

IntroductionBACK TO TOC

Perhaps any engineer developing for Linux encounters this problem. What’s is the right way to terminate the program? What are the ways to receive notifications from operating system about events that occur.

Traditional Unix systems have the answers ready. The answer to these questions is signals.

This article addresses these questions. Here, I’ll try to explain what signals are, their nature. We’ll talk about what are the right ways to handle signals, what signals to handle and what are the pitfalls of signal handling in Linux in particular.

What are signals?BACK TO TOC

Signal is a notification, a message sent by either operating system or some application to your program (or one of its threads).

Each signal identified by a number, from 1 to 31. Signals don’t carry any argument and their names are mostly self explanatory. For instance SIGKILL or signal number 9 tells the program that someone tries to kill it.

Signal as interruptBACK TO TOC

In addition to informative nature of signals, they also interrupt your program. I.e to handle a signal, one of the threads in your program, stops its execution and temporarily switches to signal handler. Note that as in version 2.6 of Linux kernel, most of the signals interrupt only one thread and not the entire application as it used to be once. Moreover, signal handler itself can be interrupted by some other signal.

Signal masksBACK TO TOC

Each one of signals can be in one of three states:

  • We may have our own signal handler for the signal.
  • Signal may be handled by the default handler. Every signal has its default handler function. For instance, SIGINT default handler will terminate your application.
  • Signal may be ignored. Ignoring signal sometimes referred to as blocking signal.

When manipulating signals and managing signal configuration, it is often easier to manage a so called signal mask. It is a bit-mask, where each bit has a corresponding signal. There are 32 (actually 31, 0 doesn’t count) different signals, thus we can use single 32-bit integer (unsigned int) to keep information about 32 signals. This is exactly what operating system does. Moreover, signal masks used as arguments in different system calls, thus we will have to work with signal masks.

The C library assigns default signal handlers. This means that even if you leave signals untouched, your program will process signals and will respond to them according to default behavior. I will describe default signal behavior a little later in this article.

What signals are good forBACK TO TOC

Signals, as their name implies, used to signal something. There are several types of signals, each indicating something of its own. For instance SIGINT that I already mentioned, tells your program that someone tries to interrupt it with CTRL-C.

Dedication of each signal is a matter of semantics. I.e. you may want to decide what action shall be associated with each one of the signals. You may decide that some signal will cause your program to print something or draw something on the screen. It is up to you, most of the time. However, there is a common convention of what each and every signal should do. According to this common convention SIGINT expected to cause your program to terminate itself. This is the default response for SIGINT signal and it is in your interest to keep it this way. It is a question of usability. No one wants a program that cannot be interrupted.

Signals that report exceptionsBACK TO TOC

Another way of using signals is to indicate that that something bad have happened. For instance when your program causes a segmentation fault, operating system sends SIGSEGV signal to your application.

Other uses of signalsBACK TO TOC

Signals have several different usages. For instance debuggers rely on signals to receive events about programs that being debugged (read more about this in my article How Debugger Works). Signals is one of so called IPC – Inter Process Communication mechanisms. IPC used to, as the abbreviation implies, to allow processes communicate with one another.

Another common use is when user wishes that our program will reinitialize itself, but not terminate. In this case, user can send our program a signal from the terminal, using a program called kill. You may be already familiar with this program. It used to kill processes. The truth is that it sends a signal. Each signal has a number that identifies it. By default it sends signal 15, SIGTERM, but it can send just any signal.

Lets see most common and their use.

Types of signalsBACK TO TOC

    This signal indicates that someone has killed the controlling terminal. For instance, lets say our program runs in xterm or in gnome-terminal. When someone kills the terminal program, without killing applications running inside of terminal window, operating system sends SIGHUP to the program. Default handler for this signal will terminate your program.
    Thanks to Mark Pettit for the tip.
    This is the signal that being sent to your application when it is running in a foreground in a terminal and someone presses CTRL-C. Default handler of this signal will quietly terminate your program.
    Again, according to documentation, this signal means “Quit from keyboard”. In reality I couldn’t find who sends this signal. I.e. you can only send it explicitly.
    Illegal instruction signal. This is a exception signal, sent to your application by the operating system when it encounters an illegal instruction inside of your program. Something like this may happen when executable file of your program has been corrupted. Another option is when your program loads dynamic library that has been corrupted. Consider this as an exception of a kind, but the one that is very unlikely to happen.
    Abort signal means you used used abort() API inside of your program. It is yet another method to terminate your program. abort() issues SIGABRT signal which in its term terminates your program (unless handled by your custom handler). It is up to you to decide whether you want to use abort() or not.
    Floating point exception. This is another exception signal, issued by operating system when your application caused an exception.
    This is an exception signal as well. Operating system sends a program this signal when it tries to access memory that does not belong to it.
    Broken pipe. As documentation states, this signal sent to your program when you try to write into pipe (another IPC) with no readers on the other side.
    Alarm signal. Sent to your program using alarm() system call. The alarm() system call is basically a timer that allows you to receive SIGALRM in preconfigured number of seconds. This can be handy, although there are more accurate timer API out there.
    This signal tells your program to terminate itself. Consider this as a signal to cleanly shut down while SIGKILL is an abnormal termination signal.
    Tells you that a child process of your program has stopped or terminated. This is handy when you wish to synchronize your process with a process with its child.
    Finally, SIGUSR1 and SIGUSR2 are two signals that have no predefined meaning and are left for your consideration. You may use these signals to synchronise your program with some other program or to communicate with it.

Handling exception signalsBACK TO TOC

In general I think it would be a good advice to avoid changing signal handler for these signals. Default signal handler for these signals generates core file. Later, you can use core file to analyze the problem and perhaps find a solution. Overwriting signal handler for one of the exception signals, will cause your program to ignore this signal and an exception that has caused the signal. This is something that you don’t want to do.

In case you still want to handle exception signals, read my How to handle SIGSEGV, but also generate a core dump article.


These two signals are special. You cannot change how your program handles these two.


SIGKILL, on the contrary to SIGTERM, indicates abnormal termination of the program. You cannot change how your program handles it. It will always terminate your program. However, you can send this signal.

SIGKILL’s value is 9. This is why kill -9 <pid> shell command is so effective – it sends SIGKILL signal to the process.


SIGSTOP used when debugging. When you debug your program, operating system sends SIGSTOP to stop your program, for instance in case it reaches a breakpoint. Operating system does not let you change its handler because you may cause your program to be undebuggable.

Registering signal handlerBACK TO TOC

There are several interfaces that allow you to register your own signal handler.

signal()BACK TO TOC

This is the oldest one. It accepts two arguments, first signal number (one of those SIGsomething) and second pointer to a signal handler function. Signal handler function returns void and accepts single integer argument that represents a signal number that has been sent. This way you can use the same signal handler function for several different signals.

Here is a short code snippet demonstrating how to use it.

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

void sig_handler(int signum)
    printf("Received signal %d\n", signum);

int main()
    signal(SIGINT, sig_handler);
    sleep(10); // This is your chance to press CTRL-C
    return 0;

This nice and small application registers its own SIGINT signal. Try compiling this small program. See what is happening when you run it and press CTRL-C.

Ignoring signals and restoring original signal handler functionBACK TO TOC

Using signal() you can set default signal handler for certain signal to be used. You can also tell the system that you would like to ignore certain signal. To ignore the signal, specify SIG_IGN as a signal handler. To restore default signal handler, specify SIG_DFL as signal handler.

Although this seems to be everything you may need, it is better to avoid using signal(). There’s a portability problem with this system call. I.e. it behaves differently on different operating systems. There’s a newer system call that does everything signal() does and also gives slightly more information about the actual signal, its origin, etc.

sigaction()BACK TO TOC

sigaction() is another system call that manipulates signal handler. It is much more advanced comparing to good old signal(). Let us take a look at its declaration

int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);

Its first argument specifies a signal number. Second and third arguments are pointers to structure called sigaction. This structure specifies how process should handle given signal.

struct sigaction
    void (*sa_handler)(int signum);
    void (*sa_sigaction)(int signum, siginfo_t *siginfo,
        void *uctx);
    sigset_t sa_mask;
    int sa_flags;
    void (*sa_restorer)(void);

sa_handler is a pointer to the signal handler routine. The routine accepts single integer number containing signal number that it handles and returns void – same as signal handler registered by signal(). In addition, sigaction() let you have more advanced signal handler routine. If needed sa_sigaction pointer should point to the advanced signal handler routine. This one receives much more information about the origin of the signal.

To use sa_sigaction routine, make sure to set SA_SIGINFO flag in sa_flags member of struct sigaction. Similarily to sa_handler, sa_sigaction receives an integer telling it what signal has been triggered. In addition it receives a pointer to structure called siginfo_t. It describes the origin of the signal. For instance, si_pid member of siginfo_t holds the process ID of the process that has sent the signal. There are several other fields that tell you lots of useful information about the signal. You can find all the details on sigaction‘s manual page (man sigaction).

Last argument received by sa_sigaction handler is a pointer to ucontext_t. This type different from architecture to architecture. My advice to you is to ignore this pointer, unless you are writing a new debugger.

One additional advantage of sigaction() compared to signal() is that it allows you to tell operating system what signals can handle signal you are registering. I.e. it gives you full control over what signals can arrive, while your program handling another signal.

To tell this, you should manipulate sa_mask member of the struct sigaction. Note that is a sigset_t field. sigset_t type represents signal masks. To manipulate signal masks, use one of the following functions:

  • int sigemptyset(sigset_t *) – to clear the mask.
  • int sigfillset(sigset_t *) – to set all bits in the mask.
  • int sigaddset(sigset_t *, int signum) – to set bit that represents certain signal.
  • int sigdelset(sigset_t *, int signum) – to clear bit that represents certain signal.
  • int sigismember(sigset_t *, int signum) – to check status of certain signal in a mask.

sigaction() in actionBACK TO TOC

To conclude, I would like to show a small program that demonstrates sigaction() in use. I would like the program to register signal handler for SIGTERM and then, when it receives the signal, print some information about the origin of the signal.

On the other hand, I will use Python interpretor to send the program a signal.

Here is a program.

#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>

struct sigaction act;

void sighandler(int signum, siginfo_t *info, void *ptr)
    printf("Received signal %d\n", signum);
    printf("Signal originates from process %lu\n",
        (unsigned long)info->si_pid);

int main()
    printf("I am %lu\n", (unsigned long)getpid());

    memset(&act, 0, sizeof(act));

    act.sa_sigaction = sighandler;
    act.sa_flags = SA_SIGINFO;

    sigaction(SIGTERM, &act, NULL);

    // Waiting for CTRL+C...

    return 0;

And this is what happens when we try to run it. First we run the program.

~/works/sigs --> ./a.out
I am 18074

While it sleeps I ran Python shell and killed it.

~ --> python
Python 2.5.2 (r252:60911, Jul 31 2008, 17:31:22)
[GCC 4.2.3 (Ubuntu 4.2.3-2ubuntu7)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> import signal
>>> print os.getpid()
>>> os.kill(18074, signal.SIGTERM)

Here’s the rest of the output of the program.

~/lab/sigs --> ./a.out
I am 18074
Received signal 15
Signal originates from process 18075
~/lab/sigs -->

We can see that it recognized the process that has killed it and printed its process ID.

ConclusionBACK TO TOC

I hope you found this article interesting. If you have questions, don’t hesitate to email me to

Did you know that you can receive periodical updates with the latest articles that I write right into your email box? Alternatively, you subscribe to the RSS feed!

Want to know how? Check out
Subscribe page


  1. Mark Pettit says:

    Your comment on SIGHUP regarding ‘not using controlling terminals” is technically not true. From X-windows, opening a session to xterm/aterm/konsole etc opens a controlling terminal. Then, killing or closing such a window wile it was running a program (say vi), would cause SIGHUP to be sent to the program (vi).

    In fact, if as I do here at my work, I have an ssh session to a Solaris box, and I switch off my laptop or pull the ethernet, eventually the ssh session on the Solaris box will detect that I’ve gone and send a SIGHUP to whatever program I was running.

  2. @Mark Pettit
    You are right. Thank you for pointing this out. I’ll fix the article.

  3. Clayton says:


    Extremely helpful article!

    I’m impressed with the wealth of information on your blog, definitely looking forward to more posts :)

  4. @Clayton
    Thanks for a warm comment. You are most welcome :-)

  5. Andre Goddard Rosa says:

    Thanks for another nice article!

    I’d like to emphasize what you’ve said stressing that signals are a process-wide resource that must be managed with care, normally on a central place so that it does not gets messed. Important to check if a library that you could probably use depends on some signal to behave, as it could also mess the application state. Also, I’d like to say that signal handlers are very restricted environment, with different stack information, and not all functions can be called safely from inside a signal handler. There are many restrictions from calling arbitrary functions from inside a handler.

    Thanks again!

  6. kamal says:

    Hi Alex ,

    Thanks for sharing the information.

    I am implementing one signal handler for three signals (SIGSEGV, SIGILL, SIGBUS ).

    I want to mask other two signals before entering into the handler(no nesting of signals). and when i return from handler , restore the signal mask usng (sigsetjmp /siglongjmp).
    and it should be ready to server any of three handler again.

    sigsegtjmp( env,1);

    sigemptyset(&sa.sa_mask); <<<< does this right way to do this ?
    sigaddset(&sset , SIGILL); <<< shd i use sigprocmask ?
    sigaddset(&sset , SIGSEGV);
    sigaddset(&sset , SIGBUS);

    sigaction (…);

    hanlder ()
    /* doing my work */



  7. kamal says:

    I think below code shd work. Please correct if i am wrong





    and in handler i ll call siglongjmp to restore env .

    problem is its not working on AIX5.1 , Linux is ok.

  8. @kamal
    I don’t know if what you’ve suggested will work. However, there is a much easier way of doing the same thing – actually it is in the article and careful reader should have seen this ;-) Use sigaction() to register signal handlers. When calling sigaction(), one of the things you pass in called sa_mask. This is a signal mask that tells the OS what signals should be blocked when handling the signal you’re registering. This is exactly what you need.

  9. kamal says:

    Thanks for reply Alex! :-)

    I understood the functionality of sigaction + sa_mask.

    Here my intention is to block some particular set of signals , and once i am done with the handling then jump back and restore ( un block all those handlers ) and get ready to handle signals again.

    If i will use sigsetjmp/siglongjmp , does signal will be restored ??
    I am thought of putting sigsetjmp just above sigaction and corresponding siglongjmp at the end of handler.

  10. kamal says:

    typo : ( un block all those signals** )

  11. @kamal
    I’ve never used sigsetjmp() and siglongjmp() before so I honestly cannot tell you if these API will do the job for you. According to their man page, you can use them to do that.
    I am wondering though, why you are reinventing the wheel if operating system/libc already can do it for you using?

  12. kamal says:

    OS will block only that signal for which handler is installed. In case , if i have same handler for three different signals and when any of one those signal will come OS/Libc will block that signal BUT who will re responsible for blocking the other two signals ( I want handle one signal at a time- No nesting ). Thats what i am trying to do here.


  13. Kevin says:

    Taking an operating systems class in college now. This tutorial was on the dot with respect to what i needed to learn. Thanks!!

  14. @Kevin
    I was glad to hear that you found it useful. Please come again (and bring all your student fellows along with you :-) )

  15. Jithu M says:

    thanx a lot…

  16. Namekata says:

    FYI, you can send SIGQUIT with Ctrl-¥.

  17. Rajiv says:

    Alex, good info, Just wondering, how to create customized signals…

  18. @Rajiv
    I am afraid you can’t. There are 32 predefined signals. You can use SIGUSR1 and SIGUSR2 for your own purposed, but otherwise you’re pretty much stuck with what’s already there.

  19. bindhi06 says:

    Hi Alexander,
    Thanks for sharing this information. Its really useful.

  20. Deepak John Paul says:

    Thank you Alex, it was a very helpful blog…

  21. misserwell says:

    The clear and respectable blog, I have learned much from it .

    do you have any update about your issue? I feel it is very interesting about hat you said.
    Looking forward to your reply or mail .


  22. M.USAMA says:

    I Want to do Packet filtring with the help of linux signal handleing please guide me is it possible if it is which signal dispatch when packet arrives ….plz help

  23. Angel Genchev says:

    I think of signals as of messages in WindowsAPI since the threads in Win32 can receive messages without having window handle – on the thread handle & I`m using it. IMO Windows has more flexible approach as there is huge number of possible user-defined messages for communication. What I`m trying to do in linux is asynchronous sending/receiving of messages in a processing threads so my sending threads to be non-blocking. I`m trying with pthread_sigqueue(..) so far, but my app terminates by it`s own signals. Instead going to the targeted thread, the signals get caught somewhere in the framework (FPC/Lazarus) and the framework kills the main thread. Second and third resort are:
    - to use unix sockets;
    - my own asynchronous message processing framework.

  24. @Angel Genchev
    Indeed, Linux signals were not designed as mean of communication between processes. Signals are more like exceptions. There are lots of different limitations that apply on code that runs inside of signal handler.

  25. Angel Genchev says:

    @Alexander Sandler – Yes, thanks. I was misguided by my winAPI knowledge. This (..SIGNALS are more like exceptions..) was not written in any of the signals-related manuals I read also. If I knew it, it would save me more than 1 week of building test programs and wondering why it didn`t work. If somebody is fighting with the same thus reading this, here is what i did:
    - read tons of manuals and blogs :-) about linux signals, signal queues, etc.
    - read linux headers and defined kernel syscalls and pthread calls to use the functions that were not available to the user in my framework (LCL). – Wrote and did tests with most signals.
    Finally I had partial success with using SIGRTMIN()..SIGRTMAX(), synchronous signal handling within a thread and sending with pthread_sigqueue(…) from the main thread.
    A concurent implementation was done by using pipes and fixed message size. Synchronous message handling – with poll(…) on the read end.
    The speed, benchmarked was *the same*. It took about 1.0 .. 1.6 mS to queue 1000 messages (varies with the hardware) with both implementations. The second implementation worked flawlessly while the first (using signals) gave headaches(like unpredictable calling the signal handling function within the thread instead of returning from sigtimed_wait(…) and was abandoned.
    I had ideas to try: 1)POSIX.4 Message Queues (had to implement the syscalls). Think the speed will be the same. 2)Someting homebrew with a mutex/futex protected queue and signalling with a second futex/mutex. Potentially faster until get done :-).

  26. interreq says:

    @Angel Genchev – gud to start with

  27. Amazing article. Thanks for fluent and easy-to-understand explanations. The person who’s mother tongue is not English can understand the article very easly and clearly (like me :) ). Thanks for a million time.

  28. @Burak
    My pleasure :-) Please come again.

  29. Azzza says:

    Written so humans can understand! Nice article.

  30. Thanks :-) My pleasure. Please visit again.

  31. abhijit teke says:

    my question is
    signal system call
    when we want to terminate program in execution by another process
    ex. kill -9 process id of program in execution

    when user defined signal handler executes then where it returns because,we are not calling the signal handler function…….

  32. @abhijit teke – signal is like an interrupt. It stops execution of the process in arbitrary place and continues from exactly the same spot.

  33. sridhar s says:

    Thanks for information. In my opinion the signal handler is called by the kernel. So, I guess it must use the kernel stack to store the local variables in the signal handler. But, I can see local variables (in the signal handler ) in the process stack in my observation (through gdb).
    If my understanding is incorrect, can you please give me details in the usage of process stack in this regard? Thanks

  34. sridhar s says:

    My question is signal handler is executed in the process context or Kernel context? Thanks

  35. vamshi says:

    does signal handler run concurrently with the process to which signal is delivered or is it(the given process) blocked until signal handler completes execution ?

  36. Vlad says:

    There are also at least two modern ways to handle signals, both of which are a lot more safe and sound, but not that many people know about — Kqueue and signalfd(). For details, see

  37. Petiepooo says:

    Nice article, but a little misleading regarding SIGKILL and SIGSTOP.

    The reason that those two signal handlers cannot be changed by your program is that they never reach your program. Instead, they are handled by the kernel. SIGKILL removes your process from the process table, effectively ending it. SIGSTOP removes your process from the scheduler’s table, effectively freezing it until a SIGCONT is received to add it back to the scheduler’s table.

    The way I like to consider it is: a SIGINT or SIGQUIT is a message to your process saying, “Please shut yourself down.” A SIGKILL is a signal to the kernel saying, “Please shut that process down.” That’s why, in the Ctrl-Alt-SysRq+REISUB sequence, you first send E for SIGTERM, then I for SIGKILL. That gives processes a chance to gracefully shutdown before they’re blindly ended.

    With that in mind, using SIGKILL as the initial example in “What are signals?” section isn’t the best choice. I’d recommend using SIGINT there, as that is handled by the user process, and is commonly handled with user code trying to prevent Ctrl-C from terminating an app.

  38. vpsampath says:

    am well impressed.
    i didnnt get output for this

    While it sleeps I ran Python shell and killed it.

    ~ –> python
    Python 2.5.2 (r252:60911, Jul 31 2008, 17:31:22)
    [GCC 4.2.3 (Ubuntu 4.2.3-2ubuntu7)] on linux2
    Type “help”, “copyright”, “credits” or “license” for more information.
    >>> import os
    >>> import signal
    >>> print os.getpid()
    >>> os.kill(18074, signal.SIGTERM)

  39. I have to thank you for the efforts you have put in penning
    this blog. I am hoping to view the same high-grade
    content by you in the future as well. In fact, your creative
    writing abilities has motivated me to get my own, personal site now

    Feel free to visit my web blog; baner odblaskowy Krapkowice

  40. I wish that people would realise how dangerous gas burning appliances can be.

    A yearly gas safety inspection would save lives.

Leave a Reply