]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/timer.c
timer: make sure we restart timers even if units are still running or if one of their...
[thirdparty/systemd.git] / src / core / timer.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <errno.h>
23
24 #include "unit.h"
25 #include "unit-name.h"
26 #include "timer.h"
27 #include "dbus-timer.h"
28 #include "special.h"
29 #include "dbus-common.h"
30
31 static const UnitActiveState state_translation_table[_TIMER_STATE_MAX] = {
32 [TIMER_DEAD] = UNIT_INACTIVE,
33 [TIMER_WAITING] = UNIT_ACTIVE,
34 [TIMER_RUNNING] = UNIT_ACTIVE,
35 [TIMER_ELAPSED] = UNIT_ACTIVE,
36 [TIMER_FAILED] = UNIT_FAILED
37 };
38
39 static void timer_init(Unit *u) {
40 Timer *t = TIMER(u);
41
42 assert(u);
43 assert(u->load_state == UNIT_STUB);
44
45 t->next_elapse_monotonic = (usec_t) -1;
46 t->next_elapse_realtime = (usec_t) -1;
47 watch_init(&t->monotonic_watch);
48 watch_init(&t->realtime_watch);
49 }
50
51 void timer_free_values(Timer *t) {
52 TimerValue *v;
53
54 assert(t);
55
56 while ((v = t->values)) {
57 LIST_REMOVE(TimerValue, value, t->values, v);
58
59 if (v->calendar_spec)
60 calendar_spec_free(v->calendar_spec);
61
62 free(v);
63 }
64 }
65
66 static void timer_done(Unit *u) {
67 Timer *t = TIMER(u);
68
69 assert(t);
70
71 timer_free_values(t);
72
73 unit_unwatch_timer(u, &t->monotonic_watch);
74 unit_unwatch_timer(u, &t->realtime_watch);
75 }
76
77 static int timer_verify(Timer *t) {
78 assert(t);
79
80 if (UNIT(t)->load_state != UNIT_LOADED)
81 return 0;
82
83 if (!t->values) {
84 log_error_unit(UNIT(t)->id,
85 "%s lacks value setting. Refusing.", UNIT(t)->id);
86 return -EINVAL;
87 }
88
89 return 0;
90 }
91
92 static int timer_add_default_dependencies(Timer *t) {
93 int r;
94
95 assert(t);
96
97 r = unit_add_dependency_by_name(UNIT(t), UNIT_BEFORE, SPECIAL_TIMERS_TARGET, NULL, true);
98 if (r < 0)
99 return r;
100
101 if (UNIT(t)->manager->running_as == SYSTEMD_SYSTEM) {
102 r = unit_add_two_dependencies_by_name(UNIT(t), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true);
103 if (r < 0)
104 return r;
105 }
106
107 return unit_add_two_dependencies_by_name(UNIT(t), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
108 }
109
110 static int timer_load(Unit *u) {
111 Timer *t = TIMER(u);
112 int r;
113
114 assert(u);
115 assert(u->load_state == UNIT_STUB);
116
117 r = unit_load_fragment_and_dropin(u);
118 if (r < 0)
119 return r;
120
121 if (u->load_state == UNIT_LOADED) {
122
123 if (set_isempty(u->dependencies[UNIT_TRIGGERS])) {
124 Unit *x;
125
126 r = unit_load_related_unit(u, ".service", &x);
127 if (r < 0)
128 return r;
129
130 r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, x, true);
131 if (r < 0)
132 return r;
133 }
134
135 if (UNIT(t)->default_dependencies) {
136 r = timer_add_default_dependencies(t);
137 if (r < 0)
138 return r;
139 }
140 }
141
142 return timer_verify(t);
143 }
144
145 static void timer_dump(Unit *u, FILE *f, const char *prefix) {
146 Timer *t = TIMER(u);
147 Unit *trigger;
148 TimerValue *v;
149
150 trigger = UNIT_TRIGGER(u);
151
152 fprintf(f,
153 "%sTimer State: %s\n"
154 "%sResult: %s\n"
155 "%sUnit: %s\n",
156 prefix, timer_state_to_string(t->state),
157 prefix, timer_result_to_string(t->result),
158 prefix, trigger ? trigger->id : "n/a");
159
160 LIST_FOREACH(value, v, t->values) {
161
162 if (v->base == TIMER_CALENDAR) {
163 _cleanup_free_ char *p = NULL;
164
165 calendar_spec_to_string(v->calendar_spec, &p);
166
167 fprintf(f,
168 "%s%s: %s\n",
169 prefix,
170 timer_base_to_string(v->base),
171 strna(p));
172 } else {
173 char timespan1[FORMAT_TIMESPAN_MAX];
174
175 fprintf(f,
176 "%s%s: %s\n",
177 prefix,
178 timer_base_to_string(v->base),
179 strna(format_timespan(timespan1, sizeof(timespan1), v->value, 0)));
180 }
181 }
182 }
183
184 static void timer_set_state(Timer *t, TimerState state) {
185 TimerState old_state;
186 assert(t);
187
188 old_state = t->state;
189 t->state = state;
190
191 if (state != TIMER_WAITING) {
192 unit_unwatch_timer(UNIT(t), &t->monotonic_watch);
193 unit_unwatch_timer(UNIT(t), &t->realtime_watch);
194 }
195
196 if (state != old_state)
197 log_debug_unit(UNIT(t)->id,
198 "%s changed %s -> %s", UNIT(t)->id,
199 timer_state_to_string(old_state),
200 timer_state_to_string(state));
201
202 unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], true);
203 }
204
205 static void timer_enter_waiting(Timer *t, bool initial);
206
207 static int timer_coldplug(Unit *u) {
208 Timer *t = TIMER(u);
209
210 assert(t);
211 assert(t->state == TIMER_DEAD);
212
213 if (t->deserialized_state != t->state) {
214
215 if (t->deserialized_state == TIMER_WAITING)
216 timer_enter_waiting(t, false);
217 else
218 timer_set_state(t, t->deserialized_state);
219 }
220
221 return 0;
222 }
223
224 static void timer_enter_dead(Timer *t, TimerResult f) {
225 assert(t);
226
227 if (f != TIMER_SUCCESS)
228 t->result = f;
229
230 timer_set_state(t, t->result != TIMER_SUCCESS ? TIMER_FAILED : TIMER_DEAD);
231 }
232
233 static void timer_enter_waiting(Timer *t, bool initial) {
234 TimerValue *v;
235 usec_t base = 0;
236 dual_timestamp ts;
237 bool found_monotonic = false, found_realtime = false;
238 int r;
239
240 dual_timestamp_get(&ts);
241 t->next_elapse_monotonic = t->next_elapse_realtime = 0;
242
243 LIST_FOREACH(value, v, t->values) {
244
245 if (v->disabled)
246 continue;
247
248 if (v->base == TIMER_CALENDAR) {
249
250 r = calendar_spec_next_usec(v->calendar_spec, ts.realtime, &v->next_elapse);
251 if (r < 0)
252 continue;
253
254 if (!found_realtime)
255 t->next_elapse_realtime = v->next_elapse;
256 else
257 t->next_elapse_realtime = MIN(t->next_elapse_realtime, v->next_elapse);
258
259 found_realtime = true;
260
261 } else {
262 switch (v->base) {
263
264 case TIMER_ACTIVE:
265 if (state_translation_table[t->state] == UNIT_ACTIVE)
266 base = UNIT(t)->inactive_exit_timestamp.monotonic;
267 else
268 base = ts.monotonic;
269 break;
270
271 case TIMER_BOOT:
272 /* CLOCK_MONOTONIC equals the uptime on Linux */
273 base = 0;
274 break;
275
276 case TIMER_STARTUP:
277 base = UNIT(t)->manager->userspace_timestamp.monotonic;
278 break;
279
280 case TIMER_UNIT_ACTIVE:
281
282 base = UNIT_TRIGGER(UNIT(t))->inactive_exit_timestamp.monotonic;
283
284 if (base <= 0)
285 base = t->last_trigger_monotonic;
286
287 if (base <= 0)
288 continue;
289
290 break;
291
292 case TIMER_UNIT_INACTIVE:
293
294 base = UNIT_TRIGGER(UNIT(t))->inactive_enter_timestamp.monotonic;
295
296 if (base <= 0)
297 base = t->last_trigger_monotonic;
298
299 if (base <= 0)
300 continue;
301
302 break;
303
304 default:
305 assert_not_reached("Unknown timer base");
306 }
307
308 v->next_elapse = base + v->value;
309
310 if (!initial &&
311 v->next_elapse < ts.monotonic &&
312 (v->base == TIMER_ACTIVE || v->base == TIMER_BOOT || v->base == TIMER_STARTUP)) {
313 /* This is a one time trigger, disable it now */
314 v->disabled = true;
315 continue;
316 }
317
318 if (!found_monotonic)
319 t->next_elapse_monotonic = v->next_elapse;
320 else
321 t->next_elapse_monotonic = MIN(t->next_elapse_monotonic, v->next_elapse);
322
323 found_monotonic = true;
324 }
325 }
326
327 if (!found_monotonic && !found_realtime) {
328 log_debug_unit(UNIT(t)->id, "%s: Timer is elapsed.", UNIT(t)->id);
329 timer_set_state(t, TIMER_ELAPSED);
330 return;
331 }
332
333 if (found_monotonic) {
334 char buf[FORMAT_TIMESPAN_MAX];
335 log_debug_unit(UNIT(t)->id,
336 "%s: Monotonic timer elapses in %s.",
337 UNIT(t)->id,
338 format_timespan(buf, sizeof(buf), t->next_elapse_monotonic > ts.monotonic ? t->next_elapse_monotonic - ts.monotonic : 0, 0));
339
340 r = unit_watch_timer(UNIT(t), CLOCK_MONOTONIC, false, t->next_elapse_monotonic, &t->monotonic_watch);
341 if (r < 0)
342 goto fail;
343 } else
344 unit_unwatch_timer(UNIT(t), &t->monotonic_watch);
345
346 if (found_realtime) {
347 char buf[FORMAT_TIMESTAMP_MAX];
348 log_debug_unit(UNIT(t)->id,
349 "%s: Realtime timer elapses at %s.",
350 UNIT(t)->id,
351 format_timestamp(buf, sizeof(buf), t->next_elapse_realtime));
352
353 r = unit_watch_timer(UNIT(t), CLOCK_REALTIME, false, t->next_elapse_realtime, &t->realtime_watch);
354 if (r < 0)
355 goto fail;
356 } else
357 unit_unwatch_timer(UNIT(t), &t->realtime_watch);
358
359 timer_set_state(t, TIMER_WAITING);
360 return;
361
362 fail:
363 log_warning_unit(UNIT(t)->id,
364 "%s failed to enter waiting state: %s",
365 UNIT(t)->id, strerror(-r));
366 timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
367 }
368
369 static void timer_enter_running(Timer *t) {
370 DBusError error;
371 int r;
372
373 assert(t);
374 dbus_error_init(&error);
375
376 /* Don't start job if we are supposed to go down */
377 if (unit_pending_inactive(UNIT(t)))
378 return;
379
380 r = manager_add_job(UNIT(t)->manager, JOB_START, UNIT_TRIGGER(UNIT(t)),
381 JOB_REPLACE, true, &error, NULL);
382 if (r < 0)
383 goto fail;
384
385 t->last_trigger_monotonic = now(CLOCK_MONOTONIC);
386
387 timer_set_state(t, TIMER_RUNNING);
388 return;
389
390 fail:
391 log_warning_unit(UNIT(t)->id,
392 "%s failed to queue unit startup job: %s",
393 UNIT(t)->id, bus_error(&error, r));
394 timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
395
396 dbus_error_free(&error);
397 }
398
399 static int timer_start(Unit *u) {
400 Timer *t = TIMER(u);
401
402 assert(t);
403 assert(t->state == TIMER_DEAD || t->state == TIMER_FAILED);
404
405 if (UNIT_TRIGGER(u)->load_state != UNIT_LOADED)
406 return -ENOENT;
407
408 t->result = TIMER_SUCCESS;
409 timer_enter_waiting(t, true);
410 return 0;
411 }
412
413 static int timer_stop(Unit *u) {
414 Timer *t = TIMER(u);
415
416 assert(t);
417 assert(t->state == TIMER_WAITING || t->state == TIMER_RUNNING || t->state == TIMER_ELAPSED);
418
419 timer_enter_dead(t, TIMER_SUCCESS);
420 return 0;
421 }
422
423 static int timer_serialize(Unit *u, FILE *f, FDSet *fds) {
424 Timer *t = TIMER(u);
425
426 assert(u);
427 assert(f);
428 assert(fds);
429
430 unit_serialize_item(u, f, "state", timer_state_to_string(t->state));
431 unit_serialize_item(u, f, "result", timer_result_to_string(t->result));
432
433 return 0;
434 }
435
436 static int timer_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
437 Timer *t = TIMER(u);
438
439 assert(u);
440 assert(key);
441 assert(value);
442 assert(fds);
443
444 if (streq(key, "state")) {
445 TimerState state;
446
447 state = timer_state_from_string(value);
448 if (state < 0)
449 log_debug_unit(u->id, "Failed to parse state value %s", value);
450 else
451 t->deserialized_state = state;
452 } else if (streq(key, "result")) {
453 TimerResult f;
454
455 f = timer_result_from_string(value);
456 if (f < 0)
457 log_debug_unit(u->id, "Failed to parse result value %s", value);
458 else if (f != TIMER_SUCCESS)
459 t->result = f;
460
461 } else
462 log_debug_unit(u->id, "Unknown serialization key '%s'", key);
463
464 return 0;
465 }
466
467 static UnitActiveState timer_active_state(Unit *u) {
468 assert(u);
469
470 return state_translation_table[TIMER(u)->state];
471 }
472
473 static const char *timer_sub_state_to_string(Unit *u) {
474 assert(u);
475
476 return timer_state_to_string(TIMER(u)->state);
477 }
478
479 static void timer_timer_event(Unit *u, uint64_t elapsed, Watch *w) {
480 Timer *t = TIMER(u);
481
482 assert(t);
483 assert(elapsed == 1);
484
485 if (t->state != TIMER_WAITING)
486 return;
487
488 log_debug_unit(u->id, "Timer elapsed on %s", u->id);
489 timer_enter_running(t);
490 }
491
492 static void timer_trigger_notify(Unit *u, Unit *other) {
493 Timer *t = TIMER(u);
494 TimerValue *v;
495
496 assert(u);
497 assert(other);
498
499 if (other->load_state != UNIT_LOADED)
500 return;
501
502 /* Reenable all timers that depend on unit state */
503 LIST_FOREACH(value, v, t->values)
504 if (v->base == TIMER_UNIT_ACTIVE ||
505 v->base == TIMER_UNIT_INACTIVE)
506 v->disabled = false;
507
508 switch (t->state) {
509
510 case TIMER_WAITING:
511 case TIMER_ELAPSED:
512
513 /* Recalculate sleep time */
514 timer_enter_waiting(t, false);
515 break;
516
517 case TIMER_RUNNING:
518
519 if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other))) {
520 log_debug_unit(UNIT(t)->id,
521 "%s got notified about unit deactivation.",
522 UNIT(t)->id);
523 timer_enter_waiting(t, false);
524 }
525 break;
526
527 case TIMER_DEAD:
528 case TIMER_FAILED:
529 break;
530
531 default:
532 assert_not_reached("Unknown timer state");
533 }
534 }
535
536 static void timer_reset_failed(Unit *u) {
537 Timer *t = TIMER(u);
538
539 assert(t);
540
541 if (t->state == TIMER_FAILED)
542 timer_set_state(t, TIMER_DEAD);
543
544 t->result = TIMER_SUCCESS;
545 }
546
547 static void timer_time_change(Unit *u) {
548 Timer *t = TIMER(u);
549
550 assert(u);
551
552 if (t->state != TIMER_WAITING)
553 return;
554
555 log_debug_unit(u->id,
556 "%s: time change, recalculating next elapse.", u->id);
557 timer_enter_waiting(t, false);
558 }
559
560 static const char* const timer_state_table[_TIMER_STATE_MAX] = {
561 [TIMER_DEAD] = "dead",
562 [TIMER_WAITING] = "waiting",
563 [TIMER_RUNNING] = "running",
564 [TIMER_ELAPSED] = "elapsed",
565 [TIMER_FAILED] = "failed"
566 };
567
568 DEFINE_STRING_TABLE_LOOKUP(timer_state, TimerState);
569
570 static const char* const timer_base_table[_TIMER_BASE_MAX] = {
571 [TIMER_ACTIVE] = "OnActiveSec",
572 [TIMER_BOOT] = "OnBootSec",
573 [TIMER_STARTUP] = "OnStartupSec",
574 [TIMER_UNIT_ACTIVE] = "OnUnitActiveSec",
575 [TIMER_UNIT_INACTIVE] = "OnUnitInactiveSec",
576 [TIMER_CALENDAR] = "OnCalendar"
577 };
578
579 DEFINE_STRING_TABLE_LOOKUP(timer_base, TimerBase);
580
581 static const char* const timer_result_table[_TIMER_RESULT_MAX] = {
582 [TIMER_SUCCESS] = "success",
583 [TIMER_FAILURE_RESOURCES] = "resources"
584 };
585
586 DEFINE_STRING_TABLE_LOOKUP(timer_result, TimerResult);
587
588 const UnitVTable timer_vtable = {
589 .object_size = sizeof(Timer),
590 .sections =
591 "Unit\0"
592 "Timer\0"
593 "Install\0",
594
595 .init = timer_init,
596 .done = timer_done,
597 .load = timer_load,
598
599 .coldplug = timer_coldplug,
600
601 .dump = timer_dump,
602
603 .start = timer_start,
604 .stop = timer_stop,
605
606 .serialize = timer_serialize,
607 .deserialize_item = timer_deserialize_item,
608
609 .active_state = timer_active_state,
610 .sub_state_to_string = timer_sub_state_to_string,
611
612 .timer_event = timer_timer_event,
613
614 .trigger_notify = timer_trigger_notify,
615
616 .reset_failed = timer_reset_failed,
617 .time_change = timer_time_change,
618
619 .bus_interface = "org.freedesktop.systemd1.Timer",
620 .bus_message_handler = bus_timer_message_handler,
621 .bus_invalidating_properties = bus_timer_invalidating_properties
622 };