Skip to content

Commit e972ea5

Browse files
authored
Merge pull request #114 from pks-t/pks/pdeathsignal
Add '-p' flag to get signalled when parent dies
2 parents 5b117de + a500ee7 commit e972ea5

6 files changed

Lines changed: 172 additions & 3 deletions

File tree

README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,20 @@ closely to what happens when you do ctrl-C etc. in a terminal: The
175175
signal is sent to the foreground process group.
176176

177177

178+
### Parent Death Signal ###
179+
180+
Tini can set its parent death signal, which is the signal Tini should receive
181+
when *its* parent exits. To set the parent death signal, use the `-p` flag with
182+
the name of the signal Tini should receive when its parent exits:
183+
184+
```
185+
tini -p SIGTERM -- ...
186+
```
187+
188+
*NOTE: See [this PR discussion][12] to learn more about the parent death signal
189+
and use cases.*
190+
191+
178192
More
179193
----
180194

@@ -257,6 +271,7 @@ Contributors:
257271
+ [David Wragg][31]
258272
+ [Michael Crosby][32]
259273
+ [Wyatt Preul][33]
274+
+ [Patrick Steinhardt][34]
260275

261276
Special thanks to:
262277

@@ -268,10 +283,12 @@ Special thanks to:
268283
[5]: https://docs.docker.com/engine/reference/commandline/run/
269284
[10]: https://github.com/krallin/tini-images
270285
[11]: https://github.com/krallin/tini/releases
286+
[12]: https://github.com/krallin/tini/pull/114
271287
[20]: https://github.com/krallin/
272288
[30]: https://github.com/tianon
273289
[31]: https://github.com/dpw
274290
[32]: https://github.com/crosbymichael
275291
[33]: https://github.com/geek
292+
[34]: https://github.com/pks-t
276293
[40]: https://github.com/danilobuerger
277294
[41]: https://github.com/datakurre

src/tini.c

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,17 +50,51 @@ typedef struct {
5050
struct sigaction* const sigttou_action_ptr;
5151
} signal_configuration_t;
5252

53+
static const struct {
54+
char *const name;
55+
int number;
56+
} signal_names[] = {
57+
{ "SIGHUP", SIGHUP },
58+
{ "SIGINT", SIGINT },
59+
{ "SIGQUIT", SIGQUIT },
60+
{ "SIGILL", SIGILL },
61+
{ "SIGTRAP", SIGTRAP },
62+
{ "SIGABRT", SIGABRT },
63+
{ "SIGBUS", SIGBUS },
64+
{ "SIGFPE", SIGFPE },
65+
{ "SIGKILL", SIGKILL },
66+
{ "SIGUSR1", SIGUSR1 },
67+
{ "SIGSEGV", SIGSEGV },
68+
{ "SIGUSR2", SIGUSR2 },
69+
{ "SIGPIPE", SIGPIPE },
70+
{ "SIGALRM", SIGALRM },
71+
{ "SIGTERM", SIGTERM },
72+
{ "SIGCHLD", SIGCHLD },
73+
{ "SIGCONT", SIGCONT },
74+
{ "SIGSTOP", SIGSTOP },
75+
{ "SIGTSTP", SIGTSTP },
76+
{ "SIGTTIN", SIGTTIN },
77+
{ "SIGTTOU", SIGTTOU },
78+
{ "SIGURG", SIGURG },
79+
{ "SIGXCPU", SIGXCPU },
80+
{ "SIGXFSZ", SIGXFSZ },
81+
{ "SIGVTALRM", SIGVTALRM },
82+
{ "SIGPROF", SIGPROF },
83+
{ "SIGWINCH", SIGWINCH },
84+
{ "SIGSYS", SIGSYS },
85+
};
86+
5387
static unsigned int verbosity = DEFAULT_VERBOSITY;
5488

5589
static int32_t expect_status[(STATUS_MAX - STATUS_MIN + 1) / 32];
5690

