+bool event_loop_run(event_loop_t *loop, meshlink_handle_t *mesh) {
+ assert(mesh);
+
+ fd_set readable;
+ fd_set writable;
+ int errors = 0;
+
+ while(loop->running) {
+ clock_gettime(EVENT_CLOCK, &loop->now);
+ struct timespec it, ts = {3600, 0};
+
+ while(loop->timeouts.head) {
+ timeout_t *timeout = loop->timeouts.head->data;
+
+ if(timespec_lt(&timeout->tv, &loop->now)) {
+ timeout_disable(loop, timeout);
+ timeout->cb(loop, timeout->data);
+ } else {
+ timespec_sub(&timeout->tv, &loop->now, &ts);
+ break;
+ }
+ }
+
+ if(loop->idle_cb) {
+ it = loop->idle_cb(loop, loop->idle_data);
+
+ if(it.tv_sec >= 0 && timespec_lt(&it, &ts)) {
+ ts = it;
+ }
+ }
+
+ memcpy(&readable, &loop->readfds, sizeof(readable));
+ memcpy(&writable, &loop->writefds, sizeof(writable));
+
+ int fds = 0;
+
+ if(loop->ios.tail) {
+ io_t *last = loop->ios.tail->data;
+ fds = last->fd + 1;
+ }
+
+ // release mesh mutex during select
+ pthread_mutex_unlock(&mesh->mutex);
+
+#ifdef HAVE_PSELECT
+ int n = pselect(fds, &readable, &writable, NULL, &ts, NULL);
+#else
+ struct timeval tv = {ts.tv_sec, ts.tv_nsec / 1000};
+ int n = select(fds, &readable, &writable, NULL, (struct timeval *)&tv);
+#endif
+
+ if(pthread_mutex_lock(&mesh->mutex) != 0) {
+ abort();
+ }
+
+ clock_gettime(EVENT_CLOCK, &loop->now);
+
+ if(n < 0) {
+ if(sockwouldblock(errno)) {
+ continue;
+ } else {
+ errors++;
+
+ if(errors > 10) {
+ logger(mesh, MESHLINK_ERROR, "Unrecoverable error from select(): %s", strerror(errno));
+ return false;
+ }
+
+ logger(mesh, MESHLINK_WARNING, "Error from select(), checking for bad fds: %s", strerror(errno));
+ check_bad_fds(loop, mesh);
+ continue;
+ }
+ }
+
+ errors = 0;
+
+ if(!n) {
+ continue;
+ }