You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
85 lines
3.2 KiB
85 lines
3.2 KiB
From 2a0feeb4252cbf1207f45e978fe7eb02bb0182ec Mon Sep 17 00:00:00 2001 |
|
From: Kyle Walker <walker.kyle.t@gmail.com> |
|
Date: Thu, 30 Jun 2016 15:12:18 -0400 |
|
Subject: [PATCH] manager: Only invoke a single sigchld per unit within a |
|
cleanup cycle |
|
|
|
By default, each iteration of manager_dispatch_sigchld() results in a unit level |
|
sigchld event being invoked. For scope units, this results in a scope_sigchld_event() |
|
which can seemingly stall for workloads that have a large number of PIDs within the |
|
scope. The stall exhibits itself as a SIG_0 being initiated for each u->pids entry |
|
as a result of pid_is_unwaited(). |
|
|
|
v2: |
|
This patch resolves this condition by only paying to cost of a sigchld in the underlying |
|
scope unit once per sigchld iteration. A new "sigchldgen" member resides within the |
|
Unit struct. The Manager is incremented via the sd event loop, accessed via |
|
sd_event_get_iteration, and the Unit member is set to the same value as the manager each |
|
time that a sigchld event is invoked. If the Manager iteration value and Unit member |
|
match, the sigchld event is not invoked for that iteration. |
|
|
|
Cherry-picked from: 36f20ae3b2975e44b6ef17e453ae06a289e9a122 |
|
Resolves: #1342173 |
|
--- |
|
src/core/manager.c | 13 ++++++++++++- |
|
src/core/unit.c | 1 + |
|
src/core/unit.h | 3 +++ |
|
3 files changed, 16 insertions(+), 1 deletion(-) |
|
|
|
diff --git a/src/core/manager.c b/src/core/manager.c |
|
index e5226a8a6..63693b93a 100644 |
|
--- a/src/core/manager.c |
|
+++ b/src/core/manager.c |
|
@@ -1747,14 +1747,25 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t |
|
} |
|
|
|
static void invoke_sigchld_event(Manager *m, Unit *u, siginfo_t *si) { |
|
+ uint64_t iteration; |
|
+ |
|
assert(m); |
|
assert(u); |
|
assert(si); |
|
|
|
+ sd_event_get_iteration(m->event, &iteration); |
|
+ |
|
log_unit_debug(u->id, "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) { |
|
+ if (set_size(u->pids) <= 1 || iteration != u->sigchldgen) { |
|
+ UNIT_VTABLE(u)->sigchld_event(u, si->si_pid, si->si_code, si->si_status); |
|
+ u->sigchldgen = iteration; |
|
+ } else |
|
+ log_debug("%s already issued a sigchld this iteration %llu, skipping. Pids still being watched %d", u->id, iteration, set_size(u->pids)); |
|
+ } |
|
} |
|
|
|
static int manager_dispatch_sigchld(Manager *m) { |
|
diff --git a/src/core/unit.c b/src/core/unit.c |
|
index d6ead7d67..d62135d87 100644 |
|
--- a/src/core/unit.c |
|
+++ b/src/core/unit.c |
|
@@ -94,6 +94,7 @@ Unit *unit_new(Manager *m, size_t size) { |
|
u->unit_file_state = _UNIT_FILE_STATE_INVALID; |
|
u->unit_file_preset = -1; |
|
u->on_failure_job_mode = JOB_REPLACE; |
|
+ u->sigchldgen = 0; |
|
|
|
return u; |
|
} |
|
diff --git a/src/core/unit.h b/src/core/unit.h |
|
index 0eebc0b89..d93645777 100644 |
|
--- a/src/core/unit.h |
|
+++ b/src/core/unit.h |
|
@@ -167,6 +167,9 @@ struct Unit { |
|
* process SIGCHLD for */ |
|
Set *pids; |
|
|
|
+ /* Used in sigchld event invocation to avoid repeat events being invoked */ |
|
+ uint64_t sigchldgen; |
|
+ |
|
/* Used during GC sweeps */ |
|
unsigned gc_marker; |
|
|
|
|