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; |