diff options
author | Lennart Poettering <lennart@poettering.net> | 2016-08-15 18:12:01 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2016-08-22 16:14:21 +0200 |
commit | 05a98afd3e0513de50c5949b7fa50ff0989d68bc (patch) | |
tree | 74ef3320a2f75dac4285843098b2b33e5e0c817c /src/core/dbus-manager.c | |
parent | ecddb2b586d1b69e5538fb85262d2b9e6d253ac0 (diff) |
core: add Ref()/Unref() bus calls for units
This adds two (privileged) bus calls Ref() and Unref() to the Unit interface.
The two calls may be used by clients to pin a unit into memory, so that various
runtime properties aren't flushed out by the automatic GC. This is necessary
to permit clients to race-freely acquire runtime results (such as process exit
status/code or accumulated CPU time) on successful service termination.
Ref() and Unref() are fully recursive, hence act like the usual reference
counting concept in C. Taking a reference is a privileged operation, as this
allows pinning units into memory which consumes resources.
Transient units may also gain a reference at the time of creation, via the new
AddRef property (that is only defined for transient units at the time of
creation).
Diffstat (limited to 'src/core/dbus-manager.c')
-rw-r--r-- | src/core/dbus-manager.c | 57 |
1 files changed, 57 insertions, 0 deletions
diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index ef05a75a8b..ea7ced2fd0 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -643,6 +643,54 @@ static int method_set_unit_properties(sd_bus_message *message, void *userdata, s return bus_unit_method_set_properties(message, u, error); } +static int method_ref_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + const char *name; + Unit *u; + int r; + + assert(message); + assert(m); + + r = sd_bus_message_read(message, "s", &name); + if (r < 0) + return r; + + r = manager_load_unit(m, name, NULL, error, &u); + if (r < 0) + return r; + + r = bus_unit_check_load_state(u, error); + if (r < 0) + return r; + + return bus_unit_method_ref(message, u, error); +} + +static int method_unref_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + const char *name; + Unit *u; + int r; + + assert(message); + assert(m); + + r = sd_bus_message_read(message, "s", &name); + if (r < 0) + return r; + + r = manager_load_unit(m, name, NULL, error, &u); + if (r < 0) + return r; + + r = bus_unit_check_load_state(u, error); + if (r < 0) + return r; + + return bus_unit_method_unref(message, u, error); +} + static int reply_unit_info(sd_bus_message *reply, Unit *u) { _cleanup_free_ char *unit_path = NULL, *job_path = NULL; Unit *following; @@ -781,6 +829,13 @@ static int transient_unit_from_message( if (r < 0) return r; + /* If the client asked for it, automatically add a reference to this unit. */ + if (u->bus_track_add) { + r = bus_unit_track_add_sender(u, message); + if (r < 0) + return log_error_errno(r, "Failed to watch sender: %m"); + } + /* Now load the missing bits of the unit we just created */ unit_add_to_load_queue(u); manager_dispatch_load_queue(m); @@ -2211,6 +2266,8 @@ const sd_bus_vtable bus_manager_vtable[] = { SD_BUS_METHOD("KillUnit", "ssi", NULL, method_kill_unit, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("ResetFailedUnit", "s", NULL, method_reset_failed_unit, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("SetUnitProperties", "sba(sv)", NULL, method_set_unit_properties, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("RefUnit", "s", NULL, method_ref_unit, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("UnrefUnit", "s", NULL, method_unref_unit, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("StartTransientUnit", "ssa(sv)a(sa(sv))", "o", method_start_transient_unit, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("GetUnitProcesses", "s", "a(sus)", method_get_unit_processes, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("GetJob", "u", "o", method_get_job, SD_BUS_VTABLE_UNPRIVILEGED), |