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 |