Signal Handling Using "Term"

Signal handling using TERM

Update May 2012 (2 and half years later)

Trejkaz comments:

On current versions of Java this signal handling code fails because the "INT" signal is "reserved by the VM or the OS".

Additionally, none of the other valid signal names actually fire when something requests the application to close (I just painstakingly tested all of the ones I could find out about...)

The shutdown hook mostly works but we find that in our case it isn't firing, so the next step is obviously to resort to registering a handler behind the JVM's back

The chapter "Integrating Signal and Exception Handling" of the "Troubleshooting Guide for HotSpot VM" mentions the signals "SIGTERM, SIGINT, SIGHUP" only for Solaris OS and Linux.

Only Exception Handling on Windows are mentioned.


Original answer (Sept 2009)

a ShutdownHook should be able to handle that case

Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
public void run() {
// what you want to do
}
}));

(with caveats)

See also:

  • Java signal handling and termination (link is dead, see archive or mirror)
  • java exit signal handling:

as an illustration of simple signal handling:

public class Aaarggh {
public static void main(String[] args) throws Exception {
Signal.handle(new Signal("INT"), new SignalHandler () {
public void handle(Signal sig) {
System.out.println(
"Aaarggh, a user is trying to interrupt me!!");
System.out.println(
"(throw garlic at user, say `shoo, go away')");
}
});
for(int i=0; i<100; i++) {
Thread.sleep(1000);
System.out.print('.');
}
}
}

Signal handling with multiple threads in Linux

This is slightly nuanced, based on which version of the Linux kernel you are using.

Assuming 2.6 posix threads, and if you are talking about the OS sending SIGTERM or SIGHUP, the signal is sent to process, which is received by and handled by root thread. Using POSIX threads, you can also sent SIGTERM to individual threads as well, but I suspect you are asking about what happens when the OS sends the signal to the process.

In 2.6, SIGTERM will cause child threads to exit "cleanly", where as 2.4, child threads were left in an indeterminate state.

Understanding bash signal handling

/usr/bin/spotify receives SIGINT and dies before driver.sh terminates listen.sh, thus the empty output from pactl. You should run /usr/bin/spotify at the background and terminate it after terminating listen.sh.

So, your scripts should look like:

driver.sh

#!/bin/bash
trap 'kill -TERM $bg_pid $!' SIGINT SIGTERM
./listen.sh &
bg_pid=$!
echo "bg_pid: $bg_pid"
/usr/bin/spotify &
wait

listen.sh

#!/bin/bash
trap 'echo trap:; func; exit' SIGINT SIGTERM
func() {
echo func: $(pactl list | sed -E '/media\.name/p;d')
}
while true; do
func
sleep 1
done

Perl Term::ReadLine::Gnu Signal Handling Difficulties

This is due to perl's default paranoid handling of signals - behind the scenes, perl blocks SIGTERM before starting the readline call and restores it when it's finished. See Deferred Signals in perlipc for the details.

Term::ReadLine::Perl uses perl's IO, which knows about these issues and deals with them, so you don't see this bug with it. Term::ReadLine::Gnu uses the C library, which doesn't, so you do.

You can work around this with one of two methods:

  1. set the environment variable PERL_SIGNALS to unsafe before running the script, as in:

    bash$ PERL_SIGNALS=unsafe perl readline-test.pl

    Note, BEGIN { $ENV{PERL_SIGNALS} = "unsafe"; } isn't enough, it needs to be set before perl itself starts.

  2. Use POSIX signal functions:

    #~ $SIG{TERM} = sub { print "I got a TERM\n"; exit; };
    use POSIX;
    sigaction SIGTERM, new POSIX::SigAction sub { print "I got a TERM\n"; exit; };

    Both the above seem to work in Linux; can't speak for Windows or other unices. Also, both of the above come with risks - see perlipc for the details.

signal handling

This actually caused me brain freeze for a few minutes, and the reason why one should never use signal() in this day and age only grew stronger in me.

First of all, from the man pages for signal()

The behavior of signal() varies across
UNIX versions, and has also varied
historically across different versions
of Linux. Avoid its use: use
sigaction(2) instead.

and further down :

  • If the disposition is set to a function, then first either the
    disposition is reset to SIG_DFL, or
    the signal is blocked (see Portability
    below), and then handler is called
    with argument signum. If invocation
    of the handler caused the signal to be
    blocked, then the signal is unblocked
    upon return from the handler.

