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:
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.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
)
#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 bevolatile
? 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 usesigaction()
. Are
there any really good examples to show how to convert from the
previoussignal()
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:
- Beginning Linux Programming, 4th Edition: in this book, exactly your code is explained with
sigaction()
nicely in "Chapter 11: Processes and Signals". - The sigaction documentation, including an example (quick learning).
- 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 forsigaction()
?
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
Java Switch Statement Multiple Cases
Annotations from Javax.Validation.Constraints Not Working
Fixedthreadpool VS Cachedthreadpool: the Lesser of Two Evils
Declaring Floats, Why Default Type Double
Error: Java_Home Is Not Defined Correctly Executing Maven
How to Achieve Conditional Resource Import in a Spring Xml Context
Block()/Blockfirst()/Blocklast() Are Blocking Error When Calling Bodytomono After Exchange()
Make Hibernate Ignore Instance Variables That Are Not Mapped
Log4J2 - Assigning File Appender Filename at Runtime
Compile Error: Package Javax.Servlet Does Not Exist
How to Pass C Structs Back and Forth to Java Code in Jni
Are There Any Other Java Libraries for Bonjour/Zeroconf Apart from Jmdns
What's the Difference Between a Resource, Uri, Url, Path and File in Java
Differencebetween a Hashmap and a Treemap
Installing Java on Os X 10.9 (Mavericks)
Add Multiple Items to an Already Initialized Arraylist in Java
What's the Purpose of Meta-Inf
What Is the Optimal Capacity and Load Factor for a Fixed-Size Hashmap