| OLD | NEW |
| 1 /* | 1 /* |
| 2 * poll_windows: poll compatibility wrapper for Windows | 2 * poll_windows: poll compatibility wrapper for Windows |
| 3 * Copyright (C) 2009-2010 Pete Batard <pbatard@gmail.com> | 3 * Copyright © 2012-2013 RealVNC Ltd. |
| 4 * Copyright © 2009-2010 Pete Batard <pete@akeo.ie> |
| 4 * With contributions from Michael Plante, Orin Eman et al. | 5 * With contributions from Michael Plante, Orin Eman et al. |
| 5 * Parts of poll implementation from libusb-win32, by Stephan Meyer et al. | 6 * Parts of poll implementation from libusb-win32, by Stephan Meyer et al. |
| 6 * | 7 * |
| 7 * This library is free software; you can redistribute it and/or | 8 * This library is free software; you can redistribute it and/or |
| 8 * modify it under the terms of the GNU Lesser General Public | 9 * modify it under the terms of the GNU Lesser General Public |
| 9 * License as published by the Free Software Foundation; either | 10 * License as published by the Free Software Foundation; either |
| 10 * version 2.1 of the License, or (at your option) any later version. | 11 * version 2.1 of the License, or (at your option) any later version. |
| 11 * | 12 * |
| 12 * This library is distributed in the hope that it will be useful, | 13 * This library is distributed in the hope that it will be useful, |
| 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 15 * Lesser General Public License for more details. | 16 * Lesser General Public License for more details. |
| 16 * | 17 * |
| 17 * You should have received a copy of the GNU Lesser General Public | 18 * You should have received a copy of the GNU Lesser General Public |
| 18 * License along with this library; if not, write to the Free Software | 19 * License along with this library; if not, write to the Free Software |
| 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| 20 * | 21 * |
| 21 */ | 22 */ |
| 22 | 23 |
| 23 /* | 24 /* |
| 24 * poll() and pipe() Windows compatibility layer for libusb 1.0 | 25 * poll() and pipe() Windows compatibility layer for libusbx 1.0 |
| 25 * | 26 * |
| 26 * The way this layer works is by using OVERLAPPED with async I/O transfers, as | 27 * The way this layer works is by using OVERLAPPED with async I/O transfers, as |
| 27 * OVERLAPPED have an associated event which is flagged for I/O completion. | 28 * OVERLAPPED have an associated event which is flagged for I/O completion. |
| 28 * | 29 * |
| 29 * For USB pollable async I/O, you would typically: | 30 * For USB pollable async I/O, you would typically: |
| 30 * - obtain a Windows HANDLE to a file or device that has been opened in | 31 * - obtain a Windows HANDLE to a file or device that has been opened in |
| 31 * OVERLAPPED mode | 32 * OVERLAPPED mode |
| 32 * - call usbi_create_fd with this handle to obtain a custom fd. | 33 * - call usbi_create_fd with this handle to obtain a custom fd. |
| 33 * Note that if you need simultaneous R/W access, you need to call create_fd | 34 * Note that if you need simultaneous R/W access, you need to call create_fd |
| 34 * twice, once in _O_RDONLY and once in _O_WRONLY mode to obtain 2 separate | 35 * twice, once in RW_READ and once in RW_WRITE mode to obtain 2 separate |
| 35 * pollable fds | 36 * pollable fds |
| 36 * - leave the core functions call the poll routine and flag POLLIN/POLLOUT | 37 * - leave the core functions call the poll routine and flag POLLIN/POLLOUT |
| 37 * | 38 * |
| 38 * The pipe pollable synchronous I/O works using the overlapped event associated | 39 * The pipe pollable synchronous I/O works using the overlapped event associated |
| 39 * with a fake pipe. The read/write functions are only meant to be used in that | 40 * with a fake pipe. The read/write functions are only meant to be used in that |
| 40 * context. | 41 * context. |
| 41 */ | 42 */ |
| 42 #include <errno.h> | 43 #include <errno.h> |
| 43 #include <fcntl.h> | |
| 44 #include <stdio.h> | 44 #include <stdio.h> |
| 45 #include <stdlib.h> | 45 #include <stdlib.h> |
| 46 #include <io.h> | |
| 47 | 46 |
| 48 #include <libusbi.h> | 47 #include "libusbi.h" |
| 49 | 48 |
| 50 // Uncomment to debug the polling layer | 49 // Uncomment to debug the polling layer |
| 51 //#define DEBUG_POLL_WINDOWS | 50 //#define DEBUG_POLL_WINDOWS |
| 52 #if defined(DEBUG_POLL_WINDOWS) | 51 #if defined(DEBUG_POLL_WINDOWS) |
| 53 #define poll_dbg usbi_dbg | 52 #define poll_dbg usbi_dbg |
| 54 #else | 53 #else |
| 55 // MSVC++ < 2005 cannot use a variadic argument and non MSVC | 54 // MSVC++ < 2005 cannot use a variadic argument and non MSVC |
| 56 // compilers produce warnings if parenthesis are omitted. | 55 // compilers produce warnings if parenthesis are ommitted. |
| 57 #if defined(_MSC_VER) && _MSC_VER < 1400 | 56 #if defined(_MSC_VER) && (_MSC_VER < 1400) |
| 58 #define poll_dbg | 57 #define poll_dbg |
| 59 #else | 58 #else |
| 60 #define poll_dbg(...) | 59 #define poll_dbg(...) |
| 61 #endif | 60 #endif |
| 62 #endif | 61 #endif |
| 63 | 62 |
| 64 #if defined(_PREFAST_) | 63 #if defined(_PREFAST_) |
| 65 #pragma warning(disable:28719) | 64 #pragma warning(disable:28719) |
| 66 #endif | 65 #endif |
| 67 | 66 |
| 68 #if defined(__CYGWIN__) | |
| 69 // cygwin produces a warning unless these prototypes are defined | |
| 70 extern int _open(char* name, int flags); | |
| 71 extern int _close(int fd); | |
| 72 extern int _snprintf(char *buffer, size_t count, const char *format, ...); | |
| 73 #define NUL_DEVICE "/dev/null" | |
| 74 #else | |
| 75 #define NUL_DEVICE "NUL" | |
| 76 #endif | |
| 77 | |
| 78 #define CHECK_INIT_POLLING do {if(!is_polling_set) init_polling();} while(0) | 67 #define CHECK_INIT_POLLING do {if(!is_polling_set) init_polling();} while(0) |
| 79 | 68 |
| 80 // public fd data | 69 // public fd data |
| 81 const struct winfd INVALID_WINFD = {-1, INVALID_HANDLE_VALUE, NULL, RW_NONE}; | 70 const struct winfd INVALID_WINFD = {-1, INVALID_HANDLE_VALUE, NULL, NULL, NULL,
RW_NONE}; |
| 82 struct winfd poll_fd[MAX_FDS]; | 71 struct winfd poll_fd[MAX_FDS]; |
| 83 // internal fd data | 72 // internal fd data |
| 84 struct { | 73 struct { |
| 85 CRITICAL_SECTION mutex; // lock for fds | 74 CRITICAL_SECTION mutex; // lock for fds |
| 86 // Additional variables for XP CancelIoEx partial emulation | 75 // Additional variables for XP CancelIoEx partial emulation |
| 87 HANDLE original_handle; | 76 HANDLE original_handle; |
| 88 DWORD thread_id; | 77 DWORD thread_id; |
| 89 } _poll_fd[MAX_FDS]; | 78 } _poll_fd[MAX_FDS]; |
| 90 | 79 |
| 91 // globals | 80 // globals |
| 92 BOOLEAN is_polling_set = FALSE; | 81 BOOLEAN is_polling_set = FALSE; |
| 93 LONG pipe_number = 0; | 82 LONG pipe_number = 0; |
| 94 static volatile LONG compat_spinlock = 0; | 83 static volatile LONG compat_spinlock = 0; |
| 95 | 84 |
| 85 #if !defined(_WIN32_WCE) |
| 96 // CancelIoEx, available on Vista and later only, provides the ability to cancel | 86 // CancelIoEx, available on Vista and later only, provides the ability to cancel |
| 97 // a single transfer (OVERLAPPED) when used. As it may not be part of any of the | 87 // a single transfer (OVERLAPPED) when used. As it may not be part of any of the |
| 98 // platform headers, we hook into the Kernel32 system DLL directly to seek it. | 88 // platform headers, we hook into the Kernel32 system DLL directly to seek it. |
| 99 static BOOL (__stdcall *pCancelIoEx)(HANDLE, LPOVERLAPPED) = NULL; | 89 static BOOL (__stdcall *pCancelIoEx)(HANDLE, LPOVERLAPPED) = NULL; |
| 100 #define CancelIoEx_Available (pCancelIoEx != NULL) | 90 #define Use_Duplicate_Handles (pCancelIoEx == NULL) |
| 101 static __inline BOOL cancel_io(int _index) | 91 |
| 92 static inline void setup_cancel_io(void) |
| 93 { |
| 94 » HMODULE hKernel32 = GetModuleHandleA("KERNEL32"); |
| 95 » if (hKernel32 != NULL) { |
| 96 » » pCancelIoEx = (BOOL (__stdcall *)(HANDLE,LPOVERLAPPED)) |
| 97 » » » GetProcAddress(hKernel32, "CancelIoEx"); |
| 98 » } |
| 99 » usbi_dbg("Will use CancelIo%s for I/O cancellation", |
| 100 » » Use_Duplicate_Handles?"":"Ex"); |
| 101 } |
| 102 |
| 103 static inline BOOL cancel_io(int _index) |
| 102 { | 104 { |
| 103 if ((_index < 0) || (_index >= MAX_FDS)) { | 105 if ((_index < 0) || (_index >= MAX_FDS)) { |
| 104 return FALSE; | 106 return FALSE; |
| 105 } | 107 } |
| 106 | 108 |
| 107 if ( (poll_fd[_index].fd < 0) || (poll_fd[_index].handle == INVALID_HAND
LE_VALUE) | 109 if ( (poll_fd[_index].fd < 0) || (poll_fd[_index].handle == INVALID_HAND
LE_VALUE) |
| 108 || (poll_fd[_index].handle == 0) || (poll_fd[_index].overlapped == NUL
L) ) { | 110 || (poll_fd[_index].handle == 0) || (poll_fd[_index].overlapped == NUL
L) ) { |
| 109 return TRUE; | 111 return TRUE; |
| 110 } | 112 } |
| 111 » if (CancelIoEx_Available) { | 113 » if (poll_fd[_index].itransfer && poll_fd[_index].cancel_fn) { |
| 114 » » // Cancel outstanding transfer via the specific callback |
| 115 » » (*poll_fd[_index].cancel_fn)(poll_fd[_index].itransfer); |
| 116 » » return TRUE; |
| 117 » } |
| 118 » if (pCancelIoEx != NULL) { |
| 112 return (*pCancelIoEx)(poll_fd[_index].handle, poll_fd[_index].ov
erlapped); | 119 return (*pCancelIoEx)(poll_fd[_index].handle, poll_fd[_index].ov
erlapped); |
| 113 } | 120 } |
| 114 if (_poll_fd[_index].thread_id == GetCurrentThreadId()) { | 121 if (_poll_fd[_index].thread_id == GetCurrentThreadId()) { |
| 115 return CancelIo(poll_fd[_index].handle); | 122 return CancelIo(poll_fd[_index].handle); |
| 116 } | 123 } |
| 117 usbi_warn(NULL, "Unable to cancel I/O that was started from another thre
ad"); | 124 usbi_warn(NULL, "Unable to cancel I/O that was started from another thre
ad"); |
| 118 return FALSE; | 125 return FALSE; |
| 119 } | 126 } |
| 127 #else |
| 128 #define Use_Duplicate_Handles FALSE |
| 129 |
| 130 static __inline void setup_cancel_io() |
| 131 { |
| 132 // No setup needed on WinCE |
| 133 } |
| 134 |
| 135 static __inline BOOL cancel_io(int _index) |
| 136 { |
| 137 if ((_index < 0) || (_index >= MAX_FDS)) { |
| 138 return FALSE; |
| 139 } |
| 140 if ( (poll_fd[_index].fd < 0) || (poll_fd[_index].handle == INVALID_HAND
LE_VALUE) |
| 141 || (poll_fd[_index].handle == 0) || (poll_fd[_index].overlapped == NUL
L) ) { |
| 142 return TRUE; |
| 143 } |
| 144 if (poll_fd[_index].itransfer && poll_fd[_index].cancel_fn) { |
| 145 // Cancel outstanding transfer via the specific callback |
| 146 (*poll_fd[_index].cancel_fn)(poll_fd[_index].itransfer); |
| 147 } |
| 148 return TRUE; |
| 149 } |
| 150 #endif |
| 120 | 151 |
| 121 // Init | 152 // Init |
| 122 void init_polling(void) | 153 void init_polling(void) |
| 123 { | 154 { |
| 124 int i; | 155 int i; |
| 125 | 156 |
| 126 while (InterlockedExchange((LONG *)&compat_spinlock, 1) == 1) { | 157 while (InterlockedExchange((LONG *)&compat_spinlock, 1) == 1) { |
| 127 SleepEx(0, TRUE); | 158 SleepEx(0, TRUE); |
| 128 } | 159 } |
| 129 if (!is_polling_set) { | 160 if (!is_polling_set) { |
| 130 » » pCancelIoEx = (BOOL (__stdcall *)(HANDLE,LPOVERLAPPED)) | 161 » » setup_cancel_io(); |
| 131 » » » GetProcAddress(GetModuleHandleA("KERNEL32"), "CancelIoEx
"); | |
| 132 » » usbi_dbg("Will use CancelIo%s for I/O cancellation", | |
| 133 » » » CancelIoEx_Available?"Ex":""); | |
| 134 for (i=0; i<MAX_FDS; i++) { | 162 for (i=0; i<MAX_FDS; i++) { |
| 135 poll_fd[i] = INVALID_WINFD; | 163 poll_fd[i] = INVALID_WINFD; |
| 136 _poll_fd[i].original_handle = INVALID_HANDLE_VALUE; | 164 _poll_fd[i].original_handle = INVALID_HANDLE_VALUE; |
| 137 _poll_fd[i].thread_id = 0; | 165 _poll_fd[i].thread_id = 0; |
| 138 InitializeCriticalSection(&_poll_fd[i].mutex); | 166 InitializeCriticalSection(&_poll_fd[i].mutex); |
| 139 } | 167 } |
| 140 is_polling_set = TRUE; | 168 is_polling_set = TRUE; |
| 141 } | 169 } |
| 142 » compat_spinlock = 0; | 170 » InterlockedExchange((LONG *)&compat_spinlock, 0); |
| 143 } | 171 } |
| 144 | 172 |
| 145 // Internal function to retrieve the table index (and lock the fd mutex) | 173 // Internal function to retrieve the table index (and lock the fd mutex) |
| 146 int _fd_to_index_and_lock(int fd) | 174 static int _fd_to_index_and_lock(int fd) |
| 147 { | 175 { |
| 148 int i; | 176 int i; |
| 149 | 177 |
| 150 » if (fd <= 0) | 178 » if (fd < 0) |
| 151 return -1; | 179 return -1; |
| 152 | 180 |
| 153 for (i=0; i<MAX_FDS; i++) { | 181 for (i=0; i<MAX_FDS; i++) { |
| 154 if (poll_fd[i].fd == fd) { | 182 if (poll_fd[i].fd == fd) { |
| 155 EnterCriticalSection(&_poll_fd[i].mutex); | 183 EnterCriticalSection(&_poll_fd[i].mutex); |
| 156 // fd might have changed before we got to critical | 184 // fd might have changed before we got to critical |
| 157 if (poll_fd[i].fd != fd) { | 185 if (poll_fd[i].fd != fd) { |
| 158 LeaveCriticalSection(&_poll_fd[i].mutex); | 186 LeaveCriticalSection(&_poll_fd[i].mutex); |
| 159 continue; | 187 continue; |
| 160 } | 188 } |
| 161 return i; | 189 return i; |
| 162 } | 190 } |
| 163 } | 191 } |
| 164 return -1; | 192 return -1; |
| 165 } | 193 } |
| 166 | 194 |
| 167 OVERLAPPED *create_overlapped(void) | 195 static OVERLAPPED *create_overlapped(void) |
| 168 { | 196 { |
| 169 OVERLAPPED *overlapped = (OVERLAPPED*) calloc(1, sizeof(OVERLAPPED)); | 197 OVERLAPPED *overlapped = (OVERLAPPED*) calloc(1, sizeof(OVERLAPPED)); |
| 170 if (overlapped == NULL) { | 198 if (overlapped == NULL) { |
| 171 return NULL; | 199 return NULL; |
| 172 } | 200 } |
| 173 overlapped->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); | 201 overlapped->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); |
| 174 if(overlapped->hEvent == NULL) { | 202 if(overlapped->hEvent == NULL) { |
| 175 free (overlapped); | 203 free (overlapped); |
| 176 return NULL; | 204 return NULL; |
| 177 } | 205 } |
| 178 return overlapped; | 206 return overlapped; |
| 179 } | 207 } |
| 180 | 208 |
| 181 void free_overlapped(OVERLAPPED *overlapped) | 209 static void free_overlapped(OVERLAPPED *overlapped) |
| 182 { | 210 { |
| 183 if (overlapped == NULL) | 211 if (overlapped == NULL) |
| 184 return; | 212 return; |
| 185 | 213 |
| 186 if ( (overlapped->hEvent != 0) | 214 if ( (overlapped->hEvent != 0) |
| 187 && (overlapped->hEvent != INVALID_HANDLE_VALUE) ) { | 215 && (overlapped->hEvent != INVALID_HANDLE_VALUE) ) { |
| 188 CloseHandle(overlapped->hEvent); | 216 CloseHandle(overlapped->hEvent); |
| 189 } | 217 } |
| 190 free(overlapped); | 218 free(overlapped); |
| 191 } | 219 } |
| 192 | 220 |
| 193 void reset_overlapped(OVERLAPPED *overlapped) | |
| 194 { | |
| 195 HANDLE event_handle; | |
| 196 if (overlapped == NULL) | |
| 197 return; | |
| 198 | |
| 199 event_handle = overlapped->hEvent; | |
| 200 if (event_handle != NULL) { | |
| 201 ResetEvent(event_handle); | |
| 202 } | |
| 203 memset(overlapped, 0, sizeof(OVERLAPPED)); | |
| 204 overlapped->hEvent = event_handle; | |
| 205 } | |
| 206 | |
| 207 void exit_polling(void) | 221 void exit_polling(void) |
| 208 { | 222 { |
| 209 int i; | 223 int i; |
| 210 | 224 |
| 211 while (InterlockedExchange((LONG *)&compat_spinlock, 1) == 1) { | 225 while (InterlockedExchange((LONG *)&compat_spinlock, 1) == 1) { |
| 212 SleepEx(0, TRUE); | 226 SleepEx(0, TRUE); |
| 213 } | 227 } |
| 214 if (is_polling_set) { | 228 if (is_polling_set) { |
| 215 is_polling_set = FALSE; | 229 is_polling_set = FALSE; |
| 216 | 230 |
| 217 for (i=0; i<MAX_FDS; i++) { | 231 for (i=0; i<MAX_FDS; i++) { |
| 218 // Cancel any async I/O (handle can be invalid) | 232 // Cancel any async I/O (handle can be invalid) |
| 219 cancel_io(i); | 233 cancel_io(i); |
| 220 // If anything was pending on that I/O, it should be | 234 // If anything was pending on that I/O, it should be |
| 221 // terminating, and we should be able to access the fd | 235 // terminating, and we should be able to access the fd |
| 222 // mutex lock before too long | 236 // mutex lock before too long |
| 223 EnterCriticalSection(&_poll_fd[i].mutex); | 237 EnterCriticalSection(&_poll_fd[i].mutex); |
| 224 if ( (poll_fd[i].fd > 0) && (poll_fd[i].handle != INVALI
D_HANDLE_VALUE) && (poll_fd[i].handle != 0) | |
| 225 && (GetFileType(poll_fd[i].handle) == FILE_TYPE_UNKNOW
N) ) { | |
| 226 _close(poll_fd[i].fd); | |
| 227 } | |
| 228 free_overlapped(poll_fd[i].overlapped); | 238 free_overlapped(poll_fd[i].overlapped); |
| 229 » » » if (!CancelIoEx_Available) { | 239 » » » if (Use_Duplicate_Handles) { |
| 230 // Close duplicate handle | 240 // Close duplicate handle |
| 231 if (_poll_fd[i].original_handle != INVALID_HANDL
E_VALUE) { | 241 if (_poll_fd[i].original_handle != INVALID_HANDL
E_VALUE) { |
| 232 CloseHandle(poll_fd[i].handle); | 242 CloseHandle(poll_fd[i].handle); |
| 233 } | 243 } |
| 234 } | 244 } |
| 235 poll_fd[i] = INVALID_WINFD; | 245 poll_fd[i] = INVALID_WINFD; |
| 236 LeaveCriticalSection(&_poll_fd[i].mutex); | 246 LeaveCriticalSection(&_poll_fd[i].mutex); |
| 237 DeleteCriticalSection(&_poll_fd[i].mutex); | 247 DeleteCriticalSection(&_poll_fd[i].mutex); |
| 238 } | 248 } |
| 239 } | 249 } |
| 240 » compat_spinlock = 0; | 250 » InterlockedExchange((LONG *)&compat_spinlock, 0); |
| 241 } | 251 } |
| 242 | 252 |
| 243 /* | 253 /* |
| 244 * Create a fake pipe. | 254 * Create a fake pipe. |
| 245 * As libusb only uses pipes for signaling, all we need from a pipe is an | 255 * As libusbx only uses pipes for signaling, all we need from a pipe is an |
| 246 * event. To that extent, we create a single wfd and overlapped as a means | 256 * event. To that extent, we create a single wfd and overlapped as a means |
| 247 * to access that event. | 257 * to access that event. |
| 248 */ | 258 */ |
| 249 int usbi_pipe(int filedes[2]) | 259 int usbi_pipe(int filedes[2]) |
| 250 { | 260 { |
| 251 int i; | 261 int i; |
| 252 OVERLAPPED* overlapped; | 262 OVERLAPPED* overlapped; |
| 253 | 263 |
| 254 CHECK_INIT_POLLING; | 264 CHECK_INIT_POLLING; |
| 255 | 265 |
| 256 » overlapped = (OVERLAPPED*) calloc(1, sizeof(OVERLAPPED)); | 266 » overlapped = create_overlapped(); |
| 267 |
| 257 if (overlapped == NULL) { | 268 if (overlapped == NULL) { |
| 258 return -1; | 269 return -1; |
| 259 } | 270 } |
| 260 // The overlapped must have status pending for signaling to work in poll | 271 // The overlapped must have status pending for signaling to work in poll |
| 261 overlapped->Internal = STATUS_PENDING; | 272 overlapped->Internal = STATUS_PENDING; |
| 262 overlapped->InternalHigh = 0; | 273 overlapped->InternalHigh = 0; |
| 263 | 274 |
| 264 // Read end of the "pipe" | |
| 265 filedes[0] = _open(NUL_DEVICE, _O_WRONLY); | |
| 266 if (filedes[0] < 0) { | |
| 267 usbi_err(NULL, "could not create pipe: errno %d", errno); | |
| 268 goto out1; | |
| 269 } | |
| 270 // We can use the same handle for both ends | |
| 271 filedes[1] = filedes[0]; | |
| 272 poll_dbg("pipe filedes = %d", filedes[0]); | |
| 273 | |
| 274 // Note: manual reset must be true (second param) as the reset occurs in
read | |
| 275 overlapped->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); | |
| 276 if(!overlapped->hEvent) { | |
| 277 goto out2; | |
| 278 } | |
| 279 | |
| 280 for (i=0; i<MAX_FDS; i++) { | 275 for (i=0; i<MAX_FDS; i++) { |
| 281 if (poll_fd[i].fd < 0) { | 276 if (poll_fd[i].fd < 0) { |
| 282 EnterCriticalSection(&_poll_fd[i].mutex); | 277 EnterCriticalSection(&_poll_fd[i].mutex); |
| 283 // fd might have been allocated before we got to critica
l | 278 // fd might have been allocated before we got to critica
l |
| 284 if (poll_fd[i].fd >= 0) { | 279 if (poll_fd[i].fd >= 0) { |
| 285 LeaveCriticalSection(&_poll_fd[i].mutex); | 280 LeaveCriticalSection(&_poll_fd[i].mutex); |
| 286 continue; | 281 continue; |
| 287 } | 282 } |
| 288 | 283 |
| 289 » » » poll_fd[i].fd = filedes[0]; | 284 » » » // Use index as the unique fd number |
| 285 » » » poll_fd[i].fd = i; |
| 286 » » » // Read end of the "pipe" |
| 287 » » » filedes[0] = poll_fd[i].fd; |
| 288 » » » // We can use the same handle for both ends |
| 289 » » » filedes[1] = filedes[0]; |
| 290 |
| 290 poll_fd[i].handle = DUMMY_HANDLE; | 291 poll_fd[i].handle = DUMMY_HANDLE; |
| 291 poll_fd[i].overlapped = overlapped; | 292 poll_fd[i].overlapped = overlapped; |
| 292 // There's no polling on the write end, so we just use R
EAD for our needs | 293 // There's no polling on the write end, so we just use R
EAD for our needs |
| 293 poll_fd[i].rw = RW_READ; | 294 poll_fd[i].rw = RW_READ; |
| 294 _poll_fd[i].original_handle = INVALID_HANDLE_VALUE; | 295 _poll_fd[i].original_handle = INVALID_HANDLE_VALUE; |
| 295 LeaveCriticalSection(&_poll_fd[i].mutex); | 296 LeaveCriticalSection(&_poll_fd[i].mutex); |
| 296 return 0; | 297 return 0; |
| 297 } | 298 } |
| 298 } | 299 } |
| 299 | 300 » free_overlapped(overlapped); |
| 300 » CloseHandle(overlapped->hEvent); | |
| 301 out2: | |
| 302 » _close(filedes[0]); | |
| 303 out1: | |
| 304 » free(overlapped); | |
| 305 return -1; | 301 return -1; |
| 306 } | 302 } |
| 307 | 303 |
| 308 /* | 304 /* |
| 309 * Create both an fd and an OVERLAPPED from an open Windows handle, so that | 305 * Create both an fd and an OVERLAPPED from an open Windows handle, so that |
| 310 * it can be used with our polling function | 306 * it can be used with our polling function |
| 311 * The handle MUST support overlapped transfers (usually requires CreateFile | 307 * The handle MUST support overlapped transfers (usually requires CreateFile |
| 312 * with FILE_FLAG_OVERLAPPED) | 308 * with FILE_FLAG_OVERLAPPED) |
| 313 * Return a pollable file descriptor struct, or INVALID_WINFD on error | 309 * Return a pollable file descriptor struct, or INVALID_WINFD on error |
| 314 * | 310 * |
| 315 * Note that the fd returned by this function is a per-transfer fd, rather | 311 * Note that the fd returned by this function is a per-transfer fd, rather |
| 316 * than a per-session fd and cannot be used for anything else but our | 312 * than a per-session fd and cannot be used for anything else but our |
| 317 * custom functions (the fd itself points to the NUL: device) | 313 * custom functions (the fd itself points to the NUL: device) |
| 318 * if you plan to do R/W on the same handle, you MUST create 2 fds: one for | 314 * if you plan to do R/W on the same handle, you MUST create 2 fds: one for |
| 319 * read and one for write. Using a single R/W fd is unsupported and will | 315 * read and one for write. Using a single R/W fd is unsupported and will |
| 320 * produce unexpected results | 316 * produce unexpected results |
| 321 */ | 317 */ |
| 322 struct winfd usbi_create_fd(HANDLE handle, int access_mode) | 318 struct winfd usbi_create_fd(HANDLE handle, int access_mode, struct usbi_transfer
*itransfer, cancel_transfer *cancel_fn) |
| 323 { | 319 { |
| 324 » int i, fd; | 320 » int i; |
| 325 struct winfd wfd = INVALID_WINFD; | 321 struct winfd wfd = INVALID_WINFD; |
| 326 OVERLAPPED* overlapped = NULL; | 322 OVERLAPPED* overlapped = NULL; |
| 327 | 323 |
| 328 CHECK_INIT_POLLING; | 324 CHECK_INIT_POLLING; |
| 329 | 325 |
| 330 if ((handle == 0) || (handle == INVALID_HANDLE_VALUE)) { | 326 if ((handle == 0) || (handle == INVALID_HANDLE_VALUE)) { |
| 331 return INVALID_WINFD; | 327 return INVALID_WINFD; |
| 332 } | 328 } |
| 333 | 329 |
| 334 » if ((access_mode != _O_RDONLY) && (access_mode != _O_WRONLY)) { | 330 » wfd.itransfer = itransfer; |
| 335 » » usbi_warn(NULL, "only one of _O_RDONLY or _O_WRONLY are supporte
d.\n" | 331 » wfd.cancel_fn = cancel_fn; |
| 332 |
| 333 » if ((access_mode != RW_READ) && (access_mode != RW_WRITE)) { |
| 334 » » usbi_warn(NULL, "only one of RW_READ or RW_WRITE are supported.\
n" |
| 336 "If you want to poll for R/W simultaneously, create mult
iple fds from the same handle."); | 335 "If you want to poll for R/W simultaneously, create mult
iple fds from the same handle."); |
| 337 return INVALID_WINFD; | 336 return INVALID_WINFD; |
| 338 } | 337 } |
| 339 » if (access_mode == _O_RDONLY) { | 338 » if (access_mode == RW_READ) { |
| 340 wfd.rw = RW_READ; | 339 wfd.rw = RW_READ; |
| 341 } else { | 340 } else { |
| 342 wfd.rw = RW_WRITE; | 341 wfd.rw = RW_WRITE; |
| 343 } | 342 } |
| 344 | 343 |
| 345 » // Ensure that we get a non system conflicting unique fd, using | 344 » overlapped = create_overlapped(); |
| 346 » // the same fd attribution system as the pipe ends | 345 » if(overlapped == NULL) { |
| 347 » fd = _open(NUL_DEVICE, _O_WRONLY); | |
| 348 » if (fd < 0) { | |
| 349 return INVALID_WINFD; | 346 return INVALID_WINFD; |
| 350 } | 347 } |
| 351 | 348 |
| 352 overlapped = create_overlapped(); | |
| 353 if(overlapped == NULL) { | |
| 354 _close(fd); | |
| 355 return INVALID_WINFD; | |
| 356 } | |
| 357 | |
| 358 for (i=0; i<MAX_FDS; i++) { | 349 for (i=0; i<MAX_FDS; i++) { |
| 359 if (poll_fd[i].fd < 0) { | 350 if (poll_fd[i].fd < 0) { |
| 360 EnterCriticalSection(&_poll_fd[i].mutex); | 351 EnterCriticalSection(&_poll_fd[i].mutex); |
| 361 // fd might have been removed before we got to critical | 352 // fd might have been removed before we got to critical |
| 362 if (poll_fd[i].fd >= 0) { | 353 if (poll_fd[i].fd >= 0) { |
| 363 LeaveCriticalSection(&_poll_fd[i].mutex); | 354 LeaveCriticalSection(&_poll_fd[i].mutex); |
| 364 continue; | 355 continue; |
| 365 } | 356 } |
| 366 » » » wfd.fd = fd; | 357 » » » // Use index as the unique fd number |
| 358 » » » wfd.fd = i; |
| 367 // Attempt to emulate some of the CancelIoEx behaviour o
n platforms | 359 // Attempt to emulate some of the CancelIoEx behaviour o
n platforms |
| 368 // that don't have it | 360 // that don't have it |
| 369 » » » if (!CancelIoEx_Available) { | 361 » » » if (Use_Duplicate_Handles) { |
| 370 _poll_fd[i].thread_id = GetCurrentThreadId(); | 362 _poll_fd[i].thread_id = GetCurrentThreadId(); |
| 371 if (!DuplicateHandle(GetCurrentProcess(), handle
, GetCurrentProcess(), | 363 if (!DuplicateHandle(GetCurrentProcess(), handle
, GetCurrentProcess(), |
| 372 &wfd.handle, 0, TRUE, DUPLICATE_SAME_ACC
ESS)) { | 364 &wfd.handle, 0, TRUE, DUPLICATE_SAME_ACC
ESS)) { |
| 373 usbi_dbg("could not duplicate handle for
CancelIo - using original one"); | 365 usbi_dbg("could not duplicate handle for
CancelIo - using original one"); |
| 374 wfd.handle = handle; | 366 wfd.handle = handle; |
| 375 // Make sure we won't close the original
handle on fd deletion then | 367 // Make sure we won't close the original
handle on fd deletion then |
| 376 _poll_fd[i].original_handle = INVALID_HA
NDLE_VALUE; | 368 _poll_fd[i].original_handle = INVALID_HA
NDLE_VALUE; |
| 377 } else { | 369 } else { |
| 378 _poll_fd[i].original_handle = handle; | 370 _poll_fd[i].original_handle = handle; |
| 379 } | 371 } |
| 380 } else { | 372 } else { |
| 381 wfd.handle = handle; | 373 wfd.handle = handle; |
| 382 } | 374 } |
| 383 wfd.overlapped = overlapped; | 375 wfd.overlapped = overlapped; |
| 384 memcpy(&poll_fd[i], &wfd, sizeof(struct winfd)); | 376 memcpy(&poll_fd[i], &wfd, sizeof(struct winfd)); |
| 385 LeaveCriticalSection(&_poll_fd[i].mutex); | 377 LeaveCriticalSection(&_poll_fd[i].mutex); |
| 386 return wfd; | 378 return wfd; |
| 387 } | 379 } |
| 388 } | 380 } |
| 389 free_overlapped(overlapped); | 381 free_overlapped(overlapped); |
| 390 _close(fd); | |
| 391 return INVALID_WINFD; | 382 return INVALID_WINFD; |
| 392 } | 383 } |
| 393 | 384 |
| 394 void _free_index(int _index) | 385 static void _free_index(int _index) |
| 395 { | 386 { |
| 396 // Cancel any async IO (Don't care about the validity of our handles for
this) | 387 // Cancel any async IO (Don't care about the validity of our handles for
this) |
| 397 cancel_io(_index); | 388 cancel_io(_index); |
| 398 // close fake handle for devices | |
| 399 if ( (poll_fd[_index].handle != INVALID_HANDLE_VALUE) && (poll_fd[_index
].handle != 0) | |
| 400 && (GetFileType(poll_fd[_index].handle) == FILE_TYPE_UNKNOWN) ) { | |
| 401 _close(poll_fd[_index].fd); | |
| 402 } | |
| 403 // close the duplicate handle (if we have an actual duplicate) | 389 // close the duplicate handle (if we have an actual duplicate) |
| 404 » if (!CancelIoEx_Available) { | 390 » if (Use_Duplicate_Handles) { |
| 405 if (_poll_fd[_index].original_handle != INVALID_HANDLE_VALUE) { | 391 if (_poll_fd[_index].original_handle != INVALID_HANDLE_VALUE) { |
| 406 CloseHandle(poll_fd[_index].handle); | 392 CloseHandle(poll_fd[_index].handle); |
| 407 } | 393 } |
| 408 _poll_fd[_index].original_handle = INVALID_HANDLE_VALUE; | 394 _poll_fd[_index].original_handle = INVALID_HANDLE_VALUE; |
| 409 _poll_fd[_index].thread_id = 0; | 395 _poll_fd[_index].thread_id = 0; |
| 410 } | 396 } |
| 411 free_overlapped(poll_fd[_index].overlapped); | 397 free_overlapped(poll_fd[_index].overlapped); |
| 412 poll_fd[_index] = INVALID_WINFD; | 398 poll_fd[_index] = INVALID_WINFD; |
| 413 } | 399 } |
| 414 | 400 |
| 415 /* | 401 /* |
| 416 * Release a pollable file descriptor. | 402 * Release a pollable file descriptor. |
| 417 * | 403 * |
| 418 * Note that the associated Windows handle is not closed by this call | 404 * Note that the associated Windows handle is not closed by this call |
| 419 */ | 405 */ |
| 420 void usbi_free_fd(int fd) | 406 void usbi_free_fd(struct winfd *wfd) |
| 421 { | 407 { |
| 422 int _index; | 408 int _index; |
| 423 | 409 |
| 424 CHECK_INIT_POLLING; | 410 CHECK_INIT_POLLING; |
| 425 | 411 |
| 426 » _index = _fd_to_index_and_lock(fd); | 412 » _index = _fd_to_index_and_lock(wfd->fd); |
| 427 if (_index < 0) { | 413 if (_index < 0) { |
| 428 return; | 414 return; |
| 429 } | 415 } |
| 430 _free_index(_index); | 416 _free_index(_index); |
| 417 *wfd = INVALID_WINFD; |
| 431 LeaveCriticalSection(&_poll_fd[_index].mutex); | 418 LeaveCriticalSection(&_poll_fd[_index].mutex); |
| 432 } | 419 } |
| 433 | 420 |
| 434 /* | 421 /* |
| 435 * The functions below perform various conversions between fd, handle and OVERLA
PPED | 422 * The functions below perform various conversions between fd, handle and OVERLA
PPED |
| 436 */ | 423 */ |
| 437 struct winfd fd_to_winfd(int fd) | 424 struct winfd fd_to_winfd(int fd) |
| 438 { | 425 { |
| 439 int i; | 426 int i; |
| 440 struct winfd wfd; | 427 struct winfd wfd; |
| (...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 644 int _index; | 631 int _index; |
| 645 int r = -1; | 632 int r = -1; |
| 646 | 633 |
| 647 CHECK_INIT_POLLING; | 634 CHECK_INIT_POLLING; |
| 648 | 635 |
| 649 _index = _fd_to_index_and_lock(fd); | 636 _index = _fd_to_index_and_lock(fd); |
| 650 | 637 |
| 651 if (_index < 0) { | 638 if (_index < 0) { |
| 652 errno = EBADF; | 639 errno = EBADF; |
| 653 } else { | 640 } else { |
| 654 » » if (poll_fd[_index].overlapped != NULL) { | 641 » » free_overlapped(poll_fd[_index].overlapped); |
| 655 » » » // Must be a different event for each end of the pipe | |
| 656 » » » CloseHandle(poll_fd[_index].overlapped->hEvent); | |
| 657 » » » free(poll_fd[_index].overlapped); | |
| 658 » » } | |
| 659 » » r = _close(poll_fd[_index].fd); | |
| 660 » » if (r != 0) { | |
| 661 » » » errno = EIO; | |
| 662 » » } | |
| 663 poll_fd[_index] = INVALID_WINFD; | 642 poll_fd[_index] = INVALID_WINFD; |
| 664 LeaveCriticalSection(&_poll_fd[_index].mutex); | 643 LeaveCriticalSection(&_poll_fd[_index].mutex); |
| 665 } | 644 } |
| 666 return r; | 645 return r; |
| 667 } | 646 } |
| 668 | 647 |
| 669 /* | 648 /* |
| 670 * synchronous write for fake "pipe" signaling | 649 * synchronous write for fake "pipe" signaling |
| 671 */ | 650 */ |
| 672 ssize_t usbi_write(int fd, const void *buf, size_t count) | 651 ssize_t usbi_write(int fd, const void *buf, size_t count) |
| 673 { | 652 { |
| 674 int _index; | 653 int _index; |
| 654 UNUSED(buf); |
| 675 | 655 |
| 676 CHECK_INIT_POLLING; | 656 CHECK_INIT_POLLING; |
| 677 | 657 |
| 678 if (count != sizeof(unsigned char)) { | 658 if (count != sizeof(unsigned char)) { |
| 679 usbi_err(NULL, "this function should only used for signaling"); | 659 usbi_err(NULL, "this function should only used for signaling"); |
| 680 return -1; | 660 return -1; |
| 681 } | 661 } |
| 682 | 662 |
| 683 _index = _fd_to_index_and_lock(fd); | 663 _index = _fd_to_index_and_lock(fd); |
| 684 | 664 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 701 return sizeof(unsigned char); | 681 return sizeof(unsigned char); |
| 702 } | 682 } |
| 703 | 683 |
| 704 /* | 684 /* |
| 705 * synchronous read for fake "pipe" signaling | 685 * synchronous read for fake "pipe" signaling |
| 706 */ | 686 */ |
| 707 ssize_t usbi_read(int fd, void *buf, size_t count) | 687 ssize_t usbi_read(int fd, void *buf, size_t count) |
| 708 { | 688 { |
| 709 int _index; | 689 int _index; |
| 710 ssize_t r = -1; | 690 ssize_t r = -1; |
| 691 UNUSED(buf); |
| 711 | 692 |
| 712 CHECK_INIT_POLLING; | 693 CHECK_INIT_POLLING; |
| 713 | 694 |
| 714 if (count != sizeof(unsigned char)) { | 695 if (count != sizeof(unsigned char)) { |
| 715 usbi_err(NULL, "this function should only used for signaling"); | 696 usbi_err(NULL, "this function should only used for signaling"); |
| 716 return -1; | 697 return -1; |
| 717 } | 698 } |
| 718 | 699 |
| 719 _index = _fd_to_index_and_lock(fd); | 700 _index = _fd_to_index_and_lock(fd); |
| 720 | 701 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 736 ResetEvent(poll_fd[_index].overlapped->hEvent); | 717 ResetEvent(poll_fd[_index].overlapped->hEvent); |
| 737 poll_fd[_index].overlapped->Internal = STATUS_PENDING; | 718 poll_fd[_index].overlapped->Internal = STATUS_PENDING; |
| 738 } | 719 } |
| 739 | 720 |
| 740 r = sizeof(unsigned char); | 721 r = sizeof(unsigned char); |
| 741 | 722 |
| 742 out: | 723 out: |
| 743 LeaveCriticalSection(&_poll_fd[_index].mutex); | 724 LeaveCriticalSection(&_poll_fd[_index].mutex); |
| 744 return r; | 725 return r; |
| 745 } | 726 } |
| OLD | NEW |