X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Flibsystemd%2Fsd-event%2Fsd-event.c;h=a4b67431ef66ffb97cb17a6afb065d6aa898ebf1;hb=79e16ce3bf734434081e57f1170333277830a592;hp=f33a9ecf9ac8dee1b8d6ba4f74c68429d120ad9e;hpb=607553f9306286fdccf0b356bc3d1087adfe21c4;p=elogind.git diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c index f33a9ecf9..a4b67431e 100644 --- a/src/libsystemd/sd-event/sd-event.c +++ b/src/libsystemd/sd-event/sd-event.c @@ -32,6 +32,7 @@ #include "util.h" #include "time-util.h" #include "missing.h" +#include "set.h" #include "sd-event.h" @@ -40,15 +41,22 @@ typedef enum EventSourceType { SOURCE_IO, - SOURCE_MONOTONIC, - SOURCE_REALTIME, + SOURCE_TIME_REALTIME, + 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, + _SOUFCE_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_MONOTONIC, SOURCE_TIME_REALTIME_ALARM, SOURCE_TIME_BOOTTIME_ALARM) + struct sd_event_source { unsigned n_ref; @@ -56,7 +64,7 @@ struct sd_event_source { void *userdata; sd_event_handler_t prepare; - EventSourceType type:4; + EventSourceType type:5; int enabled:3; bool pending:1; bool dispatching:1; @@ -95,6 +103,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 +113,39 @@ 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; +}; + 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 four 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 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 +154,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; @@ -227,8 +250,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 +283,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,6 +340,14 @@ 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) { assert(e); assert(e->n_sources == 0); @@ -324,32 +355,23 @@ static void event_free(sd_event *e) { 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->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 +386,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->monotonic.fd = e->realtime_alarm.fd = e->boottime_alarm.fd = -1; + e->realtime.next = e->monotonic.next = e->realtime_alarm.next = e->boottime_alarm.next = (usec_t) -1; e->original_pid = getpid(); + e->perturb = (usec_t) -1; assert_se(sigemptyset(&e->sigset) == 0); @@ -470,6 +493,70 @@ static int source_io_register( return 0; } +static clockid_t event_source_type_to_clock(EventSourceType t) { + + switch (t) { + + case SOURCE_TIME_REALTIME: + return CLOCK_REALTIME; + + 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_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_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_free(sd_event_source *s) { assert(s); @@ -484,15 +571,19 @@ static void source_free(sd_event_source *s) { break; - 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; + case SOURCE_TIME_REALTIME: + case SOURCE_TIME_MONOTONIC: + case SOURCE_TIME_REALTIME_ALARM: + case SOURCE_TIME_BOOTTIME_ALARM: { + struct clock_data *d; - 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); + d = event_get_clock_data(s->event, s->type); + assert(d); + + prioq_remove(d->earliest, s, &s->time.earliest_index); + prioq_remove(d->latest, s, &s->time.latest_index); break; + } case SOURCE_SIGNAL: if (s->signal.sig > 0) { @@ -524,11 +615,15 @@ static void source_free(sd_event_source *s) { /* nothing */ break; + case SOURCE_POST: + set_remove(s->event->post_sources, s); + break; + case SOURCE_EXIT: prioq_remove(s->event->exit, s, &s->exit.prioq_index); break; - case SOURCE_WATCHDOG: + default: assert_not_reached("Wut? I shouldn't exist."); } @@ -567,12 +662,14 @@ 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); } return 0; @@ -599,11 +696,11 @@ static sd_event_source *source_new(sd_event *e, EventSourceType type) { _public_ int sd_event_add_io( sd_event *e, + sd_event_source **ret, int fd, uint32_t events, sd_event_io_handler_t callback, - void *userdata, - sd_event_source **ret) { + void *userdata) { sd_event_source *s; int r; @@ -638,33 +735,34 @@ _public_ int sd_event_add_io( 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; - sd_id128_t bootid; 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; } + d->fd = fd; + /* 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 @@ -674,55 +772,55 @@ static int event_setup_timer_fd( 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; + if (e->perturb == (usec_t) -1) + if (sd_id128_get_boot(&bootid) >= 0) + e->perturb = (bootid.qwords[0] ^ bootid.qwords[1]) % USEC_PER_MINUTE; - *timer_fd = fd; return 0; } -static int event_add_time_internal( +_public_ int sd_event_add_time( sd_event *e, - EventSourceType type, - int *timer_fd, - clockid_t id, - Prioq **earliest, - Prioq **latest, + sd_event_source **ret, + clockid_t clock, uint64_t usec, uint64_t accuracy, sd_event_time_handler_t callback, - void *userdata, - sd_event_source **ret) { + 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; } @@ -738,11 +836,11 @@ static int event_add_time_internal( s->userdata = userdata; s->enabled = SD_EVENT_ONESHOT; - r = prioq_put(*earliest, s, &s->time.earliest_index); + 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; @@ -754,26 +852,6 @@ fail: return r; } -_public_ int sd_event_add_monotonic(sd_event *e, - uint64_t usec, - uint64_t accuracy, - sd_event_time_handler_t callback, - void *userdata, - sd_event_source **ret) { - - return event_add_time_internal(e, SOURCE_MONOTONIC, &e->monotonic_fd, CLOCK_MONOTONIC, &e->monotonic_earliest, &e->monotonic_latest, usec, accuracy, callback, userdata, ret); -} - -_public_ int sd_event_add_realtime(sd_event *e, - uint64_t usec, - uint64_t accuracy, - sd_event_time_handler_t callback, - void *userdata, - sd_event_source **ret) { - - return event_add_time_internal(e, SOURCE_REALTIME, &e->realtime_fd, CLOCK_REALTIME, &e->realtime_earliest, &e->monotonic_latest, usec, accuracy, callback, userdata, ret); -} - static int event_update_signal_fd(sd_event *e) { struct epoll_event ev = {}; bool add_to_epoll; @@ -797,9 +875,7 @@ 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; } @@ -808,10 +884,10 @@ static int event_update_signal_fd(sd_event *e) { _public_ int sd_event_add_signal( sd_event *e, + sd_event_source **ret, int sig, sd_event_signal_handler_t callback, - void *userdata, - sd_event_source **ret) { + void *userdata) { sd_event_source *s; sigset_t ss; @@ -865,11 +941,11 @@ _public_ int sd_event_add_signal( _public_ int sd_event_add_child( sd_event *e, + sd_event_source **ret, pid_t pid, int options, sd_event_child_handler_t callback, - void *userdata, - sd_event_source **ret) { + void *userdata) { sd_event_source *s; int r; @@ -926,9 +1002,9 @@ _public_ int sd_event_add_child( _public_ int sd_event_add_defer( sd_event *e, + sd_event_source **ret, sd_event_handler_t callback, - void *userdata, - sd_event_source **ret) { + void *userdata) { sd_event_source *s; int r; @@ -957,11 +1033,48 @@ _public_ int sd_event_add_defer( 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(ret, -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, 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; + } + + *ret = s; + return 0; +} + _public_ int sd_event_add_exit( sd_event *e, + sd_event_source **ret, sd_event_handler_t callback, - void *userdata, - sd_event_source **ret) { + void *userdata) { sd_event_source *s; int r; @@ -1206,17 +1319,20 @@ _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_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); break; + } case SOURCE_SIGNAL: s->enabled = m; @@ -1246,10 +1362,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 +1381,20 @@ _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_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); break; + } case SOURCE_SIGNAL: s->enabled = m; @@ -1286,8 +1406,6 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) { break; case SOURCE_CHILD: - s->enabled = m; - if (s->enabled == SD_EVENT_OFF) { s->event->n_enabled_child_sources++; @@ -1296,6 +1414,8 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) { event_update_signal_fd(s->event); } } + + s->enabled = m; break; case SOURCE_EXIT: @@ -1304,10 +1424,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 +1445,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 +1453,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 +1465,11 @@ _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); return 0; } @@ -1356,7 +1477,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 +1485,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 +1500,21 @@ _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); + + 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; } @@ -1522,10 +1655,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 +1663,34 @@ static int event_arm_timer( int r; assert(e); - assert(next); + assert(d); - a = prioq_peek(earliest); + 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_t) -1) 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_t) -1; 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 +1699,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; } @@ -1626,16 +1755,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 +1775,8 @@ 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); } return 0; @@ -1763,8 +1892,6 @@ static int process_signal(sd_event *e, uint32_t events) { if (r < 0) return r; } - - return 0; } static int source_dispatch(sd_event_source *s) { @@ -1779,6 +1906,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 +1937,10 @@ 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_MONOTONIC: + case SOURCE_TIME_REALTIME_ALARM: + case SOURCE_TIME_BOOTTIME_ALARM: r = s->time.callback(s, s->time.next, s->userdata); break; @@ -1825,6 +1968,10 @@ 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; @@ -1979,16 +2126,25 @@ _public_ int sd_event_run(sd_event *e, uint64_t timeout) { if (r < 0) goto finish; - 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; + + r = event_arm_timer(e, &e->monotonic); + if (r < 0) + goto finish; + + r = event_arm_timer(e, &e->realtime_alarm); if (r < 0) goto finish; - r = event_arm_timer(e, e->realtime_fd, e->realtime_earliest, e->realtime_latest, &e->realtime_next); + r = event_arm_timer(e, &e->boottime_alarm); if (r < 0) goto finish; if (event_next_pending(e) || e->need_process_child) timeout = 0; + ev_queue_max = CLAMP(e->n_sources, 1U, EPOLL_QUEUE_MAX); ev_queue = newa(struct epoll_event, ev_queue_max); @@ -2000,13 +2156,18 @@ _public_ int sd_event_run(sd_event *e, uint64_t timeout) { } 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_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 +2183,19 @@ _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.monotonic, &e->monotonic); if (r < 0) goto finish; - r = process_timer(e, e->timestamp.realtime, e->realtime_earliest, e->realtime_latest); + 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; @@ -2103,30 +2272,38 @@ _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_ALARM: + *usec = e->timestamp_boottime; + break; + } - *usec = e->timestamp.monotonic; return 0; } _public_ int sd_event_default(sd_event **ret) { static thread_local sd_event *default_event = NULL; - sd_event *e; + sd_event *e = NULL; int r; if (!ret) @@ -2202,8 +2379,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 +2387,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; }