event: refuse operation if the caller tries to reuse an event loop after a fork()
This commit is contained in:
+105
-45
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
|
||||
Reference in New Issue
Block a user