s->timeout_usec = DEFAULT_TIMEOUT_USEC;
s->restart_usec = DEFAULT_RESTART_USEC;
+
+ s->watchdog_watch.type = WATCH_INVALID;
+
s->timer_watch.type = WATCH_INVALID;
#ifdef HAVE_SYSV_COMPAT
s->sysv_start_priority = -1;
static void service_stop_watchdog(Service *s) {
assert(s);
+ unit_unwatch_timer(UNIT(s), &s->watchdog_watch);
s->watchdog_timestamp.realtime = 0;
s->watchdog_timestamp.monotonic = 0;
}
+static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart);
+
+static void service_handle_watchdog(Service *s) {
+ usec_t offset;
+ int r;
+
+ assert(s);
+
+ if (s->watchdog_usec == 0)
+ return;
+
+ offset = now(CLOCK_MONOTONIC) - s->watchdog_timestamp.monotonic;
+ if (offset >= s->watchdog_usec) {
+ log_error("%s watchdog timeout!", UNIT(s)->id);
+ service_enter_dead(s, SERVICE_FAILURE_WATCHDOG, true);
+ return;
+ }
+
+ r = unit_watch_timer(UNIT(s), s->watchdog_usec - offset, &s->watchdog_watch);
+ if (r < 0)
+ log_warning("%s failed to install watchdog timer: %s", UNIT(s)->id, strerror(-r));
+}
+
static void service_reset_watchdog(Service *s) {
assert(s);
dual_timestamp_get(&s->watchdog_timestamp);
+ service_handle_watchdog(s);
}
static void service_done(Unit *u) {
unit_ref_unset(&s->accept_socket);
+ service_stop_watchdog(s);
+
unit_unwatch_timer(u, &s->timer_watch);
}
s->remain_after_exit = !s->pid_file;
s->guess_main_pid = false;
s->restart = SERVICE_RESTART_NO;
+ s->exec_context.ignore_sigpipe = false;
if (UNIT(s)->manager->sysv_console)
s->exec_context.std_output = EXEC_OUTPUT_JOURNAL_AND_CONSOLE;
if ((r = unit_watch_pid(UNIT(s), s->control_pid)) < 0)
return r;
+ if (s->deserialized_state == SERVICE_START_POST ||
+ s->deserialized_state == SERVICE_RUNNING)
+ service_handle_watchdog(s);
+
service_set_state(s, s->deserialized_state);
}
-
return 0;
}
goto fail;
}
+ if (s->watchdog_usec > 0)
+ if (asprintf(our_env + n_env++, "WATCHDOG_USEC=%llu", (unsigned long long) s->watchdog_usec) < 0) {
+ r = -ENOMEM;
+ goto fail;
+ }
+
if (!(final_env = strv_env_merge(2,
UNIT(s)->manager->environment,
our_env,
service_unwatch_control_pid(s);
+ if (s->watchdog_usec > 0)
+ service_reset_watchdog(s);
+
if ((s->control_command = s->exec_command[SERVICE_EXEC_START_POST])) {
s->control_command_id = SERVICE_EXEC_START_POST;
if (s->status_text)
unit_serialize_item(u, f, "status-text", s->status_text);
- /* There's a minor uncleanliness here: if there are multiple
- * commands attached here, we will start from the first one
- * again */
+ /* FIXME: There's a minor uncleanliness here: if there are
+ * multiple commands attached here, we will start from the
+ * first one again */
if (s->control_command_id >= 0)
unit_serialize_item(u, f, "control-command", service_exec_command_to_string(s->control_command_id));
else if (code == CLD_DUMPED)
f = SERVICE_FAILURE_CORE_DUMP;
else
- f = SERVICE_FAILURE_RESOURCES;
+ assert_not_reached("Unknown code");
if (s->main_pid == pid) {
/* Forking services may occasionally move to a new PID.
assert(s);
assert(elapsed == 1);
+ if (w == &s->watchdog_watch) {
+ service_handle_watchdog(s);
+ return;
+ }
+
assert(w == &s->timer_watch);
switch (s->state) {
[SERVICE_FAILURE_TIMEOUT] = "timeout",
[SERVICE_FAILURE_EXIT_CODE] = "exit-code",
[SERVICE_FAILURE_SIGNAL] = "signal",
- [SERVICE_FAILURE_CORE_DUMP] = "core-dump"
+ [SERVICE_FAILURE_CORE_DUMP] = "core-dump",
+ [SERVICE_FAILURE_WATCHDOG] = "watchdog"
};
DEFINE_STRING_TABLE_LOOKUP(service_result, ServiceResult);