| From 3af0a96c0fcc623bd16649fc3640396a657cf9ef Mon Sep 17 00:00:00 2001 |
| From: Yu Watanabe <watanabe.yu+github@gmail.com> |
| Date: Sun, 22 Jul 2018 23:10:02 +0900 |
| Subject: [PATCH] timedate: defer the property changed signal until job of |
| starting/stopping NTP service is finished |
| |
| Before this, the property changed signal is emitted immediately after |
| StartUnit/StopUnit method is called. So, the running state of the NTP |
| client service may not updated. |
| This makes the timing of emitting property changed signal is deferred |
| until job of starting/stopping NTP client service is completed. |
| |
| Fixes #9672. |
| --- |
| src/timedate/timedated.c | 78 ++++++++++++++++++++++++++++++++++++++++-------- |
| 1 file changed, 65 insertions(+), 13 deletions(-) |
| |
| diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c |
| index 6c95764..012cbe0 100644 |
| --- a/src/timedate/timedated.c |
| +++ b/src/timedate/timedated.c |
| @@ -46,6 +46,9 @@ typedef struct Context { |
| Hashmap *polkit_registry; |
| sd_bus_message *cache; |
| |
| + sd_bus_slot *slot_job_removed; |
| + char *path_ntp_unit; |
| + |
| LIST_HEAD(UnitStatusInfo, units); |
| } Context; |
| |
| @@ -74,6 +77,9 @@ static void context_free(Context *c) { |
| bus_verify_polkit_async_registry_free(c->polkit_registry); |
| sd_bus_message_unref(c->cache); |
| |
| + sd_bus_slot_unref(c->slot_job_removed); |
| + free(c->path_ntp_unit); |
| + |
| while ((p = c->units)) { |
| LIST_REMOVE(units, c->units, p); |
| unit_status_info_free(p); |
| @@ -345,17 +351,55 @@ static int context_update_ntp_status(Context *c, sd_bus *bus, sd_bus_message *m) |
| return 0; |
| } |
| |
| -static int unit_start_or_stop(UnitStatusInfo *u, sd_bus *bus, sd_bus_error *error, bool start) { |
| +static int match_job_removed(sd_bus_message *m, void *userdata, sd_bus_error *error) { |
| + const char *path; |
| + Context *c = userdata; |
| + int r; |
| + |
| + assert(c); |
| + assert(m); |
| + |
| + r = sd_bus_message_read(m, "uoss", NULL, &path, NULL, NULL); |
| + if (r < 0) { |
| + bus_log_parse_error(r); |
| + return 0; |
| + } |
| + |
| + if (!streq_ptr(path, c->path_ntp_unit)) |
| + return 0; |
| + |
| + (void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m), "/org/freedesktop/timedate1", "org.freedesktop.timedate1", "NTP", NULL); |
| + |
| + c->slot_job_removed = sd_bus_slot_unref(c->slot_job_removed); |
| + c->path_ntp_unit = mfree(c->path_ntp_unit); |
| + |
| + return 0; |
| +} |
| + |
| +static int unit_start_or_stop(Context *c, UnitStatusInfo *u, sd_bus *bus, sd_bus_error *error, bool start) { |
| + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; |
| + _cleanup_(sd_bus_slot_unrefp) sd_bus_slot *slot = NULL; |
| + const char *path; |
| int r; |
| |
| + assert(c); |
| assert(u); |
| assert(bus); |
| assert(error); |
| |
| - /* Call context_update_ntp_status() to update UnitStatusInfo before calling this. */ |
| + /* This method may be called frequently. Forget the previous job if it has not completed yet. */ |
| + c->slot_job_removed = sd_bus_slot_unref(c->slot_job_removed); |
| |
| - if (streq(u->active_state, "active") == start) |
| - return 0; |
| + r = sd_bus_match_signal_async( |
| + bus, |
| + &slot, |
| + "org.freedesktop.systemd1", |
| + "/org/freedesktop/systemd1", |
| + "org.freedesktop.systemd1.Manager", |
| + "JobRemoved", |
| + match_job_removed, NULL, c); |
| + if (r < 0) |
| + return r; |
| |
| r = sd_bus_call_method( |
| bus, |
| @@ -364,13 +408,22 @@ static int unit_start_or_stop(UnitStatusInfo *u, sd_bus *bus, sd_bus_error *erro |
| "org.freedesktop.systemd1.Manager", |
| start ? "StartUnit" : "StopUnit", |
| error, |
| - NULL, |
| + &reply, |
| "ss", |
| u->name, |
| "replace"); |
| if (r < 0) |
| return r; |
| |
| + r = sd_bus_message_read(reply, "o", &path); |
| + if (r < 0) |
| + return bus_log_parse_error(r); |
| + |
| + r = free_and_strdup(&c->path_ntp_unit, path); |
| + if (r < 0) |
| + return log_oom(); |
| + |
| + c->slot_job_removed = TAKE_PTR(slot); |
| return 0; |
| } |
| |
| @@ -422,8 +475,9 @@ static int unit_enable_or_disable(UnitStatusInfo *u, sd_bus *bus, sd_bus_error * |
| error, |
| NULL, |
| NULL); |
| - if (r < 0) |
| - return r; |
| + if (r < 0) |
| + return r; |
| + |
| return 0; |
| } |
| |
| @@ -813,7 +867,7 @@ static int method_set_ntp(sd_bus_message *m, void *userdata, sd_bus_error *error |
| if (q < 0) |
| r = q; |
| |
| - q = unit_start_or_stop(u, bus, error, enable); |
| + q = unit_start_or_stop(c, u, bus, error, enable); |
| if (q < 0) |
| r = q; |
| } |
| @@ -827,17 +881,17 @@ static int method_set_ntp(sd_bus_message *m, void *userdata, sd_bus_error *error |
| if (r < 0) |
| continue; |
| |
| - r = unit_start_or_stop(u, bus, error, enable); |
| + r = unit_start_or_stop(c, u, bus, error, enable); |
| break; |
| } |
| |
| - else if (context_ntp_service_is_active(c) <= 0) |
| + else |
| LIST_FOREACH(units, u, c->units) { |
| if (!streq(u->load_state, "loaded") || |
| !streq(u->unit_file_state, "enabled")) |
| continue; |
| |
| - r = unit_start_or_stop(u, bus, error, enable); |
| + r = unit_start_or_stop(c, u, bus, error, enable); |
| break; |
| } |
| |
| @@ -846,8 +900,6 @@ static int method_set_ntp(sd_bus_message *m, void *userdata, sd_bus_error *error |
| |
| log_info("Set NTP to %sd", enable_disable(enable)); |
| |
| - (void) sd_bus_emit_properties_changed(bus, "/org/freedesktop/timedate1", "org.freedesktop.timedate1", "NTP", NULL); |
| - |
| return sd_bus_reply_method_return(m, NULL); |
| } |
| |
| -- |
| 2.7.4 |
| |