SOURCE_SIGNAL,
SOURCE_CHILD,
SOURCE_DEFER,
- SOURCE_QUIT,
+ SOURCE_EXIT,
SOURCE_WATCHDOG
} EventSourceType;
EventSourceType type:4;
int enabled:3;
bool pending:1;
+ bool dispatching:1;
int priority;
unsigned pending_index;
struct {
sd_event_handler_t callback;
unsigned prioq_index;
- } quit;
+ } exit;
};
};
Hashmap *child_sources;
unsigned n_enabled_child_sources;
- Prioq *quit;
+ Prioq *exit;
pid_t original_pid;
dual_timestamp timestamp;
int state;
- bool quit_requested:1;
+ bool exit_requested:1;
bool need_process_child:1;
bool watchdog:1;
+ int exit_code;
+
pid_t tid;
sd_event **default_event_ptr;
return 0;
}
-static int quit_prioq_compare(const void *a, const void *b) {
+static int exit_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);
+ assert(x->type == SOURCE_EXIT);
+ assert(y->type == SOURCE_EXIT);
/* Enabled ones first */
if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
prioq_free(e->monotonic_latest);
prioq_free(e->realtime_earliest);
prioq_free(e->realtime_latest);
- prioq_free(e->quit);
+ prioq_free(e->exit);
free(e->signal_sources);
/* nothing */
break;
- case SOURCE_QUIT:
- prioq_remove(s->event->quit, s, &s->quit.prioq_index);
+ case SOURCE_EXIT:
+ prioq_remove(s->event->exit, s, &s->exit.prioq_index);
break;
}
int r;
assert(s);
- assert(s->type != SOURCE_QUIT);
+ assert(s->type != SOURCE_EXIT);
if (s->pending == b)
return 0;
return 0;
}
-_public_ int sd_event_add_quit(
+_public_ int sd_event_add_exit(
sd_event *e,
sd_event_handler_t callback,
void *userdata,
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)
+ if (!e->exit) {
+ e->exit = prioq_new(exit_prioq_compare);
+ if (!e->exit)
return -ENOMEM;
}
- s = source_new(e, SOURCE_QUIT);
+ s = source_new(e, SOURCE_EXIT);
if (!s)
return -ENOMEM;
- s->quit.callback = callback;
+ s->exit.callback = callback;
s->userdata = userdata;
- s->quit.prioq_index = PRIOQ_IDX_NULL;
+ s->exit.prioq_index = PRIOQ_IDX_NULL;
s->enabled = SD_EVENT_ONESHOT;
- r = prioq_put(s->event->quit, s, &s->quit.prioq_index);
+ r = prioq_put(s->event->exit, s, &s->exit.prioq_index);
if (r < 0) {
source_free(s);
return r;
assert(s->n_ref >= 1);
s->n_ref--;
- if (s->n_ref <= 0)
- source_free(s);
+ if (s->n_ref <= 0) {
+ /* Here's a special hack: when we are called from a
+ * dispatch handler we won't free the event source
+ * immediately, but we will detach the fd from the
+ * epoll. This way it is safe for the caller to unref
+ * the event source and immediately close the fd, but
+ * we still retain a valid event source object after
+ * the callback. */
+
+ if (s->dispatching) {
+ if (s->type == SOURCE_IO)
+ source_io_unregister(s);
+ } else
+ source_free(s);
+ }
return NULL;
}
_public_ int sd_event_source_get_pending(sd_event_source *s) {
assert_return(s, -EINVAL);
- assert_return(s->type != SOURCE_QUIT, -EDOM);
+ assert_return(s->type != SOURCE_EXIT, -EDOM);
assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE);
assert_return(!event_pid_changed(s->event), -ECHILD);
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);
+ if (s->type == SOURCE_EXIT)
+ prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index);
return 0;
}
break;
- case SOURCE_QUIT:
+ case SOURCE_EXIT:
s->enabled = m;
- prioq_reshuffle(s->event->quit, s, &s->quit.prioq_index);
+ prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index);
break;
case SOURCE_DEFER:
}
break;
- case SOURCE_QUIT:
+ case SOURCE_EXIT:
s->enabled = m;
- prioq_reshuffle(s->event->quit, s, &s->quit.prioq_index);
+ prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index);
break;
case SOURCE_DEFER:
int r;
assert_return(s, -EINVAL);
- assert_return(s->type != SOURCE_QUIT, -EDOM);
+ assert_return(s->type != SOURCE_EXIT, -EDOM);
assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE);
assert_return(!event_pid_changed(s->event), -ECHILD);
return s->userdata;
}
+_public_ void *sd_event_source_set_userdata(sd_event_source *s, void *userdata) {
+ void *ret;
+
+ assert_return(s, NULL);
+
+ ret = s->userdata;
+ s->userdata = userdata;
+
+ return ret;
+}
+
static usec_t sleep_between(sd_event *e, usec_t a, usec_t b) {
usec_t c;
assert(e);
int r = 0;
assert(s);
- assert(s->pending || s->type == SOURCE_QUIT);
+ assert(s->pending || s->type == SOURCE_EXIT);
- if (s->type != SOURCE_DEFER && s->type != SOURCE_QUIT) {
+ if (s->type != SOURCE_DEFER && s->type != SOURCE_EXIT) {
r = source_set_pending(s, false);
if (r < 0)
return r;
return r;
}
- sd_event_source_ref(s);
+ s->dispatching = true;
switch (s->type) {
r = s->defer.callback(s, s->userdata);
break;
- case SOURCE_QUIT:
- r = s->quit.callback(s, s->userdata);
+ case SOURCE_EXIT:
+ r = s->exit.callback(s, s->userdata);
break;
}
- sd_event_source_unref(s);
+ s->dispatching = false;
- return r;
+ if (r < 0)
+ log_debug("Event source %p returned error, disabling: %s", s, strerror(-r));
+
+ if (s->n_ref == 0)
+ source_free(s);
+ else if (r < 0)
+ sd_event_source_set_enabled(s, SD_EVENT_OFF);
+
+ return 1;
}
static int event_prepare(sd_event *e) {
return r;
assert(s->prepare);
+
+ s->dispatching = true;
r = s->prepare(s, s->userdata);
+ s->dispatching = false;
+
if (r < 0)
- return r;
+ log_debug("Prepare callback of event source %p returned error, disabling: %s", s, strerror(-r));
+ if (s->n_ref == 0)
+ source_free(s);
+ else if (r < 0)
+ sd_event_source_set_enabled(s, SD_EVENT_OFF);
}
return 0;
}
-static int dispatch_quit(sd_event *e) {
+static int dispatch_exit(sd_event *e) {
sd_event_source *p;
int r;
assert(e);
- p = prioq_peek(e->quit);
+ p = prioq_peek(e->exit);
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;
+ e->state = SD_EVENT_EXITING;
r = source_dispatch(p);
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
assert_return(e->state == SD_EVENT_PASSIVE, -EBUSY);
- if (e->quit_requested)
- return dispatch_quit(e);
+ if (e->exit_requested)
+ return dispatch_exit(e);
sd_event_ref(e);
e->iteration++;
goto finish;
}
- r = 0;
+ r = e->exit_code;
finish:
sd_event_unref(e);
return e->state;
}
-_public_ int sd_event_get_quit(sd_event *e) {
+_public_ int sd_event_get_exit_code(sd_event *e, int *code) {
assert_return(e, -EINVAL);
+ assert_return(code, -EINVAL);
assert_return(!event_pid_changed(e), -ECHILD);
- return e->quit_requested;
+ if (!e->exit_requested)
+ return -ENODATA;
+
+ *code = e->exit_code;
+ return 0;
}
-_public_ int sd_event_request_quit(sd_event *e) {
+_public_ int sd_event_exit(sd_event *e, int code) {
assert_return(e, -EINVAL);
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
assert_return(!event_pid_changed(e), -ECHILD);
- e->quit_requested = true;
+ e->exit_requested = true;
+ e->exit_code = code;
+
return 0;
}
int r;
assert_return(e, -EINVAL);
+ assert_return(!event_pid_changed(e), -ECHILD);
if (e->watchdog == !!b)
return e->watchdog;
e->watchdog_fd = -1;
return r;
}
+
+_public_ int sd_event_get_watchdog(sd_event *e) {
+ assert_return(e, -EINVAL);
+ assert_return(!event_pid_changed(e), -ECHILD);
+
+ return e->watchdog;
+}