summaryrefslogtreecommitdiff
path: root/src/core/job.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/job.c')
-rw-r--r--src/core/job.c349
1 files changed, 220 insertions, 129 deletions
diff --git a/src/core/job.c b/src/core/job.c
index 734756b666..f635b7e933 100644
--- a/src/core/job.c
+++ b/src/core/job.c
@@ -10,10 +10,12 @@
#include "dbus-job.h"
#include "dbus.h"
#include "escape.h"
+#include "fileio.h"
#include "job.h"
#include "log.h"
#include "macro.h"
#include "parse-util.h"
+#include "serialize.h"
#include "set.h"
#include "special.h"
#include "stdio-util.h"
@@ -31,14 +33,15 @@ Job* job_new_raw(Unit *unit) {
assert(unit);
- j = new0(Job, 1);
+ j = new(Job, 1);
if (!j)
return NULL;
- j->manager = unit->manager;
- j->unit = unit;
- j->type = _JOB_TYPE_INVALID;
- j->reloaded = false;
+ *j = (Job) {
+ .manager = unit->manager,
+ .unit = unit,
+ .type = _JOB_TYPE_INVALID,
+ };
return j;
}
@@ -86,7 +89,7 @@ void job_unlink(Job *j) {
j->timer_event_source = sd_event_source_unref(j->timer_event_source);
}
-void job_free(Job *j) {
+Job* job_free(Job *j) {
assert(j);
assert(!j->installed);
assert(!j->transaction_prev);
@@ -99,7 +102,7 @@ void job_free(Job *j) {
sd_bus_track_unref(j->bus_track);
strv_free(j->deserialized_clients);
- free(j);
+ return mfree(j);
}
static void job_set_state(Job *j, JobState state) {
@@ -148,7 +151,7 @@ void job_uninstall(Job *j) {
unit_add_to_gc_queue(j->unit);
- hashmap_remove(j->manager->jobs, UINT32_TO_PTR(j->id));
+ hashmap_remove_value(j->manager->jobs, UINT32_TO_PTR(j->id), j);
j->installed = false;
}
@@ -174,7 +177,7 @@ static void job_merge_into_installed(Job *j, Job *other) {
assert(j->unit == other->unit);
if (j->type != JOB_NOP)
- job_type_merge_and_collapse(&j->type, other->type, j->unit);
+ assert_se(job_type_merge_and_collapse(&j->type, other->type, j->unit) == 0);
else
assert(other->type == JOB_NOP);
@@ -233,28 +236,36 @@ Job* job_install(Job *j) {
job_add_to_gc_queue(j);
+ job_add_to_dbus_queue(j); /* announce this job to clients */
+ unit_add_to_dbus_queue(j->unit); /* The Job property of the unit has changed now */
+
return j;
}
int job_install_deserialized(Job *j) {
Job **pj;
+ int r;
assert(!j->installed);
- if (j->type < 0 || j->type >= _JOB_TYPE_MAX_IN_TRANSACTION) {
- log_debug("Invalid job type %s in deserialization.", strna(job_type_to_string(j->type)));
- return -EINVAL;
- }
+ if (j->type < 0 || j->type >= _JOB_TYPE_MAX_IN_TRANSACTION)
+ return log_unit_debug_errno(j->unit, SYNTHETIC_ERRNO(EINVAL),
+ "Invalid job type %s in deserialization.",
+ strna(job_type_to_string(j->type)));
pj = (j->type == JOB_NOP) ? &j->unit->nop_job : &j->unit->job;
- if (*pj) {
- log_unit_debug(j->unit, "Unit already has a job installed. Not installing deserialized job.");
- return -EEXIST;
- }
+ if (*pj)
+ return log_unit_debug_errno(j->unit, SYNTHETIC_ERRNO(EEXIST),
+ "Unit already has a job installed. Not installing deserialized job.");
+
+ r = hashmap_put(j->manager->jobs, UINT32_TO_PTR(j->id), j);
+ if (r == -EEXIST)
+ return log_unit_debug_errno(j->unit, r, "Job ID %" PRIu32 " already used, cannot deserialize job.", j->id);
+ if (r < 0)
+ return log_unit_debug_errno(j->unit, r, "Failed to insert job into jobs hash table: %m");
*pj = j;
j->installed = true;
- j->reloaded = true;
if (j->state == JOB_RUNNING)
j->unit->manager->n_running_jobs++;
@@ -303,7 +314,7 @@ void job_dependency_free(JobDependency *l) {
free(l);
}
-void job_dump(Job *j, FILE*f, const char *prefix) {
+void job_dump(Job *j, FILE *f, const char *prefix) {
assert(j);
assert(f);
@@ -506,6 +517,95 @@ static void job_change_type(Job *j, JobType newtype) {
j->type = newtype;
}
+_pure_ static const char* job_get_begin_status_message_format(Unit *u, JobType t) {
+ const char *format;
+
+ assert(u);
+
+ if (t == JOB_RELOAD)
+ return "Reloading %s.";
+
+ assert(IN_SET(t, JOB_START, JOB_STOP));
+
+ format = UNIT_VTABLE(u)->status_message_formats.starting_stopping[t == JOB_STOP];
+ if (format)
+ return format;
+
+ /* Return generic strings */
+ if (t == JOB_START)
+ return "Starting %s.";
+ else {
+ assert(t == JOB_STOP);
+ return "Stopping %s.";
+ }
+}
+
+static void job_print_begin_status_message(Unit *u, JobType t) {
+ const char *format;
+
+ assert(u);
+
+ /* Reload status messages have traditionally not been printed to console. */
+ if (!IN_SET(t, JOB_START, JOB_STOP))
+ return;
+
+ format = job_get_begin_status_message_format(u, t);
+
+ DISABLE_WARNING_FORMAT_NONLITERAL;
+ unit_status_printf(u, "", format);
+ REENABLE_WARNING;
+}
+
+static void job_log_begin_status_message(Unit *u, uint32_t job_id, JobType t) {
+ const char *format, *mid;
+ char buf[LINE_MAX];
+
+ assert(u);
+ assert(t >= 0);
+ assert(t < _JOB_TYPE_MAX);
+
+ if (!IN_SET(t, JOB_START, JOB_STOP, JOB_RELOAD))
+ return;
+
+ if (log_on_console()) /* Skip this if it would only go on the console anyway */
+ return;
+
+ /* We log status messages for all units and all operations. */
+
+ format = job_get_begin_status_message_format(u, t);
+
+ DISABLE_WARNING_FORMAT_NONLITERAL;
+ (void) snprintf(buf, sizeof buf, format, unit_description(u));
+ REENABLE_WARNING;
+
+ mid = t == JOB_START ? "MESSAGE_ID=" SD_MESSAGE_UNIT_STARTING_STR :
+ t == JOB_STOP ? "MESSAGE_ID=" SD_MESSAGE_UNIT_STOPPING_STR :
+ "MESSAGE_ID=" SD_MESSAGE_UNIT_RELOADING_STR;
+
+ /* Note that we deliberately use LOG_MESSAGE() instead of
+ * LOG_UNIT_MESSAGE() here, since this is supposed to mimic
+ * closely what is written to screen using the status output,
+ * which is supposed the highest level, friendliest output
+ * possible, which means we should avoid the low-level unit
+ * name. */
+ log_struct(LOG_INFO,
+ LOG_MESSAGE("%s", buf),
+ "JOB_ID=%" PRIu32, job_id,
+ "JOB_TYPE=%s", job_type_to_string(t),
+ LOG_UNIT_ID(u),
+ LOG_UNIT_INVOCATION_ID(u),
+ mid);
+}
+
+static void job_emit_begin_status_message(Unit *u, uint32_t job_id, JobType t) {
+ assert(u);
+ assert(t >= 0);
+ assert(t < _JOB_TYPE_MAX);
+
+ job_log_begin_status_message(u, job_id, t);
+ job_print_begin_status_message(u, t);
+}
+
static int job_perform_on_unit(Job **j) {
uint32_t id;
Manager *m;
@@ -547,11 +647,12 @@ static int job_perform_on_unit(Job **j) {
assert_not_reached("Invalid job type");
}
- /* Log if the job still exists and the start/stop/reload function
- * actually did something. */
+ /* Log if the job still exists and the start/stop/reload function actually did something. Note that this means
+ * for units for which there's no 'activating' phase (i.e. because we transition directly from 'inactive' to
+ * 'active') we'll possibly skip the "Starting..." message. */
*j = manager_get_job(m, id);
if (*j && r > 0)
- unit_status_emit_starting_stopping_reloading(u, t);
+ job_emit_begin_status_message(u, id, t);
return r;
}
@@ -580,7 +681,9 @@ int job_run_and_invalidate(Job *j) {
switch (j->type) {
case JOB_VERIFY_ACTIVE: {
- UnitActiveState t = unit_active_state(j->unit);
+ UnitActiveState t;
+
+ t = unit_active_state(j->unit);
if (UNIT_IS_ACTIVE_OR_RELOADING(t))
r = -EALREADY;
else if (t == UNIT_ACTIVATING)
@@ -595,8 +698,7 @@ int job_run_and_invalidate(Job *j) {
case JOB_RESTART:
r = job_perform_on_unit(&j);
- /* If the unit type does not support starting/stopping,
- * then simply wait. */
+ /* If the unit type does not support starting/stopping, then simply wait. */
if (r == -EBADR)
r = 0;
break;
@@ -614,8 +716,12 @@ int job_run_and_invalidate(Job *j) {
}
if (j) {
- if (r == -EALREADY)
+ if (r == -EAGAIN)
+ job_set_state(j, JOB_WAITING); /* Hmm, not ready after all, let's return to JOB_WAITING state */
+ else if (r == -EALREADY) /* already being executed */
r = job_finish_and_invalidate(j, JOB_DONE, true, true);
+ else if (r == -ECOMM) /* condition failed, but all is good */
+ r = job_finish_and_invalidate(j, JOB_DONE, true, false);
else if (r == -EBADR)
r = job_finish_and_invalidate(j, JOB_SKIPPED, true, false);
else if (r == -ENOEXEC)
@@ -628,8 +734,6 @@ int job_run_and_invalidate(Job *j) {
r = job_finish_and_invalidate(j, JOB_DEPENDENCY, true, false);
else if (r == -ESTALE)
r = job_finish_and_invalidate(j, JOB_ONCE, true, false);
- else if (r == -EAGAIN)
- job_set_state(j, JOB_WAITING);
else if (r < 0)
r = job_finish_and_invalidate(j, JOB_FAILED, true, false);
}
@@ -637,7 +741,7 @@ int job_run_and_invalidate(Job *j) {
return r;
}
-_pure_ static const char *job_get_status_message_format(Unit *u, JobType t, JobResult result) {
+_pure_ static const char *job_get_done_status_message_format(Unit *u, JobType t, JobResult result) {
static const char *const generic_finished_start_job[_JOB_RESULT_MAX] = {
[JOB_DONE] = "Started %s.",
@@ -666,7 +770,6 @@ _pure_ static const char *job_get_status_message_format(Unit *u, JobType t, JobR
[JOB_SKIPPED] = "%s is not active.",
};
- const UnitStatusMessageFormats *format_table;
const char *format;
assert(u);
@@ -674,13 +777,11 @@ _pure_ static const char *job_get_status_message_format(Unit *u, JobType t, JobR
assert(t < _JOB_TYPE_MAX);
if (IN_SET(t, JOB_START, JOB_STOP, JOB_RESTART)) {
- format_table = &UNIT_VTABLE(u)->status_message_formats;
- if (format_table) {
- format = t == JOB_START ? format_table->finished_start_job[result] :
- format_table->finished_stop_job[result];
- if (format)
- return format;
- }
+ format = t == JOB_START ?
+ UNIT_VTABLE(u)->status_message_formats.finished_start_job[result] :
+ UNIT_VTABLE(u)->status_message_formats.finished_stop_job[result];
+ if (format)
+ return format;
}
/* Return generic strings */
@@ -698,7 +799,7 @@ _pure_ static const char *job_get_status_message_format(Unit *u, JobType t, JobR
static const struct {
const char *color, *word;
-} job_print_status_messages [_JOB_RESULT_MAX] = {
+} job_print_done_status_messages[_JOB_RESULT_MAX] = {
[JOB_DONE] = { ANSI_OK_COLOR, " OK " },
[JOB_TIMEOUT] = { ANSI_HIGHLIGHT_RED, " TIME " },
[JOB_FAILED] = { ANSI_HIGHLIGHT_RED, "FAILED" },
@@ -710,7 +811,7 @@ static const struct {
[JOB_ONCE] = { ANSI_HIGHLIGHT_RED, " ONCE " },
};
-static void job_print_status_message(Unit *u, JobType t, JobResult result) {
+static void job_print_done_status_message(Unit *u, JobType t, JobResult result) {
const char *format;
const char *status;
@@ -722,19 +823,23 @@ static void job_print_status_message(Unit *u, JobType t, JobResult result) {
if (t == JOB_RELOAD)
return;
- if (!job_print_status_messages[result].word)
+ /* No message if the job did not actually do anything due to failed condition. */
+ if (t == JOB_START && result == JOB_DONE && !u->condition_result)
return;
- format = job_get_status_message_format(u, t, result);
+ if (!job_print_done_status_messages[result].word)
+ return;
+
+ format = job_get_done_status_message_format(u, t, result);
if (!format)
return;
if (log_get_show_color())
- status = strjoina(job_print_status_messages[result].color,
- job_print_status_messages[result].word,
+ status = strjoina(job_print_done_status_messages[result].color,
+ job_print_done_status_messages[result].word,
ANSI_NORMAL);
else
- status = job_print_status_messages[result].word;
+ status = job_print_done_status_messages[result].word;
if (result != JOB_DONE)
manager_flip_auto_status(u->manager, true);
@@ -751,7 +856,7 @@ static void job_print_status_message(Unit *u, JobType t, JobResult result) {
}
}
-static void job_log_status_message(Unit *u, JobType t, JobResult result) {
+static void job_log_done_status_message(Unit *u, uint32_t job_id, JobType t, JobResult result) {
const char *format, *mid;
char buf[LINE_MAX];
static const int job_result_log_level[_JOB_RESULT_MAX] = {
@@ -774,10 +879,24 @@ static void job_log_status_message(Unit *u, JobType t, JobResult result) {
/* Skip printing if output goes to the console, and job_print_status_message()
will actually print something to the console. */
- if (log_on_console() && job_print_status_messages[result].word)
+ if (log_on_console() && job_print_done_status_messages[result].word)
+ return;
+
+ /* Show condition check message if the job did not actually do anything due to failed condition. */
+ if (t == JOB_START && result == JOB_DONE && !u->condition_result) {
+ log_struct(LOG_INFO,
+ "MESSAGE=Condition check resulted in %s being skipped.", unit_description(u),
+ "JOB_ID=%" PRIu32, job_id,
+ "JOB_TYPE=%s", job_type_to_string(t),
+ "JOB_RESULT=%s", job_result_to_string(result),
+ LOG_UNIT_ID(u),
+ LOG_UNIT_INVOCATION_ID(u),
+ "MESSAGE_ID=" SD_MESSAGE_UNIT_STARTED_STR);
+
return;
+ }
- format = job_get_status_message_format(u, t, result);
+ format = job_get_done_status_message_format(u, t, result);
if (!format)
return;
@@ -810,6 +929,7 @@ static void job_log_status_message(Unit *u, JobType t, JobResult result) {
default:
log_struct(job_result_log_level[result],
LOG_MESSAGE("%s", buf),
+ "JOB_ID=%" PRIu32, job_id,
"JOB_TYPE=%s", job_type_to_string(t),
"JOB_RESULT=%s", job_result_to_string(result),
LOG_UNIT_ID(u),
@@ -819,6 +939,7 @@ static void job_log_status_message(Unit *u, JobType t, JobResult result) {
log_struct(job_result_log_level[result],
LOG_MESSAGE("%s", buf),
+ "JOB_ID=%" PRIu32, job_id,
"JOB_TYPE=%s", job_type_to_string(t),
"JOB_RESULT=%s", job_result_to_string(result),
LOG_UNIT_ID(u),
@@ -826,15 +947,11 @@ static void job_log_status_message(Unit *u, JobType t, JobResult result) {
mid);
}
-static void job_emit_status_message(Unit *u, JobType t, JobResult result) {
+static void job_emit_done_status_message(Unit *u, uint32_t job_id, JobType t, JobResult result) {
assert(u);
- /* No message if the job did not actually do anything due to failed condition. */
- if (t == JOB_START && result == JOB_DONE && !u->condition_result)
- return;
-
- job_log_status_message(u, t, result);
- job_print_status_message(u, t, result);
+ job_log_done_status_message(u, job_id, t, result);
+ job_print_done_status_message(u, t, result);
}
static void job_fail_dependencies(Unit *u, UnitDependency d) {
@@ -856,19 +973,6 @@ static void job_fail_dependencies(Unit *u, UnitDependency d) {
}
}
-static int job_save_pending_finished_job(Job *j) {
- int r;
-
- assert(j);
-
- r = set_ensure_allocated(&j->manager->pending_finished_jobs, NULL);
- if (r < 0)
- return r;
-
- job_unlink(j);
- return set_put(j->manager->pending_finished_jobs, j);
-}
-
int job_finish_and_invalidate(Job *j, JobResult result, bool recursive, bool already) {
Unit *u;
Unit *other;
@@ -885,11 +989,11 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive, bool alr
j->result = result;
- log_unit_debug(u, "Job %s/%s finished, result=%s", u->id, job_type_to_string(t), job_result_to_string(result));
+ log_unit_debug(u, "Job %" PRIu32 " %s/%s finished, result=%s", j->id, u->id, job_type_to_string(t), job_result_to_string(result));
/* If this job did nothing to respective unit we don't log the status message */
if (!already)
- job_emit_status_message(u, t, result);
+ job_emit_done_status_message(u, j->id, t, result);
/* Patch restart jobs so that they become normal start jobs */
if (result == JOB_DONE && t == JOB_RESTART) {
@@ -908,11 +1012,7 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive, bool alr
j->manager->n_failed_jobs++;
job_uninstall(j);
- /* Keep jobs started before the reload to send singal later, free all others */
- if (!MANAGER_IS_RELOADING(j->manager) ||
- !j->reloaded ||
- job_save_pending_finished_job(j) < 0)
- job_free(j);
+ job_free(j);
/* Fail depending jobs on failure */
if (result != JOB_DONE && recursive) {
@@ -973,7 +1073,9 @@ static int job_dispatch_timer(sd_event_source *s, uint64_t monotonic, void *user
u = j->unit;
job_finish_and_invalidate(j, JOB_TIMEOUT, true, false);
- emergency_action(u->manager, u->job_timeout_action, u->job_timeout_reboot_arg, "job timed out");
+ emergency_action(u->manager, u->job_timeout_action,
+ EMERGENCY_ACTION_IS_WATCHDOG|EMERGENCY_ACTION_WARN,
+ u->job_timeout_reboot_arg, -1, "job timed out");
return 0;
}
@@ -1028,14 +1130,19 @@ int job_start_timer(Job *j, bool job_running) {
}
void job_add_to_run_queue(Job *j) {
+ int r;
+
assert(j);
assert(j->installed);
if (j->in_run_queue)
return;
- if (!j->manager->run_queue)
- sd_event_source_set_enabled(j->manager->run_queue_event_source, SD_EVENT_ONESHOT);
+ if (!j->manager->run_queue) {
+ r = sd_event_source_set_enabled(j->manager->run_queue_event_source, SD_EVENT_ONESHOT);
+ if (r < 0)
+ log_warning_errno(r, "Failed to enable job run queue event source, ignoring: %m");
+ }
LIST_PREPEND(run_queue, j->manager->run_queue, j);
j->in_run_queue = true;
@@ -1071,17 +1178,17 @@ int job_serialize(Job *j, FILE *f) {
assert(j);
assert(f);
- fprintf(f, "job-id=%u\n", j->id);
- fprintf(f, "job-type=%s\n", job_type_to_string(j->type));
- fprintf(f, "job-state=%s\n", job_state_to_string(j->state));
- fprintf(f, "job-irreversible=%s\n", yes_no(j->irreversible));
- fprintf(f, "job-sent-dbus-new-signal=%s\n", yes_no(j->sent_dbus_new_signal));
- fprintf(f, "job-ignore-order=%s\n", yes_no(j->ignore_order));
+ (void) serialize_item_format(f, "job-id", "%u", j->id);
+ (void) serialize_item(f, "job-type", job_type_to_string(j->type));
+ (void) serialize_item(f, "job-state", job_state_to_string(j->state));
+ (void) serialize_bool(f, "job-irreversible", j->irreversible);
+ (void) serialize_bool(f, "job-sent-dbus-new-signal", j->sent_dbus_new_signal);
+ (void) serialize_bool(f, "job-ignore-order", j->ignore_order);
if (j->begin_usec > 0)
- fprintf(f, "job-begin="USEC_FMT"\n", j->begin_usec);
+ (void) serialize_usec(f, "job-begin", j->begin_usec);
if (j->begin_running_usec > 0)
- fprintf(f, "job-begin-running="USEC_FMT"\n", j->begin_running_usec);
+ (void) serialize_usec(f, "job-begin-running", j->begin_running_usec);
bus_track_serialize(j->bus_track, f, "subscribed");
@@ -1091,24 +1198,26 @@ int job_serialize(Job *j, FILE *f) {
}
int job_deserialize(Job *j, FILE *f) {
+ int r;
+
assert(j);
assert(f);
for (;;) {
- char line[LINE_MAX], *l, *v;
+ _cleanup_free_ char *line = NULL;
+ char *l, *v;
size_t k;
- if (!fgets(line, sizeof(line), f)) {
- if (feof(f))
- return 0;
- return -errno;
- }
+ r = read_line(f, LONG_LINE_MAX, &line);
+ if (r < 0)
+ return log_error_errno(r, "Failed to read serialization line: %m");
+ if (r == 0)
+ return 0;
- char_array_0(line);
l = strstrip(line);
/* End marker */
- if (l[0] == 0)
+ if (isempty(l))
return 0;
k = strcspn(l, "=");
@@ -1122,16 +1231,16 @@ int job_deserialize(Job *j, FILE *f) {
if (streq(l, "job-id")) {
if (safe_atou32(v, &j->id) < 0)
- log_debug("Failed to parse job id value %s", v);
+ log_debug("Failed to parse job id value: %s", v);
} else if (streq(l, "job-type")) {
JobType t;
t = job_type_from_string(v);
if (t < 0)
- log_debug("Failed to parse job type %s", v);
+ log_debug("Failed to parse job type: %s", v);
else if (t >= _JOB_TYPE_MAX_IN_TRANSACTION)
- log_debug("Cannot deserialize job of type %s", v);
+ log_debug("Cannot deserialize job of type: %s", v);
else
j->type = t;
@@ -1140,7 +1249,7 @@ int job_deserialize(Job *j, FILE *f) {
s = job_state_from_string(v);
if (s < 0)
- log_debug("Failed to parse job state %s", v);
+ log_debug("Failed to parse job state: %s", v);
else
job_set_state(j, s);
@@ -1149,7 +1258,7 @@ int job_deserialize(Job *j, FILE *f) {
b = parse_boolean(v);
if (b < 0)
- log_debug("Failed to parse job irreversible flag %s", v);
+ log_debug("Failed to parse job irreversible flag: %s", v);
else
j->irreversible = j->irreversible || b;
@@ -1158,7 +1267,7 @@ int job_deserialize(Job *j, FILE *f) {
b = parse_boolean(v);
if (b < 0)
- log_debug("Failed to parse job sent_dbus_new_signal flag %s", v);
+ log_debug("Failed to parse job sent_dbus_new_signal flag: %s", v);
else
j->sent_dbus_new_signal = j->sent_dbus_new_signal || b;
@@ -1167,31 +1276,21 @@ int job_deserialize(Job *j, FILE *f) {
b = parse_boolean(v);
if (b < 0)
- log_debug("Failed to parse job ignore_order flag %s", v);
+ log_debug("Failed to parse job ignore_order flag: %s", v);
else
j->ignore_order = j->ignore_order || b;
- } else if (streq(l, "job-begin")) {
- unsigned long long ull;
-
- if (sscanf(v, "%llu", &ull) != 1)
- log_debug("Failed to parse job-begin value %s", v);
- else
- j->begin_usec = ull;
-
- } else if (streq(l, "job-begin-running")) {
- unsigned long long ull;
-
- if (sscanf(v, "%llu", &ull) != 1)
- log_debug("Failed to parse job-begin-running value %s", v);
- else
- j->begin_running_usec = ull;
+ } else if (streq(l, "job-begin"))
+ (void) deserialize_usec(v, &j->begin_usec);
- } else if (streq(l, "subscribed")) {
+ else if (streq(l, "job-begin-running"))
+ (void) deserialize_usec(v, &j->begin_running_usec);
+ else if (streq(l, "subscribed")) {
if (strv_extend(&j->deserialized_clients, v) < 0)
- log_oom();
- }
+ return log_oom();
+ } else
+ log_debug("Unknown job serialization key: %s", l);
}
}
@@ -1366,7 +1465,6 @@ bool job_may_gc(Job *j) {
* we start + other stop → gc
* we stop + other start → stay
* we stop + other stop → stay
- *
*/
return true;
@@ -1385,15 +1483,8 @@ void job_add_to_gc_queue(Job *j) {
j->in_gc_queue = true;
}
-static int job_compare(const void *a, const void *b) {
- Job *x = *(Job**) a, *y = *(Job**) b;
-
- if (x->id < y->id)
- return -1;
- if (x->id > y->id)
- return 1;
-
- return 0;
+static int job_compare(Job * const *a, Job * const *b) {
+ return CMP((*a)->id, (*b)->id);
}
static size_t sort_job_list(Job **list, size_t n) {
@@ -1401,7 +1492,7 @@ static size_t sort_job_list(Job **list, size_t n) {
size_t a, b;
/* Order by numeric IDs */
- qsort_safe(list, n, sizeof(Job*), job_compare);
+ typesafe_qsort(list, n, job_compare);
/* Filter out duplicates */
for (a = 0, b = 0; a < n; a++) {