sd-event.c revision 6203e07a83214a55bb1f88508fcda2005c601dea
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering This file is part of systemd.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering Copyright 2013 Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering systemd is free software; you can redistribute it and/or modify it
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering under the terms of the GNU Lesser General Public License as published by
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering (at your option) any later version.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering systemd is distributed in the hope that it will be useful, but
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering Lesser General Public License for more details.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering You should have received a copy of the GNU Lesser General Public License
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen#define DEFAULT_ACCURACY_USEC (250 * USEC_PER_MSEC)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* For both clocks we maintain two priority queues each, one
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * ordered for the earliest times the events may be
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * dispatched, and one ordered by the latest times they must
91b14d6ff362b938a72db17b095ee9903d07381bTom Gundersen * have been dispatched. The range between the top entries in
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * the two prioqs is the time window we can freely schedule
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * wakeups in */
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poetteringstatic int pending_prioq_compare(const void *a, const void *b) {
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering const sd_event_source *x = a, *y = b;
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering /* Enabled ones first */
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering /* Lower priority values first */
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering /* Older entries first */
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering if (x->pending_iteration < y->pending_iteration)
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering if (x->pending_iteration > y->pending_iteration)
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering /* Stability for the rest */
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poetteringstatic int prepare_prioq_compare(const void *a, const void *b) {
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering const sd_event_source *x = a, *y = b;
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering /* Move most recently prepared ones last, so that we can stop
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering * preparing as soon as we hit one that has already been
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering * prepared in the current iteration */
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering if (x->prepare_iteration < y->prepare_iteration)
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering if (x->prepare_iteration > y->prepare_iteration)
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering /* Enabled ones first */
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering /* Lower priority values first */
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering /* Stability for the rest */
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poetteringstatic int earliest_time_prioq_compare(const void *a, const void *b) {
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering const sd_event_source *x = a, *y = b;
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering assert(x->type == SOURCE_MONOTONIC || x->type == SOURCE_REALTIME);
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering assert(y->type == SOURCE_MONOTONIC || y->type == SOURCE_REALTIME);
9df3ba6c6cb65eecec06f39dfe85a3596cedac4eTom Gundersen /* Enabled ones first */
9df3ba6c6cb65eecec06f39dfe85a3596cedac4eTom Gundersen if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering /* Move the pending ones to the end */
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering /* Order by time */
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering /* Stability for the rest */
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poetteringstatic int latest_time_prioq_compare(const void *a, const void *b) {
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering const sd_event_source *x = a, *y = b;
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering assert((x->type == SOURCE_MONOTONIC && y->type == SOURCE_MONOTONIC) ||
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering (x->type == SOURCE_REALTIME && y->type == SOURCE_REALTIME));
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering /* Enabled ones first */
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
84129d46cd6e95e142973da93aede4c7433c9600Lennart Poettering if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
d74fb368b18f0fbd9a4fe6f15691bbea7f3c4a01Tom Gundersen /* Move the pending ones to the end */
efd46a696d31097c38f653b36921e00c4df62319Lennart Poettering /* Order by time */
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen if (x->time.next + x->time.accuracy < y->time.next + y->time.accuracy)
9df3ba6c6cb65eecec06f39dfe85a3596cedac4eTom Gundersen if (x->time.next + x->time.accuracy > y->time.next + y->time.accuracy)
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen /* Stability for the rest */
84129d46cd6e95e142973da93aede4c7433c9600Lennart Poetteringstatic int exit_prioq_compare(const void *a, const void *b) {
84129d46cd6e95e142973da93aede4c7433c9600Lennart Poettering const sd_event_source *x = a, *y = b;
f4461e5641d53f27d6e76e0607bdaa9c0c58c1f6Lennart Poettering /* Enabled ones first */
4e0b8b17a7465653f4e7b819dad5f8e30d64c0c4Tom Gundersen if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
4e0b8b17a7465653f4e7b819dad5f8e30d64c0c4Tom Gundersen if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
f4461e5641d53f27d6e76e0607bdaa9c0c58c1f6Lennart Poettering /* Lower priority values first */
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering /* Stability for the rest */
6cb08a8930bdaca950b152b1e8b82466ed59511cLennart Poettering e->signal_fd = e->realtime_fd = e->monotonic_fd = e->watchdog_fd = e->epoll_fd = -1;
6cb08a8930bdaca950b152b1e8b82466ed59511cLennart Poettering e->realtime_next = e->monotonic_next = (usec_t) -1;
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering e->pending = prioq_new(pending_prioq_compare);
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering e->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering_public_ sd_event* sd_event_ref(sd_event *e) {
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering_public_ sd_event* sd_event_unref(sd_event *e) {
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poetteringstatic bool event_pid_changed(sd_event *e) {
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering /* We don't support people creating am event loop and keeping
6cb08a8930bdaca950b152b1e8b82466ed59511cLennart Poettering * it around over a fork(). Let's complain. */
f4461e5641d53f27d6e76e0607bdaa9c0c58c1f6Lennart Poetteringstatic int source_io_unregister(sd_event_source *s) {
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, s->io.fd, NULL);
6cb08a8930bdaca950b152b1e8b82466ed59511cLennart Poettering r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_MOD, s->io.fd, &ev);
6cb08a8930bdaca950b152b1e8b82466ed59511cLennart Poettering r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_ADD, s->io.fd, &ev);
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poetteringstatic void source_free(sd_event_source *s) {
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt prioq_remove(s->event->monotonic_earliest, s, &s->time.earliest_index);
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt prioq_remove(s->event->monotonic_latest, s, &s->time.latest_index);
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering prioq_remove(s->event->realtime_earliest, s, &s->time.earliest_index);
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering prioq_remove(s->event->realtime_latest, s, &s->time.latest_index);
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering if (s->signal.sig != SIGCHLD || s->event->n_enabled_child_sources == 0)
636e813dc98ea40c58c6c85bc5e7e3c9f0904ea2Lennart Poettering assert_se(sigdelset(&s->event->sigset, s->signal.sig) == 0);
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering s->event->signal_sources[s->signal.sig] = NULL;
636e813dc98ea40c58c6c85bc5e7e3c9f0904ea2Lennart Poettering assert(s->event->n_enabled_child_sources > 0);
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering if (!s->event->signal_sources || !s->event->signal_sources[SIGCHLD])
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering assert_se(sigdelset(&s->event->sigset, SIGCHLD) == 0);
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering hashmap_remove(s->event->child_sources, INT_TO_PTR(s->child.pid));
636e813dc98ea40c58c6c85bc5e7e3c9f0904ea2Lennart Poettering prioq_remove(s->event->exit, s, &s->exit.prioq_index);
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering prioq_remove(s->event->pending, s, &s->pending_index);
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering prioq_remove(s->event->prepare, s, &s->prepare_index);
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poetteringstatic int source_set_pending(sd_event_source *s, bool b) {
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering s->pending_iteration = s->event->iteration;
6cb08a8930bdaca950b152b1e8b82466ed59511cLennart Poettering r = prioq_put(s->event->pending, s, &s->pending_index);
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering assert_se(prioq_remove(s->event->pending, s, &s->pending_index));
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering prioq_reshuffle(s->event->realtime_earliest, s, &s->time.earliest_index);
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering prioq_reshuffle(s->event->realtime_latest, s, &s->time.latest_index);
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering } else if (s->type == SOURCE_MONOTONIC) {
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering prioq_reshuffle(s->event->monotonic_earliest, s, &s->time.earliest_index);
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering prioq_reshuffle(s->event->monotonic_latest, s, &s->time.latest_index);
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poetteringstatic sd_event_source *source_new(sd_event *e, EventSourceType type) {
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering s->pending_index = s->prepare_index = PRIOQ_IDX_NULL;
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering assert_return(!(events & ~(EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLPRI|EPOLLERR|EPOLLHUP|EPOLLET)), -EINVAL);
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering assert_return(!event_pid_changed(e), -ECHILD);
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering r = source_io_register(s, s->enabled, events);
static int event_setup_timer_fd(
sd_event *e,
int *timer_fd,
int r, fd;
assert(e);
if (fd < 0)
return -errno;
return -errno;
static int event_add_time_internal(
sd_event *e,
int *timer_fd,
void *userdata,
sd_event_source *s;
if (!*earliest) {
if (!*earliest)
return -ENOMEM;
if (!*latest) {
if (!*latest)
return -ENOMEM;
if (*timer_fd < 0) {
return -ENOMEM;
goto fail;
goto fail;
*ret = s;
fail:
source_free(s);
void *userdata,
return event_add_time_internal(e, SOURCE_MONOTONIC, &e->monotonic_fd, CLOCK_MONOTONIC, &e->monotonic_earliest, &e->monotonic_latest, usec, accuracy, callback, userdata, ret);
void *userdata,
return event_add_time_internal(e, SOURCE_REALTIME, &e->realtime_fd, CLOCK_REALTIME, &e->realtime_earliest, &e->monotonic_latest, usec, accuracy, callback, userdata, ret);
bool add_to_epoll;
assert(e);
return -errno;
e->signal_fd = r;
if (!add_to_epoll)
return -errno;
sd_event *e,
int sig,
void *userdata,
sd_event_source *s;
if (!e->signal_sources) {
if (!e->signal_sources)
return -ENOMEM;
return -EBUSY;
return -ENOMEM;
r = event_update_signal_fd(e);
source_free(s);
*ret = s;
sd_event *e,
int options,
void *userdata,
sd_event_source *s;
return -EBUSY;
return -ENOMEM;
source_free(s);
e->n_enabled_child_sources ++;
r = event_update_signal_fd(e);
source_free(s);
return -errno;
e->need_process_child = true;
*ret = s;
sd_event *e,
void *userdata,
sd_event_source *s;
return -ENOMEM;
r = source_set_pending(s, true);
source_free(s);
*ret = s;
sd_event *e,
void *userdata,
sd_event_source *s;
if (!e->exit) {
if (!e->exit)
return -ENOMEM;
return -ENOMEM;
source_free(s);
*ret = s;
s->n_ref++;
return NULL;
s->n_ref--;
if (s->n_ref <= 0)
source_free(s);
return NULL;
return s->event;
return s->pending;
assert_return(!(events & ~(EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLPRI|EPOLLERR|EPOLLHUP|EPOLLET)), -EINVAL);
source_set_pending(s, false);
return s->priority;
if (s->pending)
if (s->prepare)
*m = s->enabled;
if (s->enabled == m)
if (m == SD_EVENT_OFF) {
switch (s->type) {
case SOURCE_IO:
r = source_io_unregister(s);
s->enabled = m;
case SOURCE_MONOTONIC:
s->enabled = m;
case SOURCE_REALTIME:
s->enabled = m;
case SOURCE_SIGNAL:
s->enabled = m;
case SOURCE_CHILD:
s->enabled = m;
case SOURCE_EXIT:
s->enabled = m;
case SOURCE_DEFER:
s->enabled = m;
switch (s->type) {
case SOURCE_IO:
s->enabled = m;
case SOURCE_MONOTONIC:
s->enabled = m;
case SOURCE_REALTIME:
s->enabled = m;
case SOURCE_SIGNAL:
s->enabled = m;
case SOURCE_CHILD:
s->enabled = m;
case SOURCE_EXIT:
s->enabled = m;
case SOURCE_DEFER:
s->enabled = m;
if (s->pending)
if (s->prepare)
source_set_pending(s, false);
if (usec == 0)
source_set_pending(s, false);
if (callback) {
return s->userdata;
usec_t c;
assert(e);
assert(a <= b);
c -= USEC_PER_MINUTE;
c -= USEC_PER_SEC;
static int event_arm_timer(
sd_event *e,
int timer_fd,
sd_event_source *a, *b;
usec_t t;
assert(e);
if (timer_fd < 0)
if (*next == t)
return -errno;
*next = t;
assert(e);
assert(s);
return source_set_pending(s, true);
uint64_t x;
assert(e);
if (ss < 0) {
return -errno;
if (ss != sizeof(x))
return -EIO;
if (next)
static int process_timer(
sd_event *e,
usec_t n,
sd_event_source *s;
assert(e);
s->pending)
r = source_set_pending(s, true);
sd_event_source *s;
Iterator i;
assert(e);
e->need_process_child = false;
if (s->pending)
return -errno;
bool zombie =
r = source_set_pending(s, true);
bool read_one = false;
assert(e);
sd_event_source *s;
if (ss < 0) {
return read_one;
return -errno;
return -EIO;
read_one = true;
r = process_child(e);
return -EIO;
r = source_set_pending(s, true);
assert(s);
r = source_set_pending(s, false);
switch (s->type) {
case SOURCE_IO:
case SOURCE_MONOTONIC:
case SOURCE_REALTIME:
case SOURCE_SIGNAL:
case SOURCE_CHILD: {
bool zombie;
if (zombie)
case SOURCE_DEFER:
case SOURCE_EXIT:
assert(e);
sd_event_source *s;
sd_event_source *p;
assert(e);
sd_event_ref(e);
e->iteration++;
r = source_dispatch(p);
sd_event_unref(e);
sd_event_source *p;
assert(e);
return NULL;
return NULL;
usec_t t;
assert(e);
t = sleep_between(e,
return -errno;
assert(e);
if (!e->watchdog)
return arm_watchdog(e);
sd_event_source *p;
if (e->exit_requested)
return dispatch_exit(e);
sd_event_ref(e);
e->iteration++;
r = event_prepare(e);
goto finish;
r = event_arm_timer(e, e->monotonic_fd, e->monotonic_earliest, e->monotonic_latest, &e->monotonic_next);
goto finish;
r = event_arm_timer(e, e->realtime_fd, e->realtime_earliest, e->realtime_latest, &e->realtime_next);
goto finish;
timeout = 0;
goto finish;
goto finish;
r = process_watchdog(e);
goto finish;
goto finish;
goto finish;
if (e->need_process_child) {
r = process_child(e);
goto finish;
p = event_next_pending(e);
goto finish;
r = source_dispatch(p);
sd_event_unref(e);
sd_event_ref(e);
goto finish;
r = e->exit_code;
sd_event_unref(e);
return e->state;
if (!e->exit_requested)
return -ENODATA;
e->exit_requested = true;
sd_event *e;
if (!ret)
return !!default_event;
if (default_event) {
r = sd_event_new(&e);
default_event = e;
*ret = e;
if (e->tid != 0) {
return -ENXIO;
if (e->watchdog == !!b)
return e->watchdog;
const char *env;
if (!env)
if (e->watchdog_period <= 0)
return -EIO;
if (e->watchdog_fd < 0)
return -errno;
r = arm_watchdog(e);
goto fail;
r = -errno;
goto fail;
if (e->watchdog_fd >= 0) {
e->watchdog = !!b;
return e->watchdog;
fail: