diff options
author | Lennart Poettering <lennart@poettering.net> | 2016-11-15 19:32:50 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2016-11-16 15:03:26 +0100 |
commit | c5a97ed132b400ad82f7939d55fe1027a2b13f6e (patch) | |
tree | 924df71be2f04a66a30faccc54354d34c94f42ff /src/core/dbus-job.c | |
parent | 1a465207ab0a0b6756ab0d9305102d9159955a14 (diff) |
core: GC redundant device jobs from the run queue
In contrast to all other unit types device units when queued just track
external state, they cannot effect state changes on their own. Hence unless a
client or other job waits for them there's no reason to keep them in the job
queue. This adds a concept of GC'ing jobs of this type as soon as no client or
other job waits for them anymore.
To ensure this works correctly we need to track which clients actually
reference a job (i.e. which ones enqueued it). Unfortunately that's pretty
nasty to do for direct connections, as sd_bus_track doesn't work for
them. For now, work around this, by simply remembering in a boolean that a job
was requested by a direct connection, and reset it when we notice the direct
connection is gone. This means the GC logic works fine, except that jobs are
not immediately removed when direct connections disconnect.
In the longer term, a rework of the bus logic should fix this properly. For now
this should be good enough, as GC works for fine all cases except this one, and
thus is a clear improvement over the previous behaviour.
Fixes: #1921
Diffstat (limited to 'src/core/dbus-job.c')
-rw-r--r-- | src/core/dbus-job.c | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/src/core/dbus-job.c b/src/core/dbus-job.c index e8c69ed3e4..7888c163f1 100644 --- a/src/core/dbus-job.c +++ b/src/core/dbus-job.c @@ -191,3 +191,71 @@ void bus_job_send_removed_signal(Job *j) { if (r < 0) log_debug_errno(r, "Failed to send job remove signal for %u: %m", j->id); } + +static int bus_job_track_handler(sd_bus_track *t, void *userdata) { + Job *j = userdata; + + assert(t); + assert(j); + + j->bus_track = sd_bus_track_unref(j->bus_track); /* make sure we aren't called again */ + + /* Last client dropped off the bus, maybe we should GC this now? */ + job_add_to_gc_queue(j); + return 0; +} + +static int bus_job_allocate_bus_track(Job *j) { + int r; + + assert(j); + + if (j->bus_track) + return 0; + + r = sd_bus_track_new(j->unit->manager->api_bus, &j->bus_track, bus_job_track_handler, j); + if (r < 0) + return r; + + return 0; +} + +int bus_job_coldplug_bus_track(Job *j) { + int r = 0; + + assert(j); + + if (strv_isempty(j->deserialized_clients)) + goto finish; + + if (!j->manager->api_bus) + goto finish; + + r = bus_job_allocate_bus_track(j); + if (r < 0) + goto finish; + + r = bus_track_add_name_many(j->bus_track, j->deserialized_clients); + +finish: + j->deserialized_clients = strv_free(j->deserialized_clients); + return r; +} + +int bus_job_track_sender(Job *j, sd_bus_message *m) { + int r; + + assert(j); + assert(m); + + if (sd_bus_message_get_bus(m) != j->unit->manager->api_bus) { + j->ref_by_private_bus = true; + return 0; + } + + r = bus_job_allocate_bus_track(j); + if (r < 0) + return r; + + return sd_bus_track_add_sender(j->bus_track, m); +} |