I have a program which is supposed to handle SIGINT and gracefully shut down. When I run this program from a terminal without backgrounding it I can shut it down just fine using Ctrl-C. Inspecting the logs shows that everything worked as expected.
When I open a separate terminal and call kill -2 [pid]
or kill -s INT [pid]
it does nothing. I see nothing in the logs and the program continues to run as usual until I hit Ctrl-C in the terminal I launched it from.
Are there any differences between how Ctrl-C sends the signal and how kill does?
Additional Details:
The program in question is a Java application launched by a bash shell script which sets up some environment variables (namely CLASSPATH
) and then calls java [main class]
. Hitting Ctrl-Z and then running ps
results in the following:
$ ps -f
UID PID PPID C STIME TTY TIME CMD
mdeck 10251 10250 0 11:48 pts/2 00:00:00 -bash
mdeck 13405 10251 0 18:12 pts/2 00:00:00 /bin/bash /usr/local/bin/myapp.sh
mdeck 13509 13405 25 18:12 pts/2 00:00:03 java com.company.MyApp
mdeck 13526 10251 0 18:13 pts/2 00:00:00 ps -f
The output of stty as requested by Gilles is below:
$ stty -a </dev/pts/2
speed 38400 baud; rows 40; columns 203; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0;
-parenb -parodd cs8 -hupcl -cstopb cread -clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc -ixany -imaxbel -iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke
Best Answer
One possibility is that the program catches the Ctrl+C sequence. Check the output of
stty -a
; theintr
setting indicates which key combination (if any) sends a SIGINT signal, and theisig
indicates whether the signal keys are enabled (-isig
means they are disabled).If the program consists of several processes, pressing Ctrl+C sends SIGINT to all the processes in the process group. You can obtain the same effect by sending the signal to the process group instead of sending it to one of the processes. To send a signal to a process group, first determine its leader: that's the first process that starts all the others; if you run the process group in the background, that's the PID shown by
jobs -l
. The PID of the process group leader is the PGID (process group id); send the signal to its negative. E.g. if the PGID is 1234, runkill -INT -1234
.If the program consists of a wrapper script and a main application, there are two cases to consider. If there is no cleanup to do, so that the wrapper script terminates as soon as the main aplication terminates, make the wrapper script call
exec
:This way the application replaces the script, inheriting its PID. Some shells optimize a script that ends by executing another program, but not all. This approach doesn't work when the script needs to perform some cleanup such as removing temporary files.
Consider making the script detect a signal and transmitting the signal to the application. Here's a sketch of how this goes: