Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for killing the whole child process group #15

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,24 @@ as PID 1.
and isn't registered as a subreaper. If you don't see a warning, you're fine.*


### Process group killing ###

By default, Tini only kills its immediate child process. This can be
inconvenient if sending a signal to that process does have the desired
effect. For example, if you do

docker run krallin/ubuntu-tini sh -c 'sleep 10'

and ctrl-C it, nothing happens: SIGINT is sent to the 'sh' process,
but that shell won't react to it while it is waiting for the 'sleep'
to finish.

With the `-g` option, Tini kills the child process group , so that
every process in the group gets the signal. This corresponds more
closely to what happens when you do ctrl-C etc. in a terminal: The
signal is sent to the foreground process group.


More
----

Expand Down
20 changes: 17 additions & 3 deletions src/tini.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,19 @@

#ifdef PR_SET_CHILD_SUBREAPER
#define HAS_SUBREAPER 1
#define OPT_STRING "hsv"
#define OPT_STRING "hsvg"
#define SUBREAPER_ENV_VAR "TINI_SUBREAPER"
#else
#define HAS_SUBREAPER 0
#define OPT_STRING "hv"
#define OPT_STRING "hvg"
#endif


#if HAS_SUBREAPER
static int subreaper = 0;
#endif
static int verbosity = 1;
static int kill_process_group;

static struct timespec ts = { .tv_sec = 1, .tv_nsec = 0 };

Expand Down Expand Up @@ -68,6 +69,13 @@ int spawn(const sigset_t* const child_sigset_ptr, char* const argv[], int* const
PRINT_FATAL("Setting child signal mask failed: '%s'", strerror(errno));
return 1;
}

// Put the child into a new process group
if (setpgid(0, 0) < 0) {
PRINT_FATAL("setpgid failed: '%s'", strerror(errno));
return 1;
}

execvp(argv[0], argv);
PRINT_FATAL("Executing child process '%s' failed: '%s'", argv[0], strerror(errno));
return 1;
Expand All @@ -89,6 +97,7 @@ void print_usage(char* const name, FILE* const file) {
fprintf(file, " -s: Register as a process subreaper (requires Linux >= 3.4).\n");
#endif
fprintf(file, " -v: Generate more verbose output. Repeat up to 3 times.\n");
fprintf(file, " -g: Send signals to the child's process group.\n");
fprintf(file, "\n");
}

Expand All @@ -112,6 +121,11 @@ int parse_args(const int argc, char* const argv[], char* (**child_args_ptr_ptr)[
case 'v':
verbosity++;
break;

case 'g':
kill_process_group++;
break;

case '?':
print_usage(name, stderr);
return 1;
Expand Down Expand Up @@ -242,7 +256,7 @@ int wait_and_forward_signal(sigset_t const* const parent_sigset_ptr, pid_t const
default:
PRINT_DEBUG("Passing signal: '%s'", strsignal(sig.si_signo));
/* Forward anything else */
if (kill(child_pid, sig.si_signo)) {
if (kill(kill_process_group ? -child_pid : child_pid, sig.si_signo)) {
if (errno == ESRCH) {
PRINT_WARNING("Child was dead when forwarding signal");
} else {
Expand Down
18 changes: 18 additions & 0 deletions tpl/README.md.in
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,24 @@ as PID 1.
and isn't registered as a subreaper. If you don't see a warning, you're fine.*


### Process group killing ###

By default, Tini only kills its immediate child process. This can be
inconvenient if sending a signal to that process does have the desired
effect. For example, if you do

docker run krallin/ubuntu-tini sh -c 'sleep 10'

and ctrl-C it, nothing happens: SIGINT is sent to the 'sh' process,
but that shell won't react to it while it is waiting for the 'sleep'
to finish.

With the `-g` option, Tini kills the child process group , so that
every process in the group gets the signal. This corresponds more
closely to what happens when you do ctrl-C etc. in a terminal: The
signal is sent to the foreground process group.


More
----

Expand Down