| Index: third_party/libusb/src/libusb/os/poll_windows.c
|
| diff --git a/third_party/libusb/src/libusb/os/poll_windows.c b/third_party/libusb/src/libusb/os/poll_windows.c
|
| index 7f4d9c4e7e94def7a91a16624d16582a9f539a94..7ed19ba324f980658ae0940c88b9042e613b94ef 100644
|
| --- a/third_party/libusb/src/libusb/os/poll_windows.c
|
| +++ b/third_party/libusb/src/libusb/os/poll_windows.c
|
| @@ -1,6 +1,7 @@
|
| /*
|
| * poll_windows: poll compatibility wrapper for Windows
|
| - * Copyright (C) 2009-2010 Pete Batard <pbatard@gmail.com>
|
| + * Copyright © 2012-2013 RealVNC Ltd.
|
| + * Copyright © 2009-2010 Pete Batard <pete@akeo.ie>
|
| * With contributions from Michael Plante, Orin Eman et al.
|
| * Parts of poll implementation from libusb-win32, by Stephan Meyer et al.
|
| *
|
| @@ -21,7 +22,7 @@
|
| */
|
|
|
| /*
|
| - * poll() and pipe() Windows compatibility layer for libusb 1.0
|
| + * poll() and pipe() Windows compatibility layer for libusbx 1.0
|
| *
|
| * The way this layer works is by using OVERLAPPED with async I/O transfers, as
|
| * OVERLAPPED have an associated event which is flagged for I/O completion.
|
| @@ -31,7 +32,7 @@
|
| * OVERLAPPED mode
|
| * - call usbi_create_fd with this handle to obtain a custom fd.
|
| * Note that if you need simultaneous R/W access, you need to call create_fd
|
| - * twice, once in _O_RDONLY and once in _O_WRONLY mode to obtain 2 separate
|
| + * twice, once in RW_READ and once in RW_WRITE mode to obtain 2 separate
|
| * pollable fds
|
| * - leave the core functions call the poll routine and flag POLLIN/POLLOUT
|
| *
|
| @@ -40,12 +41,10 @@
|
| * context.
|
| */
|
| #include <errno.h>
|
| -#include <fcntl.h>
|
| #include <stdio.h>
|
| #include <stdlib.h>
|
| -#include <io.h>
|
|
|
| -#include <libusbi.h>
|
| +#include "libusbi.h"
|
|
|
| // Uncomment to debug the polling layer
|
| //#define DEBUG_POLL_WINDOWS
|
| @@ -53,8 +52,8 @@
|
| #define poll_dbg usbi_dbg
|
| #else
|
| // MSVC++ < 2005 cannot use a variadic argument and non MSVC
|
| -// compilers produce warnings if parenthesis are omitted.
|
| -#if defined(_MSC_VER) && _MSC_VER < 1400
|
| +// compilers produce warnings if parenthesis are ommitted.
|
| +#if defined(_MSC_VER) && (_MSC_VER < 1400)
|
| #define poll_dbg
|
| #else
|
| #define poll_dbg(...)
|
| @@ -65,20 +64,10 @@
|
| #pragma warning(disable:28719)
|
| #endif
|
|
|
| -#if defined(__CYGWIN__)
|
| -// cygwin produces a warning unless these prototypes are defined
|
| -extern int _open(char* name, int flags);
|
| -extern int _close(int fd);
|
| -extern int _snprintf(char *buffer, size_t count, const char *format, ...);
|
| -#define NUL_DEVICE "/dev/null"
|
| -#else
|
| -#define NUL_DEVICE "NUL"
|
| -#endif
|
| -
|
| #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, RW_NONE};
|
| +const struct winfd INVALID_WINFD = {-1, INVALID_HANDLE_VALUE, NULL, NULL, NULL, RW_NONE};
|
| struct winfd poll_fd[MAX_FDS];
|
| // internal fd data
|
| struct {
|
| @@ -93,12 +82,25 @@ BOOLEAN is_polling_set = FALSE;
|
| LONG pipe_number = 0;
|
| static volatile LONG compat_spinlock = 0;
|
|
|
| +#if !defined(_WIN32_WCE)
|
| // CancelIoEx, available on Vista and later only, provides the ability to cancel
|
| // a single transfer (OVERLAPPED) when used. As it may not be part of any of the
|
| // platform headers, we hook into the Kernel32 system DLL directly to seek it.
|
| static BOOL (__stdcall *pCancelIoEx)(HANDLE, LPOVERLAPPED) = NULL;
|
| -#define CancelIoEx_Available (pCancelIoEx != NULL)
|
| -static __inline BOOL cancel_io(int _index)
|
| +#define Use_Duplicate_Handles (pCancelIoEx == NULL)
|
| +
|
| +static inline void setup_cancel_io(void)
|
| +{
|
| + HMODULE hKernel32 = GetModuleHandleA("KERNEL32");
|
| + if (hKernel32 != NULL) {
|
| + pCancelIoEx = (BOOL (__stdcall *)(HANDLE,LPOVERLAPPED))
|
| + GetProcAddress(hKernel32, "CancelIoEx");
|
| + }
|
| + usbi_dbg("Will use CancelIo%s for I/O cancellation",
|
| + Use_Duplicate_Handles?"":"Ex");
|
| +}
|
| +
|
| +static inline BOOL cancel_io(int _index)
|
| {
|
| if ((_index < 0) || (_index >= MAX_FDS)) {
|
| return FALSE;
|
| @@ -108,7 +110,12 @@ static __inline BOOL cancel_io(int _index)
|
| || (poll_fd[_index].handle == 0) || (poll_fd[_index].overlapped == NULL) ) {
|
| return TRUE;
|
| }
|
| - if (CancelIoEx_Available) {
|
| + if (poll_fd[_index].itransfer && poll_fd[_index].cancel_fn) {
|
| + // Cancel outstanding transfer via the specific callback
|
| + (*poll_fd[_index].cancel_fn)(poll_fd[_index].itransfer);
|
| + return TRUE;
|
| + }
|
| + if (pCancelIoEx != NULL) {
|
| return (*pCancelIoEx)(poll_fd[_index].handle, poll_fd[_index].overlapped);
|
| }
|
| if (_poll_fd[_index].thread_id == GetCurrentThreadId()) {
|
| @@ -117,6 +124,30 @@ static __inline BOOL cancel_io(int _index)
|
| usbi_warn(NULL, "Unable to cancel I/O that was started from another thread");
|
| return FALSE;
|
| }
|
| +#else
|
| +#define Use_Duplicate_Handles FALSE
|
| +
|
| +static __inline void setup_cancel_io()
|
| +{
|
| + // No setup needed on WinCE
|
| +}
|
| +
|
| +static __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 (poll_fd[_index].itransfer && poll_fd[_index].cancel_fn) {
|
| + // Cancel outstanding transfer via the specific callback
|
| + (*poll_fd[_index].cancel_fn)(poll_fd[_index].itransfer);
|
| + }
|
| + return TRUE;
|
| +}
|
| +#endif
|
|
|
| // Init
|
| void init_polling(void)
|
| @@ -127,10 +158,7 @@ void init_polling(void)
|
| SleepEx(0, TRUE);
|
| }
|
| if (!is_polling_set) {
|
| - pCancelIoEx = (BOOL (__stdcall *)(HANDLE,LPOVERLAPPED))
|
| - GetProcAddress(GetModuleHandleA("KERNEL32"), "CancelIoEx");
|
| - usbi_dbg("Will use CancelIo%s for I/O cancellation",
|
| - CancelIoEx_Available?"Ex":"");
|
| + setup_cancel_io();
|
| for (i=0; i<MAX_FDS; i++) {
|
| poll_fd[i] = INVALID_WINFD;
|
| _poll_fd[i].original_handle = INVALID_HANDLE_VALUE;
|
| @@ -139,15 +167,15 @@ void init_polling(void)
|
| }
|
| is_polling_set = TRUE;
|
| }
|
| - compat_spinlock = 0;
|
| + InterlockedExchange((LONG *)&compat_spinlock, 0);
|
| }
|
|
|
| // Internal function to retrieve the table index (and lock the fd mutex)
|
| -int _fd_to_index_and_lock(int fd)
|
| +static int _fd_to_index_and_lock(int fd)
|
| {
|
| int i;
|
|
|
| - if (fd <= 0)
|
| + if (fd < 0)
|
| return -1;
|
|
|
| for (i=0; i<MAX_FDS; i++) {
|
| @@ -164,7 +192,7 @@ int _fd_to_index_and_lock(int fd)
|
| return -1;
|
| }
|
|
|
| -OVERLAPPED *create_overlapped(void)
|
| +static OVERLAPPED *create_overlapped(void)
|
| {
|
| OVERLAPPED *overlapped = (OVERLAPPED*) calloc(1, sizeof(OVERLAPPED));
|
| if (overlapped == NULL) {
|
| @@ -178,7 +206,7 @@ OVERLAPPED *create_overlapped(void)
|
| return overlapped;
|
| }
|
|
|
| -void free_overlapped(OVERLAPPED *overlapped)
|
| +static void free_overlapped(OVERLAPPED *overlapped)
|
| {
|
| if (overlapped == NULL)
|
| return;
|
| @@ -190,20 +218,6 @@ void free_overlapped(OVERLAPPED *overlapped)
|
| free(overlapped);
|
| }
|
|
|
| -void reset_overlapped(OVERLAPPED *overlapped)
|
| -{
|
| - HANDLE event_handle;
|
| - if (overlapped == NULL)
|
| - return;
|
| -
|
| - event_handle = overlapped->hEvent;
|
| - if (event_handle != NULL) {
|
| - ResetEvent(event_handle);
|
| - }
|
| - memset(overlapped, 0, sizeof(OVERLAPPED));
|
| - overlapped->hEvent = event_handle;
|
| -}
|
| -
|
| void exit_polling(void)
|
| {
|
| int i;
|
| @@ -221,12 +235,8 @@ void exit_polling(void)
|
| // terminating, and we should be able to access the fd
|
| // mutex lock before too long
|
| EnterCriticalSection(&_poll_fd[i].mutex);
|
| - if ( (poll_fd[i].fd > 0) && (poll_fd[i].handle != INVALID_HANDLE_VALUE) && (poll_fd[i].handle != 0)
|
| - && (GetFileType(poll_fd[i].handle) == FILE_TYPE_UNKNOWN) ) {
|
| - _close(poll_fd[i].fd);
|
| - }
|
| free_overlapped(poll_fd[i].overlapped);
|
| - if (!CancelIoEx_Available) {
|
| + if (Use_Duplicate_Handles) {
|
| // Close duplicate handle
|
| if (_poll_fd[i].original_handle != INVALID_HANDLE_VALUE) {
|
| CloseHandle(poll_fd[i].handle);
|
| @@ -237,12 +247,12 @@ void exit_polling(void)
|
| DeleteCriticalSection(&_poll_fd[i].mutex);
|
| }
|
| }
|
| - compat_spinlock = 0;
|
| + InterlockedExchange((LONG *)&compat_spinlock, 0);
|
| }
|
|
|
| /*
|
| * Create a fake pipe.
|
| - * As libusb only uses pipes for signaling, all we need from a pipe is an
|
| + * 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.
|
| */
|
| @@ -253,7 +263,8 @@ int usbi_pipe(int filedes[2])
|
|
|
| CHECK_INIT_POLLING;
|
|
|
| - overlapped = (OVERLAPPED*) calloc(1, sizeof(OVERLAPPED));
|
| + overlapped = create_overlapped();
|
| +
|
| if (overlapped == NULL) {
|
| return -1;
|
| }
|
| @@ -261,22 +272,6 @@ int usbi_pipe(int filedes[2])
|
| overlapped->Internal = STATUS_PENDING;
|
| overlapped->InternalHigh = 0;
|
|
|
| - // Read end of the "pipe"
|
| - filedes[0] = _open(NUL_DEVICE, _O_WRONLY);
|
| - if (filedes[0] < 0) {
|
| - usbi_err(NULL, "could not create pipe: errno %d", errno);
|
| - goto out1;
|
| - }
|
| - // We can use the same handle for both ends
|
| - filedes[1] = filedes[0];
|
| - poll_dbg("pipe filedes = %d", filedes[0]);
|
| -
|
| - // Note: manual reset must be true (second param) as the reset occurs in read
|
| - overlapped->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
| - if(!overlapped->hEvent) {
|
| - goto out2;
|
| - }
|
| -
|
| for (i=0; i<MAX_FDS; i++) {
|
| if (poll_fd[i].fd < 0) {
|
| EnterCriticalSection(&_poll_fd[i].mutex);
|
| @@ -286,7 +281,13 @@ int usbi_pipe(int filedes[2])
|
| continue;
|
| }
|
|
|
| - poll_fd[i].fd = filedes[0];
|
| + // 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
|
| @@ -296,12 +297,7 @@ int usbi_pipe(int filedes[2])
|
| return 0;
|
| }
|
| }
|
| -
|
| - CloseHandle(overlapped->hEvent);
|
| -out2:
|
| - _close(filedes[0]);
|
| -out1:
|
| - free(overlapped);
|
| + free_overlapped(overlapped);
|
| return -1;
|
| }
|
|
|
| @@ -319,9 +315,9 @@ out1:
|
| * read and one for write. Using a single R/W fd is unsupported and will
|
| * produce unexpected results
|
| */
|
| -struct winfd usbi_create_fd(HANDLE handle, int access_mode)
|
| +struct winfd usbi_create_fd(HANDLE handle, int access_mode, struct usbi_transfer *itransfer, cancel_transfer *cancel_fn)
|
| {
|
| - int i, fd;
|
| + int i;
|
| struct winfd wfd = INVALID_WINFD;
|
| OVERLAPPED* overlapped = NULL;
|
|
|
| @@ -331,27 +327,22 @@ struct winfd usbi_create_fd(HANDLE handle, int access_mode)
|
| return INVALID_WINFD;
|
| }
|
|
|
| - if ((access_mode != _O_RDONLY) && (access_mode != _O_WRONLY)) {
|
| - usbi_warn(NULL, "only one of _O_RDONLY or _O_WRONLY are supported.\n"
|
| + wfd.itransfer = itransfer;
|
| + wfd.cancel_fn = cancel_fn;
|
| +
|
| + if ((access_mode != RW_READ) && (access_mode != RW_WRITE)) {
|
| + usbi_warn(NULL, "only one of RW_READ or RW_WRITE are supported.\n"
|
| "If you want to poll for R/W simultaneously, create multiple fds from the same handle.");
|
| return INVALID_WINFD;
|
| }
|
| - if (access_mode == _O_RDONLY) {
|
| + if (access_mode == RW_READ) {
|
| wfd.rw = RW_READ;
|
| } else {
|
| wfd.rw = RW_WRITE;
|
| }
|
|
|
| - // Ensure that we get a non system conflicting unique fd, using
|
| - // the same fd attribution system as the pipe ends
|
| - fd = _open(NUL_DEVICE, _O_WRONLY);
|
| - if (fd < 0) {
|
| - return INVALID_WINFD;
|
| - }
|
| -
|
| overlapped = create_overlapped();
|
| if(overlapped == NULL) {
|
| - _close(fd);
|
| return INVALID_WINFD;
|
| }
|
|
|
| @@ -363,10 +354,11 @@ struct winfd usbi_create_fd(HANDLE handle, int access_mode)
|
| LeaveCriticalSection(&_poll_fd[i].mutex);
|
| continue;
|
| }
|
| - wfd.fd = fd;
|
| + // 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 (!CancelIoEx_Available) {
|
| + if (Use_Duplicate_Handles) {
|
| _poll_fd[i].thread_id = GetCurrentThreadId();
|
| if (!DuplicateHandle(GetCurrentProcess(), handle, GetCurrentProcess(),
|
| &wfd.handle, 0, TRUE, DUPLICATE_SAME_ACCESS)) {
|
| @@ -387,21 +379,15 @@ struct winfd usbi_create_fd(HANDLE handle, int access_mode)
|
| }
|
| }
|
| free_overlapped(overlapped);
|
| - _close(fd);
|
| return INVALID_WINFD;
|
| }
|
|
|
| -void _free_index(int _index)
|
| +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 fake handle for devices
|
| - if ( (poll_fd[_index].handle != INVALID_HANDLE_VALUE) && (poll_fd[_index].handle != 0)
|
| - && (GetFileType(poll_fd[_index].handle) == FILE_TYPE_UNKNOWN) ) {
|
| - _close(poll_fd[_index].fd);
|
| - }
|
| // close the duplicate handle (if we have an actual duplicate)
|
| - if (!CancelIoEx_Available) {
|
| + if (Use_Duplicate_Handles) {
|
| if (_poll_fd[_index].original_handle != INVALID_HANDLE_VALUE) {
|
| CloseHandle(poll_fd[_index].handle);
|
| }
|
| @@ -417,17 +403,18 @@ void _free_index(int _index)
|
| *
|
| * Note that the associated Windows handle is not closed by this call
|
| */
|
| -void usbi_free_fd(int fd)
|
| +void usbi_free_fd(struct winfd *wfd)
|
| {
|
| int _index;
|
|
|
| CHECK_INIT_POLLING;
|
|
|
| - _index = _fd_to_index_and_lock(fd);
|
| + _index = _fd_to_index_and_lock(wfd->fd);
|
| if (_index < 0) {
|
| return;
|
| }
|
| _free_index(_index);
|
| + *wfd = INVALID_WINFD;
|
| LeaveCriticalSection(&_poll_fd[_index].mutex);
|
| }
|
|
|
| @@ -651,15 +638,7 @@ int usbi_close(int fd)
|
| if (_index < 0) {
|
| errno = EBADF;
|
| } else {
|
| - if (poll_fd[_index].overlapped != NULL) {
|
| - // Must be a different event for each end of the pipe
|
| - CloseHandle(poll_fd[_index].overlapped->hEvent);
|
| - free(poll_fd[_index].overlapped);
|
| - }
|
| - r = _close(poll_fd[_index].fd);
|
| - if (r != 0) {
|
| - errno = EIO;
|
| - }
|
| + free_overlapped(poll_fd[_index].overlapped);
|
| poll_fd[_index] = INVALID_WINFD;
|
| LeaveCriticalSection(&_poll_fd[_index].mutex);
|
| }
|
| @@ -672,6 +651,7 @@ int usbi_close(int fd)
|
| ssize_t usbi_write(int fd, const void *buf, size_t count)
|
| {
|
| int _index;
|
| + UNUSED(buf);
|
|
|
| CHECK_INIT_POLLING;
|
|
|
| @@ -708,6 +688,7 @@ ssize_t usbi_read(int fd, void *buf, size_t count)
|
| {
|
| int _index;
|
| ssize_t r = -1;
|
| + UNUSED(buf);
|
|
|
| CHECK_INIT_POLLING;
|
|
|
|
|