In the original Unix systems, when a handler was installed, the disposition was reset to SIG_DFL, did not block incoming signals of the same type, and then it ran the handler function. System V provided this, and the linux kernel does the same.

This means that, once the code is run on a linux system, once second exception is called, it will exit directly.

Now to the fun part. BSD tried to improve this behaviour. From the man pages again:

On BSD, when a signal handler is
invoked, the signal disposition is not
reset, and further instances of the
signal are blocked from being
delivered while the handler is
executing.

And since mac osx is partly based on BSD, once the code is run on a mac osx, once second exception is called, it will be pending and wait for the handler of the first exception to exit. But since you will never exit, you have a deadlock.

Thats why one should use sigaction() instead and never signal().

Now to some tips:

Handlers should be short, and return quickly. If you are performing calculations and calling other functions you are probably doing something wrong. Signals are not a substitute for an event driven framework.

Calling functions that are not async-safe is bad. Consider what would happen if an exception happened during a call to fprintf, and inside the handler fprintf was called again. Both the signal handlers and the programs data could be corrupted since they operate on the stream itself.

Some more reading : "Do" and "Don't" inside A Signal Handler

When is a signal handled and why does some info freeze up?

Before explaining out your problem, a bit of context on how read command works. It reads in input data from stdin until EOF is encountered. It is safe to say the call to read command is non-blocking when it comes to reading from on-disk files. But when stdin is connected to the terminal, the command will block until the user types something.

How signal handlers work?

A simple explanation on how signal handling works. See the below snippet in C which just acts on SIGINT ( aka. CTRL+C)

Sample Image

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

/* signal handler definition */
void signal_handler(int signum){
printf("Hello World!\n");
}

int main(){
//Handle SIGINT with a signal handler
signal(SIGINT, signal_handler);
//loop forever!
while(1);
}

It will register the signal handler and then will enter the infinite loop. When we hit Ctrl-C, we can all agree that the signal handler signal_handler() should execute and "Hello World!" prints to the screen, but the program was in an infinite loop. In order to print "Hello World!" it must have been the case that it broke the loop to execute the signal handler, right? So it should exit the loop as well as the program. Let's see:

gcc -Wall -o sighdl.o signal.c
./sighdl.o
^CHello World!
^CHello World!
^CHello World!
^CHello World!
^CHello World!
^CHello World!
^CHello World!
^CHello World!
^CHello World!

As the output indicates, every time we issued Ctrl-C, "Hello World!" prints, but the program returns to the infinite loop. It is only after issuing a SIGQUIT signal with Ctrl-\ did the program actually exit. Depending on your ulimit settings, it would dump a core or print out the signal number received.

While the interpretation that the loop would exit is reasonable, it doesn't consider the primary reason for signal handling, that is, asynchronous event handling. That means the signal handler acts out of the standard flow of the control of the program; in fact, the whole program is saved within a context, and a new context is created just for the signal handler to execute in. Once the signal handler has completed its actions, the context is switched back and the normal execution flow starts (i.e. the while(1)).

To answer your questions,

The conclusion verified that When bash is executing an external command in the foreground, it does not handle any signals received until the foreground process terminates

The key thing to note here is the external command part. In the first case, where sleep is an external process but in the second case, read is a built-in from the shell itself. So the propagation of the signal to these two differs in both these cases

type read
read is a shell builtin
type sleep
sleep is /usr/bin/sleep

1.Open a terminal,named termA ,and run the created file callback.sh with /bin/bash callback.sh for first time,the info pop up instantly.

Yes, this behavior is expected. Because at this time only the function is defined and the trap handler is registered to the function myCallback and the signal is not yet received in the script. As the execution sequence goes, the message from the read prompt is thrown for the first time.

2.Open a new terminal ,named termB and run pkill -USR1 -f callback.sh first time,the info pop up instantly in termA

Yes, while the read command is waiting for string followed by the Enter key pres which signals the EOF, it receives a signal SIGUSR1 from the other terminal, the current execution context is saved and the control is switched the signal handler which prints the string with the current date.

As soon as the handler finishes executing, the context resumes to the while loop in which the read command is still waiting for an input string. Until the read command is successful, all subsequent signal traps would just print the string inside the signal handler.

Go on in termB,run pkill -USR1 -f callback.sh the second time.

Same as explained previously, the read command is not complete for once in your while loop, only if it is successful reading a string, the next iteration of the loop would start and a new prompt message would be thrown.


Image source: The Linux Programming Interface by Michael KerrisK

Simple Linux Signal Handling

