summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libusb/os/poll_windows.c38
-rw-r--r--libusb/os/poll_windows.h8
-rw-r--r--libusb/os/windows_usb.c29
3 files changed, 55 insertions, 20 deletions
diff --git a/libusb/os/poll_windows.c b/libusb/os/poll_windows.c
index 3bbe615..0d8d487 100644
--- a/libusb/os/poll_windows.c
+++ b/libusb/os/poll_windows.c
@@ -117,13 +117,15 @@ static inline int _open_osfhandle(intptr_t osfhandle, int flags)
#define CHECK_INIT_POLLING do {if(!is_polling_set) init_polling();} while(0)
// public fd data
-const struct winfd INVALID_WINFD = {-1, NULL, NULL, RW_NONE, FALSE};
+const struct winfd INVALID_WINFD = {-1, NULL, NULL, RW_NONE};
struct winfd poll_fd[MAX_FDS];
// internal fd data
struct {
CRITICAL_SECTION mutex; // lock for fds
BYTE marker; // 1st byte of a usbi_read operation gets stored here
-
+ // Additional variables for XP CancelIoEx partial emulation
+ HANDLE original_handle;
+ DWORD thread_id;
} _poll_fd[MAX_FDS];
// globals
@@ -146,11 +148,19 @@ __inline BOOL cancel_io(int index)
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) ) {
+ return TRUE;
+ }
if (pCancelIoEx != NULL) {
return (*pCancelIoEx)(poll_fd[index].handle, poll_fd[index].overlapped);
- } else {
+ }
+ if (_poll_fd[index].thread_id == GetCurrentThreadId()) {
return CancelIo(poll_fd[index].handle);
}
+ usbi_warn(NULL, "Unable to cancel I/O that was started from another thread");
+ return FALSE;
}
// Init
@@ -169,6 +179,8 @@ void init_polling(void)
for (i=0; i<MAX_FDS; i++) {
poll_fd[i] = INVALID_WINFD;
_poll_fd[i].marker = 0;
+ _poll_fd[i].original_handle = INVALID_HANDLE_VALUE;
+ _poll_fd[i].thread_id = 0;
InitializeCriticalSection(&_poll_fd[i].mutex);
}
#if defined(DYNAMIC_FDS)
@@ -385,7 +397,6 @@ int usbi_pipe(int filedes[2])
poll_fd[i].handle = handle[j];
poll_fd[i].overlapped = (j==0)?overlapped0:overlapped1;
poll_fd[i].rw = RW_READ+j;
- poll_fd[i].completed_synchronously = FALSE;
j++;
if (j==1) {
// Start a 1 byte nonblocking read operation
@@ -471,7 +482,19 @@ struct winfd usbi_create_fd(HANDLE handle, int access_mode)
continue;
}
wfd.fd = fd;
- wfd.handle = handle;
+ // Attempt to emulate some of the CancelIoEx behaviour on platforms
+ // that don't have it
+ if (pCancelIoEx == NULL) {
+ _poll_fd[i].thread_id = GetCurrentThreadId();
+ _poll_fd[i].original_handle = handle;
+ if (!DuplicateHandle(GetCurrentProcess(), handle, GetCurrentProcess(),
+ &wfd.handle, 0, TRUE, DUPLICATE_SAME_ACCESS)) {
+ usbi_warn(NULL, "could not duplicate handle for CancelIo - using orignal one");
+ wfd.handle = handle;
+ }
+ } else {
+ wfd.handle = handle;
+ }
wfd.overlapped = overlapped;
memcpy(&poll_fd[i], &wfd, sizeof(struct winfd));
LeaveCriticalSection(&_poll_fd[i].mutex);
@@ -500,6 +523,9 @@ void _free_index(int index)
_close(poll_fd[index].fd);
}
free_overlapped(poll_fd[index].overlapped);
+ CloseHandle(_poll_fd[index].original_handle);
+ _poll_fd[index].original_handle = INVALID_HANDLE_VALUE;
+ _poll_fd[index].thread_id = 0;
poll_fd[index] = INVALID_WINFD;
}
@@ -691,7 +717,7 @@ int usbi_poll(struct pollfd *fds, unsigned int nfds, int timeout)
// The following macro only works if overlapped I/O was reported pending
if ( (HasOverlappedIoCompleted(poll_fd[index].overlapped))
- || (poll_fd[index].completed_synchronously) ) {
+ || (HasOverlappedIoCompletedSync(poll_fd[index].overlapped)) ) {
poll_dbg(" completed");
// checks above should ensure this works:
fds[i].revents = fds[i].events;
diff --git a/libusb/os/poll_windows.h b/libusb/os/poll_windows.h
index 0da805b..97259e9 100644
--- a/libusb/os/poll_windows.h
+++ b/libusb/os/poll_windows.h
@@ -39,6 +39,13 @@
#endif
#endif
+// Handle synchronous completion through the overlapped structure
+#if !defined(STATUS_REPARSE) // reuse the REPARSE status code
+#define STATUS_REPARSE ((LONG)0x00000104L)
+#endif
+#define STATUS_COMPLETED_SYNCHRONOUSLY STATUS_REPARSE
+#define HasOverlappedIoCompletedSync(lpOverlapped) (((DWORD)(lpOverlapped)->Internal) == STATUS_COMPLETED_SYNCHRONOUSLY)
+
enum windows_version {
WINDOWS_UNSUPPORTED,
WINDOWS_XP,
@@ -77,7 +84,6 @@ struct winfd {
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
enum rw_type rw; // I/O transfer direction: read *XOR* write (NOT BOTH)
- BOOLEAN completed_synchronously;// flag for async transfers that completed during request
};
extern const struct winfd INVALID_WINFD;
diff --git a/libusb/os/windows_usb.c b/libusb/os/windows_usb.c
index fe7961e..a81673a 100644
--- a/libusb/os/windows_usb.c
+++ b/libusb/os/windows_usb.c
@@ -1933,10 +1933,10 @@ static int windows_handle_events(struct libusb_context *ctx, struct pollfd *fds,
if (found) {
// Handle async requests that completed synchronously first
- if (transfer_priv->pollable_fd.completed_synchronously) {
+ if (HasOverlappedIoCompletedSync(transfer_priv->pollable_fd.overlapped)) {
io_result = NO_ERROR;
io_size = (DWORD)transfer_priv->pollable_fd.overlapped->InternalHigh;
- // Regular saync overlapped
+ // Regular async overlapped
} else if (GetOverlappedResult(transfer_priv->pollable_fd.handle,
transfer_priv->pollable_fd.overlapped, &io_size, false)) {
io_result = NO_ERROR;
@@ -2555,6 +2555,7 @@ static int winusb_submit_control_transfer(struct usbi_transfer *itransfer)
winusb_handle = handle_priv->interface_handle[current_interface].api_handle;
wfd = usbi_create_fd(winusb_handle, _O_RDONLY);
+ // Always use the handle returned from usbi_create_fd (wfd.handle)
if (wfd.fd < 0) {
return LIBUSB_ERROR_NO_MEM;
}
@@ -2566,7 +2567,7 @@ static int winusb_submit_control_transfer(struct usbi_transfer *itransfer)
return LIBUSB_ERROR_IO;
}
} else {
- wfd.completed_synchronously = true;
+ wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY;
wfd.overlapped->InternalHigh = (DWORD)size;
}
@@ -2631,16 +2632,17 @@ static int winusb_submit_bulk_transfer(struct usbi_transfer *itransfer)
direction_in = transfer->endpoint & LIBUSB_ENDPOINT_IN;
wfd = usbi_create_fd(winusb_handle, direction_in?_O_RDONLY:_O_WRONLY);
+ // Always use the handle returned from usbi_create_fd (wfd.handle)
if (wfd.fd < 0) {
return LIBUSB_ERROR_NO_MEM;
}
if (direction_in) {
usbi_dbg("reading %d bytes", transfer->length);
- ret = WinUsb_ReadPipe(winusb_handle, transfer->endpoint, transfer->buffer, transfer->length, NULL, wfd.overlapped);
+ ret = WinUsb_ReadPipe(wfd.handle, transfer->endpoint, transfer->buffer, transfer->length, NULL, wfd.overlapped);
} else {
usbi_dbg("writing %d bytes", transfer->length);
- ret = WinUsb_WritePipe(winusb_handle, transfer->endpoint, transfer->buffer, transfer->length, NULL, wfd.overlapped);
+ ret = WinUsb_WritePipe(wfd.handle, transfer->endpoint, transfer->buffer, transfer->length, NULL, wfd.overlapped);
}
if (!ret) {
if(GetLastError() != ERROR_IO_PENDING) {
@@ -2649,7 +2651,7 @@ static int winusb_submit_bulk_transfer(struct usbi_transfer *itransfer)
return LIBUSB_ERROR_IO;
}
} else {
- wfd.completed_synchronously = true;
+ wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY;
wfd.overlapped->InternalHigh = (DWORD)transfer->length;
}
@@ -3593,7 +3595,7 @@ static int hid_submit_control_transfer(struct usbi_transfer *itransfer)
usbi_dbg("will use interface %d", current_interface);
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, _O_RDONLY);
if (wfd.fd < 0) {
return LIBUSB_ERROR_NO_MEM;
@@ -3603,7 +3605,7 @@ static int hid_submit_control_transfer(struct usbi_transfer *itransfer)
case LIBUSB_REQUEST_TYPE_STANDARD:
switch(setup->request) {
case LIBUSB_REQUEST_GET_DESCRIPTOR:
- r = _hid_get_descriptor(priv->hid, hid_handle, LIBUSB_REQ_RECIPIENT(setup->request_type),
+ r = _hid_get_descriptor(priv->hid, wfd.handle, LIBUSB_REQ_RECIPIENT(setup->request_type),
(setup->value >> 8) & 0xFF, setup->value & 0xFF, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, &size);
break;
case LIBUSB_REQUEST_GET_CONFIGURATION:
@@ -3638,7 +3640,7 @@ static int hid_submit_control_transfer(struct usbi_transfer *itransfer)
}
break;
case LIBUSB_REQUEST_TYPE_CLASS:
- r =_hid_class_request(priv->hid, hid_handle, setup->request_type, setup->request, setup->value,
+ r =_hid_class_request(priv->hid, wfd.handle, setup->request_type, setup->request, setup->value,
setup->index, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, transfer_priv,
&size, wfd.overlapped);
break;
@@ -3649,7 +3651,7 @@ static int hid_submit_control_transfer(struct usbi_transfer *itransfer)
if (r == LIBUSB_COMPLETED) {
// Force request to be completed synchronously. Transferred size has been set by previous call
- wfd.completed_synchronously = true;
+ wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY;
// http://msdn.microsoft.com/en-us/library/ms684342%28VS.85%29.aspx
// set InternalHigh to the number of bytes transferred
wfd.overlapped->InternalHigh = (DWORD)size;
@@ -3697,6 +3699,7 @@ static int hid_submit_bulk_transfer(struct usbi_transfer *itransfer) {
direction_in = transfer->endpoint & LIBUSB_ENDPOINT_IN;
wfd = usbi_create_fd(hid_handle, direction_in?_O_RDONLY:_O_WRONLY);
+ // Always use the handle returned from usbi_create_fd (wfd.handle)
if (wfd.fd < 0) {
return LIBUSB_ERROR_NO_MEM;
}
@@ -3709,13 +3712,13 @@ static int hid_submit_bulk_transfer(struct usbi_transfer *itransfer) {
if (direction_in) {
transfer_priv->hid_buffer[0] = priv->hid->input_report_id;
usbi_dbg("reading %d bytes (report ID: 0x%02X)", transfer->length+1, transfer_priv->hid_buffer[0]);
- ret = ReadFile(hid_handle, transfer_priv->hid_buffer, transfer->length+1, &size, wfd.overlapped);
+ ret = ReadFile(wfd.handle, transfer_priv->hid_buffer, transfer->length+1, &size, wfd.overlapped);
} else {
transfer_priv->hid_buffer[0] = priv->hid->output_report_id;
memcpy(transfer_priv->hid_buffer+1, transfer->buffer, transfer->length);
usbi_dbg("writing %d bytes (report ID: 0x%02X)", transfer->length+1, transfer_priv->hid_buffer[0]);
transfer_priv->hid_buffer[0] = 0;
- ret = WriteFile(hid_handle, transfer_priv->hid_buffer, transfer->length+1, &size, wfd.overlapped);
+ ret = WriteFile(wfd.handle, transfer_priv->hid_buffer, transfer->length+1, &size, wfd.overlapped);
}
if (!ret) {
if (GetLastError() != ERROR_IO_PENDING) {
@@ -3738,7 +3741,7 @@ static int hid_submit_bulk_transfer(struct usbi_transfer *itransfer) {
usbi_err(ctx, "OVERFLOW!");
r = LIBUSB_ERROR_OVERFLOW;
}
- wfd.completed_synchronously = true;
+ wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY;
wfd.overlapped->InternalHigh = size;
}