-static gboolean sr_session_check_aborted(struct sr_session *session)
-{
- gboolean stop;
-
- g_mutex_lock(&session->stop_mutex);
- stop = session->abort_session;
- if (stop) {
- sr_session_stop_sync(session);
- /* But once is enough. */
- session->abort_session = FALSE;
- }
- g_mutex_unlock(&session->stop_mutex);
-
- return stop;
-}
-
-/**
- * Poll the session's event sources.
- *
- * @param session The session to use. Must not be NULL.
- * @retval SR_OK Success.
- * @retval SR_ERR Error occurred.
- */
-static int sr_session_iteration(struct sr_session *session)
-{
- int64_t start_time, stop_time, min_due, due;
- int timeout_ms;
- unsigned int i;
- int k, fd_index;
- int ret;
- int fd;
- int revents;
- gboolean triggered, stopped;
- struct source *source;
- GPollFD *pollfd;
- gintptr poll_object;
-#if HAVE_LIBUSB_1_0
- int64_t usb_timeout;
- int64_t usb_due;
- struct timeval tv;
-#endif
- if (session->sources->len == 0) {
- sr_session_check_aborted(session);
- return SR_OK;
- }
- start_time = g_get_monotonic_time();
- min_due = INT64_MAX;
-
- for (i = 0; i < session->sources->len; ++i) {
- source = &g_array_index(session->sources, struct source, i);
- if (source->due < min_due)
- min_due = source->due;
- source->triggered = FALSE;
- }
-#if HAVE_LIBUSB_1_0
- usb_due = INT64_MAX;
- if (session->ctx->usb_source_present) {
- ret = libusb_get_next_timeout(session->ctx->libusb_ctx, &tv);
- if (ret < 0) {
- sr_err("Error getting libusb timeout: %s",
- libusb_error_name(ret));
- return SR_ERR;
- } else if (ret == 1) {
- usb_timeout = (int64_t)tv.tv_sec * G_USEC_PER_SEC
- + tv.tv_usec;
- usb_due = start_time + usb_timeout;
- if (usb_due < min_due)
- min_due = usb_due;
-
- sr_spew("poll: next USB timeout %g ms",
- 1e-3 * usb_timeout);
- }
- }
-#endif
- if (min_due == INT64_MAX)
- timeout_ms = -1;
- else if (min_due > start_time)
- timeout_ms = MIN((min_due - start_time + 999) / 1000, INT_MAX);
- else
- timeout_ms = 0;
-
- sr_spew("poll enter: %u sources, %u fds, %d ms timeout",
- session->sources->len, session->pollfds->len, timeout_ms);
-
- ret = g_poll((GPollFD *)session->pollfds->data,
- session->pollfds->len, timeout_ms);
-#ifdef G_OS_UNIX
- if (ret < 0 && errno != EINTR) {
- sr_err("Error in poll: %s", g_strerror(errno));
- return SR_ERR;
- }
-#else
- if (ret < 0) {
- sr_err("Error in poll: %d", ret);
- return SR_ERR;
- }
-#endif
- stop_time = g_get_monotonic_time();
-
- sr_spew("poll leave: %g ms elapsed, %d events",
- 1e-3 * (stop_time - start_time), ret);
-
- triggered = FALSE;
- stopped = FALSE;
- fd_index = 0;
-
- for (i = 0; i < session->sources->len; ++i) {
- source = &g_array_index(session->sources, struct source, i);
-
- poll_object = source->poll_object;
- fd = (int)poll_object;
- revents = 0;
-
- for (k = 0; k < source->num_fds; ++k) {
- pollfd = &g_array_index(session->pollfds,
- GPollFD, fd_index + k);
- fd = pollfd->fd;
- revents |= pollfd->revents;
- }
- fd_index += source->num_fds;
-
- if (source->triggered)
- continue; /* already handled */
- if (ret > 0 && revents == 0)
- continue; /* skip timeouts if any I/O event occurred */
-
- /* Make invalid to avoid confusion in case of multiple FDs. */
- if (source->num_fds > 1)
- fd = -1;
- if (ret <= 0)
- revents = 0;
-
- due = source->due;
-#if HAVE_LIBUSB_1_0
- if (usb_due < due && poll_object
- == (gintptr)session->ctx->libusb_ctx)
- due = usb_due;
-#endif
- if (revents == 0 && stop_time < due)
- continue;
- /*
- * The source may be gone after the callback returns,
- * so access any data now that needs accessing.
- */
- if (source->timeout >= 0)
- source->due = stop_time + source->timeout;
- source->triggered = TRUE;
- triggered = TRUE;
- /*
- * Invoke the source's callback on an event or timeout.
- */
- sr_spew("callback for event source %" G_GINTPTR_FORMAT " with"
- " event mask 0x%.2X", poll_object, (unsigned)revents);
- if (!source->cb(fd, revents, source->cb_data))
- sr_session_source_remove_internal(session, poll_object);
- /*
- * We want to take as little time as possible to stop
- * the session if we have been told to do so. Therefore,
- * we check the flag after processing every source, not
- * just once per main event loop.
- */
- if (!stopped)
- stopped = sr_session_check_aborted(session);
-
- /* Restart loop as the sources list may have changed. */
- fd_index = 0;
- i = 0;
- }
-
- /* Check for abort at least once per iteration. */
- if (!triggered)
- sr_session_check_aborted(session);
-
- return SR_OK;
-}
-