USB: Handle the case of a callback removing its event source
This commit is contained in:
parent
358c4ed5b8
commit
5a7d8dac90
|
@ -507,7 +507,7 @@ static int sr_session_iteration(struct sr_session *session)
|
||||||
|
|
||||||
due = source->due;
|
due = source->due;
|
||||||
#if HAVE_LIBUSB_1_0 && !defined(G_OS_WIN32)
|
#if HAVE_LIBUSB_1_0 && !defined(G_OS_WIN32)
|
||||||
if (usb_due < due && source->poll_object
|
if (usb_due < due && poll_object
|
||||||
== (gintptr)session->ctx->libusb_ctx)
|
== (gintptr)session->ctx->libusb_ctx)
|
||||||
due = usb_due;
|
due = usb_due;
|
||||||
#endif
|
#endif
|
||||||
|
@ -1077,6 +1077,12 @@ SR_PRIV int sr_session_source_remove_internal(struct sr_session *session,
|
||||||
g_array_remove_range(session->pollfds,
|
g_array_remove_range(session->pollfds,
|
||||||
fd_index, source->num_fds);
|
fd_index, source->num_fds);
|
||||||
g_array_remove_index(session->sources, i);
|
g_array_remove_index(session->sources, i);
|
||||||
|
/*
|
||||||
|
* This is a bit of a hack. To be removed when
|
||||||
|
* porting over to the GLib main loop.
|
||||||
|
*/
|
||||||
|
if (poll_object == (gintptr)session->ctx->libusb_ctx)
|
||||||
|
session->ctx->usb_source_present = FALSE;
|
||||||
return SR_OK;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
fd_index += source->num_fds;
|
fd_index += source->num_fds;
|
||||||
|
|
69
src/usb.c
69
src/usb.c
|
@ -200,33 +200,48 @@ static int usb_callback(int fd, int revents, void *cb_data)
|
||||||
ctx = cb_data;
|
ctx = cb_data;
|
||||||
|
|
||||||
start_time = g_get_monotonic_time();
|
start_time = g_get_monotonic_time();
|
||||||
|
|
||||||
due = ctx->usb_due;
|
due = ctx->usb_due;
|
||||||
timeout = MAX(due - start_time, 0);
|
|
||||||
tv.tv_sec = timeout / G_USEC_PER_SEC;
|
|
||||||
tv.tv_usec = timeout % G_USEC_PER_SEC;
|
|
||||||
|
|
||||||
sr_spew("libusb_handle_events enter, timeout %g ms", 1e-3 * timeout);
|
if (due > start_time) {
|
||||||
|
timeout = due - start_time;
|
||||||
|
tv.tv_sec = timeout / G_USEC_PER_SEC;
|
||||||
|
tv.tv_usec = timeout % G_USEC_PER_SEC;
|
||||||
|
|
||||||
ret = libusb_handle_events_timeout_completed(ctx->libusb_ctx,
|
sr_spew("libusb_handle_events enter: %g ms timeout",
|
||||||
(ctx->usb_timeout < 0) ? NULL : &tv, NULL);
|
1e-3 * timeout);
|
||||||
if (ret != 0) {
|
|
||||||
/* Warn but still invoke the callback, to give the driver
|
ret = libusb_handle_events_timeout_completed(ctx->libusb_ctx,
|
||||||
* a chance to deal with the problem.
|
(ctx->usb_timeout < 0) ? NULL : &tv, NULL);
|
||||||
|
if (ret != 0) {
|
||||||
|
/* Warn but still invoke the callback, to give
|
||||||
|
* the driver a chance to deal with the problem.
|
||||||
|
*/
|
||||||
|
sr_warn("Error handling libusb event (%s)",
|
||||||
|
libusb_error_name(ret));
|
||||||
|
}
|
||||||
|
stop_time = g_get_monotonic_time();
|
||||||
|
|
||||||
|
sr_spew("libusb_handle_events leave: %g ms elapsed",
|
||||||
|
1e-3 * (stop_time - start_time));
|
||||||
|
/*
|
||||||
|
* The event source may have been removed by the driver's
|
||||||
|
* libusb transfer callback. Skip the callback in that case.
|
||||||
*/
|
*/
|
||||||
sr_warn("Error handling libusb event (%s)",
|
if (!ctx->usb_source_present)
|
||||||
libusb_error_name(ret));
|
return TRUE;
|
||||||
}
|
} else {
|
||||||
stop_time = g_get_monotonic_time();
|
/* Timeout already expired on entry.
|
||||||
|
*/
|
||||||
|
stop_time = start_time;
|
||||||
|
|
||||||
sr_spew("libusb_handle_events leave, %g ms elapsed",
|
sr_spew("libusb_handle_events skipped");
|
||||||
1e-3 * (stop_time - start_time));
|
}
|
||||||
|
|
||||||
if (ctx->usb_timeout >= 0)
|
if (ctx->usb_timeout >= 0)
|
||||||
ctx->usb_due = stop_time + ctx->usb_timeout;
|
ctx->usb_due = stop_time + ctx->usb_timeout;
|
||||||
/*
|
/*
|
||||||
* Run registered callback to execute any follow-up activity
|
* Run the registered callback to execute any follow-up activity
|
||||||
* to libusb event handling.
|
* to libusb's event handling.
|
||||||
*/
|
*/
|
||||||
return ctx->usb_cb(-1, (stop_time < due) ? G_IO_IN : 0,
|
return ctx->usb_cb(-1, (stop_time < due) ? G_IO_IN : 0,
|
||||||
ctx->usb_cb_data);
|
ctx->usb_cb_data);
|
||||||
|
@ -259,7 +274,8 @@ SR_PRIV int usb_source_add(struct sr_session *session, struct sr_context *ctx,
|
||||||
* This will have to do for now, until we implement a proper way to
|
* This will have to do for now, until we implement a proper way to
|
||||||
* deal with libusb events on Windows.
|
* deal with libusb events on Windows.
|
||||||
*/
|
*/
|
||||||
ret = sr_session_source_add(session, -2, 0, 0, &usb_callback, ctx);
|
ret = sr_session_source_add_internal(session, NULL, 0,
|
||||||
|
0, &usb_callback, ctx, (gintptr)ctx->libusb_ctx);
|
||||||
#else
|
#else
|
||||||
const struct libusb_pollfd **lupfd;
|
const struct libusb_pollfd **lupfd;
|
||||||
GPollFD *pollfds;
|
GPollFD *pollfds;
|
||||||
|
@ -293,21 +309,8 @@ SR_PRIV int usb_source_add(struct sr_session *session, struct sr_context *ctx,
|
||||||
|
|
||||||
SR_PRIV int usb_source_remove(struct sr_session *session, struct sr_context *ctx)
|
SR_PRIV int usb_source_remove(struct sr_session *session, struct sr_context *ctx)
|
||||||
{
|
{
|
||||||
int ret;
|
return sr_session_source_remove_internal(session,
|
||||||
|
|
||||||
if (!ctx->usb_source_present)
|
|
||||||
return SR_OK;
|
|
||||||
|
|
||||||
#ifdef G_OS_WIN32
|
|
||||||
/* Remove our idle source */
|
|
||||||
sr_session_source_remove(session, -2);
|
|
||||||
#else
|
|
||||||
ret = sr_session_source_remove_internal(session,
|
|
||||||
(gintptr)ctx->libusb_ctx);
|
(gintptr)ctx->libusb_ctx);
|
||||||
#endif
|
|
||||||
ctx->usb_source_present = FALSE;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SR_PRIV int usb_get_port_path(libusb_device *dev, char *path, int path_len)
|
SR_PRIV int usb_get_port_path(libusb_device *dev, char *path, int path_len)
|
||||||
|
|
Loading…
Reference in New Issue