5791
#ifdef PR_SET_CHILD_SUBREAPER
5892
#define HAS_SUBREAPER 1
59-
#define OPT_STRING "hvwgle:s"
93+
#define OPT_STRING "p:hvwgle:s"
6094
#define SUBREAPER_ENV_VAR "TINI_SUBREAPER"
6195
#else
6296
#define HAS_SUBREAPER 0
63-
#define OPT_STRING "hvwgle:"
97+
#define OPT_STRING "p:hvwgle:"
6498
#endif
6599

66100
#define VERBOSITY_ENV_VAR "TINI_VERBOSITY"
@@ -71,6 +105,7 @@ static int32_t expect_status[(STATUS_MAX - STATUS_MIN + 1) / 32];
71105
#if HAS_SUBREAPER
72106
static unsigned int subreaper = 0;
73107
#endif
108+
static unsigned int parent_death_signal = 0;
74109
static unsigned int kill_process_group = 0;
75110

76111
static unsigned int warn_on_reap = 0;
@@ -207,6 +242,7 @@ void print_usage(char* const name, FILE* const file) {
207242
#if HAS_SUBREAPER
208243
fprintf(file, " -s: Register as a process subreaper (requires Linux >= 3.4).\n");
209244
#endif
245+
fprintf(file, " -p SIGNAL: Trigger SIGNAL when parent dies, e.g. \"-p SIGKILL\".\n");
210246
fprintf(file, " -v: Generate more verbose output. Repeat up to 3 times.\n");
211247
fprintf(file, " -w: Print a warning when processes are getting reaped.\n");
212248
fprintf(file, " -g: Send signals to the child's process group.\n");
@@ -235,6 +271,20 @@ void print_license(FILE* const file) {
235271
}
236272
}
237273