[Q-3] Does the terminate variable in my example have to be volatile? I've
seen many examples where this variable is volatile, and others where
it is not.

The flag terminate should be volatile sig_atomic_t:

Because handler functions can be called asynchronously. That is, a handler might be called at any point in the program, unpredictably. If two signals arrive during a very short interval, one handler can run within another. And it is considered better practice to declare volatile sig_atomic_t, this type are always accessed atomically, avoid uncertainty about interrupting access to a variable. volatile tells the compiler not to optimize and put it into register. (read: Atomic Data Access and Signal Handling for detail expiation).

One more reference: 24.4.7 Atomic Data Access and Signal Handling.
Furthermore, the C11 standard in 7.14.1.1-5 indicates that only objects of volatile sig_atomic_t can be accessed from a signal handler (accessing others has undefined behavior).

[Q-4] I've read that signal() is now deprecated, and to use sigaction(). Are
there any really good examples to show how to convert from the
previous signal() call? I'm having trouble with the new structure that
I have to create/pass and how it all fits together.

The example below (and the link in the comments) can be helpful:

// 1. Prepare struct 
struct sigaction sa;
sa.sa_handler = sighandler;

// 2. To restart functions if interrupted by handler (as handlers called asynchronously)
sa.sa_flags = SA_RESTART;

// 3. Set zero
sigemptyset(&sa.sa_mask);

/* 3b.
// uncomment if you wants to block
// some signals while one is executing.
sigaddset( &sa.sa_mask, SIGINT );
*/

// 4. Register signals
sigaction( SIGINT, &sa, NULL );

references:

  1. Beginning Linux Programming, 4th Edition: in this book, exactly your code is explained with sigaction() nicely in "Chapter 11: Processes and Signals".
  2. The sigaction documentation, including an example (quick learning).
  3. The GNU C Library: Signal Handling

    *I started from 1, Presently I am reading 3 GNU-library

[Q-5] Is the second call to signal() necessary? Is there something similar that I need to be concerned with for sigaction()?

Why you set it to default-action before program termination is unclear to me. I think the following paragraph will give you an answer:

Handling Signals


The call to signal establishes signal handling for only one occurrence of a signal. Before the signal-handling function is called, the library resets the signal so that the default action is performed if the same signal occurs again. Resetting signal handling helps to prevent an infinite loop if, for example, an action performed in the signal handler raises the same signal again. If you want your handler to be used for a signal each time it occurs, you must call signal within the handler to reinstate it. You should be cautious in reinstating signal handling. For example, if you continually reinstate SIGINT handling, you may lose the ability to interrupt and terminate your program.

The signal() function defines the handler of the next received signal only, after which the default handler is reinstated. So it is necessary for the signal handler to call signal() if the program needs to continue handling signals using a non-default handler.

Read a discussion for further reference: When to re-enable signal handlers.

[Q-1a] Is any signal handling necessary?

Yes, Linux will do cleanup for you. For example if you don't close a file or a socket, Linux will do the cleanup after the process terminates. But Linux may not necessary perform the clean up immediately and it may take some time (may be to keep system performance high or some other issues). For example if you don't close a tcp-socket and the program terminates the kernel will not close the socket immediately to ensure all data has been transmitted, TCP guarantees delivery if possible.

[Q-1b] Therefore, can I just replace the signal handler with just an infinite loop and let the OS gracefully exit the threads, de-allocate the memory, etc?

No, operating system performs do clean-up only after program terminates. While a process executes, resources that are allocated to that process don't get claimed by the OS. (The OS can't know whether your process is in an infinite loop or not - this is an unsolvable problem). If you want that after process termination the OS performs the clean-up operations for you, then you don't need to handle signals (even in case your process abnormally terminated by a signal).

[Q] All I'm trying to accomplish to to have my: main loop run until either ctrlc or power is disconnected or something really bad happens.

No, there is a limitation! You can't catch all signals. Some signals are not catchable e.g. SIGKILL and SIGSTOP and both are termination signals. Quoting one:

— Macro: int SIGKILL


The SIGKILL signal is used to cause immediate program termination. It cannot be handled or ignored, and is therefore always fatal. It is also not possible to block this signal.

So you can't make a program that cannot be interrupted (an uninterrupted program)!


I am not sure but may be you can do something like this in Windows systems: by writing TSRs (some sort of kernel-mode hooking). I remember from my thesis time that some viruses couldn't be terminated even from task manager but I also believe that they trick user by admin permissions.

I hope this answer will help you.



Related Topics



Leave a reply



Submit