+ if (r != 0)
+ continue;
+
+ if (timeout > 0) {
+ usec_t n;
+
+ n = now(CLOCK_MONOTONIC);
+ if (n >= timeout)
+ return -ETIMEDOUT;
+
+ left = timeout - n;
+ } else
+ left = (uint64_t) -1;
+
+ r = rtnl_poll(nl, true, left);
+ if (r < 0)
+ return r;
+
+ r = dispatch_wqueue(nl);
+ if (r < 0)
+ return r;
+ }
+}
+
+int sd_rtnl_flush(sd_rtnl *rtnl) {
+ int r;
+
+ assert_return(rtnl, -EINVAL);
+ assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
+
+ if (rtnl->wqueue_size <= 0)
+ return 0;
+
+ for (;;) {
+ r = dispatch_wqueue(rtnl);
+ if (r < 0)
+ return r;
+
+ if (rtnl->wqueue_size <= 0)
+ return 0;
+
+ r = rtnl_poll(rtnl, false, (uint64_t) -1);
+ if (r < 0)
+ return r;
+ }
+}
+
+int sd_rtnl_get_events(sd_rtnl *rtnl) {
+ int flags = 0;
+
+ assert_return(rtnl, -EINVAL);
+ assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
+
+ if (rtnl->rqueue_size <= 0)
+ flags |= POLLIN;
+ if (rtnl->wqueue_size > 0)
+ flags |= POLLOUT;
+
+ return flags;
+}
+
+int sd_rtnl_get_timeout(sd_rtnl *rtnl, uint64_t *timeout_usec) {
+ struct reply_callback *c;
+
+ assert_return(rtnl, -EINVAL);
+ assert_return(timeout_usec, -EINVAL);
+ assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
+
+ if (rtnl->rqueue_size > 0) {
+ *timeout_usec = 0;
+ return 1;
+ }
+
+ c = prioq_peek(rtnl->reply_callbacks_prioq);
+ if (!c) {
+ *timeout_usec = (uint64_t) -1;
+ return 0;
+ }
+
+ *timeout_usec = c->timeout;
+
+ return 1;
+}
+
+static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
+ sd_rtnl *rtnl = userdata;
+ int r;
+
+ assert(rtnl);
+
+ r = sd_rtnl_process(rtnl, NULL);
+ if (r < 0)
+ return r;
+
+ return 1;
+}
+
+static int time_callback(sd_event_source *s, uint64_t usec, void *userdata) {
+ sd_rtnl *rtnl = userdata;
+ int r;
+
+ assert(rtnl);
+
+ r = sd_rtnl_process(rtnl, NULL);
+ if (r < 0)
+ return r;
+
+ return 1;
+}
+
+static int prepare_callback(sd_event_source *s, void *userdata) {
+ sd_rtnl *rtnl = userdata;
+ int r, e;
+ usec_t until;
+
+ assert(s);
+ assert(rtnl);
+
+ e = sd_rtnl_get_events(rtnl);
+ if (e < 0)
+ return e;
+
+ r = sd_event_source_set_io_events(rtnl->io_event_source, e);
+ if (r < 0)
+ return r;
+
+ r = sd_rtnl_get_timeout(rtnl, &until);
+ if (r < 0)
+ return r;
+ if (r > 0) {
+ int j;
+
+ j = sd_event_source_set_time(rtnl->time_event_source, until);
+ if (j < 0)
+ return j;
+ }
+
+ r = sd_event_source_set_enabled(rtnl->time_event_source, r > 0);
+ if (r < 0)
+ return r;
+
+ return 1;
+}
+
+static int exit_callback(sd_event_source *event, void *userdata) {
+ sd_rtnl *rtnl = userdata;
+
+ assert(event);
+
+ sd_rtnl_flush(rtnl);
+
+ return 1;
+}
+
+int sd_rtnl_attach_event(sd_rtnl *rtnl, sd_event *event, int priority) {
+ int r;
+
+ assert_return(rtnl, -EINVAL);
+ assert_return(!rtnl->event, -EBUSY);
+
+ assert(!rtnl->io_event_source);
+ assert(!rtnl->time_event_source);
+
+ if (event)
+ rtnl->event = sd_event_ref(event);
+ else {
+ r = sd_event_default(&rtnl->event);
+ if (r < 0)
+ return r;