From b9823a693ee6fb5755ce00b970420e761c1a55fa Mon Sep 17 00:00:00 2001 From: Graeme Gill Date: Tue, 21 Sep 2010 10:57:06 +0200 Subject: Fix a race condition See http://sourceforge.net/mailarchive/message.php?msg_name=4BD920C5.3090909%40argyllcms.com --- libusb/io.c | 49 +++++++++++++++++++++++++++++++++++-------------- libusb/libusb.h | 3 +++ libusb/sync.c | 8 ++++---- 3 files changed, 42 insertions(+), 18 deletions(-) diff --git a/libusb/io.c b/libusb/io.c index ab37e8d..7ab811e 100644 --- a/libusb/io.c +++ b/libusb/io.c @@ -1948,8 +1948,8 @@ static int get_next_timeout(libusb_context *ctx, struct timeval *tv, * non-blocking mode * \returns 0 on success, or a LIBUSB_ERROR code on failure */ -int API_EXPORTED libusb_handle_events_timeout(libusb_context *ctx, - struct timeval *tv) +int API_EXPORTED libusb_handle_events_timeout_check(libusb_context *ctx, + struct timeval *tv, int *completed) { int r; struct timeval poll_timeout; @@ -1963,8 +1963,12 @@ int API_EXPORTED libusb_handle_events_timeout(libusb_context *ctx, retry: if (libusb_try_lock_events(ctx) == 0) { - /* we obtained the event lock: do our own event handling */ - r = handle_events(ctx, &poll_timeout); + r = 0; + if (completed == NULL || !*completed) { + /* we obtained the event lock: do our own event handling */ + usbi_dbg("doing our own event handling"); + r = handle_events(ctx, &poll_timeout); + } libusb_unlock_events(ctx); return r; } @@ -1973,16 +1977,18 @@ retry: * notify event completion. */ libusb_lock_event_waiters(ctx); - if (!libusb_event_handler_active(ctx)) { - /* we hit a race: whoever was event handling earlier finished in the - * time it took us to reach this point. try the cycle again. */ - libusb_unlock_event_waiters(ctx); - usbi_dbg("event handler was active but went away, retrying"); - goto retry; + if (completed == NULL || !*completed) { + if (!libusb_event_handler_active(ctx)) { + /* we hit a race: whoever was event handling earlier finished in the + * time it took us to reach this point. try the cycle again. */ + libusb_unlock_event_waiters(ctx); + usbi_dbg("event handler was active but went away, retrying"); + goto retry; + } + + usbi_dbg("another thread is doing event handling, wait for notification"); + r = libusb_wait_for_event(ctx, &poll_timeout); } - - usbi_dbg("another thread is doing event handling"); - r = libusb_wait_for_event(ctx, &poll_timeout); libusb_unlock_event_waiters(ctx); if (r < 0) @@ -1993,6 +1999,21 @@ retry: return 0; } +API_EXPORTED int libusb_handle_events_timeout(libusb_context *ctx, + struct timeval *tv) +{ + return libusb_handle_events_timeout_check(ctx, tv, NULL); +} + +API_EXPORTED int libusb_handle_events_check(libusb_context *ctx, + int *completed) +{ + struct timeval tv; + tv.tv_sec = 60; + tv.tv_usec = 0; + return libusb_handle_events_timeout_check(ctx, &tv, completed); +} + /** \ingroup poll * Handle any pending events in blocking mode. There is currently a timeout * hardcoded at 60 seconds but we plan to make it unlimited in future. For @@ -2007,7 +2028,7 @@ int API_EXPORTED libusb_handle_events(libusb_context *ctx) struct timeval tv; tv.tv_sec = 60; tv.tv_usec = 0; - return libusb_handle_events_timeout(ctx, &tv); + return libusb_handle_events_timeout_check(ctx, &tv, NULL); } /** \ingroup poll diff --git a/libusb/libusb.h b/libusb/libusb.h index e2cc606..d46c68b 100644 --- a/libusb/libusb.h +++ b/libusb/libusb.h @@ -1275,7 +1275,10 @@ int LIBUSB_CALL libusb_wait_for_event(libusb_context *ctx, struct timeval *tv); int LIBUSB_CALL libusb_handle_events_timeout(libusb_context *ctx, struct timeval *tv); +int LIBUSB_CALL libusb_handle_events_timeout_check(libusb_context *ctx, + struct timeval *tv, int *completed); int LIBUSB_CALL libusb_handle_events(libusb_context *ctx); +int LIBUSB_CALL libusb_handle_events_check(libusb_context *ctx, int *completed); int LIBUSB_CALL libusb_handle_events_locked(libusb_context *ctx, struct timeval *tv); int LIBUSB_CALL libusb_pollfds_handle_timeouts(libusb_context *ctx); diff --git a/libusb/sync.c b/libusb/sync.c index f6dc2a7..d040d98 100644 --- a/libusb/sync.c +++ b/libusb/sync.c @@ -102,13 +102,13 @@ int API_EXPORTED libusb_control_transfer(libusb_device_handle *dev_handle, } while (!completed) { - r = libusb_handle_events(HANDLE_CTX(dev_handle)); + r = libusb_handle_events_check(HANDLE_CTX(dev_handle), &completed); if (r < 0) { if (r == LIBUSB_ERROR_INTERRUPTED) continue; libusb_cancel_transfer(transfer); while (!completed) - if (libusb_handle_events(HANDLE_CTX(dev_handle)) < 0) + if (libusb_handle_events_check(HANDLE_CTX(dev_handle), &completed) < 0) break; libusb_free_transfer(transfer); return r; @@ -172,13 +172,13 @@ static int do_sync_bulk_transfer(struct libusb_device_handle *dev_handle, } while (!completed) { - r = libusb_handle_events(HANDLE_CTX(dev_handle)); + r = libusb_handle_events_check(HANDLE_CTX(dev_handle), &completed); if (r < 0) { if (r == LIBUSB_ERROR_INTERRUPTED) continue; libusb_cancel_transfer(transfer); while (!completed) - if (libusb_handle_events(HANDLE_CTX(dev_handle)) < 0) + if (libusb_handle_events_check(HANDLE_CTX(dev_handle), &completed) < 0) break; libusb_free_transfer(transfer); return r; -- cgit v1.2.1