]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/timer.c
Merge pull request #1419 from keszybz/shell-completion
[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 "bus-util.h"
30 #include "bus-error.h"
31
32 static const UnitActiveState state_translation_table[_TIMER_STATE_MAX] = {
33 [TIMER_DEAD] = UNIT_INACTIVE,
34 [TIMER_WAITING] = UNIT_ACTIVE,
35 [TIMER_RUNNING] = UNIT_ACTIVE,
36 [TIMER_ELAPSED] = UNIT_ACTIVE,
37 [TIMER_FAILED] = UNIT_FAILED
38 };
39
40 static int timer_dispatch(sd_event_source *s, uint64_t usec, void *userdata);
41
42 static void timer_init(Unit *u) {
43 Timer *t = TIMER(u);
44
45 assert(u);
46 assert(u->load_state == UNIT_STUB);
47
48 t->next_elapse_monotonic_or_boottime = USEC_INFINITY;
49 t->next_elapse_realtime = USEC_INFINITY;
50 t->accuracy_usec = u->manager->default_timer_accuracy_usec;
51 }
52
53 void timer_free_values(Timer *t) {
54 TimerValue *v;
55
56 assert(t);
57
58 while ((v = t->values)) {
59 LIST_REMOVE(value, t->values, v);
60 calendar_spec_free(v->calendar_spec);
61 free(v);
62 }
63 }
64
65 static void timer_done(Unit *u) {
66 Timer *t = TIMER(u);
67
68 assert(t);
69
70 timer_free_values(t);
71
72 t->monotonic_event_source = sd_event_source_unref(t->monotonic_event_source);
73 t->realtime_event_source = sd_event_source_unref(t->realtime_event_source);
74
75 free(t->stamp_path);
76 }
77
78 static int timer_verify(Timer *t) {
79 assert(t);
80
81 if (UNIT(t)->load_state != UNIT_LOADED)
82 return 0;
83
84 if (!t->values) {
85 log_unit_error(UNIT(t), "Timer unit lacks value setting. Refusing.");
86 return -EINVAL;
87 }
88
89 return 0;
90 }
91
92 static int timer_add_default_dependencies(Timer *t) {
93 int r;
94 TimerValue *v;
95
96 assert(t);
97
98 r = unit_add_dependency_by_name(UNIT(t), UNIT_BEFORE, SPECIAL_TIMERS_TARGET, NULL, true);
99 if (r < 0)
100 return r;
101
102 if (UNIT(t)->manager->running_as == MANAGER_SYSTEM) {
103 r = unit_add_two_dependencies_by_name(UNIT(t), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true);
104 if (r < 0)
105 return r;
106
107 LIST_FOREACH(value, v, t->values) {
108 if (v->base == TIMER_CALENDAR) {
109 r = unit_add_dependency_by_name(UNIT(t), UNIT_AFTER, SPECIAL_TIME_SYNC_TARGET, NULL, true);
110 if (r < 0)
111 return r;
112 break;
113 }
114 }
115 }
116
117 return unit_add_two_dependencies_by_name(UNIT(t), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
118 }
119
120 static int timer_setup_persistent(Timer *t) {
121 int r;
122
123 assert(t);
124
125 if (!t->persistent)
126 return 0;
127
128 if (UNIT(t)->manager->running_as == MANAGER_SYSTEM) {
129
130 r = unit_require_mounts_for(UNIT(t), "/var/lib/systemd/timers");
131 if (r < 0)
132 return r;
133
134 t->stamp_path = strappend("/var/lib/systemd/timers/stamp-", UNIT(t)->id);
135 } else {
136 const char *e;
137
138 e = getenv("XDG_DATA_HOME");
139 if (e)
140 t->stamp_path = strjoin(e, "/systemd/timers/stamp-", UNIT(t)->id, NULL);
141 else {
142
143 _cleanup_free_ char *h = NULL;
144
145 r = get_home_dir(&h);
146 if (r < 0)
147 return log_unit_error_errno(UNIT(t), r, "Failed to determine home directory: %m");
148
149 t->stamp_path = strjoin(h, "/.local/share/systemd/timers/stamp-", UNIT(t)->id, NULL);
150 }
151 }
152
153 if (!t->stamp_path)
154 return log_oom();
155
156 return 0;
157 }
158
159 static int timer_load(Unit *u) {
160 Timer *t = TIMER(u);
161 int r;
162
163 assert(u);
164 assert(u->load_state == UNIT_STUB);
165
166 r = unit_load_fragment_and_dropin(u);
167 if (r < 0)
168 return r;
169
170 if (u->load_state == UNIT_LOADED) {
171
172 if (set_isempty(u->dependencies[UNIT_TRIGGERS])) {
173 Unit *x;
174
175 r = unit_load_related_unit(u, ".service", &x);
176 if (r < 0)
177 return r;
178
179 r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, x, true);
180 if (r < 0)
181 return r;
182 }
183
184 r = timer_setup_persistent(t);
185 if (r < 0)
186 return r;
187
188 if (u->default_dependencies) {
189 r = timer_add_default_dependencies(t);
190 if (r < 0)
191 return r;
192 }
193 }
194
195 return timer_verify(t);
196 }
197
198 static void timer_dump(Unit *u, FILE *f, const char *prefix) {
199 char buf[FORMAT_TIMESPAN_MAX];
200 Timer *t = TIMER(u);
201 Unit *trigger;
202 TimerValue *v;
203
204 trigger = UNIT_TRIGGER(u);
205
206 fprintf(f,
207 "%sTimer State: %s\n"
208 "%sResult: %s\n"
209 "%sUnit: %s\n"
210 "%sPersistent: %s\n"
211 "%sWakeSystem: %s\n"
212 "%sAccuracy: %s\n",
213 prefix, timer_state_to_string(t->state),
214 prefix, timer_result_to_string(t->result),
215 prefix, trigger ? trigger->id : "n/a",
216 prefix, yes_no(t->persistent),
217 prefix, yes_no(t->wake_system),
218 prefix, format_timespan(buf, sizeof(buf), t->accuracy_usec, 1));
219
220 LIST_FOREACH(value, v, t->values) {
221
222 if (v->base == TIMER_CALENDAR) {
223 _cleanup_free_ char *p = NULL;
224
225 calendar_spec_to_string(v->calendar_spec, &p);
226
227 fprintf(f,
228 "%s%s: %s\n",
229 prefix,
230 timer_base_to_string(v->base),
231 strna(p));
232 } else {
233 char timespan1[FORMAT_TIMESPAN_MAX];
234
235 fprintf(f,
236 "%s%s: %s\n",
237 prefix,
238 timer_base_to_string(v->base),
239 format_timespan(timespan1, sizeof(timespan1), v->value, 0));
240 }
241 }
242 }
243
244 static void timer_set_state(Timer *t, TimerState state) {
245 TimerState old_state;
246 assert(t);
247
248 old_state = t->state;
249 t->state = state;
250
251 if (state != TIMER_WAITING) {
252 t->monotonic_event_source = sd_event_source_unref(t->monotonic_event_source);
253 t->realtime_event_source = sd_event_source_unref(t->realtime_event_source);
254 }
255
256 if (state != old_state)
257 log_unit_debug(UNIT(t), "Changed %s -> %s", timer_state_to_string(old_state), timer_state_to_string(state));
258
259 unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], true);
260 }
261
262 static void timer_enter_waiting(Timer *t, bool initial);
263
264 static int timer_coldplug(Unit *u) {
265 Timer *t = TIMER(u);
266
267 assert(t);
268 assert(t->state == TIMER_DEAD);
269
270 if (t->deserialized_state != t->state) {
271
272 if (t->deserialized_state == TIMER_WAITING)
273 timer_enter_waiting(t, false);
274 else
275 timer_set_state(t, t->deserialized_state);
276 }
277
278 return 0;
279 }
280
281 static void timer_enter_dead(Timer *t, TimerResult f) {
282 assert(t);
283
284 if (f != TIMER_SUCCESS)
285 t->result = f;
286
287 timer_set_state(t, t->result != TIMER_SUCCESS ? TIMER_FAILED : TIMER_DEAD);
288 }
289
290 static usec_t monotonic_to_boottime(usec_t t) {
291 usec_t a, b;
292
293 if (t <= 0)
294 return 0;
295
296 a = now(CLOCK_BOOTTIME);
297 b = now(CLOCK_MONOTONIC);
298
299 if (t + a > b)
300 return t + a - b;
301 else
302 return 0;
303 }
304
305 static void timer_enter_waiting(Timer *t, bool initial) {
306 bool found_monotonic = false, found_realtime = false;
307 usec_t ts_realtime, ts_monotonic;
308 usec_t base = 0;
309 TimerValue *v;
310 int r;
311
312 /* If we shall wake the system we use the boottime clock
313 * rather than the monotonic clock. */
314
315 ts_realtime = now(CLOCK_REALTIME);
316 ts_monotonic = now(t->wake_system ? CLOCK_BOOTTIME : CLOCK_MONOTONIC);
317 t->next_elapse_monotonic_or_boottime = t->next_elapse_realtime = 0;
318
319 LIST_FOREACH(value, v, t->values) {
320
321 if (v->disabled)
322 continue;
323
324 if (v->base == TIMER_CALENDAR) {
325 usec_t b;
326
327 /* If we know the last time this was
328 * triggered, schedule the job based relative
329 * to that. If we don't just start from
330 * now. */
331
332 b = t->last_trigger.realtime > 0 ? t->last_trigger.realtime : ts_realtime;
333
334 r = calendar_spec_next_usec(v->calendar_spec, b, &v->next_elapse);
335 if (r < 0)
336 continue;
337
338 if (!found_realtime)
339 t->next_elapse_realtime = v->next_elapse;
340 else
341 t->next_elapse_realtime = MIN(t->next_elapse_realtime, v->next_elapse);
342
343 found_realtime = true;
344
345 } else {
346 switch (v->base) {
347
348 case TIMER_ACTIVE:
349 if (state_translation_table[t->state] == UNIT_ACTIVE)
350 base = UNIT(t)->inactive_exit_timestamp.monotonic;
351 else
352 base = ts_monotonic;
353 break;
354
355 case TIMER_BOOT:
356 /* CLOCK_MONOTONIC equals the uptime on Linux */
357 base = 0;
358 break;
359
360 case TIMER_STARTUP:
361 base = UNIT(t)->manager->userspace_timestamp.monotonic;
362 break;
363
364 case TIMER_UNIT_ACTIVE:
365
366 base = UNIT_TRIGGER(UNIT(t))->inactive_exit_timestamp.monotonic;
367
368 if (base <= 0)
369 base = t->last_trigger.monotonic;
370
371 if (base <= 0)
372 continue;
373
374 break;
375
376 case TIMER_UNIT_INACTIVE:
377
378 base = UNIT_TRIGGER(UNIT(t))->inactive_enter_timestamp.monotonic;
379
380 if (base <= 0)
381 base = t->last_trigger.monotonic;
382
383 if (base <= 0)
384 continue;
385
386 break;
387
388 default:
389 assert_not_reached("Unknown timer base");
390 }
391
392 if (t->wake_system)
393 base = monotonic_to_boottime(base);
394
395 v->next_elapse = base + v->value;
396
397 if (!initial && v->next_elapse < ts_monotonic && IN_SET(v->base, TIMER_ACTIVE, TIMER_BOOT, TIMER_STARTUP)) {
398 /* This is a one time trigger, disable it now */
399 v->disabled = true;
400 continue;
401 }
402
403 if (!found_monotonic)
404 t->next_elapse_monotonic_or_boottime = v->next_elapse;
405 else
406 t->next_elapse_monotonic_or_boottime = MIN(t->next_elapse_monotonic_or_boottime, v->next_elapse);
407
408 found_monotonic = true;
409 }
410 }
411
412 if (!found_monotonic && !found_realtime) {
413 log_unit_debug(UNIT(t), "Timer is elapsed.");
414 timer_set_state(t, TIMER_ELAPSED);
415 return;
416 }
417
418 if (found_monotonic) {
419 char buf[FORMAT_TIMESPAN_MAX];
420
421 log_unit_debug(UNIT(t), "Monotonic timer elapses in %s.", format_timespan(buf, sizeof(buf), t->next_elapse_monotonic_or_boottime > ts_monotonic ? t->next_elapse_monotonic_or_boottime - ts_monotonic : 0, 0));
422
423 if (t->monotonic_event_source) {
424 r = sd_event_source_set_time(t->monotonic_event_source, t->next_elapse_monotonic_or_boottime);
425 if (r < 0)
426 goto fail;
427
428 r = sd_event_source_set_enabled(t->monotonic_event_source, SD_EVENT_ONESHOT);
429 if (r < 0)
430 goto fail;
431 } else {
432
433 r = sd_event_add_time(
434 UNIT(t)->manager->event,
435 &t->monotonic_event_source,
436 t->wake_system ? CLOCK_BOOTTIME_ALARM : CLOCK_MONOTONIC,
437 t->next_elapse_monotonic_or_boottime, t->accuracy_usec,
438 timer_dispatch, t);
439 if (r < 0)
440 goto fail;
441
442 (void) sd_event_source_set_description(t->monotonic_event_source, "timer-monotonic");
443 }
444
445 } else if (t->monotonic_event_source) {
446
447 r = sd_event_source_set_enabled(t->monotonic_event_source, SD_EVENT_OFF);
448 if (r < 0)
449 goto fail;
450 }
451
452 if (found_realtime) {
453 char buf[FORMAT_TIMESTAMP_MAX];
454 log_unit_debug(UNIT(t), "Realtime timer elapses at %s.", format_timestamp(buf, sizeof(buf), t->next_elapse_realtime));
455
456 if (t->realtime_event_source) {
457 r = sd_event_source_set_time(t->realtime_event_source, t->next_elapse_realtime);
458 if (r < 0)
459 goto fail;
460
461 r = sd_event_source_set_enabled(t->realtime_event_source, SD_EVENT_ONESHOT);
462 if (r < 0)
463 goto fail;
464 } else {
465 r = sd_event_add_time(
466 UNIT(t)->manager->event,
467 &t->realtime_event_source,
468 t->wake_system ? CLOCK_REALTIME_ALARM : CLOCK_REALTIME,
469 t->next_elapse_realtime, t->accuracy_usec,
470 timer_dispatch, t);
471 if (r < 0)
472 goto fail;
473
474 (void) sd_event_source_set_description(t->realtime_event_source, "timer-realtime");
475 }
476
477 } else if (t->realtime_event_source) {
478
479 r = sd_event_source_set_enabled(t->realtime_event_source, SD_EVENT_OFF);
480 if (r < 0)
481 goto fail;
482 }
483
484 timer_set_state(t, TIMER_WAITING);
485 return;
486
487 fail:
488 log_unit_warning_errno(UNIT(t), r, "Failed to enter waiting state: %m");
489 timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
490 }
491
492 static void timer_enter_running(Timer *t) {
493 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
494 int r;
495
496 assert(t);
497
498 /* Don't start job if we are supposed to go down */
499 if (unit_stop_pending(UNIT(t)))
500 return;
501
502 r = manager_add_job(UNIT(t)->manager, JOB_START, UNIT_TRIGGER(UNIT(t)),
503 JOB_REPLACE, true, &error, NULL);
504 if (r < 0)
505 goto fail;
506
507 dual_timestamp_get(&t->last_trigger);
508
509 if (t->stamp_path)
510 touch_file(t->stamp_path, true, t->last_trigger.realtime, UID_INVALID, GID_INVALID, 0);
511
512 timer_set_state(t, TIMER_RUNNING);
513 return;
514
515 fail:
516 log_unit_warning(UNIT(t), "Failed to queue unit startup job: %s", bus_error_message(&error, r));
517 timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
518 }
519
520 static int timer_start(Unit *u) {
521 Timer *t = TIMER(u);
522 TimerValue *v;
523
524 assert(t);
525 assert(t->state == TIMER_DEAD || t->state == TIMER_FAILED);
526
527 if (UNIT_TRIGGER(u)->load_state != UNIT_LOADED)
528 return -ENOENT;
529
530 t->last_trigger = DUAL_TIMESTAMP_NULL;
531
532 /* Reenable all timers that depend on unit activation time */
533 LIST_FOREACH(value, v, t->values)
534 if (v->base == TIMER_ACTIVE)
535 v->disabled = false;
536
537 if (t->stamp_path) {
538 struct stat st;
539
540 if (stat(t->stamp_path, &st) >= 0)
541 t->last_trigger.realtime = timespec_load(&st.st_atim);
542 else if (errno == ENOENT)
543 /* The timer has never run before,
544 * make sure a stamp file exists.
545 */
546 touch_file(t->stamp_path, true, USEC_INFINITY, UID_INVALID, GID_INVALID, 0);
547 }
548
549 t->result = TIMER_SUCCESS;
550 timer_enter_waiting(t, true);
551 return 1;
552 }
553
554 static int timer_stop(Unit *u) {
555 Timer *t = TIMER(u);
556
557 assert(t);
558 assert(t->state == TIMER_WAITING || t->state == TIMER_RUNNING || t->state == TIMER_ELAPSED);
559
560 timer_enter_dead(t, TIMER_SUCCESS);
561 return 1;
562 }
563
564 static int timer_serialize(Unit *u, FILE *f, FDSet *fds) {
565 Timer *t = TIMER(u);
566
567 assert(u);
568 assert(f);
569 assert(fds);
570
571 unit_serialize_item(u, f, "state", timer_state_to_string(t->state));
572 unit_serialize_item(u, f, "result", timer_result_to_string(t->result));
573
574 if (t->last_trigger.realtime > 0)
575 unit_serialize_item_format(u, f, "last-trigger-realtime", "%" PRIu64, t->last_trigger.realtime);
576
577 if (t->last_trigger.monotonic > 0)
578 unit_serialize_item_format(u, f, "last-trigger-monotonic", "%" PRIu64, t->last_trigger.monotonic);
579
580 return 0;
581 }
582
583 static int timer_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
584 Timer *t = TIMER(u);
585 int r;
586
587 assert(u);
588 assert(key);
589 assert(value);
590 assert(fds);
591
592 if (streq(key, "state")) {
593 TimerState state;
594
595 state = timer_state_from_string(value);
596 if (state < 0)
597 log_unit_debug(u, "Failed to parse state value: %s", value);
598 else
599 t->deserialized_state = state;
600 } else if (streq(key, "result")) {
601 TimerResult f;
602
603 f = timer_result_from_string(value);
604 if (f < 0)
605 log_unit_debug(u, "Failed to parse result value: %s", value);
606 else if (f != TIMER_SUCCESS)
607 t->result = f;
608 } else if (streq(key, "last-trigger-realtime")) {
609
610 r = safe_atou64(value, &t->last_trigger.realtime);
611 if (r < 0)
612 log_unit_debug(u, "Failed to parse last-trigger-realtime value: %s", value);
613
614 } else if (streq(key, "last-trigger-monotonic")) {
615
616 r = safe_atou64(value, &t->last_trigger.monotonic);
617 if (r < 0)
618 log_unit_debug(u, "Failed to parse last-trigger-monotonic value: %s", value);
619
620 } else
621 log_unit_debug(u, "Unknown serialization key: %s", key);
622
623 return 0;
624 }
625
626 _pure_ static UnitActiveState timer_active_state(Unit *u) {
627 assert(u);
628
629 return state_translation_table[TIMER(u)->state];
630 }
631
632 _pure_ static const char *timer_sub_state_to_string(Unit *u) {
633 assert(u);
634
635 return timer_state_to_string(TIMER(u)->state);
636 }
637
638 static int timer_dispatch(sd_event_source *s, uint64_t usec, void *userdata) {
639 Timer *t = TIMER(userdata);
640
641 assert(t);
642
643 if (t->state != TIMER_WAITING)
644 return 0;
645
646 log_unit_debug(UNIT(t), "Timer elapsed.");
647 timer_enter_running(t);
648 return 0;
649 }
650
651 static void timer_trigger_notify(Unit *u, Unit *other) {
652 Timer *t = TIMER(u);
653 TimerValue *v;
654
655 assert(u);
656 assert(other);
657
658 if (other->load_state != UNIT_LOADED)
659 return;
660
661 /* Reenable all timers that depend on unit state */
662 LIST_FOREACH(value, v, t->values)
663 if (v->base == TIMER_UNIT_ACTIVE ||
664 v->base == TIMER_UNIT_INACTIVE)
665 v->disabled = false;
666
667 switch (t->state) {
668
669 case TIMER_WAITING:
670 case TIMER_ELAPSED:
671
672 /* Recalculate sleep time */
673 timer_enter_waiting(t, false);
674 break;
675
676 case TIMER_RUNNING:
677
678 if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other))) {
679 log_unit_debug(UNIT(t), "Got notified about unit deactivation.");
680 timer_enter_waiting(t, false);
681 }
682 break;
683
684 case TIMER_DEAD:
685 case TIMER_FAILED:
686 break;
687
688 default:
689 assert_not_reached("Unknown timer state");
690 }
691 }
692
693 static void timer_reset_failed(Unit *u) {
694 Timer *t = TIMER(u);
695
696 assert(t);
697
698 if (t->state == TIMER_FAILED)
699 timer_set_state(t, TIMER_DEAD);
700
701 t->result = TIMER_SUCCESS;
702 }
703
704 static void timer_time_change(Unit *u) {
705 Timer *t = TIMER(u);
706
707 assert(u);
708
709 if (t->state != TIMER_WAITING)
710 return;
711
712 log_unit_debug(u, "Time change, recalculating next elapse.");
713 timer_enter_waiting(t, false);
714 }
715
716 static const char* const timer_base_table[_TIMER_BASE_MAX] = {
717 [TIMER_ACTIVE] = "OnActiveSec",
718 [TIMER_BOOT] = "OnBootSec",
719 [TIMER_STARTUP] = "OnStartupSec",
720 [TIMER_UNIT_ACTIVE] = "OnUnitActiveSec",
721 [TIMER_UNIT_INACTIVE] = "OnUnitInactiveSec",
722 [TIMER_CALENDAR] = "OnCalendar"
723 };
724
725 DEFINE_STRING_TABLE_LOOKUP(timer_base, TimerBase);
726
727 static const char* const timer_result_table[_TIMER_RESULT_MAX] = {
728 [TIMER_SUCCESS] = "success",
729 [TIMER_FAILURE_RESOURCES] = "resources"
730 };
731
732 DEFINE_STRING_TABLE_LOOKUP(timer_result, TimerResult);
733
734 const UnitVTable timer_vtable = {
735 .object_size = sizeof(Timer),
736
737 .sections =
738 "Unit\0"
739 "Timer\0"
740 "Install\0",
741 .private_section = "Timer",
742
743 .init = timer_init,
744 .done = timer_done,
745 .load = timer_load,
746
747 .coldplug = timer_coldplug,
748
749 .dump = timer_dump,
750
751 .start = timer_start,
752 .stop = timer_stop,
753
754 .serialize = timer_serialize,
755 .deserialize_item = timer_deserialize_item,
756
757 .active_state = timer_active_state,
758 .sub_state_to_string = timer_sub_state_to_string,
759
760 .trigger_notify = timer_trigger_notify,
761
762 .reset_failed = timer_reset_failed,
763 .time_change = timer_time_change,
764
765 .bus_vtable = bus_timer_vtable,
766 .bus_set_property = bus_timer_set_property,
767
768 .can_transient = true,
769 };