Skip to content

Bash shell Tests with Ctrl C

fscheiner edited this page Nov 21, 2014 · 14 revisions

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.

Test #1

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.

Used scripts:

guc_test.bash

#!/bin/bash                                                              

./guc_call.bash &

wait $!

exit

guc_call.bash

#!/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 a SIGINT to all processes in the foreground process group (see cracauer for more information). This is equivalent to sending a SIGINT 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 of Ctrl+C by using kill -SIGINT -1234. Please notice the - in front of the PID, this is important, as it instructs kill to send the SIGINT 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.

Before pressing Ctrl+C:

 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

After pressing Ctrl+C:

 PGID  PPID   PID     GID RUSER    CMD
12518 12517 12518 1100004 user          \_ -bash

Test #2

If we now exchange guc with some simple C program, and repeat the test, we get the following results:

Before pressing Ctrl+C:

 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

After pressing Ctrl+C:

 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.

Used scripts and source code:

sleeper_test.bash

#!/bin/bash                                                              

./sleeper_call.bash &

wait $!

exit

sleeper_call.bash

#!/bin/bash                                                              

exec ./sleeper &>/dev/null

exit

sleeper.c

#include <stdio.h>
#include <unistd.h>

int main()
{
        sleep(60);

        return(0);
}

Other information

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...