| Index: third_party/libusb/libusb/os/poll_windows.c
|
| diff --git a/third_party/libusb/libusb/os/poll_windows.c b/third_party/libusb/libusb/os/poll_windows.c
|
| deleted file mode 100644
|
| index c997c819c7f28bd4608adb82c4225d9fc31c8602..0000000000000000000000000000000000000000
|
| --- a/third_party/libusb/libusb/os/poll_windows.c
|
| +++ /dev/null
|
| @@ -1,839 +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 _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};
|
| -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)
|
| -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 (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(GetModuleHandleA("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;
|
| - 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"
|
| - 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);
|
| - // 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 = DUMMY_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:
|
| - _close(filedes[0]);
|
| -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, 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;
|
| - }
|
| -
|
| - 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);
|
| - }
|
| - r = _close(poll_fd[_index].fd);
|
| - if (r != 0) {
|
| - errno = EIO;
|
| - }
|
| - 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;
|
| -}
|
|
|