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=db7643347f3f45c9f2e8584548a43d48c0c93088;hpb=bdd13f6be4b588568683a1ab54f421fc6a636dbb;p=elogind.git diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c index db7643347..a4b67431e 100644 --- a/src/libsystemd/sd-event/sd-event.c +++ b/src/libsystemd/sd-event/sd-event.c @@ -41,16 +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; @@ -58,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; @@ -107,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; @@ -147,6 +162,7 @@ struct sd_event { unsigned iteration; dual_timestamp timestamp; + usec_t timestamp_boottime; int state; bool exit_requested:1; @@ -234,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) @@ -267,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) @@ -324,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); @@ -331,27 +355,17 @@ 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); @@ -372,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); @@ -478,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); @@ -492,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; + + d = event_get_clock_data(s->event, s->type); + assert(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); + 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) { @@ -540,7 +623,7 @@ static void source_free(sd_event_source *s) { prioq_remove(s->event->exit, s, &s->exit.prioq_index); break; - case SOURCE_WATCHDOG: + default: assert_not_reached("Wut? I shouldn't exist."); } @@ -579,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; @@ -650,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; 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 @@ -686,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, 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); + + d = event_get_clock_data(e, type); + assert(d); - if (!*earliest) { - *earliest = prioq_new(earliest_time_prioq_compare); - if (!*earliest) + 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; } @@ -750,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; @@ -766,26 +852,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->realtime_latest, usec, accuracy, callback, userdata); -} - static int event_update_signal_fd(sd_event *e) { struct epoll_event ev = {}; bool add_to_epoll; @@ -809,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; } @@ -1255,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; @@ -1299,7 +1366,7 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) { s->enabled = m; break; - case SOURCE_WATCHDOG: + default: assert_not_reached("Wut? I shouldn't exist."); } @@ -1314,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; @@ -1358,7 +1428,7 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) { s->enabled = m; break; - case SOURCE_WATCHDOG: + default: assert_not_reached("Wut? I shouldn't exist."); } } @@ -1375,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; @@ -1383,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); @@ -1393,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; } @@ -1407,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; @@ -1415,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); @@ -1428,14 +1500,24 @@ _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; +} + _public_ int sd_event_source_get_child_pid(sd_event_source *s, pid_t *pid) { assert_return(s, -EINVAL); assert_return(pid, -EINVAL); @@ -1573,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; @@ -1584,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. */ @@ -1621,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; } @@ -1677,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 || @@ -1697,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; @@ -1859,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; @@ -2049,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_fd, e->realtime_earliest, e->realtime_latest, &e->realtime_next); + r = event_arm_timer(e, &e->realtime_alarm); + if (r < 0) + goto finish; + + 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); @@ -2070,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)) @@ -2092,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.realtime, e->realtime_earliest, e->realtime_latest); + 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; @@ -2173,23 +2272,31 @@ _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; } @@ -2272,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); } } @@ -2281,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; }