(转)Signal handling in Linux

Introduction

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?

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 interrupt

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 masks

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 for?

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.

Other uses of signals

Signals have several different usages. For instance debuggers rely on signals to receive events about programs that being debugged. 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.

Types of signals

    • SIGHUP
      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
    • SIGINT
      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.
    • SIGQUIT
      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.
    • SIGILL
      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.
    • SIGABRT
      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.
    • SIGFPE
      Floating point exception. This is another exception signal, issued by operating system when your application caused an exception.
    • SIGSEGV
      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.
    • SIGPIPE
      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.
    • SIGALRM
      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.
    • SIGTERM
      This signal tells your program to terminate itself. Consider this as a signal to cleanly shut down while SIGKILL is an abnormal termination signal.
    • SIGCHLD
      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.
    • SIGUSR1 and SIGUSR2
      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.

SIGKILL and SIGSTOP

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

SIGKILL

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.

SIGSTOP

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.

原文地址:https://www.cnblogs.com/encode/p/4516921.html