X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Flibsystemd%2Fsd-event%2Fsd-event.c;h=a2935abd64903ed79d3b86a3fd271e9923a5db31;hb=f7f53e9e6ebb9f656d880f5e779fc174a1d983bf;hp=25dfd17d40a1d08f5e0c1a8aadb08f29cfe1ebc2;hpb=151b9b9662a90455262ce575a8a8ae74bf4ff336;p=elogind.git diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c index 25dfd17d4..a2935abd6 100644 --- a/src/libsystemd/sd-event/sd-event.c +++ b/src/libsystemd/sd-event/sd-event.c @@ -32,6 +32,8 @@ #include "util.h" #include "time-util.h" #include "missing.h" +#include "set.h" +#include "list.h" #include "sd-event.h" @@ -40,15 +42,23 @@ typedef enum EventSourceType { SOURCE_IO, - SOURCE_MONOTONIC, - SOURCE_REALTIME, + SOURCE_TIME_REALTIME, + SOURCE_TIME_BOOTTIME, + SOURCE_TIME_MONOTONIC, + SOURCE_TIME_REALTIME_ALARM, + SOURCE_TIME_BOOTTIME_ALARM, SOURCE_SIGNAL, SOURCE_CHILD, SOURCE_DEFER, + SOURCE_POST, SOURCE_EXIT, - SOURCE_WATCHDOG + SOURCE_WATCHDOG, + _SOURCE_EVENT_SOURCE_TYPE_MAX, + _SOURCE_EVENT_SOURCE_TYPE_INVALID = -1 } EventSourceType; +#define EVENT_SOURCE_IS_TIME(t) IN_SET((t), SOURCE_TIME_REALTIME, SOURCE_TIME_BOOTTIME, SOURCE_TIME_MONOTONIC, SOURCE_TIME_REALTIME_ALARM, SOURCE_TIME_BOOTTIME_ALARM) + struct sd_event_source { unsigned n_ref; @@ -56,10 +66,13 @@ struct sd_event_source { void *userdata; sd_event_handler_t prepare; - EventSourceType type:4; + char *name; + + EventSourceType type:5; int enabled:3; bool pending:1; bool dispatching:1; + bool floating:1; int64_t priority; unsigned pending_index; @@ -67,6 +80,8 @@ struct sd_event_source { unsigned pending_iteration; unsigned prepare_iteration; + LIST_FIELDS(sd_event_source, sources); + union { struct { sd_event_io_handler_t callback; @@ -95,6 +110,9 @@ struct sd_event_source { struct { sd_event_handler_t callback; } defer; + struct { + sd_event_handler_t callback; + } post; struct { sd_event_handler_t callback; unsigned prioq_index; @@ -102,30 +120,42 @@ struct sd_event_source { }; }; +struct clock_data { + int fd; + + /* For all clocks we maintain two priority queues each, one + * ordered for the earliest times the events may be + * dispatched, and one ordered by the latest times they must + * have been dispatched. The range between the top entries in + * the two prioqs is the time window we can freely schedule + * wakeups in */ + + Prioq *earliest; + Prioq *latest; + usec_t next; + + bool needs_rearm:1; +}; + struct sd_event { unsigned n_ref; int epoll_fd; int signal_fd; - int realtime_fd; - int monotonic_fd; int watchdog_fd; Prioq *pending; Prioq *prepare; - /* For both clocks we maintain two priority queues each, one - * ordered for the earliest times the events may be - * dispatched, and one ordered by the latest times they must - * have been dispatched. The range between the top entries in - * the two prioqs is the time window we can freely schedule - * wakeups in */ - Prioq *monotonic_earliest; - Prioq *monotonic_latest; - Prioq *realtime_earliest; - Prioq *realtime_latest; + /* timerfd_create() only supports these five clocks so far. We + * can add support for more clocks when the kernel learns to + * deal with them, too. */ + struct clock_data realtime; + struct clock_data boottime; + struct clock_data monotonic; + struct clock_data realtime_alarm; + struct clock_data boottime_alarm; - usec_t realtime_next, monotonic_next; usec_t perturb; sigset_t sigset; @@ -134,12 +164,15 @@ struct sd_event { Hashmap *child_sources; unsigned n_enabled_child_sources; + Set *post_sources; + Prioq *exit; pid_t original_pid; unsigned iteration; dual_timestamp timestamp; + usec_t timestamp_boottime; int state; bool exit_requested:1; @@ -154,8 +187,12 @@ struct sd_event { usec_t watchdog_last, watchdog_period; unsigned n_sources; + + LIST_HEAD(sd_event_source, sources); }; +static void source_disconnect(sd_event_source *s); + static int pending_prioq_compare(const void *a, const void *b) { const sd_event_source *x = a, *y = b; @@ -227,8 +264,8 @@ static int prepare_prioq_compare(const void *a, const void *b) { static int earliest_time_prioq_compare(const void *a, const void *b) { const sd_event_source *x = a, *y = b; - assert(x->type == SOURCE_MONOTONIC || x->type == SOURCE_REALTIME); - assert(y->type == SOURCE_MONOTONIC || y->type == SOURCE_REALTIME); + assert(EVENT_SOURCE_IS_TIME(x->type)); + assert(x->type == y->type); /* Enabled ones first */ if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF) @@ -260,8 +297,8 @@ static int earliest_time_prioq_compare(const void *a, const void *b) { static int latest_time_prioq_compare(const void *a, const void *b) { const sd_event_source *x = a, *y = b; - assert((x->type == SOURCE_MONOTONIC && y->type == SOURCE_MONOTONIC) || - (x->type == SOURCE_REALTIME && y->type == SOURCE_REALTIME)); + assert(EVENT_SOURCE_IS_TIME(x->type)); + assert(x->type == y->type); /* Enabled ones first */ if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF) @@ -317,39 +354,48 @@ static int exit_prioq_compare(const void *a, const void *b) { return 0; } +static void free_clock_data(struct clock_data *d) { + assert(d); + + safe_close(d->fd); + prioq_free(d->earliest); + prioq_free(d->latest); +} + static void event_free(sd_event *e) { + sd_event_source *s; + assert(e); + + while ((s = e->sources)) { + assert(s->floating); + source_disconnect(s); + sd_event_source_unref(s); + } + assert(e->n_sources == 0); if (e->default_event_ptr) *(e->default_event_ptr) = NULL; - if (e->epoll_fd >= 0) - close_nointr_nofail(e->epoll_fd); - - if (e->signal_fd >= 0) - close_nointr_nofail(e->signal_fd); + safe_close(e->epoll_fd); + safe_close(e->signal_fd); + safe_close(e->watchdog_fd); - if (e->realtime_fd >= 0) - close_nointr_nofail(e->realtime_fd); - - if (e->monotonic_fd >= 0) - close_nointr_nofail(e->monotonic_fd); - - if (e->watchdog_fd >= 0) - close_nointr_nofail(e->watchdog_fd); + free_clock_data(&e->realtime); + free_clock_data(&e->boottime); + free_clock_data(&e->monotonic); + free_clock_data(&e->realtime_alarm); + free_clock_data(&e->boottime_alarm); prioq_free(e->pending); prioq_free(e->prepare); - prioq_free(e->monotonic_earliest); - prioq_free(e->monotonic_latest); - prioq_free(e->realtime_earliest); - prioq_free(e->realtime_latest); prioq_free(e->exit); free(e->signal_sources); hashmap_free(e->child_sources); + set_free(e->post_sources); free(e); } @@ -364,9 +410,10 @@ _public_ int sd_event_new(sd_event** ret) { return -ENOMEM; e->n_ref = 1; - e->signal_fd = e->realtime_fd = e->monotonic_fd = e->watchdog_fd = e->epoll_fd = -1; - e->realtime_next = e->monotonic_next = (usec_t) -1; + e->signal_fd = e->watchdog_fd = e->epoll_fd = e->realtime.fd = e->boottime.fd = e->monotonic.fd = e->realtime_alarm.fd = e->boottime_alarm.fd = -1; + e->realtime.next = e->boottime.next = e->monotonic.next = e->realtime_alarm.next = e->boottime_alarm.next = USEC_INFINITY; e->original_pid = getpid(); + e->perturb = USEC_INFINITY; assert_se(sigemptyset(&e->sigset) == 0); @@ -470,78 +517,177 @@ static int source_io_register( return 0; } -static void source_free(sd_event_source *s) { +static clockid_t event_source_type_to_clock(EventSourceType t) { + + switch (t) { + + case SOURCE_TIME_REALTIME: + return CLOCK_REALTIME; + + case SOURCE_TIME_BOOTTIME: + return CLOCK_BOOTTIME; + + case SOURCE_TIME_MONOTONIC: + return CLOCK_MONOTONIC; + + case SOURCE_TIME_REALTIME_ALARM: + return CLOCK_REALTIME_ALARM; + + case SOURCE_TIME_BOOTTIME_ALARM: + return CLOCK_BOOTTIME_ALARM; + + default: + return (clockid_t) -1; + } +} + +static EventSourceType clock_to_event_source_type(clockid_t clock) { + + switch (clock) { + + case CLOCK_REALTIME: + return SOURCE_TIME_REALTIME; + + case CLOCK_BOOTTIME: + return SOURCE_TIME_BOOTTIME; + + case CLOCK_MONOTONIC: + return SOURCE_TIME_MONOTONIC; + + case CLOCK_REALTIME_ALARM: + return SOURCE_TIME_REALTIME_ALARM; + + case CLOCK_BOOTTIME_ALARM: + return SOURCE_TIME_BOOTTIME_ALARM; + + default: + return _SOURCE_EVENT_SOURCE_TYPE_INVALID; + } +} + +static struct clock_data* event_get_clock_data(sd_event *e, EventSourceType t) { + assert(e); + + switch (t) { + + case SOURCE_TIME_REALTIME: + return &e->realtime; + + case SOURCE_TIME_BOOTTIME: + return &e->boottime; + + case SOURCE_TIME_MONOTONIC: + return &e->monotonic; + + case SOURCE_TIME_REALTIME_ALARM: + return &e->realtime_alarm; + + case SOURCE_TIME_BOOTTIME_ALARM: + return &e->boottime_alarm; + + default: + return NULL; + } +} + +static void source_disconnect(sd_event_source *s) { + sd_event *event; + assert(s); - if (s->event) { - assert(s->event->n_sources > 0); + if (!s->event) + return; - switch (s->type) { + assert(s->event->n_sources > 0); - case SOURCE_IO: - if (s->io.fd >= 0) - source_io_unregister(s); + switch (s->type) { - break; + case SOURCE_IO: + if (s->io.fd >= 0) + source_io_unregister(s); - case SOURCE_MONOTONIC: - prioq_remove(s->event->monotonic_earliest, s, &s->time.earliest_index); - prioq_remove(s->event->monotonic_latest, s, &s->time.latest_index); - break; + break; - case SOURCE_REALTIME: - prioq_remove(s->event->realtime_earliest, s, &s->time.earliest_index); - prioq_remove(s->event->realtime_latest, s, &s->time.latest_index); - break; + case SOURCE_TIME_REALTIME: + case SOURCE_TIME_BOOTTIME: + case SOURCE_TIME_MONOTONIC: + case SOURCE_TIME_REALTIME_ALARM: + case SOURCE_TIME_BOOTTIME_ALARM: { + struct clock_data *d; - case SOURCE_SIGNAL: - if (s->signal.sig > 0) { - if (s->signal.sig != SIGCHLD || s->event->n_enabled_child_sources == 0) - assert_se(sigdelset(&s->event->sigset, s->signal.sig) == 0); + d = event_get_clock_data(s->event, s->type); + assert(d); - if (s->event->signal_sources) - s->event->signal_sources[s->signal.sig] = NULL; - } + prioq_remove(d->earliest, s, &s->time.earliest_index); + prioq_remove(d->latest, s, &s->time.latest_index); + d->needs_rearm = true; + break; + } - break; + case SOURCE_SIGNAL: + if (s->signal.sig > 0) { + if (s->signal.sig != SIGCHLD || s->event->n_enabled_child_sources == 0) + assert_se(sigdelset(&s->event->sigset, s->signal.sig) == 0); - case SOURCE_CHILD: - if (s->child.pid > 0) { - if (s->enabled != SD_EVENT_OFF) { - assert(s->event->n_enabled_child_sources > 0); - s->event->n_enabled_child_sources--; - } + if (s->event->signal_sources) + s->event->signal_sources[s->signal.sig] = NULL; + } - if (!s->event->signal_sources || !s->event->signal_sources[SIGCHLD]) - assert_se(sigdelset(&s->event->sigset, SIGCHLD) == 0); + break; - hashmap_remove(s->event->child_sources, INT_TO_PTR(s->child.pid)); + case SOURCE_CHILD: + if (s->child.pid > 0) { + if (s->enabled != SD_EVENT_OFF) { + assert(s->event->n_enabled_child_sources > 0); + s->event->n_enabled_child_sources--; } - break; + if (!s->event->signal_sources || !s->event->signal_sources[SIGCHLD]) + assert_se(sigdelset(&s->event->sigset, SIGCHLD) == 0); - case SOURCE_DEFER: - /* nothing */ - break; + hashmap_remove(s->event->child_sources, INT_TO_PTR(s->child.pid)); + } - case SOURCE_EXIT: - prioq_remove(s->event->exit, s, &s->exit.prioq_index); - break; + break; - case SOURCE_WATCHDOG: - assert_not_reached("Wut? I shouldn't exist."); - } + case SOURCE_DEFER: + /* nothing */ + break; - if (s->pending) - prioq_remove(s->event->pending, s, &s->pending_index); + case SOURCE_POST: + set_remove(s->event->post_sources, s); + break; - if (s->prepare) - prioq_remove(s->event->prepare, s, &s->prepare_index); + case SOURCE_EXIT: + prioq_remove(s->event->exit, s, &s->exit.prioq_index); + break; - s->event->n_sources--; - sd_event_unref(s->event); + default: + assert_not_reached("Wut? I shouldn't exist."); } + if (s->pending) + prioq_remove(s->event->pending, s, &s->pending_index); + + if (s->prepare) + prioq_remove(s->event->prepare, s, &s->prepare_index); + + event = s->event; + + s->type = _SOURCE_EVENT_SOURCE_TYPE_INVALID; + s->event = NULL; + LIST_REMOVE(sources, event->sources, s); + event->n_sources--; + + if (!s->floating) + sd_event_unref(event); +} + +static void source_free(sd_event_source *s) { + assert(s); + + source_disconnect(s); + free(s->name); free(s); } @@ -567,18 +713,21 @@ static int source_set_pending(sd_event_source *s, bool b) { } else assert_se(prioq_remove(s->event->pending, s, &s->pending_index)); - if (s->type == SOURCE_REALTIME) { - prioq_reshuffle(s->event->realtime_earliest, s, &s->time.earliest_index); - prioq_reshuffle(s->event->realtime_latest, s, &s->time.latest_index); - } else if (s->type == SOURCE_MONOTONIC) { - prioq_reshuffle(s->event->monotonic_earliest, s, &s->time.earliest_index); - prioq_reshuffle(s->event->monotonic_latest, s, &s->time.latest_index); + if (EVENT_SOURCE_IS_TIME(s->type)) { + struct clock_data *d; + + d = event_get_clock_data(s->event, s->type); + assert(d); + + prioq_reshuffle(d->earliest, s, &s->time.earliest_index); + prioq_reshuffle(d->latest, s, &s->time.latest_index); + d->needs_rearm = true; } return 0; } -static sd_event_source *source_new(sd_event *e, EventSourceType type) { +static sd_event_source *source_new(sd_event *e, bool floating, EventSourceType type) { sd_event_source *s; assert(e); @@ -588,10 +737,15 @@ static sd_event_source *source_new(sd_event *e, EventSourceType type) { return NULL; s->n_ref = 1; - s->event = sd_event_ref(e); + s->event = e; + s->floating = floating; s->type = type; s->pending_index = s->prepare_index = PRIOQ_IDX_NULL; + if (!floating) + sd_event_ref(e); + + LIST_PREPEND(sources, e->sources, s); e->n_sources ++; return s; @@ -612,11 +766,10 @@ _public_ int sd_event_add_io( assert_return(fd >= 0, -EINVAL); assert_return(!(events & ~(EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLPRI|EPOLLERR|EPOLLHUP|EPOLLET)), -EINVAL); assert_return(callback, -EINVAL); - assert_return(ret, -EINVAL); assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); assert_return(!event_pid_changed(e), -ECHILD); - s = source_new(e, SOURCE_IO); + s = source_new(e, !ret, SOURCE_IO); if (!s) return -ENOMEM; @@ -629,105 +782,111 @@ _public_ int sd_event_add_io( r = source_io_register(s, s->enabled, events); if (r < 0) { source_free(s); - return -errno; + return r; } - *ret = s; + if (ret) + *ret = s; + return 0; } +static void initialize_perturb(sd_event *e) { + sd_id128_t bootid = {}; + + /* When we sleep for longer, we try to realign the wakeup to + the same time wihtin each minute/second/250ms, so that + events all across the system can be coalesced into a single + CPU wakeup. However, let's take some system-specific + randomness for this value, so that in a network of systems + with synced clocks timer events are distributed a + bit. Here, we calculate a perturbation usec offset from the + boot ID. */ + + if (_likely_(e->perturb != USEC_INFINITY)) + return; + + if (sd_id128_get_boot(&bootid) >= 0) + e->perturb = (bootid.qwords[0] ^ bootid.qwords[1]) % USEC_PER_MINUTE; +} + static int event_setup_timer_fd( sd_event *e, - EventSourceType type, - int *timer_fd, - clockid_t id) { + struct clock_data *d, + clockid_t clock) { - sd_id128_t bootid = {}; struct epoll_event ev = {}; int r, fd; assert(e); - assert(timer_fd); + assert(d); - if (_likely_(*timer_fd >= 0)) + if (_likely_(d->fd >= 0)) return 0; - fd = timerfd_create(id, TFD_NONBLOCK|TFD_CLOEXEC); + fd = timerfd_create(clock, TFD_NONBLOCK|TFD_CLOEXEC); if (fd < 0) return -errno; ev.events = EPOLLIN; - ev.data.ptr = INT_TO_PTR(type); + ev.data.ptr = INT_TO_PTR(clock_to_event_source_type(clock)); r = epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, fd, &ev); if (r < 0) { - close_nointr_nofail(fd); + safe_close(fd); return -errno; } - /* When we sleep for longer, we try to realign the wakeup to - the same time wihtin each minute/second/250ms, so that - events all across the system can be coalesced into a single - CPU wakeup. However, let's take some system-specific - randomness for this value, so that in a network of systems - with synced clocks timer events are distributed a - bit. Here, we calculate a perturbation usec offset from the - boot ID. */ - - if (sd_id128_get_boot(&bootid) >= 0) - e->perturb = (bootid.qwords[0] ^ bootid.qwords[1]) % USEC_PER_MINUTE; - - *timer_fd = fd; + d->fd = fd; return 0; } -static int event_add_time_internal( +_public_ int sd_event_add_time( sd_event *e, sd_event_source **ret, - EventSourceType type, - int *timer_fd, - clockid_t id, - Prioq **earliest, - Prioq **latest, + clockid_t clock, uint64_t usec, uint64_t accuracy, sd_event_time_handler_t callback, void *userdata) { + EventSourceType type; sd_event_source *s; + struct clock_data *d; int r; assert_return(e, -EINVAL); - assert_return(callback, -EINVAL); - assert_return(ret, -EINVAL); assert_return(usec != (uint64_t) -1, -EINVAL); assert_return(accuracy != (uint64_t) -1, -EINVAL); + assert_return(callback, -EINVAL); assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); assert_return(!event_pid_changed(e), -ECHILD); - assert(timer_fd); - assert(earliest); - assert(latest); + type = clock_to_event_source_type(clock); + assert_return(type >= 0, -ENOTSUP); - if (!*earliest) { - *earliest = prioq_new(earliest_time_prioq_compare); - if (!*earliest) + 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; } - if (!*latest) { - *latest = prioq_new(latest_time_prioq_compare); - if (!*latest) + if (!d->latest) { + d->latest = prioq_new(latest_time_prioq_compare); + if (!d->latest) return -ENOMEM; } - if (*timer_fd < 0) { - r = event_setup_timer_fd(e, type, timer_fd, id); + if (d->fd < 0) { + r = event_setup_timer_fd(e, d, clock); if (r < 0) return r; } - s = source_new(e, type); + s = source_new(e, !ret, type); if (!s) return -ENOMEM; @@ -738,15 +897,19 @@ static int event_add_time_internal( s->userdata = userdata; s->enabled = SD_EVENT_ONESHOT; - r = prioq_put(*earliest, s, &s->time.earliest_index); + d->needs_rearm = true; + + r = prioq_put(d->earliest, s, &s->time.earliest_index); if (r < 0) goto fail; - r = prioq_put(*latest, s, &s->time.latest_index); + r = prioq_put(d->latest, s, &s->time.latest_index); if (r < 0) goto fail; - *ret = s; + if (ret) + *ret = s; + return 0; fail: @@ -754,26 +917,6 @@ fail: return r; } -_public_ int sd_event_add_monotonic(sd_event *e, - sd_event_source **ret, - uint64_t usec, - uint64_t accuracy, - sd_event_time_handler_t callback, - void *userdata) { - - return event_add_time_internal(e, ret, SOURCE_MONOTONIC, &e->monotonic_fd, CLOCK_MONOTONIC, &e->monotonic_earliest, &e->monotonic_latest, usec, accuracy, callback, userdata); -} - -_public_ int sd_event_add_realtime(sd_event *e, - sd_event_source **ret, - uint64_t usec, - uint64_t accuracy, - sd_event_time_handler_t callback, - void *userdata) { - - return event_add_time_internal(e, ret, SOURCE_REALTIME, &e->realtime_fd, CLOCK_REALTIME, &e->realtime_earliest, &e->monotonic_latest, usec, accuracy, callback, userdata); -} - static int event_update_signal_fd(sd_event *e) { struct epoll_event ev = {}; bool add_to_epoll; @@ -797,15 +940,19 @@ static int event_update_signal_fd(sd_event *e) { r = epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, e->signal_fd, &ev); if (r < 0) { - close_nointr_nofail(e->signal_fd); - e->signal_fd = -1; - + e->signal_fd = safe_close(e->signal_fd); return -errno; } return 0; } +static int signal_exit_callback(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) { + assert(s); + + return sd_event_exit(sd_event_source_get_event(s), PTR_TO_INT(userdata)); +} + _public_ int sd_event_add_signal( sd_event *e, sd_event_source **ret, @@ -820,11 +967,12 @@ _public_ int sd_event_add_signal( assert_return(e, -EINVAL); assert_return(sig > 0, -EINVAL); assert_return(sig < _NSIG, -EINVAL); - assert_return(callback, -EINVAL); - assert_return(ret, -EINVAL); assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); assert_return(!event_pid_changed(e), -ECHILD); + if (!callback) + callback = signal_exit_callback; + r = pthread_sigmask(SIG_SETMASK, NULL, &ss); if (r < 0) return -errno; @@ -839,7 +987,7 @@ _public_ int sd_event_add_signal( } else if (e->signal_sources[sig]) return -EBUSY; - s = source_new(e, SOURCE_SIGNAL); + s = source_new(e, !ret, SOURCE_SIGNAL); if (!s) return -ENOMEM; @@ -859,7 +1007,9 @@ _public_ int sd_event_add_signal( } } - *ret = s; + if (ret) + *ret = s; + return 0; } @@ -879,7 +1029,6 @@ _public_ int sd_event_add_child( assert_return(!(options & ~(WEXITED|WSTOPPED|WCONTINUED)), -EINVAL); assert_return(options != 0, -EINVAL); assert_return(callback, -EINVAL); - assert_return(ret, -EINVAL); assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); assert_return(!event_pid_changed(e), -ECHILD); @@ -890,7 +1039,7 @@ _public_ int sd_event_add_child( if (hashmap_contains(e->child_sources, INT_TO_PTR(pid))) return -EBUSY; - s = source_new(e, SOURCE_CHILD); + s = source_new(e, !ret, SOURCE_CHILD); if (!s) return -ENOMEM; @@ -914,13 +1063,15 @@ _public_ int sd_event_add_child( r = event_update_signal_fd(e); if (r < 0) { source_free(s); - return -errno; + return r; } } e->need_process_child = true; - *ret = s; + if (ret) + *ret = s; + return 0; } @@ -935,11 +1086,10 @@ _public_ int sd_event_add_defer( assert_return(e, -EINVAL); assert_return(callback, -EINVAL); - assert_return(ret, -EINVAL); assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); assert_return(!event_pid_changed(e), -ECHILD); - s = source_new(e, SOURCE_DEFER); + s = source_new(e, !ret, SOURCE_DEFER); if (!s) return -ENOMEM; @@ -953,7 +1103,47 @@ _public_ int sd_event_add_defer( return r; } - *ret = s; + if (ret) + *ret = s; + + return 0; +} + +_public_ int sd_event_add_post( + sd_event *e, + sd_event_source **ret, + sd_event_handler_t callback, + void *userdata) { + + sd_event_source *s; + int r; + + assert_return(e, -EINVAL); + assert_return(callback, -EINVAL); + assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); + assert_return(!event_pid_changed(e), -ECHILD); + + r = set_ensure_allocated(&e->post_sources, trivial_hash_func, trivial_compare_func); + if (r < 0) + return r; + + s = source_new(e, !ret, SOURCE_POST); + if (!s) + return -ENOMEM; + + s->post.callback = callback; + s->userdata = userdata; + s->enabled = SD_EVENT_ON; + + r = set_put(e->post_sources, s); + if (r < 0) { + source_free(s); + return r; + } + + if (ret) + *ret = s; + return 0; } @@ -968,7 +1158,6 @@ _public_ int sd_event_add_exit( assert_return(e, -EINVAL); assert_return(callback, -EINVAL); - assert_return(ret, -EINVAL); assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); assert_return(!event_pid_changed(e), -ECHILD); @@ -978,7 +1167,7 @@ _public_ int sd_event_add_exit( return -ENOMEM; } - s = source_new(e, SOURCE_EXIT); + s = source_new(e, !ret, SOURCE_EXIT); if (!s) return -ENOMEM; @@ -993,7 +1182,9 @@ _public_ int sd_event_add_exit( return r; } - *ret = s; + if (ret) + *ret = s; + return 0; } @@ -1026,6 +1217,8 @@ _public_ sd_event_source* sd_event_source_unref(sd_event_source *s) { if (s->dispatching) { if (s->type == SOURCE_IO) source_io_unregister(s); + + source_disconnect(s); } else source_free(s); } @@ -1033,6 +1226,32 @@ _public_ sd_event_source* sd_event_source_unref(sd_event_source *s) { return NULL; } +_public_ int sd_event_source_set_name(sd_event_source *s, const char *name) { + char *new_name = NULL; + + assert_return(s, -EINVAL); + + if (name) { + new_name = strdup(name); + if (!new_name) + return -ENOMEM; + } + + free(s->name); + s->name = new_name; + + return 0; +} + +_public_ int sd_event_source_get_name(sd_event_source *s, const char **name) { + assert_return(s, -EINVAL); + assert_return(name, -EINVAL); + + *name = s->name; + + return 0; +} + _public_ sd_event *sd_event_source_get_event(sd_event_source *s) { assert_return(s, NULL); @@ -1111,7 +1330,8 @@ _public_ int sd_event_source_set_io_events(sd_event_source *s, uint32_t events) assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE); assert_return(!event_pid_changed(s->event), -ECHILD); - if (s->io.events == events) + /* edge-triggered updates are never skipped, so we can reset edges */ + if (s->io.events == events && !(events & EPOLLET)) return 0; if (s->enabled != SD_EVENT_OFF) { @@ -1188,9 +1408,13 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) { assert_return(s, -EINVAL); assert_return(m == SD_EVENT_OFF || m == SD_EVENT_ON || m == SD_EVENT_ONESHOT, -EINVAL); - assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE); assert_return(!event_pid_changed(s->event), -ECHILD); + /* If we are dead anyway, we are fine with turning off + * sources, but everything else needs to fail. */ + if (s->event->state == SD_EVENT_FINISHED) + return m == SD_EVENT_OFF ? 0 : -ESTALE; + if (s->enabled == m) return 0; @@ -1206,17 +1430,22 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) { s->enabled = m; break; - case SOURCE_MONOTONIC: - s->enabled = m; - prioq_reshuffle(s->event->monotonic_earliest, s, &s->time.earliest_index); - prioq_reshuffle(s->event->monotonic_latest, s, &s->time.latest_index); - break; + case SOURCE_TIME_REALTIME: + case SOURCE_TIME_BOOTTIME: + case SOURCE_TIME_MONOTONIC: + case SOURCE_TIME_REALTIME_ALARM: + case SOURCE_TIME_BOOTTIME_ALARM: { + struct clock_data *d; - case SOURCE_REALTIME: s->enabled = m; - prioq_reshuffle(s->event->realtime_earliest, s, &s->time.earliest_index); - prioq_reshuffle(s->event->realtime_latest, s, &s->time.latest_index); + d = event_get_clock_data(s->event, s->type); + assert(d); + + prioq_reshuffle(d->earliest, s, &s->time.earliest_index); + prioq_reshuffle(d->latest, s, &s->time.latest_index); + d->needs_rearm = true; break; + } case SOURCE_SIGNAL: s->enabled = m; @@ -1246,10 +1475,11 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) { break; case SOURCE_DEFER: + case SOURCE_POST: s->enabled = m; break; - case SOURCE_WATCHDOG: + default: assert_not_reached("Wut? I shouldn't exist."); } @@ -1264,17 +1494,22 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) { s->enabled = m; break; - case SOURCE_MONOTONIC: - s->enabled = m; - prioq_reshuffle(s->event->monotonic_earliest, s, &s->time.earliest_index); - prioq_reshuffle(s->event->monotonic_latest, s, &s->time.latest_index); - break; + case SOURCE_TIME_REALTIME: + case SOURCE_TIME_BOOTTIME: + case SOURCE_TIME_MONOTONIC: + case SOURCE_TIME_REALTIME_ALARM: + case SOURCE_TIME_BOOTTIME_ALARM: { + struct clock_data *d; - case SOURCE_REALTIME: s->enabled = m; - prioq_reshuffle(s->event->realtime_earliest, s, &s->time.earliest_index); - prioq_reshuffle(s->event->realtime_latest, s, &s->time.latest_index); + d = event_get_clock_data(s->event, s->type); + assert(d); + + prioq_reshuffle(d->earliest, s, &s->time.earliest_index); + prioq_reshuffle(d->latest, s, &s->time.latest_index); + d->needs_rearm = true; break; + } case SOURCE_SIGNAL: s->enabled = m; @@ -1304,10 +1539,11 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) { break; case SOURCE_DEFER: + case SOURCE_POST: s->enabled = m; break; - case SOURCE_WATCHDOG: + default: assert_not_reached("Wut? I shouldn't exist."); } } @@ -1324,7 +1560,7 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) { _public_ int sd_event_source_get_time(sd_event_source *s, uint64_t *usec) { assert_return(s, -EINVAL); assert_return(usec, -EINVAL); - assert_return(s->type == SOURCE_REALTIME || s->type == SOURCE_MONOTONIC, -EDOM); + assert_return(EVENT_SOURCE_IS_TIME(s->type), -EDOM); assert_return(!event_pid_changed(s->event), -ECHILD); *usec = s->time.next; @@ -1332,9 +1568,11 @@ _public_ int sd_event_source_get_time(sd_event_source *s, uint64_t *usec) { } _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(s->type == SOURCE_REALTIME || s->type == SOURCE_MONOTONIC, -EDOM); + 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); @@ -1342,13 +1580,12 @@ _public_ int sd_event_source_set_time(sd_event_source *s, uint64_t usec) { source_set_pending(s, false); - if (s->type == SOURCE_REALTIME) { - prioq_reshuffle(s->event->realtime_earliest, s, &s->time.earliest_index); - prioq_reshuffle(s->event->realtime_latest, s, &s->time.latest_index); - } else { - prioq_reshuffle(s->event->monotonic_earliest, s, &s->time.earliest_index); - prioq_reshuffle(s->event->monotonic_latest, s, &s->time.latest_index); - } + d = event_get_clock_data(s->event, s->type); + assert(d); + + prioq_reshuffle(d->earliest, s, &s->time.earliest_index); + prioq_reshuffle(d->latest, s, &s->time.latest_index); + d->needs_rearm = true; return 0; } @@ -1356,7 +1593,7 @@ _public_ int sd_event_source_set_time(sd_event_source *s, uint64_t usec) { _public_ int sd_event_source_get_time_accuracy(sd_event_source *s, uint64_t *usec) { assert_return(s, -EINVAL); assert_return(usec, -EINVAL); - assert_return(s->type == SOURCE_REALTIME || s->type == SOURCE_MONOTONIC, -EDOM); + assert_return(EVENT_SOURCE_IS_TIME(s->type), -EDOM); assert_return(!event_pid_changed(s->event), -ECHILD); *usec = s->time.accuracy; @@ -1364,9 +1601,11 @@ _public_ int sd_event_source_get_time_accuracy(sd_event_source *s, uint64_t *use } _public_ int sd_event_source_set_time_accuracy(sd_event_source *s, uint64_t usec) { + struct clock_data *d; + assert_return(s, -EINVAL); assert_return(usec != (uint64_t) -1, -EINVAL); - assert_return(s->type == SOURCE_REALTIME || s->type == SOURCE_MONOTONIC, -EDOM); + 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); @@ -1377,11 +1616,22 @@ _public_ int sd_event_source_set_time_accuracy(sd_event_source *s, uint64_t usec source_set_pending(s, false); - if (s->type == SOURCE_REALTIME) - prioq_reshuffle(s->event->realtime_latest, s, &s->time.latest_index); - else - prioq_reshuffle(s->event->monotonic_latest, s, &s->time.latest_index); + d = event_get_clock_data(s->event, s->type); + assert(d); + + prioq_reshuffle(d->latest, s, &s->time.latest_index); + d->needs_rearm = true; + + return 0; +} +_public_ int sd_event_source_get_time_clock(sd_event_source *s, clockid_t *clock) { + assert_return(s, -EINVAL); + assert_return(clock, -EINVAL); + assert_return(EVENT_SOURCE_IS_TIME(s->type), -EDOM); + assert_return(!event_pid_changed(s->event), -ECHILD); + + *clock = event_source_type_to_clock(s->type); return 0; } @@ -1455,6 +1705,8 @@ static usec_t sleep_between(sd_event *e, usec_t a, usec_t b) { if (b <= a + 1) return a; + initialize_perturb(e); + /* Find a good time to wake up again between times a and b. We have two goals here: @@ -1522,10 +1774,7 @@ static usec_t sleep_between(sd_event *e, usec_t a, usec_t b) { static int event_arm_timer( sd_event *e, - int timer_fd, - Prioq *earliest, - Prioq *latest, - usec_t *next) { + struct clock_data *d) { struct itimerspec its = {}; sd_event_source *a, *b; @@ -1533,35 +1782,39 @@ static int event_arm_timer( int r; assert(e); - assert(next); + assert(d); - a = prioq_peek(earliest); + if (!d->needs_rearm) + return 0; + else + d->needs_rearm = false; + + a = prioq_peek(d->earliest); if (!a || a->enabled == SD_EVENT_OFF) { - if (timer_fd < 0) + if (d->fd < 0) return 0; - if (*next == (usec_t) -1) + if (d->next == USEC_INFINITY) return 0; /* disarm */ - r = timerfd_settime(timer_fd, TFD_TIMER_ABSTIME, &its, NULL); + r = timerfd_settime(d->fd, TFD_TIMER_ABSTIME, &its, NULL); if (r < 0) return r; - *next = (usec_t) -1; - + d->next = USEC_INFINITY; return 0; } - b = prioq_peek(latest); + 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); - if (*next == t) + if (d->next == t) return 0; - assert_se(timer_fd >= 0); + assert_se(d->fd >= 0); if (t == 0) { /* We don' want to disarm here, just mean some time looooong ago. */ @@ -1570,11 +1823,11 @@ static int event_arm_timer( } else timespec_store(&its.it_value, t); - r = timerfd_settime(timer_fd, TFD_TIMER_ABSTIME, &its, NULL); + r = timerfd_settime(d->fd, TFD_TIMER_ABSTIME, &its, NULL); if (r < 0) return -errno; - *next = t; + d->next = t; return 0; } @@ -1618,7 +1871,7 @@ static int flush_timer(sd_event *e, int fd, uint32_t events, usec_t *next) { return -EIO; if (next) - *next = (usec_t) -1; + *next = USEC_INFINITY; return 0; } @@ -1626,16 +1879,16 @@ static int flush_timer(sd_event *e, int fd, uint32_t events, usec_t *next) { static int process_timer( sd_event *e, usec_t n, - Prioq *earliest, - Prioq *latest) { + struct clock_data *d) { sd_event_source *s; int r; assert(e); + assert(d); for (;;) { - s = prioq_peek(earliest); + s = prioq_peek(d->earliest); if (!s || s->time.next > n || s->enabled == SD_EVENT_OFF || @@ -1646,8 +1899,9 @@ static int process_timer( if (r < 0) return r; - prioq_reshuffle(earliest, s, &s->time.earliest_index); - prioq_reshuffle(latest, s, &s->time.latest_index); + prioq_reshuffle(d->earliest, s, &s->time.earliest_index); + prioq_reshuffle(d->latest, s, &s->time.latest_index); + d->needs_rearm = true; } return 0; @@ -1725,14 +1979,13 @@ static int process_signal(sd_event *e, uint32_t events) { int r; assert(e); - assert(e->signal_sources); assert_return(events == EPOLLIN, -EIO); for (;;) { struct signalfd_siginfo si; ssize_t ss; - sd_event_source *s; + sd_event_source *s = NULL; ss = read(e->signal_fd, &si, sizeof(si)); if (ss < 0) { @@ -1747,24 +2000,25 @@ static int process_signal(sd_event *e, uint32_t events) { read_one = true; - s = e->signal_sources[si.ssi_signo]; if (si.ssi_signo == SIGCHLD) { r = process_child(e); if (r < 0) return r; - if (r > 0 || !s) + if (r > 0) continue; - } else - if (!s) - return -EIO; + } + + if (e->signal_sources) + s = e->signal_sources[si.ssi_signo]; + + if (!s) + continue; s->signal.siginfo = si; r = source_set_pending(s, true); if (r < 0) return r; } - - return 0; } static int source_dispatch(sd_event_source *s) { @@ -1779,6 +2033,23 @@ static int source_dispatch(sd_event_source *s) { return r; } + if (s->type != SOURCE_POST) { + sd_event_source *z; + Iterator i; + + /* If we execute a non-post source, let's mark all + * post sources as pending */ + + SET_FOREACH(z, s->event->post_sources, i) { + if (z->enabled == SD_EVENT_OFF) + continue; + + r = source_set_pending(z, true); + if (r < 0) + return r; + } + } + if (s->enabled == SD_EVENT_ONESHOT) { r = sd_event_source_set_enabled(s, SD_EVENT_OFF); if (r < 0) @@ -1793,11 +2064,11 @@ static int source_dispatch(sd_event_source *s) { r = s->io.callback(s, s->io.fd, s->io.revents, s->userdata); break; - case SOURCE_MONOTONIC: - r = s->time.callback(s, s->time.next, s->userdata); - break; - - case SOURCE_REALTIME: + case SOURCE_TIME_REALTIME: + case SOURCE_TIME_BOOTTIME: + case SOURCE_TIME_MONOTONIC: + case SOURCE_TIME_REALTIME_ALARM: + case SOURCE_TIME_BOOTTIME_ALARM: r = s->time.callback(s, s->time.next, s->userdata); break; @@ -1825,11 +2096,17 @@ static int source_dispatch(sd_event_source *s) { r = s->defer.callback(s, s->userdata); break; + case SOURCE_POST: + r = s->post.callback(s, s->userdata); + break; + case SOURCE_EXIT: r = s->exit.callback(s, s->userdata); break; case SOURCE_WATCHDOG: + case _SOURCE_EVENT_SOURCE_TYPE_MAX: + case _SOURCE_EVENT_SOURCE_TYPE_INVALID: assert_not_reached("Wut? I shouldn't exist."); } @@ -1934,6 +2211,11 @@ static int arm_watchdog(sd_event *e) { timespec_store(&its.it_value, t); + /* Make sure we never set the watchdog to 0, which tells the + * kernel to disable it. */ + if (its.it_value.tv_sec == 0 && its.it_value.tv_nsec == 0) + its.it_value.tv_nsec = 1; + r = timerfd_settime(e->watchdog_fd, TFD_TIMER_ABSTIME, &its, NULL); if (r < 0) return -errno; @@ -1957,11 +2239,8 @@ static int process_watchdog(sd_event *e) { return arm_watchdog(e); } -_public_ int sd_event_run(sd_event *e, uint64_t timeout) { - struct epoll_event *ev_queue; - unsigned ev_queue_max; - sd_event_source *p; - int r, i, m; +_public_ int sd_event_prepare(sd_event *e) { + int r; assert_return(e, -EINVAL); assert_return(!event_pid_changed(e), -ECHILD); @@ -1969,44 +2248,96 @@ _public_ int sd_event_run(sd_event *e, uint64_t timeout) { assert_return(e->state == SD_EVENT_PASSIVE, -EBUSY); if (e->exit_requested) - return dispatch_exit(e); + goto pending; - sd_event_ref(e); e->iteration++; - e->state = SD_EVENT_RUNNING; r = event_prepare(e); if (r < 0) - goto finish; + return r; - r = event_arm_timer(e, e->monotonic_fd, e->monotonic_earliest, e->monotonic_latest, &e->monotonic_next); + r = event_arm_timer(e, &e->realtime); if (r < 0) - goto finish; + return r; - r = event_arm_timer(e, e->realtime_fd, e->realtime_earliest, e->realtime_latest, &e->realtime_next); + r = event_arm_timer(e, &e->boottime); if (r < 0) - goto finish; + return r; + + r = event_arm_timer(e, &e->monotonic); + if (r < 0) + return r; + + r = event_arm_timer(e, &e->realtime_alarm); + if (r < 0) + return r; + + r = event_arm_timer(e, &e->boottime_alarm); + if (r < 0) + return r; if (event_next_pending(e) || e->need_process_child) - timeout = 0; + goto pending; + + e->state = SD_EVENT_PREPARED; + + return 0; + +pending: + e->state = SD_EVENT_PREPARED; + r = sd_event_wait(e, 0); + if (r == 0) + e->state = SD_EVENT_PREPARED; + + return r; +} + +_public_ int sd_event_wait(sd_event *e, uint64_t timeout) { + struct epoll_event *ev_queue; + unsigned ev_queue_max; + int r, m, i; + + assert_return(e, -EINVAL); + assert_return(!event_pid_changed(e), -ECHILD); + assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); + assert_return(e->state == SD_EVENT_PREPARED, -EBUSY); + + if (e->exit_requested) { + e->state = SD_EVENT_PENDING; + return 1; + } + ev_queue_max = CLAMP(e->n_sources, 1U, EPOLL_QUEUE_MAX); ev_queue = newa(struct epoll_event, ev_queue_max); m = epoll_wait(e->epoll_fd, ev_queue, ev_queue_max, timeout == (uint64_t) -1 ? -1 : (int) ((timeout + USEC_PER_MSEC - 1) / USEC_PER_MSEC)); if (m < 0) { - r = errno == EAGAIN || errno == EINTR ? 1 : -errno; + if (errno == EINTR) { + e->state = SD_EVENT_PENDING; + return 1; + } + + r = -errno; + goto finish; } dual_timestamp_get(&e->timestamp); + e->timestamp_boottime = now(CLOCK_BOOTTIME); for (i = 0; i < m; i++) { - if (ev_queue[i].data.ptr == INT_TO_PTR(SOURCE_MONOTONIC)) - r = flush_timer(e, e->monotonic_fd, ev_queue[i].events, &e->monotonic_next); - else if (ev_queue[i].data.ptr == INT_TO_PTR(SOURCE_REALTIME)) - r = flush_timer(e, e->realtime_fd, ev_queue[i].events, &e->realtime_next); + if (ev_queue[i].data.ptr == INT_TO_PTR(SOURCE_TIME_REALTIME)) + r = flush_timer(e, e->realtime.fd, ev_queue[i].events, &e->realtime.next); + else if (ev_queue[i].data.ptr == INT_TO_PTR(SOURCE_TIME_BOOTTIME)) + r = flush_timer(e, e->boottime.fd, ev_queue[i].events, &e->boottime.next); + else if (ev_queue[i].data.ptr == INT_TO_PTR(SOURCE_TIME_MONOTONIC)) + r = flush_timer(e, e->monotonic.fd, ev_queue[i].events, &e->monotonic.next); + else if (ev_queue[i].data.ptr == INT_TO_PTR(SOURCE_TIME_REALTIME_ALARM)) + r = flush_timer(e, e->realtime_alarm.fd, ev_queue[i].events, &e->realtime_alarm.next); + else if (ev_queue[i].data.ptr == INT_TO_PTR(SOURCE_TIME_BOOTTIME_ALARM)) + r = flush_timer(e, e->boottime_alarm.fd, ev_queue[i].events, &e->boottime_alarm.next); else if (ev_queue[i].data.ptr == INT_TO_PTR(SOURCE_SIGNAL)) r = process_signal(e, ev_queue[i].events); else if (ev_queue[i].data.ptr == INT_TO_PTR(SOURCE_WATCHDOG)) @@ -2022,11 +2353,23 @@ _public_ int sd_event_run(sd_event *e, uint64_t timeout) { if (r < 0) goto finish; - r = process_timer(e, e->timestamp.monotonic, e->monotonic_earliest, e->monotonic_latest); + r = process_timer(e, e->timestamp.realtime, &e->realtime); if (r < 0) goto finish; - r = process_timer(e, e->timestamp.realtime, e->realtime_earliest, e->realtime_latest); + r = process_timer(e, e->timestamp_boottime, &e->boottime); + if (r < 0) + goto finish; + + r = process_timer(e, e->timestamp.monotonic, &e->monotonic); + if (r < 0) + goto finish; + + r = process_timer(e, e->timestamp.realtime, &e->realtime_alarm); + if (r < 0) + goto finish; + + r = process_timer(e, e->timestamp_boottime, &e->boottime_alarm); if (r < 0) goto finish; @@ -2036,21 +2379,71 @@ _public_ int sd_event_run(sd_event *e, uint64_t timeout) { goto finish; } - p = event_next_pending(e); - if (!p) { - r = 1; - goto finish; + if (event_next_pending(e)) { + e->state = SD_EVENT_PENDING; + + return 1; } - r = source_dispatch(p); + r = 0; finish: e->state = SD_EVENT_PASSIVE; - sd_event_unref(e); return r; } +_public_ int sd_event_dispatch(sd_event *e) { + sd_event_source *p; + int r; + + assert_return(e, -EINVAL); + assert_return(!event_pid_changed(e), -ECHILD); + assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); + assert_return(e->state == SD_EVENT_PENDING, -EBUSY); + + if (e->exit_requested) + return dispatch_exit(e); + + p = event_next_pending(e); + if (p) { + sd_event_ref(e); + + e->state = SD_EVENT_RUNNING; + r = source_dispatch(p); + e->state = SD_EVENT_PASSIVE; + + sd_event_unref(e); + + return r; + } + + e->state = SD_EVENT_PASSIVE; + + return 1; +} + +_public_ int sd_event_run(sd_event *e, uint64_t timeout) { + int r; + + assert_return(e, -EINVAL); + assert_return(!event_pid_changed(e), -ECHILD); + assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); + assert_return(e->state == SD_EVENT_PASSIVE, -EBUSY); + + r = sd_event_prepare(e); + if (r > 0) + return sd_event_dispatch(e); + else if (r < 0) + return r; + + r = sd_event_wait(e, timeout); + if (r > 0) + return sd_event_dispatch(e); + else + return r; +} + _public_ int sd_event_loop(sd_event *e) { int r; @@ -2073,6 +2466,14 @@ finish: return r; } +_public_ int sd_event_get_fd(sd_event *e) { + + assert_return(e, -EINVAL); + assert_return(!event_pid_changed(e), -ECHILD); + + return e->epoll_fd; +} + _public_ int sd_event_get_state(sd_event *e) { assert_return(e, -EINVAL); assert_return(!event_pid_changed(e), -ECHILD); @@ -2103,23 +2504,32 @@ _public_ int sd_event_exit(sd_event *e, int code) { return 0; } -_public_ int sd_event_get_now_realtime(sd_event *e, uint64_t *usec) { +_public_ int sd_event_now(sd_event *e, clockid_t clock, uint64_t *usec) { assert_return(e, -EINVAL); assert_return(usec, -EINVAL); - assert_return(dual_timestamp_is_set(&e->timestamp), -ENODATA); assert_return(!event_pid_changed(e), -ECHILD); - *usec = e->timestamp.realtime; - return 0; -} + /* If we haven't run yet, just get the actual time */ + if (!dual_timestamp_is_set(&e->timestamp)) + return -ENODATA; -_public_ int sd_event_get_now_monotonic(sd_event *e, uint64_t *usec) { - assert_return(e, -EINVAL); - assert_return(usec, -EINVAL); - assert_return(dual_timestamp_is_set(&e->timestamp), -ENODATA); - assert_return(!event_pid_changed(e), -ECHILD); + 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 = e->timestamp.monotonic; return 0; } @@ -2202,8 +2612,7 @@ _public_ int sd_event_set_watchdog(sd_event *e, int b) { } else { if (e->watchdog_fd >= 0) { epoll_ctl(e->epoll_fd, EPOLL_CTL_DEL, e->watchdog_fd, NULL); - close_nointr_nofail(e->watchdog_fd); - e->watchdog_fd = -1; + e->watchdog_fd = safe_close(e->watchdog_fd); } } @@ -2211,8 +2620,7 @@ _public_ int sd_event_set_watchdog(sd_event *e, int b) { return e->watchdog; fail: - close_nointr_nofail(e->watchdog_fd); - e->watchdog_fd = -1; + e->watchdog_fd = safe_close(e->watchdog_fd); return r; }