+
+static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
+ void *bus = userdata;
+ int r;
+
+ assert(bus);
+
+ r = sd_bus_process(bus, NULL);
+ if (r < 0)
+ return r;
+
+ return 1;
+}
+
+static int time_callback(sd_event_source *s, uint64_t usec, void *userdata) {
+ void *bus = userdata;
+ int r;
+
+ assert(bus);
+
+ r = sd_bus_process(bus, NULL);
+ if (r < 0)
+ return r;
+
+ return 1;
+}
+
+static int prepare_callback(sd_event_source *s, void *userdata) {
+ sd_bus *bus = userdata;
+ int r, e;
+ usec_t until;
+
+ assert(s);
+ assert(bus);
+
+ e = sd_bus_get_events(bus);
+ if (e < 0)
+ return e;
+
+ if (bus->output_fd != bus->input_fd) {
+
+ r = sd_event_source_set_io_events(bus->input_io_event_source, e & POLLIN);
+ if (r < 0)
+ return r;
+
+ r = sd_event_source_set_io_events(bus->output_io_event_source, e & POLLOUT);
+ if (r < 0)
+ return r;
+ } else {
+ r = sd_event_source_set_io_events(bus->input_io_event_source, e);
+ if (r < 0)
+ return r;
+ }
+
+ r = sd_bus_get_timeout(bus, &until);
+ if (r < 0)
+ return r;
+ if (r > 0) {
+ int j;
+
+ j = sd_event_source_set_time(bus->time_event_source, until);
+ if (j < 0)
+ return j;
+ }
+
+ r = sd_event_source_set_enabled(bus->time_event_source, r > 0);
+ if (r < 0)
+ return r;
+
+ return 1;
+}
+
+int sd_bus_attach_event(sd_bus *bus, sd_event *event, int priority) {
+ int r;
+
+ assert_return(bus, -EINVAL);
+ assert_return(event, -EINVAL);
+ assert_return(!bus->event, -EBUSY);
+
+ assert(!bus->input_io_event_source);
+ assert(!bus->output_io_event_source);
+ assert(!bus->time_event_source);
+
+ bus->event = sd_event_ref(event);
+
+ r = sd_event_add_io(event, bus->input_fd, 0, io_callback, bus, &bus->input_io_event_source);
+ if (r < 0)
+ goto fail;
+
+ r = sd_event_source_set_priority(bus->input_io_event_source, priority);
+ if (r < 0)
+ goto fail;
+
+ if (bus->output_fd != bus->input_fd) {
+ r = sd_event_add_io(event, bus->output_fd, 0, io_callback, bus, &bus->output_io_event_source);
+ if (r < 0)
+ goto fail;
+
+ r = sd_event_source_set_priority(bus->output_io_event_source, priority);
+ if (r < 0)
+ goto fail;
+ }
+
+ r = sd_event_source_set_prepare(bus->input_io_event_source, prepare_callback);
+ if (r < 0)
+ goto fail;
+
+ r = sd_event_add_monotonic(event, 0, 0, time_callback, bus, &bus->time_event_source);
+ if (r < 0)
+ goto fail;
+
+ r = sd_event_source_set_priority(bus->time_event_source, priority);
+ if (r < 0)
+ goto fail;
+
+ return 0;
+
+fail:
+ sd_bus_detach_event(bus);
+ return r;
+}
+
+int sd_bus_detach_event(sd_bus *bus) {
+ assert_return(bus, -EINVAL);
+ assert_return(bus->event, -ENXIO);
+
+ if (bus->input_io_event_source)
+ bus->input_io_event_source = sd_event_source_unref(bus->input_io_event_source);
+
+ if (bus->output_io_event_source)
+ bus->output_io_event_source = sd_event_source_unref(bus->output_io_event_source);
+
+ if (bus->time_event_source)
+ bus->time_event_source = sd_event_source_unref(bus->time_event_source);
+
+ if (bus->event)
+ bus->event = sd_event_unref(bus->event);
+
+ return 0;
+}