EventSourceType type:4;
int enabled:3;
bool pending:1;
+ bool dispatching:1;
int priority;
unsigned pending_index;
case SOURCE_EXIT:
prioq_remove(s->event->exit, s, &s->exit.prioq_index);
break;
+
+ case SOURCE_WATCHDOG:
+ assert_not_reached("Wut? I shouldn't exist.");
}
if (s->pending)
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;
}
return s->io.fd;
}
+_public_ int sd_event_source_set_io_fd(sd_event_source *s, int fd) {
+ int r;
+
+ assert_return(s, -EINVAL);
+ assert_return(fd >= 0, -EINVAL);
+ assert_return(s->type == SOURCE_IO, -EDOM);
+ assert_return(!event_pid_changed(s->event), -ECHILD);
+
+ if (s->io.fd == fd)
+ return 0;
+
+ if (s->enabled == SD_EVENT_OFF) {
+ s->io.fd = fd;
+ s->io.registered = false;
+ } else {
+ int saved_fd;
+
+ saved_fd = s->io.fd;
+ assert(s->io.registered);
+
+ s->io.fd = fd;
+ s->io.registered = false;
+
+ r = source_io_register(s, s->enabled, s->io.events);
+ if (r < 0) {
+ s->io.fd = saved_fd;
+ s->io.registered = true;
+ return r;
+ }
+
+ epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, saved_fd, NULL);
+ }
+
+ return 0;
+}
+
_public_ int sd_event_source_get_io_events(sd_event_source *s, uint32_t* events) {
assert_return(s, -EINVAL);
assert_return(events, -EINVAL);
case SOURCE_DEFER:
s->enabled = m;
break;
+
+ case SOURCE_WATCHDOG:
+ assert_not_reached("Wut? I shouldn't exist.");
}
} else {
case SOURCE_DEFER:
s->enabled = m;
break;
+
+ case SOURCE_WATCHDOG:
+ assert_not_reached("Wut? I shouldn't exist.");
}
}
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);
return r;
}
- sd_event_source_ref(s);
+ s->dispatching = true;
switch (s->type) {
case SOURCE_EXIT:
r = s->exit.callback(s, s->userdata);
break;
+
+ case SOURCE_WATCHDOG:
+ assert_not_reached("Wut? I shouldn't exist.");
}
- if (r < 0) {
+ s->dispatching = false;
+
+ 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);
- }
- sd_event_source_unref(s);
return 1;
}
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;
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;
+}