chiark / gitweb /
unit: rework stop pending logic
[elogind.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_stop_pending(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 };