X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Flibelogind%2Fsd-event%2Fsd-event.c;h=383de48d55fb712aaf6bb00e05619cda66bdc7e6;hp=062f19b56790e0e27d7c1c99a2205a0c706aee2a;hb=971e2488dda5dbdfddc29adabc9a10590b084ba5;hpb=3b22396a4b2767a98172f6915929c47738cb0a1e diff --git a/src/libelogind/sd-event/sd-event.c b/src/libelogind/sd-event/sd-event.c index 062f19b56..383de48d5 100644 --- a/src/libelogind/sd-event/sd-event.c +++ b/src/libelogind/sd-event/sd-event.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -23,19 +21,24 @@ #include #include -#include "sd-id128.h" #include "sd-daemon.h" -#include "macro.h" -#include "prioq.h" +#include "sd-event.h" +#include "sd-id128.h" + +#include "alloc-util.h" +#include "fd-util.h" #include "hashmap.h" -#include "util.h" -#include "time-util.h" +#include "list.h" +#include "macro.h" #include "missing.h" +#include "prioq.h" +#include "process-util.h" #include "set.h" -#include "list.h" #include "signal-util.h" - -#include "sd-event.h" +#include "string-table.h" +#include "string-util.h" +#include "time-util.h" +#include "util.h" #define DEFAULT_ACCURACY_USEC (250 * USEC_PER_MSEC) @@ -56,6 +59,23 @@ typedef enum EventSourceType { _SOURCE_EVENT_SOURCE_TYPE_INVALID = -1 } EventSourceType; +static const char* const event_source_type_table[_SOURCE_EVENT_SOURCE_TYPE_MAX] = { + [SOURCE_IO] = "io", + [SOURCE_TIME_REALTIME] = "realtime", + [SOURCE_TIME_BOOTTIME] = "bootime", + [SOURCE_TIME_MONOTONIC] = "monotonic", + [SOURCE_TIME_REALTIME_ALARM] = "realtime-alarm", + [SOURCE_TIME_BOOTTIME_ALARM] = "boottime-alarm", + [SOURCE_SIGNAL] = "signal", + [SOURCE_CHILD] = "child", + [SOURCE_DEFER] = "defer", + [SOURCE_POST] = "post", + [SOURCE_EXIT] = "exit", + [SOURCE_WATCHDOG] = "watchdog", +}; + +DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(event_source_type, int); + /* All objects we use in epoll events start with this value, so that * we know how to dispatch it */ typedef enum WakeupType { @@ -89,8 +109,8 @@ struct sd_event_source { int64_t priority; unsigned pending_index; unsigned prepare_index; - unsigned pending_iteration; - unsigned prepare_iteration; + uint64_t pending_iteration; + uint64_t prepare_iteration; LIST_FIELDS(sd_event_source, sources); @@ -195,14 +215,14 @@ struct sd_event { pid_t original_pid; - unsigned iteration; - dual_timestamp timestamp; - usec_t timestamp_boottime; + uint64_t iteration; + triple_timestamp timestamp; int state; bool exit_requested:1; bool need_process_child:1; bool watchdog:1; + bool profile_delays:1; int exit_code; @@ -214,6 +234,9 @@ struct sd_event { unsigned n_sources; LIST_HEAD(sd_event_source, sources); + + usec_t last_run, last_log; + unsigned delays[sizeof(usec_t) * 8]; }; static void source_disconnect(sd_event_source *s); @@ -242,12 +265,6 @@ static int pending_prioq_compare(const void *a, const void *b) { if (x->pending_iteration > y->pending_iteration) return 1; - /* Stability for the rest */ - if (x < y) - return -1; - if (x > y) - return 1; - return 0; } @@ -257,6 +274,12 @@ static int prepare_prioq_compare(const void *a, const void *b) { assert(x->prepare); assert(y->prepare); + /* Enabled ones first */ + if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF) + return -1; + if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF) + return 1; + /* Move most recently prepared ones last, so that we can stop * preparing as soon as we hit one that has already been * prepared in the current iteration */ @@ -265,24 +288,12 @@ static int prepare_prioq_compare(const void *a, const void *b) { if (x->prepare_iteration > y->prepare_iteration) return 1; - /* Enabled ones first */ - if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF) - return -1; - if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF) - return 1; - /* Lower priority values first */ if (x->priority < y->priority) return -1; if (x->priority > y->priority) return 1; - /* Stability for the rest */ - if (x < y) - return -1; - if (x > y) - return 1; - return 0; } @@ -310,15 +321,13 @@ static int earliest_time_prioq_compare(const void *a, const void *b) { if (x->time.next > y->time.next) return 1; - /* Stability for the rest */ - if (x < y) - return -1; - if (x > y) - return 1; - return 0; } +static usec_t time_event_source_latest(const sd_event_source *s) { + return usec_add(s->time.next, s->time.accuracy); +} + static int latest_time_prioq_compare(const void *a, const void *b) { const sd_event_source *x = a, *y = b; @@ -338,15 +347,9 @@ static int latest_time_prioq_compare(const void *a, const void *b) { return 1; /* Order by time */ - if (x->time.next + x->time.accuracy < y->time.next + y->time.accuracy) + if (time_event_source_latest(x) < time_event_source_latest(y)) return -1; - if (x->time.next + x->time.accuracy > y->time.next + y->time.accuracy) - return 1; - - /* Stability for the rest */ - if (x < y) - return -1; - if (x > y) + if (time_event_source_latest(x) > time_event_source_latest(y)) return 1; return 0; @@ -370,12 +373,6 @@ static int exit_prioq_compare(const void *a, const void *b) { if (x->priority > y->priority) return 1; - /* Stability for the rest */ - if (x < y) - return -1; - if (x > y) - return 1; - return 0; } @@ -442,11 +439,9 @@ _public_ int sd_event_new(sd_event** ret) { e->original_pid = getpid(); e->perturb = USEC_INFINITY; - e->pending = prioq_new(pending_prioq_compare); - if (!e->pending) { - r = -ENOMEM; + r = prioq_ensure_allocated(&e->pending, pending_prioq_compare); + if (r < 0) goto fail; - } e->epoll_fd = epoll_create1(EPOLL_CLOEXEC); if (e->epoll_fd < 0) { @@ -454,6 +449,11 @@ _public_ int sd_event_new(sd_event** ret) { goto fail; } + if (secure_getenv("SD_EVENT_PROFILE_DELAYS")) { + log_debug("Event loop profiling enabled. Logarithmic histogram of event loop iterations in the range 2^0 ... 2^63 us will be logged every 5s."); + e->profile_delays = true; + } + *ret = e; return 0; @@ -463,7 +463,9 @@ fail: } _public_ sd_event* sd_event_ref(sd_event *e) { - assert_return(e, NULL); + + if (!e) + return NULL; assert(e->n_ref >= 1); e->n_ref++; @@ -508,7 +510,8 @@ static void source_io_unregister(sd_event_source *s) { r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, s->io.fd, NULL); if (r < 0) - log_debug_errno(errno, "Failed to remove source %s from epoll: %m", strna(s->description)); + log_debug_errno(errno, "Failed to remove source %s (type %s) from epoll: %m", + strna(s->description), event_source_type_to_string(s->type)); s->io.registered = false; } @@ -543,8 +546,7 @@ static int source_io_register( return 0; } -/// UNNEEDED by elogind -#if 0 +#if 0 /// UNNEEDED by elogind static clockid_t event_source_type_to_clock(EventSourceType t) { switch (t) { @@ -646,7 +648,7 @@ static int event_make_signal_data( if (sigismember(&d->sigset, sig) > 0) { if (ret) *ret = d; - return 0; + return 0; } } else { r = hashmap_ensure_allocated(&e->signal_data, &uint64_hash_ops); @@ -662,8 +664,10 @@ static int event_make_signal_data( d->priority = priority; r = hashmap_put(e->signal_data, &d->priority, d); - if (r < 0) + if (r < 0) { + free(d); return r; + } added = true; } @@ -691,7 +695,7 @@ static int event_make_signal_data( ev.data.ptr = d; r = epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, d->fd, &ev); - if (r < 0) { + if (r < 0) { r = -errno; goto fail; } @@ -838,7 +842,7 @@ static void source_disconnect(sd_event_source *s) { s->event->n_enabled_child_sources--; } - (void) hashmap_remove(s->event->child_sources, INT_TO_PTR(s->child.pid)); + (void) hashmap_remove(s->event->child_sources, PID_TO_PTR(s->child.pid)); event_gc_signal_data(s->event, &s->priority, SIGCHLD); } @@ -948,7 +952,7 @@ static sd_event_source *source_new(sd_event *e, bool floating, EventSourceType t sd_event_ref(e); LIST_PREPEND(sources, e->sources, s); - e->n_sources ++; + e->n_sources++; return s; } @@ -1065,31 +1069,30 @@ _public_ int sd_event_add_time( int r; assert_return(e, -EINVAL); - assert_return(usec != (uint64_t) -1, -EINVAL); assert_return(accuracy != (uint64_t) -1, -EINVAL); assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); assert_return(!event_pid_changed(e), -ECHILD); + if (!clock_supported(clock)) /* Checks whether the kernel supports the clock */ + return -EOPNOTSUPP; + + type = clock_to_event_source_type(clock); /* checks whether sd-event supports this clock */ + if (type < 0) + return -EOPNOTSUPP; + if (!callback) callback = time_exit_callback; - type = clock_to_event_source_type(clock); - assert_return(type >= 0, -EOPNOTSUPP); - d = event_get_clock_data(e, type); assert(d); - if (!d->earliest) { - d->earliest = prioq_new(earliest_time_prioq_compare); - if (!d->earliest) - return -ENOMEM; - } + r = prioq_ensure_allocated(&d->earliest, earliest_time_prioq_compare); + if (r < 0) + return r; - if (!d->latest) { - d->latest = prioq_new(latest_time_prioq_compare); - if (!d->latest) - return -ENOMEM; - } + r = prioq_ensure_allocated(&d->latest, latest_time_prioq_compare); + if (r < 0) + return r; if (d->fd < 0) { r = event_setup_timer_fd(e, d, clock); @@ -1147,8 +1150,7 @@ _public_ int sd_event_add_signal( int r; assert_return(e, -EINVAL); - assert_return(sig > 0, -EINVAL); - assert_return(sig < _NSIG, -EINVAL); + assert_return(SIGNAL_VALID(sig), -EINVAL); assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); assert_return(!event_pid_changed(e), -ECHILD); @@ -1156,8 +1158,8 @@ _public_ int sd_event_add_signal( callback = signal_exit_callback; r = pthread_sigmask(SIG_SETMASK, NULL, &ss); - if (r < 0) - return -errno; + if (r != 0) + return -r; if (!sigismember(&ss, sig)) return -EBUSY; @@ -1181,10 +1183,10 @@ _public_ int sd_event_add_signal( e->signal_sources[sig] = s; r = event_make_signal_data(e, sig, &d); - if (r < 0) { - source_free(s); - return r; - } + if (r < 0) { + source_free(s); + return r; + } /* Use the signal name as description for the event source by default */ (void) sd_event_source_set_description(s, signal_to_string(sig)); @@ -1195,6 +1197,7 @@ _public_ int sd_event_add_signal( return 0; } +#if 0 /// UNNEEDED by elogind _public_ int sd_event_add_child( sd_event *e, sd_event_source **ret, @@ -1218,7 +1221,7 @@ _public_ int sd_event_add_child( if (r < 0) return r; - if (hashmap_contains(e->child_sources, INT_TO_PTR(pid))) + if (hashmap_contains(e->child_sources, PID_TO_PTR(pid))) return -EBUSY; s = source_new(e, !ret, SOURCE_CHILD); @@ -1231,20 +1234,20 @@ _public_ int sd_event_add_child( s->userdata = userdata; s->enabled = SD_EVENT_ONESHOT; - r = hashmap_put(e->child_sources, INT_TO_PTR(pid), s); + r = hashmap_put(e->child_sources, PID_TO_PTR(pid), s); if (r < 0) { source_free(s); return r; } - e->n_enabled_child_sources ++; + e->n_enabled_child_sources++; r = event_make_signal_data(e, SIGCHLD, NULL); - if (r < 0) { + if (r < 0) { e->n_enabled_child_sources--; - source_free(s); - return r; - } + source_free(s); + return r; + } e->need_process_child = true; @@ -1287,6 +1290,7 @@ _public_ int sd_event_add_defer( return 0; } +#endif // 0 _public_ int sd_event_add_post( sd_event *e, @@ -1340,11 +1344,9 @@ _public_ int sd_event_add_exit( assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); assert_return(!event_pid_changed(e), -ECHILD); - if (!e->exit) { - e->exit = prioq_new(exit_prioq_compare); - if (!e->exit) - return -ENOMEM; - } + r = prioq_ensure_allocated(&e->exit, exit_prioq_compare); + if (r < 0) + return r; s = source_new(e, !ret, SOURCE_EXIT); if (!s) @@ -1367,10 +1369,11 @@ _public_ int sd_event_add_exit( return 0; } -/// UNNEEDED by elogind -#if 0 +#if 0 /// UNNEEDED by elogind _public_ sd_event_source* sd_event_source_ref(sd_event_source *s) { - assert_return(s, NULL); + + if (!s) + return NULL; assert(s->n_ref >= 1); s->n_ref++; @@ -1415,8 +1418,7 @@ _public_ int sd_event_source_set_description(sd_event_source *s, const char *des return free_and_strdup(&s->description, description); } -/// UNNEEDED by elogind -#if 0 +#if 0 /// UNNEEDED by elogind _public_ int sd_event_source_get_description(sd_event_source *s, const char **description) { assert_return(s, -EINVAL); assert_return(description, -EINVAL); @@ -1434,8 +1436,7 @@ _public_ sd_event *sd_event_source_get_event(sd_event_source *s) { return s->event; } -/// UNNEEDED by elogind -#if 0 +#if 0 /// UNNEEDED by elogind _public_ int sd_event_source_get_pending(sd_event_source *s) { assert_return(s, -EINVAL); assert_return(s->type != SOURCE_EXIT, -EDOM); @@ -1490,8 +1491,7 @@ _public_ int sd_event_source_set_io_fd(sd_event_source *s, int fd) { return 0; } -/// UNNEEDED by elogind -#if 0 +#if 0 /// UNNEEDED by elogind _public_ int sd_event_source_get_io_events(sd_event_source *s, uint32_t* events) { assert_return(s, -EINVAL); assert_return(events, -EINVAL); @@ -1528,8 +1528,7 @@ _public_ int sd_event_source_set_io_events(sd_event_source *s, uint32_t events) return 0; } -/// UNNEEDED by elogind -#if 0 +#if 0 /// UNNEEDED by elogind _public_ int sd_event_source_get_io_revents(sd_event_source *s, uint32_t* revents) { assert_return(s, -EINVAL); assert_return(revents, -EINVAL); @@ -1553,7 +1552,8 @@ _public_ int sd_event_source_get_priority(sd_event_source *s, int64_t *priority) assert_return(s, -EINVAL); assert_return(!event_pid_changed(s->event), -ECHILD); - return s->priority; + *priority = s->priority; + return 0; } #endif // 0 @@ -1585,7 +1585,7 @@ _public_ int sd_event_source_set_priority(sd_event_source *s, int64_t priority) event_unmask_signal_data(s->event, old, s->signal.sig); } else - s->priority = priority; + s->priority = priority; if (s->pending) prioq_reshuffle(s->event->pending, s, &s->pending_index); @@ -1599,8 +1599,7 @@ _public_ int sd_event_source_set_priority(sd_event_source *s, int64_t priority) return 0; } -/// UNNEEDED by elogind -#if 0 +#if 0 /// UNNEEDED by elogind _public_ int sd_event_source_get_enabled(sd_event_source *s, int *m) { assert_return(s, -EINVAL); assert_return(m, -EINVAL); @@ -1714,11 +1713,11 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) { s->enabled = m; r = event_make_signal_data(s->event, s->signal.sig, NULL); - if (r < 0) { - s->enabled = SD_EVENT_OFF; + if (r < 0) { + s->enabled = SD_EVENT_OFF; event_gc_signal_data(s->event, &s->priority, s->signal.sig); - return r; - } + return r; + } break; @@ -1730,12 +1729,12 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) { s->enabled = m; r = event_make_signal_data(s->event, SIGCHLD, NULL); - if (r < 0) { - s->enabled = SD_EVENT_OFF; + if (r < 0) { + s->enabled = SD_EVENT_OFF; s->event->n_enabled_child_sources--; event_gc_signal_data(s->event, &s->priority, SIGCHLD); - return r; - } + return r; + } break; @@ -1777,7 +1776,6 @@ _public_ int sd_event_source_set_time(sd_event_source *s, uint64_t usec) { struct clock_data *d; assert_return(s, -EINVAL); - assert_return(usec != (uint64_t) -1, -EINVAL); assert_return(EVENT_SOURCE_IS_TIME(s->type), -EDOM); assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE); assert_return(!event_pid_changed(s->event), -ECHILD); @@ -1796,8 +1794,7 @@ _public_ int sd_event_source_set_time(sd_event_source *s, uint64_t usec) { return 0; } -/// UNNEEDED by elogind -#if 0 +#if 0 /// UNNEEDED by elogind _public_ int sd_event_source_get_time_accuracy(sd_event_source *s, uint64_t *usec) { assert_return(s, -EINVAL); assert_return(usec, -EINVAL); @@ -1886,8 +1883,7 @@ _public_ int sd_event_source_set_prepare(sd_event_source *s, sd_event_handler_t return 0; } -/// UNNEEDED by elogind -#if 0 +#if 0 /// UNNEEDED by elogind _public_ void* sd_event_source_get_userdata(sd_event_source *s) { assert_return(s, NULL); @@ -1913,6 +1909,8 @@ static usec_t sleep_between(sd_event *e, usec_t a, usec_t b) { if (a <= 0) return 0; + if (a >= USEC_INFINITY) + return USEC_INFINITY; if (b <= a + 1) return a; @@ -2002,7 +2000,7 @@ static int event_arm_timer( d->needs_rearm = false; a = prioq_peek(d->earliest); - if (!a || a->enabled == SD_EVENT_OFF) { + if (!a || a->enabled == SD_EVENT_OFF || a->time.next == USEC_INFINITY) { if (d->fd < 0) return 0; @@ -2022,7 +2020,7 @@ static int event_arm_timer( b = prioq_peek(d->latest); assert_se(b && b->enabled != SD_EVENT_OFF); - t = sleep_between(e, a->time.next, b->time.next + b->time.accuracy); + t = sleep_between(e, a->time.next, time_event_source_latest(b)); if (d->next == t) return 0; @@ -2225,7 +2223,7 @@ static int process_signal(sd_event *e, struct signal_data *d, uint32_t events) { if (_unlikely_(n != sizeof(si))) return -EIO; - assert(si.ssi_signo < _NSIG); + assert(SIGNAL_VALID(si.ssi_signo)); read_one = true; @@ -2338,12 +2336,9 @@ static int source_dispatch(sd_event_source *s) { s->dispatching = false; - if (r < 0) { - if (s->description) - log_debug_errno(r, "Event source '%s' returned error, disabling: %m", s->description); - else - log_debug_errno(r, "Event source %p returned error, disabling: %m", s); - } + if (r < 0) + log_debug_errno(r, "Event source %s (type %s) returned error, disabling: %m", + strna(s->description), event_source_type_to_string(s->type)); if (s->n_ref == 0) source_free(s); @@ -2376,12 +2371,9 @@ static int event_prepare(sd_event *e) { r = s->prepare(s, s->userdata); s->dispatching = false; - if (r < 0) { - if (s->description) - log_debug_errno(r, "Prepare callback of event source '%s' returned error, disabling: %m", s->description); - else - log_debug_errno(r, "Prepare callback of event source %p returned error, disabling: %m", s); - } + if (r < 0) + log_debug_errno(r, "Prepare callback of event source %s (type %s) returned error, disabling: %m", + strna(s->description), event_source_type_to_string(s->type)); if (s->n_ref == 0) source_free(s); @@ -2486,7 +2478,9 @@ _public_ int sd_event_prepare(sd_event *e) { e->iteration++; + e->state = SD_EVENT_PREPARING; r = event_prepare(e); + e->state = SD_EVENT_INITIAL; if (r < 0) return r; @@ -2556,8 +2550,7 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) { goto finish; } - dual_timestamp_get(&e->timestamp); - e->timestamp_boottime = now(CLOCK_BOOTTIME); + triple_timestamp_get(&e->timestamp); for (i = 0; i < m; i++) { @@ -2569,7 +2562,7 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) { switch (*t) { case WAKEUP_EVENT_SOURCE: - r = process_io(e, ev_queue[i].data.ptr, ev_queue[i].events); + r = process_io(e, ev_queue[i].data.ptr, ev_queue[i].events); break; case WAKEUP_CLOCK_DATA: { @@ -2598,7 +2591,7 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) { if (r < 0) goto finish; - r = process_timer(e, e->timestamp_boottime, &e->boottime); + r = process_timer(e, e->timestamp.boottime, &e->boottime); if (r < 0) goto finish; @@ -2610,7 +2603,7 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) { if (r < 0) goto finish; - r = process_timer(e, e->timestamp_boottime, &e->boottime_alarm); + r = process_timer(e, e->timestamp.boottime, &e->boottime_alarm); if (r < 0) goto finish; @@ -2664,6 +2657,18 @@ _public_ int sd_event_dispatch(sd_event *e) { return 1; } +static void event_log_delays(sd_event *e) { + char b[ELEMENTSOF(e->delays) * DECIMAL_STR_MAX(unsigned) + 1]; + unsigned i; + int o; + + for (i = o = 0; i < ELEMENTSOF(e->delays); i++) { + o += snprintf(&b[o], sizeof(b) - o, "%u ", e->delays[i]); + e->delays[i] = 0; + } + log_debug("Event loop iterations: %.*s", o, b); +} + _public_ int sd_event_run(sd_event *e, uint64_t timeout) { int r; @@ -2672,11 +2677,30 @@ _public_ int sd_event_run(sd_event *e, uint64_t timeout) { assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); assert_return(e->state == SD_EVENT_INITIAL, -EBUSY); + if (e->profile_delays && e->last_run) { + usec_t this_run; + unsigned l; + + this_run = now(CLOCK_MONOTONIC); + + l = u64log2(this_run - e->last_run); + assert(l < sizeof(e->delays)); + e->delays[l]++; + + if (this_run - e->last_log >= 5*USEC_PER_SEC) { + event_log_delays(e); + e->last_log = this_run; + } + } + r = sd_event_prepare(e); if (r == 0) /* There was nothing? Then wait... */ r = sd_event_wait(e, timeout); + if (e->profile_delays) + e->last_run = now(CLOCK_MONOTONIC); + if (r > 0) { /* There's something now, then let's dispatch it */ r = sd_event_dispatch(e); @@ -2689,8 +2713,7 @@ _public_ int sd_event_run(sd_event *e, uint64_t timeout) { return r; } -/// UNNEEDED by elogind -#if 0 +#if 0 /// UNNEEDED by elogind _public_ int sd_event_loop(sd_event *e) { int r; @@ -2729,6 +2752,7 @@ _public_ int sd_event_get_state(sd_event *e) { return e->state; } +#if 0 /// UNNEEDED by elogind _public_ int sd_event_get_exit_code(sd_event *e, int *code) { assert_return(e, -EINVAL); assert_return(code, -EINVAL); @@ -2740,6 +2764,7 @@ _public_ int sd_event_get_exit_code(sd_event *e, int *code) { *code = e->exit_code; return 0; } +#endif // 0 _public_ int sd_event_exit(sd_event *e, int code) { assert_return(e, -EINVAL); @@ -2752,37 +2777,29 @@ _public_ int sd_event_exit(sd_event *e, int code) { return 0; } -/// UNNEEDED by elogind -#if 0 +#if 0 /// UNNEEDED by elogind _public_ int sd_event_now(sd_event *e, clockid_t clock, uint64_t *usec) { assert_return(e, -EINVAL); assert_return(usec, -EINVAL); assert_return(!event_pid_changed(e), -ECHILD); - if (!dual_timestamp_is_set(&e->timestamp)) { + if (!TRIPLE_TIMESTAMP_HAS_CLOCK(clock)) + return -EOPNOTSUPP; + + /* Generate a clean error in case CLOCK_BOOTTIME is not available. Note that don't use clock_supported() here, + * for a reason: there are systems where CLOCK_BOOTTIME is supported, but CLOCK_BOOTTIME_ALARM is not, but for + * the purpose of getting the time this doesn't matter. */ + if (IN_SET(clock, CLOCK_BOOTTIME, CLOCK_BOOTTIME_ALARM) && !clock_boottime_supported()) + return -EOPNOTSUPP; + + if (!triple_timestamp_is_set(&e->timestamp)) { /* Implicitly fall back to now() if we never ran * before and thus have no cached time. */ *usec = now(clock); return 1; } - switch (clock) { - - case CLOCK_REALTIME: - case CLOCK_REALTIME_ALARM: - *usec = e->timestamp.realtime; - break; - - case CLOCK_MONOTONIC: - *usec = e->timestamp.monotonic; - break; - - case CLOCK_BOOTTIME: - case CLOCK_BOOTTIME_ALARM: - *usec = e->timestamp_boottime; - break; - } - + *usec = triple_timestamp_by_clock(&e->timestamp, clock); return 0; } #endif // 0 @@ -2813,6 +2830,7 @@ _public_ int sd_event_default(sd_event **ret) { return 1; } +#if 0 /// UNNEEDED by elogind _public_ int sd_event_get_tid(sd_event *e, pid_t *tid) { assert_return(e, -EINVAL); assert_return(tid, -EINVAL); @@ -2825,6 +2843,7 @@ _public_ int sd_event_get_tid(sd_event *e, pid_t *tid) { return -ENXIO; } +#endif // 0 _public_ int sd_event_set_watchdog(sd_event *e, int b) { int r; @@ -2878,8 +2897,7 @@ fail: return r; } -/// UNNEEDED by elogind -#if 0 +#if 0 /// UNNEEDED by elogind _public_ int sd_event_get_watchdog(sd_event *e) { assert_return(e, -EINVAL); assert_return(!event_pid_changed(e), -ECHILD); @@ -2887,3 +2905,11 @@ _public_ int sd_event_get_watchdog(sd_event *e) { return e->watchdog; } #endif // 0 + +_public_ int sd_event_get_iteration(sd_event *e, uint64_t *ret) { + assert_return(e, -EINVAL); + assert_return(!event_pid_changed(e), -ECHILD); + + *ret = e->iteration; + return 0; +}