274+
int set_pdeathsig(char* const arg) {
275+
size_t i;
276+
277+
for (i = 0; i < ARRAY_LEN(signal_names); i++) {
278+
if (strcmp(signal_names[i].name, arg) == 0) {
279+
/* Signals start at value "1" */
280+
parent_death_signal = signal_names[i].number;
281+
return 0;
282+
}
283+
}
284+
285+
return 1;
286+
}
287+
238288
int add_expect_status(char* arg) {
239289
long status = 0;
240290
char* endptr = NULL;
@@ -276,6 +326,14 @@ int parse_args(const int argc, char* const argv[], char* (**child_args_ptr_ptr)[
276326
subreaper++;
277327
break;
278328
#endif
329+
case 'p':
330+
if (set_pdeathsig(optarg)) {
331+
PRINT_FATAL("Not a valid option for -p: %s", optarg);
332+
*parse_fail_exitcode_ptr = 1;
333+
return 1;
334+
}
335+
break;
336+
279337
case 'v':
280338
verbosity++;
281339
break;
@@ -575,6 +633,12 @@ int main(int argc, char *argv[]) {
575633
return 1;
576634
}
577635

636+
/* Trigger signal on this process when the parent process exits. */
637+
if (parent_death_signal && prctl(PR_SET_PDEATHSIG, parent_death_signal)) {
638+
PRINT_FATAL("Failed to set up parent death signal");
639+
return 1;
640+
}
641+
578642
#if HAS_SUBREAPER
579643
/* If available and requested, register as a subreaper */
580644
if (register_subreaper()) {

test/pdeathsignal/stage_1.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#!/usr/bin/env python
2+
from __future__ import print_function
3+
4+
import os
5+
import sys
6+
import subprocess
7+
8+
9+
def main():
10+
pid = os.getpid()
11+
12+
tini = sys.argv[1]
13+
ret = sys.argv[2]
14+
stage_2 = os.path.join(os.path.dirname(__file__), "stage_2.py")
15+
16+
cmd = [
17+
tini,
18+
"-vvv",
19+
"-p",
20+
"SIGUSR1",
21+
"--",
22+
stage_2,
23+
str(pid),
24+
ret
25+
]
26+
27+
subprocess.Popen(cmd).wait()
28+
29+
if __name__ == "__main__":
30+
main()

test/pdeathsignal/stage_2.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#!/usr/bin/env python
2+
from __future__ import print_function
3+
4+
import os
5+
import sys
6+
import signal
7+
import time
8+
9+
10+
def main():
11+
ret = sys.argv[2]
12+
13+
def handler(*args):
14+
with open(ret, "w") as f:
15+
f.write("ok")
16+
sys.exit(0)
17+
18+
signal.signal(signal.SIGUSR1, handler)
19+
pid = int(sys.argv[1])
20+
21+
os.kill(pid, signal.SIGKILL)
22+
time.sleep(5)
23+
24+
if __name__ == "__main__":
25+
main()

test/run_inner_tests.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import bitmap
1010
import re
1111
import itertools
12+
import tempfile
1213

1314
DEVNULL = open(os.devnull, 'wb')
1415

@@ -133,7 +134,7 @@ def main():
133134
assert ret == 1, "Reaping test succeeded (it should have failed)!"
134135

135136
# Test that the signals are properly in place here.
136-
print "running signal configuration test"
137+
print "Running signal configuration test"
137138

138139
p = subprocess.Popen([os.path.join(build, "sigconf-test"), tini, "cat", "/proc/self/status"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
139140
out, err = p.communicate()
@@ -156,6 +157,21 @@ def main():
156157
# Use signum - 1 because the bitmap is 0-indexed but represents signals strting at 1
157158
assert (signum - 1) in props[signal_set_name].nonzero(), "{0} ({1}) is missing in {2}!".format(SIGNUM_TO_SIGNAME[signum], signum, signal_set_name)
158159

160+
# Test parent death signal handling.
161+
if not args_disabled:
162+
print "Running parent death signal test"
163+
f = tempfile.NamedTemporaryFile()
164+
try:
165+
p = subprocess.Popen(
166+
[os.path.join(src, "test", "pdeathsignal", "stage_1.py"), tini, f.name],
167+
stdout=DEVNULL, stderr=DEVNULL
168+
)
169+
p.wait()
170+
171+
busy_wait(lambda: open(f.name).read() == "ok", 10)
172+
finally:
173+
f.close()
174+
159175
print "---------------------------"
160176
print "All done, tests as expected"
161177
print "---------------------------"

tpl/README.md.in

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,20 @@ closely to what happens when you do ctrl-C etc. in a terminal: The
175175
signal is sent to the foreground process group.
176176

177177

178+
### Parent Death Signal ###
179+
180+
Tini can set its parent death signal, which is the signal Tini should receive
181+
when *its* parent exits. To set the parent death signal, use the `-p` flag with
182+
the name of the signal Tini should receive when its parent exits:
183+
184+
```
185+
tini -p SIGTERM -- ...
186+
```
187+
188+
*NOTE: See [this PR discussion][12] to learn more about the parent death signal
189+
and use cases.*
190+
191+
178192
More
179193
----
180194

@@ -257,6 +271,7 @@ Contributors:
257271
+ [David Wragg][31]
258272
+ [Michael Crosby][32]
259273
+ [Wyatt Preul][33]
274+
+ [Patrick Steinhardt][34]
260275

261276
Special thanks to:
262277

@@ -268,10 +283,12 @@ Special thanks to:
268283
[5]: https://docs.docker.com/engine/reference/commandline/run/
269284
[10]: https://github.com/krallin/tini-images
270285
[11]: https://github.com/krallin/tini/releases
286+
[12]: https://github.com/krallin/tini/pull/114
271287
[20]: https://github.com/krallin/
272288
[30]: https://github.com/tianon
273289
[31]: https://github.com/dpw
274290
[32]: https://github.com/crosbymichael
275291
[33]: https://github.com/geek
292+
[34]: https://github.com/pks-t
276293
[40]: https://github.com/danilobuerger
277294
[41]: https://github.com/datakurre

0 commit comments

Comments
 (0)