summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTejun Heo <htejun@fb.com>2016-03-25 11:38:50 -0400
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2016-03-26 12:06:06 -0400
commite57051f542080a4ec1d9e4e1c428b39defe9f098 (patch)
tree9f661a0897c78c10cb7f9bf993f770ffc16d8669
parentab2c3861dcbece00d1c03357556faced6e048de0 (diff)
downloadsystemd-e57051f542080a4ec1d9e4e1c428b39defe9f098.tar.gz
core: update invoke_sigchld_event() to handle NULL ->sigchld_event()
After receiving SIGCHLD, one of the ways manager_dispatch_sigchld() maps the now zombie $PID to its unit is through manager_get_unit_by_pid_cgroup() which reads /proc/$PID/cgroup and looks up the unit associated with the cgroup path. On non-unified cgroup hierarchies, a process is immediately migrated to the root cgroup on death and the cgroup lookup would always have returned the unit associated with it, making it rather pointless but safe. On unified hierarchy, a zombie remains associated with the cgroup that it was associated with at the time of death and thus manager_get_unit_by_pid_cgroup() will look up the unit properly. However, by the time manager_dispatch_sigchld() is running, the original cgroup may have become empty and it and its associated unit might already have been removed. If the cgroup path doesn't yield a match, manager_dispatch_sigchld() keeps pruning the leaf component. This means that the function may return a slice unit for a pid and as a slice doesn't have ->sigchld_event() handler, calling invoke_sigchld_event() on it causes a segfault. This patch updates invoke_sigchld_event() so that it skips calling if the handler is not set.
-rw-r--r--src/core/manager.c4
1 files changed, 3 insertions, 1 deletions
diff --git a/src/core/manager.c b/src/core/manager.c
index f13e933578..78f2a21061 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -1631,7 +1631,9 @@ static void invoke_sigchld_event(Manager *m, Unit *u, const siginfo_t *si) {
log_unit_debug(u, "Child "PID_FMT" belongs to %s", si->si_pid, u->id);
unit_unwatch_pid(u, si->si_pid);
- UNIT_VTABLE(u)->sigchld_event(u, si->si_pid, si->si_code, si->si_status);
+
+ if (UNIT_VTABLE(u)->sigchld_event)
+ UNIT_VTABLE(u)->sigchld_event(u, si->si_pid, si->si_code, si->si_status);
}
static int manager_dispatch_sigchld(Manager *m) {