-
Notifications
You must be signed in to change notification settings - Fork 1
Bash shell Tests with Ctrl C
During fixing some bugs and adding additional functionality to tgftp I stumbled across the following interesting issue, which I still don't understand even after studying a lot of resources in the web.
The following two scripts work somewhat similar to tgftp. In principle you could exchange guc_test.bash
with tgftp and guc_call.bash
with the script that tgftp creates for the transfer (let's call it transfer_command) and which uses globus-url-copy (guc). tgftp calls the transfer command in the background and then uses wait
to actively wait for its termination.
NOTICE: Using this approach instead of running the child program in the foreground has the advantage, that you can interrupt the father even if the child intercepts
SIGINT
and does not exit. Hence if your child program cannot be interrupted, you can still get back to your shell by interrupting the father.
#!/bin/bash
./guc_call.bash &
wait $!
exit
#!/bin/bash
exec guc -dbg gsiftp://gridftp.omicron.jupiter/~/my_source_dir/* gsiftp://gridftp.omicron.neptune/~/my_destination_dir/ &>log.txt
exit
The interesting issue happens, when you hit Ctrl+C
during execution of tgftp, e.g. to interrupt a guc transfer and later continuing it - a functionality used by gtransfer.
NOTICE: When you hit
Ctrl+C
in your current shell session, by default the shell sends aSIGINT
to all processes in the foreground process group (see cracauer for more information). This is equivalent to sending aSIGINT
to the process group of your shell, e.g. if your current shell is a session leader and has the PID 1234, then you can mimic the behaviour ofCtrl+C
by usingkill -SIGINT -1234
. Please notice the-
in front of the PID, this is important, as it instructskill
to send theSIGINT
to the whole process group.
Although guc runs in the background it seems to receive a SIGINT
and is interrupted (compare the two printouts of ps -o pgid,ppid,pid,gid,ruser,cmd axf | egrep "user|PGID"
below). Don't get me wrong, this behaviour is actually very useful, but the issue is, I don't understand why.
PGID PPID PID GID RUSER CMD
12518 12517 12518 1100004 user \_ -bash
12910 12518 12910 1100004 user \_ /bin/bash ./guc_test.bash
12910 12910 12911 1100004 user \_ guc -dbg gsiftp://gridftp.omicron.jupiter/~/my_source_dir/* gsiftp://gridftp.omicron.neptune/~/my_destinatio
PGID PPID PID GID RUSER CMD
12518 12517 12518 1100004 user \_ -bash
If we now exchange guc with some simple C program, and repeat the test, we get the following results:
PGID PPID PID GID RUSER CMD
12518 12517 12518 1100004 user \_ -bash
13124 12518 13124 1100004 user \_ /bin/bash ./sleeper_test.bash
13124 13124 13125 1100004 user \_ ./sleeper
PGID PPID PID GID RUSER CMD
12518 12517 12518 1100004 user \_ -bash
13124 1 13125 1100004 user ./sleeper
This result conforms with the expected behaviour of Ctrl+C
, i.e. because sleeper
runs in the background it does not get a SIGINT
sent.
#!/bin/bash
./sleeper_call.bash &
wait $!
exit
#!/bin/bash
exec ./sleeper &>/dev/null
exit
#include <stdio.h>
#include <unistd.h>
int main()
{
sleep(60);
return(0);
}
All tests were done on a x86_64 machine running SLES10 and a bash 3.1.17(1). The tests were also repeated on another x86_64 machine running Ubuntu 11.04 and a bash 4.2.8(1). Interestingly the repeated tests done on Ubuntu show the same effect for both guc and sleeper: After hitting Ctrl+C
the father and the child exit. Quite strange...