This change removes the fake FDs and replaces them with event handles. --- libusb/os/poll_windows.c | 466 ++++++++-------------------------------------- libusb/os/poll_windows.h | 10 +- libusb/os/wince_usb.c | 14 +- libusb/os/windows_usb.c | 53 ++++-- 4 files changed, 118 insertions(+), 425 deletions(-)
diff --git a/libusb/os/poll_windows.c b/libusb/os/poll_windows.c index 6d4f934..5a96111 100644 --- a/libusb/os/poll_windows.c +++ b/libusb/os/poll_windows.c @@ -67,15 +67,8 @@ #define CHECK_INIT_POLLING do {if(!is_polling_set) init_polling();} while(0) // public fd data -const struct winfd INVALID_WINFD = {-1, INVALID_HANDLE_VALUE, NULL, NULL, NULL, RW_NONE}; -struct winfd poll_fd[MAX_FDS]; -// internal fd data -struct { - CRITICAL_SECTION mutex; // lock for fds - // Additional variables for XP CancelIoEx partial emulation - HANDLE original_handle; - DWORD thread_id; -} _poll_fd[MAX_FDS]; +const struct winfd INVALID_WINFD = {INVALID_HANDLE_VALUE, NULL, NULL, NULL, RW_NONE, + INVALID_HANDLE_VALUE, 0}; // globals BOOLEAN is_polling_set = FALSE; @@ -100,26 +93,22 @@ static inline void setup_cancel_io(void) Use_Duplicate_Handles?"":"Ex"); } -static inline BOOL cancel_io(int _index) +static inline BOOL cancel_io(struct winfd * wfd) { - if ((_index < 0) || (_index >= MAX_FDS)) { - return FALSE; - } - - if ( (poll_fd[_index].fd < 0) || (poll_fd[_index].handle == INVALID_HANDLE_VALUE) - || (poll_fd[_index].handle == 0) || (poll_fd[_index].overlapped == NULL) ) { + if ( (wfd->handle == INVALID_HANDLE_VALUE) + || (wfd->handle == 0) || (wfd->overlapped == NULL) ) { return TRUE; } - if (poll_fd[_index].itransfer && poll_fd[_index].cancel_fn) { + if (wfd->itransfer && wfd->cancel_fn) { // Cancel outstanding transfer via the specific callback - (*poll_fd[_index].cancel_fn)(poll_fd[_index].itransfer); + (*wfd->cancel_fn)(wfd->itransfer); return TRUE; } if (pCancelIoEx != NULL) { - return (*pCancelIoEx)(poll_fd[_index].handle, poll_fd[_index].overlapped); + return (*pCancelIoEx)(wfd->handle, wfd->overlapped); } - if (_poll_fd[_index].thread_id == GetCurrentThreadId()) { - return CancelIo(poll_fd[_index].handle); + if (wfd->thread_id == GetCurrentThreadId()) { + return CancelIo(wfd->handle); } usbi_warn(NULL, "Unable to cancel I/O that was started from another thread"); return FALSE; @@ -132,18 +121,15 @@ static __inline void setup_cancel_io() // No setup needed on WinCE } -static __inline BOOL cancel_io(int _index) +static __inline BOOL cancel_io(struct winfd * wfd) { - if ((_index < 0) || (_index >= MAX_FDS)) { - return FALSE; - } - if ( (poll_fd[_index].fd < 0) || (poll_fd[_index].handle == INVALID_HANDLE_VALUE) - || (poll_fd[_index].handle == 0) || (poll_fd[_index].overlapped == NULL) ) { + if ( (wfd->handle == INVALID_HANDLE_VALUE) + || (wfd->handle == 0) || (wfd->overlapped == NULL) ) { return TRUE; } - if (poll_fd[_index].itransfer && poll_fd[_index].cancel_fn) { + if (wfd->itransfer && wfd->cancel_fn) { // Cancel outstanding transfer via the specific callback - (*poll_fd[_index].cancel_fn)(poll_fd[_index].itransfer); + (*wfd->cancel_fn)(wfd->itransfer); } return TRUE; } @@ -152,45 +138,16 @@ static __inline BOOL cancel_io(int _index) // Init void init_polling(void) { - int i; - while (InterlockedExchange((LONG *)&compat_spinlock, 1) == 1) { SleepEx(0, TRUE); } if (!is_polling_set) { setup_cancel_io(); - for (i=0; i<MAX_FDS; i++) { - poll_fd[i] = INVALID_WINFD; - _poll_fd[i].original_handle = INVALID_HANDLE_VALUE; - _poll_fd[i].thread_id = 0; - InitializeCriticalSection(&_poll_fd[i].mutex); - } is_polling_set = TRUE; } InterlockedExchange((LONG *)&compat_spinlock, 0); } -// Internal function to retrieve the table index (and lock the fd mutex) -static int _fd_to_index_and_lock(int fd) -{ - int i; - - if (fd < 0) - return -1; - - for (i=0; i<MAX_FDS; i++) { - if (poll_fd[i].fd == fd) { - EnterCriticalSection(&_poll_fd[i].mutex); - // fd might have changed before we got to critical - if (poll_fd[i].fd != fd) { - LeaveCriticalSection(&_poll_fd[i].mutex); - continue; - } - return i; - } - } - return -1; -} static OVERLAPPED *create_overlapped(void) { @@ -218,87 +175,28 @@ static void free_overlapped(OVERLAPPED *overlapped) free(overlapped); } -void exit_polling(void) -{ - int i; - - while (InterlockedExchange((LONG *)&compat_spinlock, 1) == 1) { - SleepEx(0, TRUE); - } - if (is_polling_set) { - is_polling_set = FALSE; - - for (i=0; i<MAX_FDS; i++) { - // Cancel any async I/O (handle can be invalid) - cancel_io(i); - // If anything was pending on that I/O, it should be - // terminating, and we should be able to access the fd - // mutex lock before too long - EnterCriticalSection(&_poll_fd[i].mutex); - free_overlapped(poll_fd[i].overlapped); - if (Use_Duplicate_Handles) { - // Close duplicate handle - if (_poll_fd[i].original_handle != INVALID_HANDLE_VALUE) { - CloseHandle(poll_fd[i].handle); - } - } - poll_fd[i] = INVALID_WINFD; - LeaveCriticalSection(&_poll_fd[i].mutex); - DeleteCriticalSection(&_poll_fd[i].mutex); - } - } - InterlockedExchange((LONG *)&compat_spinlock, 0); -} - /* * Create a fake pipe. - * As libusbx only uses pipes for signaling, all we need from a pipe is an - * event. To that extent, we create a single wfd and overlapped as a means - * to access that event. + * As libusbx only uses pipes for signaling, all we need from a pipe is a + * semaphore. */ int usbi_pipe(libusb_event_handle filedes[2]) { - int i; - OVERLAPPED* overlapped; - CHECK_INIT_POLLING; - overlapped = create_overlapped(); - - if (overlapped == NULL) { + filedes[0] = CreateSemaphore(NULL, 0, LONG_MAX, NULL); + if (filedes[0] == NULL) + { return -1; } - // The overlapped must have status pending for signaling to work in poll - overlapped->Internal = STATUS_PENDING; - overlapped->InternalHigh = 0; - - for (i=0; i<MAX_FDS; i++) { - if (poll_fd[i].fd < 0) { - EnterCriticalSection(&_poll_fd[i].mutex); - // fd might have been allocated before we got to critical - if (poll_fd[i].fd >= 0) { - LeaveCriticalSection(&_poll_fd[i].mutex); - continue; - } - - // Use index as the unique fd number - poll_fd[i].fd = i; - // Read end of the "pipe" - filedes[0] = poll_fd[i].fd; - // We can use the same handle for both ends - filedes[1] = filedes[0]; - - poll_fd[i].handle = DUMMY_HANDLE; - poll_fd[i].overlapped = overlapped; - // There's no polling on the write end, so we just use READ for our needs - poll_fd[i].rw = RW_READ; - _poll_fd[i].original_handle = INVALID_HANDLE_VALUE; - LeaveCriticalSection(&_poll_fd[i].mutex); - return 0; - } + if (!DuplicateHandle(GetCurrentProcess(), + filedes[0], GetCurrentProcess(), + &filedes[1], 0, FALSE, DUPLICATE_SAME_ACCESS)) + { + CloseHandle(filedes[0]); + return -1; } - free_overlapped(overlapped); - return -1; + return 0; } /* @@ -317,7 +215,6 @@ int usbi_pipe(libusb_event_handle filedes[2]) */ struct winfd usbi_create_fd(HANDLE handle, int access_mode, struct usbi_transfer *itransfer, cancel_transfer *cancel_fn) { - int i; struct winfd wfd = INVALID_WINFD; OVERLAPPED* overlapped = NULL; @@ -346,56 +243,22 @@ struct winfd usbi_create_fd(HANDLE handle, int access_mode, struct usbi_transfer return INVALID_WINFD; } - for (i=0; i<MAX_FDS; i++) { - if (poll_fd[i].fd < 0) { - EnterCriticalSection(&_poll_fd[i].mutex); - // fd might have been removed before we got to critical - if (poll_fd[i].fd >= 0) { - LeaveCriticalSection(&_poll_fd[i].mutex); - continue; - } - // Use index as the unique fd number - wfd.fd = i; - // Attempt to emulate some of the CancelIoEx behaviour on platforms - // that don't have it - if (Use_Duplicate_Handles) { - _poll_fd[i].thread_id = GetCurrentThreadId(); - if (!DuplicateHandle(GetCurrentProcess(), handle, GetCurrentProcess(), - &wfd.handle, 0, TRUE, DUPLICATE_SAME_ACCESS)) { - usbi_dbg("could not duplicate handle for CancelIo - using original one"); - wfd.handle = handle; - // Make sure we won't close the original handle on fd deletion then - _poll_fd[i].original_handle = INVALID_HANDLE_VALUE; - } else { - _poll_fd[i].original_handle = handle; - } - } else { - wfd.handle = handle; - } - wfd.overlapped = overlapped; - memcpy(&poll_fd[i], &wfd, sizeof(struct winfd)); - LeaveCriticalSection(&_poll_fd[i].mutex); - return wfd; - } - } - free_overlapped(overlapped); - return INVALID_WINFD; -} - -static void _free_index(int _index) -{ - // Cancel any async IO (Don't care about the validity of our handles for this) - cancel_io(_index); - // close the duplicate handle (if we have an actual duplicate) if (Use_Duplicate_Handles) { - if (_poll_fd[_index].original_handle != INVALID_HANDLE_VALUE) { - CloseHandle(poll_fd[_index].handle); + wfd.thread_id = GetCurrentThreadId(); + if (!DuplicateHandle(GetCurrentProcess(), handle, GetCurrentProcess(), + &wfd.handle, 0, TRUE, DUPLICATE_SAME_ACCESS)) { + usbi_dbg("could not duplicate handle for CancelIo - using original one"); + wfd.handle = handle; + // Make sure we won't close the original handle on fd deletion then + wfd.original_handle = INVALID_HANDLE_VALUE; + } else { + wfd.original_handle = handle; } - _poll_fd[_index].original_handle = INVALID_HANDLE_VALUE; - _poll_fd[_index].thread_id = 0; + } else { + wfd.handle = handle; } - free_overlapped(poll_fd[_index].overlapped); - poll_fd[_index] = INVALID_WINFD; + wfd.overlapped = overlapped; + return wfd; } /* @@ -405,98 +268,18 @@ static void _free_index(int _index) */ void usbi_free_fd(struct winfd *wfd) { - int _index; - - CHECK_INIT_POLLING; - - _index = _fd_to_index_and_lock(wfd->fd); - if (_index < 0) { - return; - } - _free_index(_index); - *wfd = INVALID_WINFD; - LeaveCriticalSection(&_poll_fd[_index].mutex); -} - -/* - * The functions below perform various conversions between fd, handle and OVERLAPPED - */ -struct winfd fd_to_winfd(int fd) -{ - int i; - struct winfd wfd; - - CHECK_INIT_POLLING; - - if (fd <= 0) - return INVALID_WINFD; - - for (i=0; i<MAX_FDS; i++) { - if (poll_fd[i].fd == fd) { - EnterCriticalSection(&_poll_fd[i].mutex); - // fd might have been deleted before we got to critical - if (poll_fd[i].fd != fd) { - LeaveCriticalSection(&_poll_fd[i].mutex); - continue; - } - memcpy(&wfd, &poll_fd[i], sizeof(struct winfd)); - LeaveCriticalSection(&_poll_fd[i].mutex); - return wfd; - } - } - return INVALID_WINFD; -} - -struct winfd handle_to_winfd(HANDLE handle) -{ - int i; - struct winfd wfd; - - CHECK_INIT_POLLING; - - if ((handle == 0) || (handle == INVALID_HANDLE_VALUE)) - return INVALID_WINFD; - - for (i=0; i<MAX_FDS; i++) { - if (poll_fd[i].handle == handle) { - EnterCriticalSection(&_poll_fd[i].mutex); - // fd might have been deleted before we got to critical - if (poll_fd[i].handle != handle) { - LeaveCriticalSection(&_poll_fd[i].mutex); - continue; - } - memcpy(&wfd, &poll_fd[i], sizeof(struct winfd)); - LeaveCriticalSection(&_poll_fd[i].mutex); - return wfd; - } - } - return INVALID_WINFD; -} - -struct winfd overlapped_to_winfd(OVERLAPPED* overlapped) -{ - int i; - struct winfd wfd; - - CHECK_INIT_POLLING; - - if (overlapped == NULL) - return INVALID_WINFD; - - for (i=0; i<MAX_FDS; i++) { - if (poll_fd[i].overlapped == overlapped) { - EnterCriticalSection(&_poll_fd[i].mutex); - // fd might have been deleted before we got to critical - if (poll_fd[i].overlapped != overlapped) { - LeaveCriticalSection(&_poll_fd[i].mutex); - continue; - } - memcpy(&wfd, &poll_fd[i], sizeof(struct winfd)); - LeaveCriticalSection(&_poll_fd[i].mutex); - return wfd; + // Cancel any async IO (Don't care about the validity of our handles for this) + cancel_io(wfd); + // close the duplicate handle (if we have an actual duplicate) + if (Use_Duplicate_Handles) { + if (wfd->original_handle != INVALID_HANDLE_VALUE) { + CloseHandle(wfd->handle); } + wfd->original_handle = INVALID_HANDLE_VALUE; + wfd->thread_id = 0; } - return INVALID_WINFD; + free_overlapped(wfd->overlapped); + *wfd = INVALID_WINFD; } /* @@ -507,9 +290,8 @@ struct winfd overlapped_to_winfd(OVERLAPPED* overlapped) int usbi_poll(struct pollfd *fds, unsigned int nfds, int timeout) { unsigned i; - int _index, object_index, triggered; + int triggered, object_index; HANDLE *handles_to_wait_on; - int *handle_to_index; DWORD nb_handles_to_wait_on = 0; DWORD ret; @@ -517,8 +299,7 @@ int usbi_poll(struct pollfd *fds, unsigned int nfds, int timeout) triggered = 0; handles_to_wait_on = (HANDLE*) calloc(nfds+1, sizeof(HANDLE)); // +1 for fd_update - handle_to_index = (int*) calloc(nfds, sizeof(int)); - if ((handles_to_wait_on == NULL) || (handle_to_index == NULL)) { + if (handles_to_wait_on == NULL) { errno = ENOMEM; triggered = -1; goto poll_exit; @@ -535,54 +316,10 @@ int usbi_poll(struct pollfd *fds, unsigned int nfds, int timeout) triggered = -1; goto poll_exit; } - - _index = _fd_to_index_and_lock(fds[i].fd); - poll_dbg("fd[%d]=%d: (overlapped=%p) got events %04X", i, poll_fd[_index].fd, poll_fd[_index].overlapped, fds[i].events); - - if ( (_index < 0) || (poll_fd[_index].handle == INVALID_HANDLE_VALUE) - || (poll_fd[_index].handle == 0) || (poll_fd[_index].overlapped == NULL)) { - fds[i].revents |= POLLNVAL | POLLERR; - errno = EBADF; - if (_index >= 0) { - LeaveCriticalSection(&_poll_fd[_index].mutex); - } - usbi_warn(NULL, "invalid fd"); - triggered = -1; - goto poll_exit; - } - - // IN or OUT must match our fd direction - if ((fds[i].events & POLLIN) && (poll_fd[_index].rw != RW_READ)) { - fds[i].revents |= POLLNVAL | POLLERR; - errno = EBADF; - usbi_warn(NULL, "attempted POLLIN on fd without READ access"); - LeaveCriticalSection(&_poll_fd[_index].mutex); - triggered = -1; - goto poll_exit; - } - - if ((fds[i].events & POLLOUT) && (poll_fd[_index].rw != RW_WRITE)) { - fds[i].revents |= POLLNVAL | POLLERR; - errno = EBADF; - usbi_warn(NULL, "attempted POLLOUT on fd without WRITE access"); - LeaveCriticalSection(&_poll_fd[_index].mutex); - triggered = -1; - goto poll_exit; - } - - // The following macro only works if overlapped I/O was reported pending - if ( (HasOverlappedIoCompleted(poll_fd[_index].overlapped)) - || (HasOverlappedIoCompletedSync(poll_fd[_index].overlapped)) ) { - poll_dbg(" completed"); - // checks above should ensure this works: - fds[i].revents = fds[i].events; - triggered++; - } else { - handles_to_wait_on[nb_handles_to_wait_on] = poll_fd[_index].overlapped->hEvent; - handle_to_index[nb_handles_to_wait_on] = i; + if (fds[i].fd != INVALID_HANDLE_VALUE) { + handles_to_wait_on[nb_handles_to_wait_on] = fds[i].fd; nb_handles_to_wait_on++; } - LeaveCriticalSection(&_poll_fd[_index].mutex); } // If nothing was triggered, wait on all fds that require it @@ -597,17 +334,14 @@ int usbi_poll(struct pollfd *fds, unsigned int nfds, int timeout) object_index = ret-WAIT_OBJECT_0; if ((object_index >= 0) && ((DWORD)object_index < nb_handles_to_wait_on)) { poll_dbg(" completed after wait"); - i = handle_to_index[object_index]; - _index = _fd_to_index_and_lock(fds[i].fd); - fds[i].revents = fds[i].events; + fds[object_index].revents = fds[object_index].events; triggered++; - if (_index >= 0) { - LeaveCriticalSection(&_poll_fd[_index].mutex); - } } else if (ret == WAIT_TIMEOUT) { poll_dbg(" timed out"); triggered = 0; // 0 = timeout } else { + poll_dbg(" wait failed, return 0x%08x, last error %d", + ret, GetLastError()); errno = EIO; triggered = -1; // error } @@ -617,9 +351,6 @@ poll_exit: if (handles_to_wait_on != NULL) { free(handles_to_wait_on); } - if (handle_to_index != NULL) { - free(handle_to_index); - } return triggered; } @@ -628,21 +359,14 @@ poll_exit: */ int usbi_close(libusb_event_handle fd) { - int _index; - int r = -1; - - CHECK_INIT_POLLING; - - _index = _fd_to_index_and_lock(fd); - - if (_index < 0) { - errno = EBADF; - } else { - free_overlapped(poll_fd[_index].overlapped); - poll_fd[_index] = INVALID_WINFD; - LeaveCriticalSection(&_poll_fd[_index].mutex); + if (fd != INVALID_HANDLE_VALUE && + !CloseHandle(fd)) + { + /* Failed to close handle */ + return -1; } - return r; + /* Already closed or closed successfully */ + return 0; } /* @@ -650,34 +374,17 @@ int usbi_close(libusb_event_handle fd) */ ssize_t usbi_write(libusb_event_handle fd, const void *buf, size_t count) { - int _index; UNUSED(buf); - CHECK_INIT_POLLING; - if (count != sizeof(unsigned char)) { - usbi_err(NULL, "this function should only used for signaling"); + usbi_err(NULL, "usbi_write should only used for signaling"); return -1; } - - _index = _fd_to_index_and_lock(fd); - - if ( (_index < 0) || (poll_fd[_index].overlapped == NULL) ) { - errno = EBADF; - if (_index >= 0) { - LeaveCriticalSection(&_poll_fd[_index].mutex); - } + /* Only need to signal the semaphore */ + if (!ReleaseSemaphore(fd, 1, NULL)) { + usbi_err(NULL, "failed to release semaphore in usbi_write: %d", GetLastError()); return -1; } - - poll_dbg("set pipe event (fd = %d, thread = %08X)", _index, GetCurrentThreadId()); - SetEvent(poll_fd[_index].overlapped->hEvent); - poll_fd[_index].overlapped->Internal = STATUS_WAIT_0; - // If two threads write on the pipe at the same time, we need to - // process two separate reads => use the overlapped as a counter - poll_fd[_index].overlapped->InternalHigh++; - - LeaveCriticalSection(&_poll_fd[_index].mutex); return sizeof(unsigned char); } @@ -686,41 +393,14 @@ ssize_t usbi_write(libusb_event_handle fd, const void *buf, size_t count) */ ssize_t usbi_read(libusb_event_handle fd, void *buf, size_t count) { - int _index; - ssize_t r = -1; + UNUSED(fd); UNUSED(buf); - CHECK_INIT_POLLING; - if (count != sizeof(unsigned char)) { - usbi_err(NULL, "this function should only used for signaling"); - return -1; - } - - _index = _fd_to_index_and_lock(fd); - - if (_index < 0) { - errno = EBADF; + usbi_err(NULL, "usbi_read should only used for signaling"); return -1; } - - if (WaitForSingleObject(poll_fd[_index].overlapped->hEvent, INFINITE) != WAIT_OBJECT_0) { - usbi_warn(NULL, "waiting for event failed: %d", (int)GetLastError()); - errno = EIO; - goto out; - } - - poll_dbg("clr pipe event (fd = %d, thread = %08X)", _index, GetCurrentThreadId()); - poll_fd[_index].overlapped->InternalHigh--; - // Don't reset unless we don't have any more events to process - if (poll_fd[_index].overlapped->InternalHigh <= 0) { - ResetEvent(poll_fd[_index].overlapped->hEvent); - poll_fd[_index].overlapped->Internal = STATUS_PENDING; - } - - r = sizeof(unsigned char); - -out: - LeaveCriticalSection(&_poll_fd[_index].mutex); - return r; + /* Nothing to do as the wait for this object will have already decremented the + * semaphore */ + return sizeof(unsigned char); } diff --git a/libusb/os/poll_windows.h b/libusb/os/poll_windows.h index b52031b..47d57a1 100644 --- a/libusb/os/poll_windows.h +++ b/libusb/os/poll_windows.h @@ -49,8 +49,6 @@ enum windows_version { }; extern enum windows_version windows_version; -#define MAX_FDS 256 - #define POLLIN 0x0001 /* There is data to read */ #define POLLPRI 0x0002 /* There is urgent data to read */ #define POLLOUT 0x0004 /* Writing now will not block */ @@ -75,12 +73,14 @@ enum rw_type { typedef int cancel_transfer(struct usbi_transfer *itransfer); struct winfd { - int fd; // what's exposed to libusb core HANDLE handle; // what we need to attach overlapped to the I/O op, so we can poll it OVERLAPPED* overlapped; // what will report our I/O status struct usbi_transfer *itransfer; // Associated transfer, or NULL if completed cancel_transfer *cancel_fn; // Function pointer to cancel transfer API enum rw_type rw; // I/O transfer direction: read *XOR* write (NOT BOTH) + // Additional variables for XP CancelIoEx partial emulation + HANDLE original_handle; + DWORD thread_id; }; extern const struct winfd INVALID_WINFD; @@ -91,13 +91,9 @@ ssize_t usbi_read(libusb_event_handle fd, void *buf, size_t count); int usbi_close(libusb_event_handle fd); void init_polling(void); -void exit_polling(void); struct winfd usbi_create_fd(HANDLE handle, int access_mode, struct usbi_transfer *transfer, cancel_transfer *cancel_fn); void usbi_free_fd(struct winfd* winfd); -struct winfd fd_to_winfd(int fd); -struct winfd handle_to_winfd(HANDLE handle); -struct winfd overlapped_to_winfd(OVERLAPPED* overlapped); /* * Timeval operations diff --git a/libusb/os/wince_usb.c b/libusb/os/wince_usb.c index e4a6633..9957b8e 100644 --- a/libusb/os/wince_usb.c +++ b/libusb/os/wince_usb.c @@ -299,7 +299,6 @@ static void wince_exit(void) // Only works if exits and inits are balanced exactly if (--concurrent_usage < 0) { // Last exit - exit_polling(); if (timer_thread) { SetEvent(timer_request[1]); // actually the signal to quit the thread. @@ -588,10 +587,9 @@ static void wince_clear_transfer_priv( struct usbi_transfer *itransfer) { struct wince_transfer_priv *transfer_priv = (struct wince_transfer_priv*)usbi_transfer_get_os_priv(itransfer); - struct winfd wfd = fd_to_winfd(transfer_priv->pollable_fd.fd); // No need to cancel transfer as it is either complete or abandoned - wfd.itransfer = NULL; - CloseHandle(wfd.handle); + transfer_priv->pollable_fd.itransfer = NULL; + CloseHandle(transfer_priv->pollable_fd.handle); usbi_free_fd(&transfer_priv->pollable_fd); } @@ -638,7 +636,7 @@ static int wince_submit_control_or_bulk_transfer(struct usbi_transfer *itransfer } wfd = usbi_create_fd(eventHandle, direction_in ? RW_READ : RW_WRITE, itransfer, &wince_cancel_transfer); - if (wfd.fd < 0) { + if (wfd.handle == INVALID_HANDLE_VALUE) { CloseHandle(eventHandle); return LIBUSB_ERROR_NO_MEM; } @@ -661,7 +659,7 @@ static int wince_submit_control_or_bulk_transfer(struct usbi_transfer *itransfer wince_clear_transfer_priv(itransfer); return libusbErr; } - usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, direction_in ? POLLIN : POLLOUT); + usbi_add_pollfd(ctx, transfer_priv->pollable_fd.overlapped->hEvent, direction_in ? POLLIN : POLLOUT); itransfer->flags |= USBI_TRANSFER_UPDATED_FDS; return LIBUSB_SUCCESS; @@ -827,7 +825,7 @@ static int wince_handle_events( usbi_mutex_lock(&ctx->flying_transfers_lock); list_for_each_entry(transfer, &ctx->flying_transfers, list, struct usbi_transfer) { transfer_priv = usbi_transfer_get_os_priv(transfer); - if (transfer_priv->pollable_fd.fd == fds[i].fd) { + if (transfer_priv->pollable_fd.overlapped->hEvent == fds[i].fd) { found = TRUE; break; } @@ -837,7 +835,7 @@ static int wince_handle_events( if (found && HasOverlappedIoCompleted(transfer_priv->pollable_fd.overlapped)) { io_result = (DWORD)transfer_priv->pollable_fd.overlapped->Internal; io_size = (DWORD)transfer_priv->pollable_fd.overlapped->InternalHigh; - usbi_remove_pollfd(ctx, transfer_priv->pollable_fd.fd); + usbi_remove_pollfd(ctx, transfer_priv->pollable_fd.overlapped->hEvent); // let handle_callback free the event using the transfer wfd // If you don't use the transfer wfd, you run a risk of trying to free a // newly allocated wfd that took the place of the one from the transfer. diff --git a/libusb/os/windows_usb.c b/libusb/os/windows_usb.c index 63357b1..26cb7f8 100644 --- a/libusb/os/windows_usb.c +++ b/libusb/os/windows_usb.c @@ -1698,7 +1698,6 @@ static void windows_exit(void) for (i=0; i<USB_API_MAX; i++) { usb_api_backend[i].exit(SUB_API_NOTSET); } - exit_polling(); if (timer_thread) { SetEvent(timer_request[1]); // actually the signal to quit the thread. @@ -1933,7 +1932,7 @@ static int submit_bulk_transfer(struct usbi_transfer *itransfer) return r; } - usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, + usbi_add_pollfd(ctx, transfer_priv->pollable_fd.overlapped->hEvent, (short)(IS_XFERIN(transfer) ? POLLIN : POLLOUT)); itransfer->flags |= USBI_TRANSFER_UPDATED_FDS; @@ -1953,7 +1952,7 @@ static int submit_iso_transfer(struct usbi_transfer *itransfer) return r; } - usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, + usbi_add_pollfd(ctx, transfer_priv->pollable_fd.overlapped->hEvent, (short)(IS_XFERIN(transfer) ? POLLIN : POLLOUT)); itransfer->flags |= USBI_TRANSFER_UPDATED_FDS; @@ -1973,7 +1972,7 @@ static int submit_control_transfer(struct usbi_transfer *itransfer) return r; } - usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, POLLIN); + usbi_add_pollfd(ctx, transfer_priv->pollable_fd.overlapped->hEvent, POLLIN); itransfer->flags |= USBI_TRANSFER_UPDATED_FDS; return LIBUSB_SUCCESS; @@ -2116,7 +2115,7 @@ static int windows_handle_events(struct libusb_context *ctx, struct pollfd *fds, usbi_mutex_lock(&ctx->flying_transfers_lock); list_for_each_entry(transfer, &ctx->flying_transfers, list, struct usbi_transfer) { transfer_priv = usbi_transfer_get_os_priv(transfer); - if (transfer_priv->pollable_fd.fd == fds[i].fd) { + if (transfer_priv->pollable_fd.overlapped->hEvent == fds[i].fd) { found = true; break; } @@ -2135,7 +2134,7 @@ static int windows_handle_events(struct libusb_context *ctx, struct pollfd *fds, } else { io_result = GetLastError(); } - usbi_remove_pollfd(ctx, transfer_priv->pollable_fd.fd); + usbi_remove_pollfd(ctx, transfer_priv->pollable_fd.overlapped->hEvent); // let handle_callback free the event using the transfer wfd // If you don't use the transfer wfd, you run a risk of trying to free a // newly allocated wfd that took the place of the one from the transfer. @@ -2880,7 +2879,7 @@ static int winusbx_submit_control_transfer(int sub_api, struct usbi_transfer *it wfd = usbi_create_fd(winusb_handle, RW_READ, NULL, NULL); // Always use the handle returned from usbi_create_fd (wfd.handle) - if (wfd.fd < 0) { + if (wfd.handle == INVALID_HANDLE_VALUE) { return LIBUSB_ERROR_NO_MEM; } @@ -2969,7 +2968,7 @@ static int winusbx_submit_bulk_transfer(int sub_api, struct usbi_transfer *itran wfd = usbi_create_fd(winusb_handle, IS_XFERIN(transfer) ? RW_READ : RW_WRITE, NULL, NULL); // Always use the handle returned from usbi_create_fd (wfd.handle) - if (wfd.fd < 0) { + if (wfd.handle == INVALID_HANDLE_VALUE) { return LIBUSB_ERROR_NO_MEM; } @@ -3088,14 +3087,34 @@ static int winusbx_reset_device(int sub_api, struct libusb_device_handle *dev_ha // Reset any available pipe (except control) for (i=0; i<USB_MAXINTERFACES; i++) { winusb_handle = handle_priv->interface_handle[i].api_handle; - for (wfd = handle_to_winfd(winusb_handle); wfd.fd > 0;) - { - // Cancel any pollable I/O - usbi_remove_pollfd(ctx, wfd.fd); - usbi_free_fd(&wfd); - wfd = handle_to_winfd(winusb_handle); - } + /* need to go through the flying transfer list and + * find and cancel any IO on this handle. */ + do { + struct windows_transfer_priv* transfer_priv = NULL; + struct usbi_transfer *transfer; + + if ((winusb_handle == 0) || (winusb_handle == INVALID_HANDLE_VALUE)) { + wfd = INVALID_WINFD; + break; + } + + /* Look through the flying transfers for matching handles */ + usbi_mutex_lock(&ctx->flying_transfers_lock); + list_for_each_entry(transfer, &ctx->flying_transfers, list, struct usbi_transfer) { + transfer_priv = usbi_transfer_get_os_priv(transfer); + if (transfer_priv->pollable_fd.handle == winusb_handle) { + wfd = transfer_priv->pollable_fd; + break; + } + } + usbi_mutex_unlock(&ctx->flying_transfers_lock); + if (wfd.handle != INVALID_HANDLE_VALUE) { + usbi_remove_pollfd(ctx, wfd.overlapped->hEvent); + usbi_free_fd(&wfd); + } + } while (wfd.handle != INVALID_HANDLE_VALUE); + /* Now that all IO is cancelled it is ok to reset the pipes */ if ( (winusb_handle != 0) && (winusb_handle != INVALID_HANDLE_VALUE)) { for (j=0; j<priv->usb_interface[i].nb_endpoints; j++) { usbi_dbg("resetting ep %02X", priv->usb_interface[i].endpoint[j]); @@ -3900,7 +3919,7 @@ static int hid_submit_control_transfer(int sub_api, struct usbi_transfer *itrans hid_handle = handle_priv->interface_handle[current_interface].api_handle; // Always use the handle returned from usbi_create_fd (wfd.handle) wfd = usbi_create_fd(hid_handle, RW_READ, NULL, NULL); - if (wfd.fd < 0) { + if (wfd.handle == INVALID_HANDLE_VALUE) { return LIBUSB_ERROR_NOT_FOUND; } @@ -4007,7 +4026,7 @@ static int hid_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer wfd = usbi_create_fd(hid_handle, direction_in?RW_READ:RW_WRITE, NULL, NULL); // Always use the handle returned from usbi_create_fd (wfd.handle) - if (wfd.fd < 0) { + if (wfd.handle == INVALID_HANDLE_VALUE) { return LIBUSB_ERROR_NO_MEM; } -- 1.7.9.5 ------------------------------------------------------------------------------ This SF.net email is sponsored by Windows: Build for Windows Store. http://p.sf.net/sfu/windows-dev2dev _______________________________________________ libusbx-devel mailing list libusbx-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/libusbx-devel