From eaa3cbef3b8c214cd5c2d75b04e70ad477187e17 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 10 Oct 2013 21:37:50 +0200 Subject: event: refuse operation if the caller tries to reuse an event loop after a fork() --- src/libsystemd-bus/sd-event.c | 150 +++++++++++++++++++++++++++++------------- src/systemd/sd-event.h | 2 +- 2 files changed, 106 insertions(+), 46 deletions(-) (limited to 'src') diff --git a/src/libsystemd-bus/sd-event.c b/src/libsystemd-bus/sd-event.c index 511b271d45..e3110c3d6b 100644 --- a/src/libsystemd-bus/sd-event.c +++ b/src/libsystemd-bus/sd-event.c @@ -124,11 +124,12 @@ struct sd_event { unsigned iteration; usec_t realtime_next, monotonic_next; - usec_t perturb; - bool quit; - bool need_process_child; + bool quit:1; + bool need_process_child:1; + + pid_t original_pid; }; static int pending_prioq_compare(const void *a, const void *b) { @@ -307,6 +308,7 @@ int sd_event_new(sd_event** ret) { e->n_ref = REFCNT_INIT; 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(); assert_se(sigemptyset(&e->sigset) == 0); @@ -349,6 +351,15 @@ sd_event* sd_event_unref(sd_event *e) { return NULL; } +static bool event_pid_changed(sd_event *e) { + assert(e); + + /* We don't support people creating am event loop and keeping + * it around over a fork(). Let's complain. */ + + return e->original_pid != getpid(); +} + static int source_io_unregister(sd_event_source *s) { int r; @@ -517,6 +528,8 @@ int sd_event_add_io( return -EINVAL; if (!ret) return -EINVAL; + if (event_pid_changed(e)) + return -ECHILD; s = source_new(e, SOURCE_IO); if (!s) @@ -607,6 +620,8 @@ static int event_add_time_internal( return -EINVAL; if (accuracy == (uint64_t) -1) return -EINVAL; + if (event_pid_changed(e)) + return -ECHILD; assert(timer_fd); assert(earliest); @@ -711,6 +726,8 @@ int sd_event_add_signal(sd_event *e, int sig, sd_signal_handler_t callback, void return -EINVAL; if (!ret) return -EINVAL; + if (event_pid_changed(e)) + return -ECHILD; if (!e->signal_sources) { e->signal_sources = new0(sd_event_source*, _NSIG); @@ -756,6 +773,8 @@ int sd_event_add_child(sd_event *e, pid_t pid, int options, sd_child_handler_t c return -EINVAL; if (!ret) return -EINVAL; + if (event_pid_changed(e)) + return -ECHILD; r = hashmap_ensure_allocated(&e->child_sources, trivial_hash_func, trivial_compare_func); if (r < 0) @@ -805,6 +824,8 @@ int sd_event_add_defer(sd_event *e, sd_defer_handler_t callback, void *userdata, return -EINVAL; if (!ret) return -EINVAL; + if (event_pid_changed(e)) + return -ECHILD; s = source_new(e, SOURCE_DEFER); if (!s) @@ -842,9 +863,19 @@ sd_event_source* sd_event_source_unref(sd_event_source *s) { return NULL; } + +sd_event *sd_event_get(sd_event_source *s) { + if (!s) + return 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; return s->pending; } @@ -854,6 +885,8 @@ int sd_event_source_get_io_fd(sd_event_source *s) { return -EINVAL; if (s->type != SOURCE_IO) return -EDOM; + if (event_pid_changed(s->event)) + return -ECHILD; return s->io.fd; } @@ -865,6 +898,8 @@ int sd_event_source_get_io_events(sd_event_source *s, uint32_t* events) { return -EDOM; if (!events) return -EINVAL; + if (event_pid_changed(s->event)) + return -ECHILD; *events = s->io.events; return 0; @@ -879,6 +914,8 @@ int sd_event_source_set_io_events(sd_event_source *s, uint32_t events) { return -EDOM; if (events & ~(EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLPRI|EPOLLERR|EPOLLHUP)) return -EINVAL; + if (event_pid_changed(s->event)) + return -ECHILD; if (s->io.events == events) return 0; @@ -903,6 +940,8 @@ int sd_event_source_get_io_revents(sd_event_source *s, uint32_t* revents) { return -EINVAL; if (!s->pending) return -ENODATA; + if (event_pid_changed(s->event)) + return -ECHILD; *revents = s->io.revents; return 0; @@ -913,6 +952,8 @@ int sd_event_source_get_signal(sd_event_source *s) { return -EINVAL; if (s->type != SOURCE_SIGNAL) return -EDOM; + if (event_pid_changed(s->event)) + return -ECHILD; return s->signal.sig; } @@ -920,6 +961,8 @@ int sd_event_source_get_signal(sd_event_source *s) { int sd_event_source_get_priority(sd_event_source *s, int *priority) { if (!s) return -EINVAL; + if (event_pid_changed(s->event)) + return -ECHILD; return s->priority; } @@ -927,6 +970,8 @@ int sd_event_source_get_priority(sd_event_source *s, int *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; if (s->priority == priority) return 0; @@ -947,6 +992,8 @@ int sd_event_source_get_mute(sd_event_source *s, sd_event_mute_t *m) { return -EINVAL; if (!m) return -EINVAL; + if (event_pid_changed(s->event)) + return -ECHILD; *m = s->mute; return 0; @@ -959,6 +1006,8 @@ int sd_event_source_set_mute(sd_event_source *s, sd_event_mute_t m) { return -EINVAL; if (m != SD_EVENT_MUTED && m != SD_EVENT_UNMUTED && !SD_EVENT_ONESHOT) return -EINVAL; + if (event_pid_changed(s->event)) + return -ECHILD; if (s->mute == m) return 0; @@ -1081,6 +1130,8 @@ int sd_event_source_get_time(sd_event_source *s, uint64_t *usec) { return -EINVAL; if (s->type != SOURCE_REALTIME && s->type != SOURCE_MONOTONIC) return -EDOM; + if (event_pid_changed(s->event)) + return -ECHILD; *usec = s->time.next; return 0; @@ -1093,6 +1144,8 @@ int sd_event_source_set_time(sd_event_source *s, uint64_t usec) { return -EINVAL; if (s->type != SOURCE_REALTIME && s->type != SOURCE_MONOTONIC) return -EDOM; + if (event_pid_changed(s->event)) + return -ECHILD; if (s->time.next == usec) return 0; @@ -1110,11 +1163,52 @@ int sd_event_source_set_time(sd_event_source *s, uint64_t usec) { 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; + + if (usec == 0) + usec = DEFAULT_ACCURACY_USEC; + + if (s->time.accuracy == usec) + return 0; + + + s->time.accuracy = usec; + + 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); + + 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; + + *usec = s->time.accuracy; + 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; if (s->prepare == callback) return 0; @@ -1500,6 +1594,8 @@ int sd_event_run(sd_event *e, uint64_t timeout) { return -EINVAL; if (e->quit) return -ESTALE; + if (event_pid_changed(e)) + return -ECHILD; e->iteration++; @@ -1568,6 +1664,8 @@ int sd_event_loop(sd_event *e) { if (!e) return -EINVAL; + if (event_pid_changed(e)) + return -ECHILD; while (!e->quit) { r = sd_event_run(e, (uint64_t) -1); @@ -1581,6 +1679,8 @@ int sd_event_loop(sd_event *e) { int sd_event_quit(sd_event *e) { if (!e) return EINVAL; + if (event_pid_changed(e)) + return -ECHILD; return e->quit; } @@ -1588,49 +1688,9 @@ int sd_event_quit(sd_event *e) { int sd_event_request_quit(sd_event *e) { if (!e) return -EINVAL; + if (event_pid_changed(e)) + return -ECHILD; e->quit = true; return 0; } - -sd_event *sd_event_get(sd_event_source *s) { - if (!s) - return NULL; - - return s->event; -} - -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 (usec == 0) - usec = DEFAULT_ACCURACY_USEC; - - if (s->time.accuracy == usec) - return 0; - - - s->time.accuracy = usec; - - 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); - - 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; - - *usec = s->time.accuracy; - return 0; -} diff --git a/src/systemd/sd-event.h b/src/systemd/sd-event.h index 90fea4e17a..8908c8454d 100644 --- a/src/systemd/sd-event.h +++ b/src/systemd/sd-event.h @@ -33,11 +33,11 @@ - Supports event source priorisation - Scales better with a large number of time events, since it doesn't require one timerfd each + - Automatically tries to coalesce timer events system-wide - Handles signals and child PIDs TODO: - - Detect forks and return ECHILD - quit hooks */ -- cgit v1.2.3-54-g00ecf