From: Toby Gray Date: Tue, 15 Jan 2013 22:46:49 +0000 (+0000) Subject: Windows: Simplify poll_windows and add provisions for WinCE X-Git-Tag: upstream/1.0.21~557 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=790ffc78b008a03c95d10899f53997b504f55c72;p=platform%2Fupstream%2Flibusb.git Windows: Simplify poll_windows and add provisions for WinCE * Because poll_windows now requires struct usbi_transfer to be defined, it's inclusion in libusbi.h had to be moved down. --- diff --git a/libusb/libusbi.h b/libusb/libusbi.h index 725c611..39e4c79 100644 --- a/libusb/libusbi.h +++ b/libusb/libusbi.h @@ -192,32 +192,13 @@ static inline void usbi_dbg(const char *format, ...) #define IS_XFERIN(xfer) (0 != ((xfer)->endpoint & LIBUSB_ENDPOINT_IN)) #define IS_XFEROUT(xfer) (!IS_XFERIN(xfer)) -/* Internal abstractions for thread synchronization and poll */ +/* Internal abstraction for thread synchronization */ #if defined(THREADS_POSIX) #include "os/threads_posix.h" #elif defined(OS_WINDOWS) #include #endif -#if defined(OS_LINUX) || defined(OS_DARWIN) || defined(OS_OPENBSD) -#include -#include "os/poll_posix.h" -#elif defined(OS_WINDOWS) -#include -#endif - -#if defined(OS_WINDOWS) && !defined(__GCC__) -#undef HAVE_GETTIMEOFDAY -int usbi_gettimeofday(struct timeval *tp, void *tzp); -#define LIBUSB_GETTIMEOFDAY_WIN32 -#define HAVE_USBI_GETTIMEOFDAY -#else -#ifdef HAVE_GETTIMEOFDAY -#define usbi_gettimeofday(tv, tz) gettimeofday((tv), (tz)) -#define HAVE_USBI_GETTIMEOFDAY -#endif -#endif - extern struct libusb_context *usbi_default_context; struct libusb_context { @@ -407,7 +388,25 @@ int usbi_parse_descriptor(unsigned char *source, const char *descriptor, int usbi_get_config_index_by_value(struct libusb_device *dev, uint8_t bConfigurationValue, int *idx); -/* polling */ +/* Internal abstraction for poll (needs struct usbi_transfer on Windows) */ +#if defined(OS_LINUX) || defined(OS_DARWIN) || defined(OS_OPENBSD) +#include +#include "os/poll_posix.h" +#elif defined(OS_WINDOWS) || defined(OS_WINCE) +#include +#endif + +#if defined(OS_WINDOWS) && !defined(__GCC__) +#undef HAVE_GETTIMEOFDAY +int usbi_gettimeofday(struct timeval *tp, void *tzp); +#define LIBUSB_GETTIMEOFDAY_WIN32 +#define HAVE_USBI_GETTIMEOFDAY +#else +#ifdef HAVE_GETTIMEOFDAY +#define usbi_gettimeofday(tv, tz) gettimeofday((tv), (tz)) +#define HAVE_USBI_GETTIMEOFDAY +#endif +#endif struct usbi_pollfd { /* must come first */ diff --git a/libusb/os/poll_windows.c b/libusb/os/poll_windows.c index 4601a79..9ece711 100644 --- a/libusb/os/poll_windows.c +++ b/libusb/os/poll_windows.c @@ -31,7 +31,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,10 +40,8 @@ * context. */ #include -#include #include #include -#include #include @@ -65,20 +63,16 @@ #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" +#if defined(_WIN32_WCE) +#define usbi_sleep(ms) Sleep(ms) #else -#define NUL_DEVICE "NUL" +#define usbi_sleep(ms) SleepEx(ms, TRUE) #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 +87,22 @@ 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) +{ + pCancelIoEx = (BOOL (__stdcall *)(HANDLE,LPOVERLAPPED)) + GetProcAddress(GetModuleHandleA("KERNEL32"), "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 +112,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 +126,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) @@ -124,13 +157,10 @@ void init_polling(void) int i; while (InterlockedExchange((LONG *)&compat_spinlock, 1) == 1) { - SleepEx(0, TRUE); + usbi_sleep(0); } 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 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); @@ -253,7 +279,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 +288,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; ihEvent); -out2: - _close(filedes[0]); -out1: - free(overlapped); + free_overlapped(overlapped); return -1; } @@ -319,9 +331,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 +343,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 +370,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,7 +395,6 @@ struct winfd usbi_create_fd(HANDLE handle, int access_mode) } } free_overlapped(overlapped); - _close(fd); return INVALID_WINFD; } @@ -395,13 +402,8 @@ 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); } @@ -651,15 +653,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); } diff --git a/libusb/os/poll_windows.h b/libusb/os/poll_windows.h index e53af2d..32145fd 100644 --- a/libusb/os/poll_windows.h +++ b/libusb/os/poll_windows.h @@ -31,12 +31,17 @@ #define STATUS_REPARSE ((LONG)0x00000104L) #endif #define STATUS_COMPLETED_SYNCHRONOUSLY STATUS_REPARSE +#if defined(_WIN32_WCE) +// WinCE doesn't have a HasOverlappedIoCompleted() macro, so attempt to emulate it +#define HasOverlappedIoCompleted(lpOverlapped) (((DWORD)(lpOverlapped)->Internal) != STATUS_PENDING) +#endif #define HasOverlappedIoCompletedSync(lpOverlapped) (((DWORD)(lpOverlapped)->Internal) == STATUS_COMPLETED_SYNCHRONOUSLY) #define DUMMY_HANDLE ((HANDLE)(LONG_PTR)-2) enum windows_version { WINDOWS_UNSUPPORTED, + WINDOWS_CE, WINDOWS_XP, WINDOWS_2003, // also includes XP 64 WINDOWS_VISTA_AND_LATER, @@ -66,10 +71,14 @@ enum rw_type { }; // fd struct that can be used for polling on Windows +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) }; extern const struct winfd INVALID_WINFD; @@ -82,7 +91,8 @@ int usbi_close(int fd); void init_polling(void); void exit_polling(void); -struct winfd usbi_create_fd(HANDLE handle, int access_mode); +struct winfd usbi_create_fd(HANDLE handle, int access_mode, + struct usbi_transfer *transfer, cancel_transfer *cancel_fn); void usbi_free_fd(int fd); struct winfd fd_to_winfd(int fd); struct winfd handle_to_winfd(HANDLE handle); diff --git a/libusb/os/threads_windows.c b/libusb/os/threads_windows.c index 7c09e7d..393d498 100644 --- a/libusb/os/threads_windows.c +++ b/libusb/os/threads_windows.c @@ -25,6 +25,11 @@ #include "libusbi.h" +#if defined(_WIN32_WCE) +#define usbi_sleep(ms) Sleep(ms) +#else +#define usbi_sleep(ms) SleepEx(ms, TRUE) +#endif int usbi_mutex_init(usbi_mutex_t *mutex, const usbi_mutexattr_t *attr) { @@ -70,7 +75,7 @@ int usbi_mutex_unlock(usbi_mutex_t *mutex) { int usbi_mutex_static_lock(usbi_mutex_static_t *mutex) { if(!mutex) return ((errno=EINVAL)); while (InterlockedExchange((LONG *)mutex, 1) == 1) { - SleepEx(0, TRUE); + usbi_sleep(0); } return 0; } @@ -184,7 +189,13 @@ int usbi_cond_timedwait(usbi_cond_t *cond, DWORD millis; extern const uint64_t epoch_time; +#ifdef _WIN32_WCE + SYSTEMTIME st; + GetSystemTime(&st); + SystemTimeToFileTime(&st, &filetime); +#else GetSystemTimeAsFileTime(&filetime); +#endif rtime.LowPart = filetime.dwLowDateTime; rtime.HighPart = filetime.dwHighDateTime; rtime.QuadPart -= epoch_time; diff --git a/libusb/os/windows_usb.c b/libusb/os/windows_usb.c index 914461d..341f4ed 100644 --- a/libusb/os/windows_usb.c +++ b/libusb/os/windows_usb.c @@ -2862,7 +2862,7 @@ static int winusbx_submit_control_transfer(int sub_api, struct usbi_transfer *it usbi_dbg("will use interface %d", current_interface); winusb_handle = handle_priv->interface_handle[current_interface].api_handle; - wfd = usbi_create_fd(winusb_handle, _O_RDONLY); + 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) { return LIBUSB_ERROR_NO_MEM; @@ -2951,7 +2951,7 @@ static int winusbx_submit_bulk_transfer(int sub_api, struct usbi_transfer *itran winusb_handle = handle_priv->interface_handle[current_interface].api_handle; - wfd = usbi_create_fd(winusb_handle, IS_XFERIN(transfer) ? _O_RDONLY : _O_WRONLY); + 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) { return LIBUSB_ERROR_NO_MEM; @@ -3884,7 +3884,7 @@ static int hid_submit_control_transfer(int sub_api, struct usbi_transfer *itrans 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); + wfd = usbi_create_fd(hid_handle, RW_READ, NULL, NULL); if (wfd.fd < 0) { return LIBUSB_ERROR_NOT_FOUND; } @@ -3990,7 +3990,7 @@ static int hid_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer hid_handle = handle_priv->interface_handle[current_interface].api_handle; direction_in = transfer->endpoint & LIBUSB_ENDPOINT_IN; - wfd = usbi_create_fd(hid_handle, direction_in?_O_RDONLY:_O_WRONLY); + 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) { return LIBUSB_ERROR_NO_MEM; diff --git a/libusb/version_nano.h b/libusb/version_nano.h index 71078a1..40e8a76 100644 --- a/libusb/version_nano.h +++ b/libusb/version_nano.h @@ -1 +1 @@ -#define LIBUSB_NANO 10594 +#define LIBUSB_NANO 10595