diff options
Diffstat (limited to 'include/libusb-1.0/os/poll_windows.c')
-rw-r--r-- | include/libusb-1.0/os/poll_windows.c | 860 |
1 files changed, 0 insertions, 860 deletions
diff --git a/include/libusb-1.0/os/poll_windows.c b/include/libusb-1.0/os/poll_windows.c deleted file mode 100644 index 9ae9895..0000000 --- a/include/libusb-1.0/os/poll_windows.c +++ /dev/null @@ -1,860 +0,0 @@ -/* - * poll_windows: poll compatibility wrapper for Windows - * Copyright (C) 2009-2010 Pete Batard <pbatard@gmail.com> - * With contributions from Michael Plante, Orin Eman et al. - * Parts of poll implementation from libusb-win32, by Stephan Meyer et al. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -/* - * poll() and pipe() Windows compatibility layer for libusb 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. - * - * For USB pollable async I/O, you would typically: - * - obtain a Windows HANDLE to a file or device that has been opened in - * 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 - * pollable fds - * - leave the core functions call the poll routine and flag POLLIN/POLLOUT - * - * The pipe pollable synchronous I/O works using the overlapped event associated - * with a fake pipe. The read/write functions are only meant to be used in that - * context. - */ -#include <errno.h> -#include <fcntl.h> -#include <stdio.h> -#include <stdlib.h> -#include <io.h> - -#include <libusbi.h> - -// Uncomment to debug the polling layer -//#define DEBUG_POLL_WINDOWS -#if defined(DEBUG_POLL_WINDOWS) -#define poll_dbg usbi_dbg -#else -// MSVC6 cannot use a variadic argument and non MSVC -// compilers produce warnings if parenthesis are ommitted. -#if defined(_MSC_VER) -#define poll_dbg -#else -#define poll_dbg(...) -#endif -#endif - -#if defined(_PREFAST_) -#pragma warning(disable:28719) -#endif - -#if defined(__CYGWIN__) -// cygwin produces a warning unless these prototypes are defined -extern int _close(int fd); -extern int _snprintf(char *buffer, size_t count, const char *format, ...); -extern int cygwin_attach_handle_to_fd(char *name, int fd, HANDLE handle, int bin, int access_mode); -// _open_osfhandle() is not available on cygwin, but we can emulate -// it for our needs with cygwin_attach_handle_to_fd() -static inline int _open_osfhandle(intptr_t osfhandle, int flags) -{ - int access_mode; - switch (flags) { - case _O_RDONLY: - access_mode = GENERIC_READ; - break; - case _O_WRONLY: - access_mode = GENERIC_WRITE; - break; - case _O_RDWR: - access_mode = GENERIC_READ|GENERIC_WRITE; - break; - default: - usbi_err(NULL, "unsupported access mode"); - return -1; - } - return cygwin_attach_handle_to_fd("/dev/null", -1, (HANDLE)osfhandle, -1, access_mode); -} -#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}; -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]; - -// globals -BOOLEAN is_polling_set = FALSE; -#if defined(DYNAMIC_FDS) -HANDLE fd_update = INVALID_HANDLE_VALUE; // event to notify poll of fd update -HANDLE new_fd[MAX_FDS]; // overlapped event handles for fds created since last poll -unsigned nb_new_fds = 0; // nb new fds created since last poll -usbi_mutex_t new_fd_mutex; // mutex required for the above -#endif -LONG pipe_number = 0; -static volatile LONG compat_spinlock = 0; - -// 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) -__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 (CancelIoEx_Available) { - return (*pCancelIoEx)(poll_fd[index].handle, poll_fd[index].overlapped); - } - 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 -void init_polling(void) -{ - int i; - - while (InterlockedExchange((LONG *)&compat_spinlock, 1) == 1) { - SleepEx(0, TRUE); - } - if (!is_polling_set) { - pCancelIoEx = (BOOL (__stdcall *)(HANDLE,LPOVERLAPPED)) - GetProcAddress(GetModuleHandle("KERNEL32"), "CancelIoEx"); - usbi_dbg("Will use CancelIo%s for I/O cancellation", - CancelIoEx_Available?"Ex":""); - 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); - } -#if defined(DYNAMIC_FDS) - // We need to create an update event so that poll is warned when there - // are new/deleted fds during a timeout wait operation - fd_update = CreateEvent(NULL, TRUE, FALSE, NULL); - if (fd_update == NULL) { - usbi_err(NULL, "unable to create update event"); - } - usbi_mutex_init(&new_fd_mutex, NULL); - nb_new_fds = 0; -#endif - is_polling_set = TRUE; - } - compat_spinlock = 0; -} - -// Internal function to retrieve the table index (and lock the fd mutex) -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; -} - -OVERLAPPED *create_overlapped(void) -{ - OVERLAPPED *overlapped = calloc(1, sizeof(OVERLAPPED)); - if (overlapped == NULL) { - return NULL; - } - overlapped->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - if(overlapped->hEvent == NULL) { - free (overlapped); - return NULL; - } - return overlapped; -} - -void free_overlapped(OVERLAPPED *overlapped) -{ - if (overlapped == NULL) - return; - - if ( (overlapped->hEvent != 0) - && (overlapped->hEvent != INVALID_HANDLE_VALUE) ) { - CloseHandle(overlapped->hEvent); - } - 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; - - 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); - 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) { - // Close duplicate handle - if (_poll_fd[i].original_handle != INVALID_HANDLE_VALUE) { - CloseHandle(poll_fd[i].handle); - } - } - poll_fd[i] = INVALID_WINFD; -#if defined(DYNAMIC_FDS) - usbi_mutex_destroy(&new_fd_mutex); - CloseHandle(fd_update); - fd_update = INVALID_HANDLE_VALUE; -#endif - LeaveCriticalSection(&_poll_fd[i].mutex); - DeleteCriticalSection(&_poll_fd[i].mutex); - } - } - compat_spinlock = 0; -} - -/* - * Create a fake pipe. - * As libusb 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. - */ -int usbi_pipe(int filedes[2]) -{ - int i; - HANDLE handle; - OVERLAPPED* overlapped; - - CHECK_INIT_POLLING; - - overlapped = calloc(1, sizeof(OVERLAPPED)); - if (overlapped == NULL) { - return -1; - } - // The overlapped must have status pending for signaling to work in poll - overlapped->Internal = STATUS_PENDING; - overlapped->InternalHigh = 0; - - // Read end of the "pipe" - handle = CreateFileA("NUL", 0, 0, NULL, OPEN_EXISTING, 0, NULL); - if (handle == INVALID_HANDLE_VALUE) { - usbi_err(NULL, "could not create pipe: errcode %d", (int)GetLastError()); - goto out1; - } - filedes[0] = _open_osfhandle((intptr_t)handle, _O_RDONLY); - // 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); - // fd might have been allocated before we got to critical - if (poll_fd[i].fd >= 0) { - LeaveCriticalSection(&_poll_fd[i].mutex); - continue; - } - - poll_fd[i].fd = filedes[0]; - poll_fd[i].handle = 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; - } - } - - CloseHandle(overlapped->hEvent); -out2: - CloseHandle(handle); -out1: - free(overlapped); - return -1; -} - -/* - * Create both an fd and an OVERLAPPED from an open Windows handle, so that - * it can be used with our polling function - * The handle MUST support overlapped transfers (usually requires CreateFile - * with FILE_FLAG_OVERLAPPED) - * Return a pollable file descriptor struct, or INVALID_WINFD on error - * - * Note that the fd returned by this function is a per-transfer fd, rather - * than a per-session fd and cannot be used for anything else but our - * custom functions (the fd itself points to the NUL: device) - * if you plan to do R/W on the same handle, you MUST create 2 fds: one for - * 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) -{ - int i, fd; - struct winfd wfd = INVALID_WINFD; - OVERLAPPED* overlapped = NULL; - - CHECK_INIT_POLLING; - - if ((handle == 0) || (handle == INVALID_HANDLE_VALUE)) { - 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" - "If you want to poll for R/W simultaneously, create multiple fds from the same handle."); - return INVALID_WINFD; - } - if (access_mode == _O_RDONLY) { - wfd.rw = RW_READ; - } else { - wfd.rw = RW_WRITE; - } - - // Ensure that we get a non system conflicting unique fd - fd = _open_osfhandle((intptr_t)CreateFileA("NUL", 0, 0, - NULL, OPEN_EXISTING, 0, NULL), _O_RDWR); - if (fd < 0) { - return INVALID_WINFD; - } - - overlapped = create_overlapped(); - if(overlapped == NULL) { - _close(fd); - 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; - } - wfd.fd = fd; - // Attempt to emulate some of the CancelIoEx behaviour on platforms - // that don't have it - if (!CancelIoEx_Available) { - _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); -#if defined(DYNAMIC_FDS) - usbi_mutex_lock(&new_fd_mutex); - new_fd[nb_new_fds++] = overlapped->hEvent; - usbi_mutex_unlock(&new_fd_mutex); - // Notify poll that fds have been updated - SetEvent(fd_update); -#endif - return wfd; - } - } - free_overlapped(overlapped); - _close(fd); - return INVALID_WINFD; -} - -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 (_poll_fd[index].original_handle != INVALID_HANDLE_VALUE) { - CloseHandle(poll_fd[index].handle); - } - _poll_fd[index].original_handle = INVALID_HANDLE_VALUE; - _poll_fd[index].thread_id = 0; - } - free_overlapped(poll_fd[index].overlapped); - poll_fd[index] = INVALID_WINFD; -} - -/* - * Release a pollable file descriptor. - * - * Note that the associated Windows handle is not closed by this call - */ -void usbi_free_fd(int fd) -{ - int index; - - CHECK_INIT_POLLING; - - index = _fd_to_index_and_lock(fd); - if (index < 0) { - return; - } - _free_index(index); - 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; - } - } - return INVALID_WINFD; -} - -/* - * POSIX poll equivalent, using Windows OVERLAPPED - * Currently, this function only accepts one of POLLIN or POLLOUT per fd - * (but you can create multiple fds from the same handle for read and write) - */ -int usbi_poll(struct pollfd *fds, unsigned int nfds, int timeout) -{ - unsigned i; - int index, object_index, triggered; - HANDLE *handles_to_wait_on; - int *handle_to_index; - DWORD nb_handles_to_wait_on = 0; - DWORD ret; - -#if defined(DYNAMIC_FDS) - DWORD nb_extra_handles = 0; - unsigned j; - - // To address the possibility of missing new fds between the time the new - // pollable fd set is assembled, and the ResetEvent() call below, an - // additional new_fd[] HANDLE table is used for any new fd that was created - // since the last call to poll (see below) - ResetEvent(fd_update); - - // At this stage, any new fd creation will be detected through the fd_update - // event notification, and any previous creation that we may have missed - // will be picked up through the existing new_fd[] table. -#endif - - CHECK_INIT_POLLING; - - triggered = 0; - handles_to_wait_on = malloc((nfds+1)*sizeof(HANDLE)); // +1 for fd_update - handle_to_index = malloc(nfds*sizeof(int)); - if ((handles_to_wait_on == NULL) || (handle_to_index == NULL)) { - errno = ENOMEM; - triggered = -1; - goto poll_exit; - } - - for (i = 0; i < nfds; ++i) { - fds[i].revents = 0; - - // Only one of POLLIN or POLLOUT can be selected with this version of poll (not both) - if ((fds[i].events & ~POLLIN) && (!(fds[i].events & POLLOUT))) { - fds[i].revents |= POLLERR; - errno = EACCES; - usbi_warn(NULL, "unsupported set of events"); - 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 defined(DYNAMIC_FDS) - // If this fd from the poll set is also part of the new_fd event handle table, remove it - usbi_mutex_lock(&new_fd_mutex); - for (j=0; j<nb_new_fds; j++) { - if (handles_to_wait_on[nb_handles_to_wait_on] == new_fd[j]) { - new_fd[j] = INVALID_HANDLE_VALUE; - break; - } - } - usbi_mutex_unlock(&new_fd_mutex); -#endif - nb_handles_to_wait_on++; - } - LeaveCriticalSection(&_poll_fd[index].mutex); - } -#if defined(DYNAMIC_FDS) - // At this stage, new_fd[] should only contain events from fds that - // have been added since the last call to poll, but are not (yet) part - // of the pollable fd set. Typically, these would be from fds that have - // been created between the construction of the fd set and the calling - // of poll. - // Event if we won't be able to return usable poll data on these events, - // make sure we monitor them to return an EINTR code - usbi_mutex_lock(&new_fd_mutex); // We could probably do without - for (i=0; i<nb_new_fds; i++) { - if (new_fd[i] != INVALID_HANDLE_VALUE) { - handles_to_wait_on[nb_handles_to_wait_on++] = new_fd[i]; - nb_extra_handles++; - } - } - usbi_mutex_unlock(&new_fd_mutex); - poll_dbg("dynamic_fds: added %d extra handles", nb_extra_handles); -#endif - - // If nothing was triggered, wait on all fds that require it - if ((timeout != 0) && (triggered == 0) && (nb_handles_to_wait_on != 0)) { -#if defined(DYNAMIC_FDS) - // Register for fd update notifications - handles_to_wait_on[nb_handles_to_wait_on++] = fd_update; - nb_extra_handles++; -#endif - if (timeout < 0) { - poll_dbg("starting infinite wait for %d handles...", (int)nb_handles_to_wait_on); - } else { - poll_dbg("starting %d ms wait for %d handles...", timeout, (int)nb_handles_to_wait_on); - } - ret = WaitForMultipleObjects(nb_handles_to_wait_on, handles_to_wait_on, - FALSE, (timeout<0)?INFINITE:(DWORD)timeout); - object_index = ret-WAIT_OBJECT_0; - if ((object_index >= 0) && ((DWORD)object_index < nb_handles_to_wait_on)) { -#if defined(DYNAMIC_FDS) - if ((DWORD)object_index >= (nb_handles_to_wait_on-nb_extra_handles)) { - // Detected fd update => flag a poll interruption - if ((DWORD)object_index == (nb_handles_to_wait_on-1)) - poll_dbg(" dynamic_fds: fd_update event"); - else - poll_dbg(" dynamic_fds: new fd I/O event"); - errno = EINTR; - triggered = -1; - goto poll_exit; - } -#endif - 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; - triggered++; - if (index >= 0) { - LeaveCriticalSection(&_poll_fd[index].mutex); - } - } else if (ret == WAIT_TIMEOUT) { - poll_dbg(" timed out"); - triggered = 0; // 0 = timeout - } else { - errno = EIO; - triggered = -1; // error - } - } - -poll_exit: - if (handles_to_wait_on != NULL) { - free(handles_to_wait_on); - } - if (handle_to_index != NULL) { - free(handle_to_index); - } -#if defined(DYNAMIC_FDS) - usbi_mutex_lock(&new_fd_mutex); - nb_new_fds = 0; - usbi_mutex_unlock(&new_fd_mutex); -#endif - return triggered; -} - -/* - * close a fake pipe fd - */ -int usbi_close(int fd) -{ - int index; - int r = -1; - - CHECK_INIT_POLLING; - - index = _fd_to_index_and_lock(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); - } - if (CloseHandle(poll_fd[index].handle) == 0) { - errno = EIO; - } else { - r = 0; - } - poll_fd[index] = INVALID_WINFD; - LeaveCriticalSection(&_poll_fd[index].mutex); - } - return r; -} - -/* - * synchronous write for fake "pipe" signaling - */ -ssize_t usbi_write(int fd, const void *buf, size_t count) -{ - int index; - - 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) || (poll_fd[index].overlapped == NULL) ) { - errno = EBADF; - if (index >= 0) { - LeaveCriticalSection(&_poll_fd[index].mutex); - } - 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); -} - -/* - * synchronous read for fake "pipe" signaling - */ -ssize_t usbi_read(int fd, void *buf, size_t count) -{ - int index; - ssize_t r = -1; - - 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; - 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; -} |