X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;ds=sidebyside;f=src%2Flibsystemd-bus%2Fsd-event.c;h=19fa982ed391356784eeebc5ac669fe8f11173d2;hb=fe8245eb3c4bc4c492168b861ce3b631479a9046;hp=e3110c3d6bc50aa7b9fbd8a36fbfc8681c4bbcbd;hpb=eaa3cbef3b8c214cd5c2d75b04e70ad477187e17;p=elogind.git diff --git a/src/libsystemd-bus/sd-event.c b/src/libsystemd-bus/sd-event.c index e3110c3d6..19fa982ed 100644 --- a/src/libsystemd-bus/sd-event.c +++ b/src/libsystemd-bus/sd-event.c @@ -24,7 +24,6 @@ #include #include "macro.h" -#include "refcnt.h" #include "prioq.h" #include "hashmap.h" #include "util.h" @@ -42,18 +41,19 @@ typedef enum EventSourceType { SOURCE_REALTIME, SOURCE_SIGNAL, SOURCE_CHILD, - SOURCE_DEFER + SOURCE_DEFER, + SOURCE_QUIT } EventSourceType; struct sd_event_source { - RefCount n_ref; + unsigned n_ref; sd_event *event; void *userdata; sd_prepare_handler_t prepare; EventSourceType type:4; - sd_event_mute_t mute:3; + int enabled:3; bool pending:1; int priority; @@ -90,11 +90,15 @@ struct sd_event_source { struct { sd_defer_handler_t callback; } defer; + struct { + sd_quit_handler_t callback; + unsigned prioq_index; + } quit; }; }; struct sd_event { - RefCount n_ref; + unsigned n_ref; int epoll_fd; int signal_fd; @@ -115,21 +119,25 @@ struct sd_event { Prioq *realtime_earliest; Prioq *realtime_latest; + usec_t realtime_next, monotonic_next; + usec_t perturb; + sigset_t sigset; sd_event_source **signal_sources; Hashmap *child_sources; - unsigned n_unmuted_child_sources; + unsigned n_enabled_child_sources; - unsigned iteration; + Prioq *quit; - usec_t realtime_next, monotonic_next; - usec_t perturb; + pid_t original_pid; - bool quit:1; - bool need_process_child:1; + unsigned iteration; + dual_timestamp timestamp; + int state; - pid_t original_pid; + bool quit_requested:1; + bool need_process_child:1; }; static int pending_prioq_compare(const void *a, const void *b) { @@ -138,10 +146,10 @@ static int pending_prioq_compare(const void *a, const void *b) { assert(x->pending); assert(y->pending); - /* Unmuted ones first */ - if (x->mute != SD_EVENT_MUTED && y->mute == SD_EVENT_MUTED) + /* Enabled ones first */ + if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF) return -1; - if (x->mute == SD_EVENT_MUTED && y->mute != SD_EVENT_MUTED) + if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF) return 1; /* Lower priority values first */ @@ -179,10 +187,10 @@ static int prepare_prioq_compare(const void *a, const void *b) { if (x->prepare_iteration > y->prepare_iteration) return 1; - /* Unmuted ones first */ - if (x->mute != SD_EVENT_MUTED && y->mute == SD_EVENT_MUTED) + /* Enabled ones first */ + if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF) return -1; - if (x->mute == SD_EVENT_MUTED && y->mute != SD_EVENT_MUTED) + if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF) return 1; /* Lower priority values first */ @@ -206,10 +214,10 @@ static int earliest_time_prioq_compare(const void *a, const void *b) { assert(x->type == SOURCE_MONOTONIC || x->type == SOURCE_REALTIME); assert(y->type == SOURCE_MONOTONIC || y->type == SOURCE_REALTIME); - /* Unmuted ones first */ - if (x->mute != SD_EVENT_MUTED && y->mute == SD_EVENT_MUTED) + /* Enabled ones first */ + if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF) return -1; - if (x->mute == SD_EVENT_MUTED && y->mute != SD_EVENT_MUTED) + if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF) return 1; /* Move the pending ones to the end */ @@ -236,13 +244,13 @@ 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 || x->type == SOURCE_REALTIME); - assert(y->type == SOURCE_MONOTONIC || y->type == SOURCE_REALTIME); + assert((x->type == SOURCE_MONOTONIC && y->type == SOURCE_MONOTONIC) || + (x->type == SOURCE_REALTIME && y->type == SOURCE_REALTIME)); - /* Unmuted ones first */ - if (x->mute != SD_EVENT_MUTED && y->mute == SD_EVENT_MUTED) + /* Enabled ones first */ + if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF) return -1; - if (x->mute == SD_EVENT_MUTED && y->mute != SD_EVENT_MUTED) + if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF) return 1; /* Move the pending ones to the end */ @@ -266,6 +274,33 @@ static int latest_time_prioq_compare(const void *a, const void *b) { return 0; } +static int quit_prioq_compare(const void *a, const void *b) { + const sd_event_source *x = a, *y = b; + + assert(x->type == SOURCE_QUIT); + assert(y->type == SOURCE_QUIT); + + /* Enabled ones first */ + if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF) + return -1; + if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF) + return 1; + + /* Lower priority values first */ + if (x->priority < y->priority) + return -1; + if (x->priority > y->priority) + return 1; + + /* Stability for the rest */ + if (x < y) + return -1; + if (x > y) + return 1; + + return 0; +} + static void event_free(sd_event *e) { assert(e); @@ -287,6 +322,7 @@ static void event_free(sd_event *e) { prioq_free(e->monotonic_latest); prioq_free(e->realtime_earliest); prioq_free(e->realtime_latest); + prioq_free(e->quit); free(e->signal_sources); @@ -298,14 +334,13 @@ int sd_event_new(sd_event** ret) { sd_event *e; int r; - if (!ret) - return -EINVAL; + assert_return(ret, -EINVAL); e = new0(sd_event, 1); if (!e) return -ENOMEM; - e->n_ref = REFCNT_INIT; + e->n_ref = 1; e->signal_fd = e->realtime_fd = e->monotonic_fd = e->epoll_fd = -1; e->realtime_next = e->monotonic_next = (usec_t) -1; e->original_pid = getpid(); @@ -333,19 +368,21 @@ fail: } sd_event* sd_event_ref(sd_event *e) { - if (!e) - return NULL; + assert_return(e, NULL); - assert_se(REFCNT_INC(e->n_ref) >= 2); + assert(e->n_ref >= 1); + e->n_ref++; return e; } sd_event* sd_event_unref(sd_event *e) { - if (!e) - return NULL; + assert_return(e, NULL); - if (REFCNT_DEC(e->n_ref) <= 0) + assert(e->n_ref >= 1); + e->n_ref--; + + if (e->n_ref <= 0) event_free(e); return NULL; @@ -377,18 +414,22 @@ static int source_io_unregister(sd_event_source *s) { return 0; } -static int source_io_register(sd_event_source *s, sd_event_mute_t m, uint32_t events) { +static int source_io_register( + sd_event_source *s, + int enabled, + uint32_t events) { + struct epoll_event ev = {}; int r; assert(s); assert(s->type == SOURCE_IO); - assert(m != SD_EVENT_MUTED); + assert(enabled != SD_EVENT_OFF); ev.events = events; ev.data.ptr = s; - if (m == SD_EVENT_ONESHOT) + if (enabled == SD_EVENT_ONESHOT) ev.events |= EPOLLONESHOT; if (s->io.registered) @@ -428,7 +469,7 @@ static void source_free(sd_event_source *s) { case SOURCE_SIGNAL: if (s->signal.sig > 0) { - if (s->signal.sig != SIGCHLD || s->event->n_unmuted_child_sources == 0) + if (s->signal.sig != SIGCHLD || s->event->n_enabled_child_sources == 0) assert_se(sigdelset(&s->event->sigset, s->signal.sig) == 0); if (s->event->signal_sources) @@ -439,9 +480,9 @@ static void source_free(sd_event_source *s) { case SOURCE_CHILD: if (s->child.pid > 0) { - if (s->mute != SD_EVENT_MUTED) { - assert(s->event->n_unmuted_child_sources > 0); - s->event->n_unmuted_child_sources--; + 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[SIGCHLD]) @@ -451,6 +492,14 @@ static void source_free(sd_event_source *s) { } break; + + case SOURCE_DEFER: + /* nothing */ + break; + + case SOURCE_QUIT: + prioq_remove(s->event->quit, s, &s->quit.prioq_index); + break; } if (s->pending) @@ -469,6 +518,7 @@ static int source_set_pending(sd_event_source *s, bool b) { int r; assert(s); + assert(s->type != SOURCE_QUIT); if (s->pending == b) return 0; @@ -498,10 +548,9 @@ static sd_event_source *source_new(sd_event *e, EventSourceType type) { if (!s) return NULL; - s->n_ref = REFCNT_INIT; + s->n_ref = 1; s->event = sd_event_ref(e); s->type = type; - s->mute = SD_EVENT_UNMUTED; s->pending_index = s->prepare_index = PRIOQ_IDX_NULL; return s; @@ -518,18 +567,13 @@ int sd_event_add_io( sd_event_source *s; int r; - if (!e) - return -EINVAL; - if (fd < 0) - return -EINVAL; - if (events & ~(EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLPRI|EPOLLERR|EPOLLHUP)) - return -EINVAL; - if (!callback) - return -EINVAL; - if (!ret) - return -EINVAL; - if (event_pid_changed(e)) - return -ECHILD; + assert_return(e, -EINVAL); + assert_return(fd >= 0, -EINVAL); + assert_return(!(events & ~(EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLPRI|EPOLLERR|EPOLLHUP)), -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); if (!s) @@ -539,8 +583,9 @@ int sd_event_add_io( s->io.events = events; s->io.callback = callback; s->userdata = userdata; + s->enabled = SD_EVENT_ON; - r = source_io_register(s, s->mute, events); + r = source_io_register(s, s->enabled, events); if (r < 0) { source_free(s); return -errno; @@ -610,18 +655,13 @@ static int event_add_time_internal( sd_event_source *s; int r; - if (!e) - return -EINVAL; - if (!callback) - return -EINVAL; - if (!ret) - return -EINVAL; - if (usec == (uint64_t) -1) - return -EINVAL; - if (accuracy == (uint64_t) -1) - return -EINVAL; - if (event_pid_changed(e)) - return -ECHILD; + 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(e->state != SD_EVENT_FINISHED, -ESTALE); + assert_return(!event_pid_changed(e), -ECHILD); assert(timer_fd); assert(earliest); @@ -652,9 +692,9 @@ static int event_add_time_internal( s->time.next = usec; s->time.accuracy = accuracy == 0 ? DEFAULT_ACCURACY_USEC : accuracy; s->time.callback = callback; - s->time.earliest_index = PRIOQ_IDX_NULL; - s->time.latest_index = PRIOQ_IDX_NULL; + s->time.earliest_index = s->time.latest_index = PRIOQ_IDX_NULL; s->userdata = userdata; + s->enabled = SD_EVENT_ONESHOT; r = prioq_put(*earliest, s, &s->time.earliest_index); if (r < 0) @@ -712,22 +752,23 @@ static int event_update_signal_fd(sd_event *e) { return 0; } -int sd_event_add_signal(sd_event *e, int sig, sd_signal_handler_t callback, void *userdata, sd_event_source **ret) { +int sd_event_add_signal( + sd_event *e, + int sig, + sd_signal_handler_t callback, + void *userdata, + sd_event_source **ret) { + sd_event_source *s; int r; - if (!e) - return -EINVAL; - if (sig <= 0) - return -EINVAL; - if (sig >= _NSIG) - return -EINVAL; - if (!callback) - return -EINVAL; - if (!ret) - return -EINVAL; - if (event_pid_changed(e)) - return -ECHILD; + 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 (!e->signal_sources) { e->signal_sources = new0(sd_event_source*, _NSIG); @@ -743,11 +784,12 @@ int sd_event_add_signal(sd_event *e, int sig, sd_signal_handler_t callback, void s->signal.sig = sig; s->signal.callback = callback; s->userdata = userdata; + s->enabled = SD_EVENT_ON; e->signal_sources[sig] = s; assert_se(sigaddset(&e->sigset, sig) == 0); - if (sig != SIGCHLD || e->n_unmuted_child_sources == 0) { + if (sig != SIGCHLD || e->n_enabled_child_sources == 0) { r = event_update_signal_fd(e); if (r < 0) { source_free(s); @@ -759,22 +801,25 @@ int sd_event_add_signal(sd_event *e, int sig, sd_signal_handler_t callback, void return 0; } -int sd_event_add_child(sd_event *e, pid_t pid, int options, sd_child_handler_t callback, void *userdata, sd_event_source **ret) { +int sd_event_add_child( + sd_event *e, + pid_t pid, + int options, + sd_child_handler_t callback, + void *userdata, + sd_event_source **ret) { + sd_event_source *s; int r; - if (!e) - return -EINVAL; - if (pid <= 1) - return -EINVAL; - if (options & ~(WEXITED|WSTOPPED|WCONTINUED)) - return -EINVAL; - if (!callback) - return -EINVAL; - if (!ret) - return -EINVAL; - if (event_pid_changed(e)) - return -ECHILD; + assert_return(e, -EINVAL); + assert_return(pid > 1, -EINVAL); + 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); r = hashmap_ensure_allocated(&e->child_sources, trivial_hash_func, trivial_compare_func); if (r < 0) @@ -791,6 +836,7 @@ int sd_event_add_child(sd_event *e, pid_t pid, int options, sd_child_handler_t c s->child.options = options; s->child.callback = callback; s->userdata = userdata; + s->enabled = SD_EVENT_ONESHOT; r = hashmap_put(e->child_sources, INT_TO_PTR(pid), s); if (r < 0) { @@ -798,7 +844,7 @@ int sd_event_add_child(sd_event *e, pid_t pid, int options, sd_child_handler_t c return r; } - e->n_unmuted_child_sources ++; + e->n_enabled_child_sources ++; assert_se(sigaddset(&e->sigset, SIGCHLD) == 0); @@ -816,16 +862,20 @@ int sd_event_add_child(sd_event *e, pid_t pid, int options, sd_child_handler_t c return 0; } -int sd_event_add_defer(sd_event *e, sd_defer_handler_t callback, void *userdata, sd_event_source **ret) { +int sd_event_add_defer( + sd_event *e, + sd_defer_handler_t callback, + void *userdata, + sd_event_source **ret) { + sd_event_source *s; int r; - if (!e) - return -EINVAL; - if (!ret) - return -EINVAL; - if (event_pid_changed(e)) - return -ECHILD; + 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); if (!s) @@ -833,6 +883,7 @@ int sd_event_add_defer(sd_event *e, sd_defer_handler_t callback, void *userdata, s->defer.callback = callback; s->userdata = userdata; + s->enabled = SD_EVENT_ONESHOT; r = source_set_pending(s, true); if (r < 0) { @@ -844,62 +895,95 @@ int sd_event_add_defer(sd_event *e, sd_defer_handler_t callback, void *userdata, return 0; } -sd_event_source* sd_event_source_ref(sd_event_source *s) { +int sd_event_add_quit( + sd_event *e, + sd_quit_handler_t callback, + void *userdata, + sd_event_source **ret) { + + 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); + + if (!e->quit) { + e->quit = prioq_new(quit_prioq_compare); + if (!e->quit) + return -ENOMEM; + } + + s = source_new(e, SOURCE_QUIT); if (!s) - return NULL; + return -ENOMEM; - assert_se(REFCNT_INC(s->n_ref) >= 2); + s->quit.callback = callback; + s->userdata = userdata; + s->quit.prioq_index = PRIOQ_IDX_NULL; + s->enabled = SD_EVENT_ONESHOT; + + r = prioq_put(s->event->quit, s, &s->quit.prioq_index); + if (r < 0) { + source_free(s); + return r; + } + + *ret = s; + return 0; +} + +sd_event_source* sd_event_source_ref(sd_event_source *s) { + assert_return(s, NULL); + + assert(s->n_ref >= 1); + s->n_ref++; return s; } sd_event_source* sd_event_source_unref(sd_event_source *s) { - if (!s) - return NULL; + assert_return(s, NULL); + + assert(s->n_ref >= 1); + s->n_ref--; - if (REFCNT_DEC(s->n_ref) <= 0) + if (s->n_ref <= 0) source_free(s); return NULL; } - sd_event *sd_event_get(sd_event_source *s) { - if (!s) - return NULL; + assert_return(s, NULL); return s->event; } int sd_event_source_get_pending(sd_event_source *s) { - if (!s) - return -EINVAL; - if (event_pid_changed(s->event)) - return -ECHILD; + assert_return(s, -EINVAL); + assert_return(s->type != SOURCE_QUIT, -EDOM); + assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE); + assert_return(!event_pid_changed(s->event), -ECHILD); return s->pending; } int sd_event_source_get_io_fd(sd_event_source *s) { - if (!s) - return -EINVAL; - if (s->type != SOURCE_IO) - return -EDOM; - if (event_pid_changed(s->event)) - return -ECHILD; + assert_return(s, -EINVAL); + assert_return(s->type == SOURCE_IO, -EDOM); + assert_return(!event_pid_changed(s->event), -ECHILD); return s->io.fd; } int sd_event_source_get_io_events(sd_event_source *s, uint32_t* events) { - if (!s) - return -EINVAL; - if (s->type != SOURCE_IO) - return -EDOM; - if (!events) - return -EINVAL; - if (event_pid_changed(s->event)) - return -ECHILD; + assert_return(s, -EINVAL); + assert_return(events, -EINVAL); + assert_return(s->type == SOURCE_IO, -EDOM); + assert_return(!event_pid_changed(s->event), -ECHILD); *events = s->io.events; return 0; @@ -908,20 +992,17 @@ int sd_event_source_get_io_events(sd_event_source *s, uint32_t* events) { int sd_event_source_set_io_events(sd_event_source *s, uint32_t events) { int r; - if (!s) - return -EINVAL; - if (!s->type != SOURCE_IO) - return -EDOM; - if (events & ~(EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLPRI|EPOLLERR|EPOLLHUP)) - return -EINVAL; - if (event_pid_changed(s->event)) - return -ECHILD; + assert_return(s, -EINVAL); + assert_return(s->type == SOURCE_IO, -EDOM); + assert_return(!(events & ~(EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLPRI|EPOLLERR|EPOLLHUP)), -EINVAL); + assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE); + assert_return(!event_pid_changed(s->event), -ECHILD); if (s->io.events == events) return 0; - if (s->mute != SD_EVENT_MUTED) { - r = source_io_register(s, s->io.events, events); + if (s->enabled != SD_EVENT_OFF) { + r = source_io_register(s, s->enabled, events); if (r < 0) return r; } @@ -932,46 +1013,35 @@ int sd_event_source_set_io_events(sd_event_source *s, uint32_t events) { } int sd_event_source_get_io_revents(sd_event_source *s, uint32_t* revents) { - if (!s) - return -EINVAL; - if (s->type != SOURCE_IO) - return -EDOM; - if (!revents) - return -EINVAL; - if (!s->pending) - return -ENODATA; - if (event_pid_changed(s->event)) - return -ECHILD; + assert_return(s, -EINVAL); + assert_return(revents, -EINVAL); + assert_return(s->type == SOURCE_IO, -EDOM); + assert_return(s->pending, -ENODATA); + assert_return(!event_pid_changed(s->event), -ECHILD); *revents = s->io.revents; return 0; } int sd_event_source_get_signal(sd_event_source *s) { - if (!s) - return -EINVAL; - if (s->type != SOURCE_SIGNAL) - return -EDOM; - if (event_pid_changed(s->event)) - return -ECHILD; + assert_return(s, -EINVAL); + assert_return(s->type == SOURCE_SIGNAL, -EDOM); + assert_return(!event_pid_changed(s->event), -ECHILD); return s->signal.sig; } int sd_event_source_get_priority(sd_event_source *s, int *priority) { - if (!s) - return -EINVAL; - if (event_pid_changed(s->event)) - return -ECHILD; + assert_return(s, -EINVAL); + assert_return(!event_pid_changed(s->event), -ECHILD); return s->priority; } int sd_event_source_set_priority(sd_event_source *s, int priority) { - if (!s) - return -EINVAL; - if (event_pid_changed(s->event)) - return -ECHILD; + assert_return(s, -EINVAL); + assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE); + assert_return(!event_pid_changed(s->event), -ECHILD); if (s->priority == priority) return 0; @@ -984,35 +1054,33 @@ int sd_event_source_set_priority(sd_event_source *s, int priority) { if (s->prepare) prioq_reshuffle(s->event->prepare, s, &s->prepare_index); + if (s->type == SOURCE_QUIT) + prioq_reshuffle(s->event->quit, s, &s->quit.prioq_index); + return 0; } -int sd_event_source_get_mute(sd_event_source *s, sd_event_mute_t *m) { - if (!s) - return -EINVAL; - if (!m) - return -EINVAL; - if (event_pid_changed(s->event)) - return -ECHILD; +int sd_event_source_get_enabled(sd_event_source *s, int *m) { + assert_return(s, -EINVAL); + assert_return(m, -EINVAL); + assert_return(!event_pid_changed(s->event), -ECHILD); - *m = s->mute; + *m = s->enabled; return 0; } -int sd_event_source_set_mute(sd_event_source *s, sd_event_mute_t m) { +int sd_event_source_set_enabled(sd_event_source *s, int m) { int r; - if (!s) - return -EINVAL; - if (m != SD_EVENT_MUTED && m != SD_EVENT_UNMUTED && !SD_EVENT_ONESHOT) - return -EINVAL; - if (event_pid_changed(s->event)) - return -ECHILD; + 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 (s->mute == m) + if (s->enabled == m) return 0; - if (m == SD_EVENT_MUTED) { + if (m == SD_EVENT_OFF) { switch (s->type) { @@ -1021,24 +1089,24 @@ int sd_event_source_set_mute(sd_event_source *s, sd_event_mute_t m) { if (r < 0) return r; - s->mute = m; + s->enabled = m; break; case SOURCE_MONOTONIC: - s->mute = m; + 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_REALTIME: - s->mute = m; + 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); break; case SOURCE_SIGNAL: - s->mute = m; - if (s->signal.sig != SIGCHLD || s->event->n_unmuted_child_sources == 0) { + s->enabled = m; + if (s->signal.sig != SIGCHLD || s->event->n_enabled_child_sources == 0) { assert_se(sigdelset(&s->event->sigset, s->signal.sig) == 0); event_update_signal_fd(s->event); } @@ -1046,10 +1114,10 @@ int sd_event_source_set_mute(sd_event_source *s, sd_event_mute_t m) { break; case SOURCE_CHILD: - s->mute = m; + s->enabled = m; - assert(s->event->n_unmuted_child_sources > 0); - s->event->n_unmuted_child_sources--; + assert(s->event->n_enabled_child_sources > 0); + s->event->n_enabled_child_sources--; if (!s->event->signal_sources || !s->event->signal_sources[SIGCHLD]) { assert_se(sigdelset(&s->event->sigset, SIGCHLD) == 0); @@ -1058,8 +1126,13 @@ int sd_event_source_set_mute(sd_event_source *s, sd_event_mute_t m) { break; + case SOURCE_QUIT: + s->enabled = m; + prioq_reshuffle(s->event->quit, s, &s->quit.prioq_index); + break; + case SOURCE_DEFER: - s->mute = m; + s->enabled = m; break; } @@ -1071,35 +1144,35 @@ int sd_event_source_set_mute(sd_event_source *s, sd_event_mute_t m) { if (r < 0) return r; - s->mute = m; + s->enabled = m; break; case SOURCE_MONOTONIC: - s->mute = m; + 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_REALTIME: - s->mute = m; + 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); break; case SOURCE_SIGNAL: - s->mute = m; + s->enabled = m; - if (s->signal.sig != SIGCHLD || s->event->n_unmuted_child_sources == 0) { + if (s->signal.sig != SIGCHLD || s->event->n_enabled_child_sources == 0) { assert_se(sigaddset(&s->event->sigset, s->signal.sig) == 0); event_update_signal_fd(s->event); } break; case SOURCE_CHILD: - s->mute = m; + s->enabled = m; - if (s->mute == SD_EVENT_MUTED) { - s->event->n_unmuted_child_sources++; + if (s->enabled == SD_EVENT_OFF) { + s->event->n_enabled_child_sources++; if (!s->event->signal_sources || !s->event->signal_sources[SIGCHLD]) { assert_se(sigaddset(&s->event->sigset, SIGCHLD) == 0); @@ -1108,8 +1181,13 @@ int sd_event_source_set_mute(sd_event_source *s, sd_event_mute_t m) { } break; + case SOURCE_QUIT: + s->enabled = m; + prioq_reshuffle(s->event->quit, s, &s->quit.prioq_index); + break; + case SOURCE_DEFER: - s->mute = m; + s->enabled = m; break; } } @@ -1124,28 +1202,21 @@ int sd_event_source_set_mute(sd_event_source *s, sd_event_mute_t m) { } int sd_event_source_get_time(sd_event_source *s, uint64_t *usec) { - if (!s) - return -EINVAL; - if (!usec) - return -EINVAL; - if (s->type != SOURCE_REALTIME && s->type != SOURCE_MONOTONIC) - return -EDOM; - if (event_pid_changed(s->event)) - return -ECHILD; + assert_return(s, -EINVAL); + assert_return(usec, -EINVAL); + assert_return(s->type == SOURCE_REALTIME || s->type == SOURCE_MONOTONIC, -EDOM); + assert_return(!event_pid_changed(s->event), -ECHILD); *usec = s->time.next; return 0; } int sd_event_source_set_time(sd_event_source *s, uint64_t usec) { - if (!s) - return -EINVAL; - if (usec == (uint64_t) -1) - return -EINVAL; - if (s->type != SOURCE_REALTIME && s->type != SOURCE_MONOTONIC) - return -EDOM; - if (event_pid_changed(s->event)) - return -ECHILD; + assert_return(s, -EINVAL); + assert_return(usec != (uint64_t) -1, -EINVAL); + assert_return(s->type == SOURCE_REALTIME || s->type == SOURCE_MONOTONIC, -EDOM); + assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE); + assert_return(!event_pid_changed(s->event), -ECHILD); if (s->time.next == usec) return 0; @@ -1163,13 +1234,22 @@ int sd_event_source_set_time(sd_event_source *s, uint64_t usec) { return 0; } +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_pid_changed(s->event), -ECHILD); + + *usec = s->time.accuracy; + return 0; +} + int sd_event_source_set_time_accuracy(sd_event_source *s, uint64_t usec) { - if (!s) - return -EINVAL; - if (s->type != SOURCE_MONOTONIC && s->type != SOURCE_REALTIME) - return -EDOM; - if (event_pid_changed(s->event)) - return -ECHILD; + assert_return(s, -EINVAL); + assert_return(usec != (uint64_t) -1, -EINVAL); + assert_return(s->type == SOURCE_REALTIME || s->type == SOURCE_MONOTONIC, -EDOM); + assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE); + assert_return(!event_pid_changed(s->event), -ECHILD); if (usec == 0) usec = DEFAULT_ACCURACY_USEC; @@ -1177,7 +1257,6 @@ int sd_event_source_set_time_accuracy(sd_event_source *s, uint64_t usec) { if (s->time.accuracy == usec) return 0; - s->time.accuracy = usec; if (s->type == SOURCE_REALTIME) @@ -1188,27 +1267,23 @@ int sd_event_source_set_time_accuracy(sd_event_source *s, uint64_t usec) { return 0; } -int sd_event_source_get_time_accuracy(sd_event_source *s, uint64_t *usec) { - if (!s) - return -EINVAL; - if (!usec) - return -EINVAL; - if (s->type != SOURCE_MONOTONIC && s->type != SOURCE_REALTIME) - return -EDOM; - if (event_pid_changed(s->event)) - return -ECHILD; +int sd_event_source_get_child_pid(sd_event_source *s, pid_t *pid) { + assert_return(s, -EINVAL); + assert_return(pid, -EINVAL); + assert_return(s->type == SOURCE_CHILD, -EDOM); + assert_return(!event_pid_changed(s->event), -ECHILD); - *usec = s->time.accuracy; + *pid = s->child.pid; return 0; } int sd_event_source_set_prepare(sd_event_source *s, sd_prepare_handler_t callback) { int r; - if (!s) - return -EINVAL; - if (event_pid_changed(s->event)) - return -ECHILD; + assert_return(s, -EINVAL); + assert_return(s->type != SOURCE_QUIT, -EDOM); + assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE); + assert_return(!event_pid_changed(s->event), -ECHILD); if (s->prepare == callback) return 0; @@ -1235,8 +1310,7 @@ int sd_event_source_set_prepare(sd_event_source *s, sd_prepare_handler_t callbac } void* sd_event_source_get_userdata(sd_event_source *s) { - if (!s) - return NULL; + assert_return(s, NULL); return s->userdata; } @@ -1310,11 +1384,23 @@ static int event_arm_timer( assert_se(next); a = prioq_peek(earliest); - if (!a || a->mute == SD_EVENT_MUTED) + if (!a || a->enabled == SD_EVENT_OFF) { + + if (*next == (usec_t) -1) + return 0; + + /* disarm */ + r = timerfd_settime(timer_fd, TFD_TIMER_ABSTIME, &its, NULL); + if (r < 0) + return r; + + *next = (usec_t) -1; + return 0; + } b = prioq_peek(latest); - assert_se(b && b->mute != SD_EVENT_MUTED); + assert_se(b && b->enabled != SD_EVENT_OFF); t = sleep_between(e, a->time.next, b->time.next + b->time.accuracy); if (*next == t) @@ -1350,20 +1436,21 @@ static int process_io(sd_event *e, sd_event_source *s, uint32_t events) { anymore. We can save a syscall here... */ - if (s->mute == SD_EVENT_ONESHOT) + if (s->enabled == SD_EVENT_ONESHOT) s->io.registered = false; return source_set_pending(s, true); } -static int flush_timer(sd_event *e, int fd, uint32_t events) { +static int flush_timer(sd_event *e, int fd, uint32_t events, usec_t *next) { uint64_t x; ssize_t ss; assert(e); + assert(fd >= 0); + assert(next); - if (events != EPOLLIN) - return -EIO; + assert_return(events == EPOLLIN, -EIO); ss = read(fd, &x, sizeof(x)); if (ss < 0) { @@ -1376,10 +1463,17 @@ static int flush_timer(sd_event *e, int fd, uint32_t events) { if (ss != sizeof(x)) return -EIO; + *next = (usec_t) -1; + return 0; } -static int process_timer(sd_event *e, usec_t n, Prioq *earliest, Prioq *latest) { +static int process_timer( + sd_event *e, + usec_t n, + Prioq *earliest, + Prioq *latest) { + sd_event_source *s; int r; @@ -1389,7 +1483,7 @@ static int process_timer(sd_event *e, usec_t n, Prioq *earliest, Prioq *latest) s = prioq_peek(earliest); if (!s || s->time.next > n || - s->mute == SD_EVENT_MUTED || + s->enabled == SD_EVENT_OFF || s->pending) break; @@ -1433,7 +1527,7 @@ static int process_child(sd_event *e) { if (s->pending) continue; - if (s->mute == SD_EVENT_MUTED) + if (s->enabled == SD_EVENT_OFF) continue; zero(s->child.siginfo); @@ -1452,15 +1546,17 @@ static int process_child(sd_event *e) { } static int process_signal(sd_event *e, uint32_t events) { - struct signalfd_siginfo si; bool read_one = false; - ssize_t ss; int r; - if (events != EPOLLIN) - return -EIO; + assert(e); + assert(e->signal_sources); + + assert_return(events == EPOLLIN, -EIO); for (;;) { + struct signalfd_siginfo si; + ssize_t ss; sd_event_source *s; ss = read(e->signal_fd, &si, sizeof(si)); @@ -1476,17 +1572,16 @@ 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 || !e->signal_sources[si.ssi_signo]) + if (r > 0 || !s) continue; - } else { - s = e->signal_sources[si.ssi_signo]; + } else if (!s) return -EIO; - } s->signal.siginfo = si; r = source_set_pending(s, true); @@ -1499,17 +1594,19 @@ static int process_signal(sd_event *e, uint32_t events) { } static int source_dispatch(sd_event_source *s) { - int r; + int r = 0; assert(s); - assert(s->pending); + assert(s->pending || s->type == SOURCE_QUIT); - r = source_set_pending(s, false); - if (r < 0) - return r; + if (s->type != SOURCE_DEFER && s->type != SOURCE_QUIT) { + r = source_set_pending(s, false); + if (r < 0) + return r; + } - if (s->mute == SD_EVENT_ONESHOT) { - r = sd_event_source_set_mute(s, SD_EVENT_MUTED); + if (s->enabled == SD_EVENT_ONESHOT) { + r = sd_event_source_set_enabled(s, SD_EVENT_OFF); if (r < 0) return r; } @@ -1539,6 +1636,10 @@ static int source_dispatch(sd_event_source *s) { case SOURCE_DEFER: r = s->defer.callback(s, s->userdata); break; + + case SOURCE_QUIT: + r = s->quit.callback(s, s->userdata); + break; } return r; @@ -1553,7 +1654,7 @@ static int event_prepare(sd_event *e) { sd_event_source *s; s = prioq_peek(e->prepare); - if (!s || s->prepare_iteration == e->iteration || s->mute == SD_EVENT_MUTED) + if (!s || s->prepare_iteration == e->iteration || s->enabled == SD_EVENT_OFF) break; s->prepare_iteration = e->iteration; @@ -1571,14 +1672,40 @@ static int event_prepare(sd_event *e) { return 0; } +static int dispatch_quit(sd_event *e) { + sd_event_source *p; + int r; + + assert(e); + + p = prioq_peek(e->quit); + if (!p || p->enabled == SD_EVENT_OFF) { + e->state = SD_EVENT_FINISHED; + return 0; + } + + sd_event_ref(e); + e->iteration++; + e->state = SD_EVENT_QUITTING; + + r = source_dispatch(p); + + e->state = SD_EVENT_PASSIVE; + sd_event_unref(e); + + return r; +} + static sd_event_source* event_next_pending(sd_event *e) { sd_event_source *p; + assert(e); + p = prioq_peek(e->pending); if (!p) return NULL; - if (p->mute == SD_EVENT_MUTED) + if (p->enabled == SD_EVENT_OFF) return NULL; return p; @@ -1588,20 +1715,22 @@ int sd_event_run(sd_event *e, uint64_t timeout) { struct epoll_event ev_queue[EPOLL_QUEUE_MAX]; sd_event_source *p; int r, i, m; - dual_timestamp n; - if (!e) - return -EINVAL; - if (e->quit) - return -ESTALE; - if (event_pid_changed(e)) - return -ECHILD; + 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); + if (e->quit_requested) + return dispatch_quit(e); + + sd_event_ref(e); e->iteration++; + e->state = SD_EVENT_RUNNING; r = event_prepare(e); if (r < 0) - return r; + goto finish; if (event_next_pending(e) || e->need_process_child) timeout = 0; @@ -1609,88 +1738,127 @@ int sd_event_run(sd_event *e, uint64_t timeout) { if (timeout > 0) { r = event_arm_timer(e, e->monotonic_fd, e->monotonic_earliest, e->monotonic_latest, &e->monotonic_next); if (r < 0) - return r; + goto finish; r = event_arm_timer(e, e->realtime_fd, e->realtime_earliest, e->realtime_latest, &e->realtime_next); if (r < 0) - return r; + goto finish; } m = epoll_wait(e->epoll_fd, ev_queue, EPOLL_QUEUE_MAX, timeout == (uint64_t) -1 ? -1 : (int) ((timeout + USEC_PER_MSEC - 1) / USEC_PER_MSEC)); - if (m < 0) - return m; + if (m < 0) { + r = errno == EAGAIN || errno == EINTR ? 0 : -errno; + goto finish; + } - dual_timestamp_get(&n); + dual_timestamp_get(&e->timestamp); 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); + 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); + 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_SIGNAL)) r = process_signal(e, ev_queue[i].events); else r = process_io(e, ev_queue[i].data.ptr, ev_queue[i].events); if (r < 0) - return r; + goto finish; } - r = process_timer(e, n.monotonic, e->monotonic_earliest, e->monotonic_latest); + r = process_timer(e, e->timestamp.monotonic, e->monotonic_earliest, e->monotonic_latest); if (r < 0) - return r; + goto finish; - r = process_timer(e, n.realtime, e->realtime_earliest, e->realtime_latest); + r = process_timer(e, e->timestamp.realtime, e->realtime_earliest, e->realtime_latest); if (r < 0) - return r; + goto finish; if (e->need_process_child) { r = process_child(e); if (r < 0) - return r; + goto finish; } p = event_next_pending(e); - if (!p) - return 0; + if (!p) { + r = 0; + goto finish; + } + + r = source_dispatch(p); - return source_dispatch(p); +finish: + e->state = SD_EVENT_PASSIVE; + sd_event_unref(e); + + return r; } int sd_event_loop(sd_event *e) { int r; - if (!e) - return -EINVAL; - if (event_pid_changed(e)) - return -ECHILD; + assert_return(e, -EINVAL); + assert_return(!event_pid_changed(e), -ECHILD); + assert_return(e->state == SD_EVENT_PASSIVE, -EBUSY); - while (!e->quit) { + sd_event_ref(e); + + while (e->state != SD_EVENT_FINISHED) { r = sd_event_run(e, (uint64_t) -1); if (r < 0) - return r; + goto finish; } - return 0; + r = 0; + +finish: + sd_event_unref(e); + return r; } -int sd_event_quit(sd_event *e) { - if (!e) - return EINVAL; - if (event_pid_changed(e)) - return -ECHILD; +int sd_event_get_state(sd_event *e) { + assert_return(e, -EINVAL); + assert_return(!event_pid_changed(e), -ECHILD); - return e->quit; + return e->state; +} + +int sd_event_get_quit(sd_event *e) { + assert_return(e, -EINVAL); + assert_return(!event_pid_changed(e), -ECHILD); + + return e->quit_requested; } int sd_event_request_quit(sd_event *e) { - if (!e) - return -EINVAL; - if (event_pid_changed(e)) - return -ECHILD; + assert_return(e, -EINVAL); + assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); + assert_return(!event_pid_changed(e), -ECHILD); + + e->quit_requested = true; + return 0; +} + +int sd_event_get_now_realtime(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); + + *usec = e->timestamp.realtime; + return 0; +} + +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); - e->quit = true; + *usec = e->timestamp.monotonic; return 0; }