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).
This commit is contained in:
Lennart Poettering
2016-08-22 16:14:21 +02:00
parent ecddb2b586
commit 05a98afd3e
14 changed files with 342 additions and 85 deletions
+39 -13
View File
@@ -329,6 +329,9 @@ bool unit_check_gc(Unit *u) {
if (u->refs)
return true;
if (sd_bus_track_count(u->bus_track) > 0)
return true;
if (UNIT_VTABLE(u)->check_gc)
if (UNIT_VTABLE(u)->check_gc(u))
return true;
@@ -509,6 +512,9 @@ void unit_free(Unit *u) {
sd_bus_slot_unref(u->match_bus_slot);
sd_bus_track_unref(u->bus_track);
u->deserialized_refs = strv_free(u->deserialized_refs);
unit_free_requires_mounts_for(u);
SET_FOREACH(t, u->names, i)
@@ -897,6 +903,7 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
Unit *following;
_cleanup_set_free_ Set *following_set = NULL;
int r;
const char *n;
assert(u);
assert(u->type >= 0);
@@ -1038,6 +1045,8 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
else if (u->load_state == UNIT_ERROR)
fprintf(f, "%s\tLoad Error Code: %s\n", prefix, strerror(-u->load_error));
for (n = sd_bus_track_first(u->bus_track); n; n = sd_bus_track_next(u->bus_track))
fprintf(f, "%s\tBus Ref: %s\n", prefix, n);
if (u->job)
job_dump(u->job, f, prefix2);
@@ -2622,15 +2631,17 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) {
if (gid_is_valid(u->ref_gid))
unit_serialize_item_format(u, f, "ref-gid", GID_FMT, u->ref_gid);
bus_track_serialize(u->bus_track, f, "ref");
if (serialize_jobs) {
if (u->job) {
fprintf(f, "job\n");
job_serialize(u->job, f, fds);
job_serialize(u->job, f);
}
if (u->nop_job) {
fprintf(f, "job\n");
job_serialize(u->nop_job, f, fds);
job_serialize(u->nop_job, f);
}
}
@@ -2760,7 +2771,7 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
if (!j)
return log_oom();
r = job_deserialize(j, f, fds);
r = job_deserialize(j, f);
if (r < 0) {
job_free(j);
return r;
@@ -2880,6 +2891,12 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
else
unit_ref_uid_gid(u, UID_INVALID, gid);
} else if (streq(l, "ref")) {
r = strv_extend(&u->deserialized_refs, v);
if (r < 0)
log_oom();
continue;
}
@@ -2955,7 +2972,8 @@ int unit_add_node_link(Unit *u, const char *what, bool wants, UnitDependency dep
}
int unit_coldplug(Unit *u) {
int r = 0, q = 0;
int r = 0, q;
char **i;
assert(u);
@@ -2966,18 +2984,26 @@ int unit_coldplug(Unit *u) {
u->coldplugged = true;
if (UNIT_VTABLE(u)->coldplug)
r = UNIT_VTABLE(u)->coldplug(u);
STRV_FOREACH(i, u->deserialized_refs) {
q = bus_unit_track_add_name(u, *i);
if (q < 0 && r >= 0)
r = q;
}
u->deserialized_refs = strv_free(u->deserialized_refs);
if (u->job)
if (UNIT_VTABLE(u)->coldplug) {
q = UNIT_VTABLE(u)->coldplug(u);
if (q < 0 && r >= 0)
r = q;
}
if (u->job) {
q = job_coldplug(u->job);
if (q < 0 && r >= 0)
r = q;
}
if (r < 0)
return r;
if (q < 0)
return q;
return 0;
return r;
}
static bool fragment_mtime_newer(const char *path, usec_t mtime) {