OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * poll_windows: poll compatibility wrapper for Windows |
| 3 * Copyright (C) 2009-2010 Pete Batard <pbatard@gmail.com> |
| 4 * With contributions from Michael Plante, Orin Eman et al. |
| 5 * Parts of poll implementation from libusb-win32, by Stephan Meyer et al. |
| 6 * |
| 7 * This library is free software; you can redistribute it and/or |
| 8 * modify it under the terms of the GNU Lesser General Public |
| 9 * License as published by the Free Software Foundation; either |
| 10 * version 2.1 of the License, or (at your option) any later version. |
| 11 * |
| 12 * This library is distributed in the hope that it will be useful, |
| 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 15 * Lesser General Public License for more details. |
| 16 * |
| 17 * 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 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| 20 * |
| 21 */ |
| 22 |
| 23 /* |
| 24 * poll() and pipe() Windows compatibility layer for libusb 1.0 |
| 25 * |
| 26 * 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 * |
| 29 * 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 * OVERLAPPED mode |
| 32 * - 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 * twice, once in _O_RDONLY and once in _O_WRONLY mode to obtain 2 separate |
| 35 * pollable fds |
| 36 * - leave the core functions call the poll routine and flag POLLIN/POLLOUT |
| 37 * |
| 38 * 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 * context. |
| 41 */ |
| 42 #include <errno.h> |
| 43 #include <fcntl.h> |
| 44 #include <stdio.h> |
| 45 #include <stdlib.h> |
| 46 #include <io.h> |
| 47 |
| 48 #include <libusbi.h> |
| 49 |
| 50 // Uncomment to debug the polling layer |
| 51 //#define DEBUG_POLL_WINDOWS |
| 52 #if defined(DEBUG_POLL_WINDOWS) |
| 53 #define poll_dbg usbi_dbg |
| 54 #else |
| 55 // MSVC6 cannot use a variadic argument and non MSVC |
| 56 // compilers produce warnings if parenthesis are ommitted. |
| 57 #if defined(_MSC_VER) |
| 58 #define poll_dbg |
| 59 #else |
| 60 #define poll_dbg(...) |
| 61 #endif |
| 62 #endif |
| 63 |
| 64 #if defined(_PREFAST_) |
| 65 #pragma warning(disable:28719) |
| 66 #endif |
| 67 |
| 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) |
| 79 |
| 80 // public fd data |
| 81 const struct winfd INVALID_WINFD = {-1, INVALID_HANDLE_VALUE, NULL, RW_NONE}; |
| 82 struct winfd poll_fd[MAX_FDS]; |
| 83 // internal fd data |
| 84 struct { |
| 85 CRITICAL_SECTION mutex; // lock for fds |
| 86 // Additional variables for XP CancelIoEx partial emulation |
| 87 HANDLE original_handle; |
| 88 DWORD thread_id; |
| 89 } _poll_fd[MAX_FDS]; |
| 90 |
| 91 // globals |
| 92 BOOLEAN is_polling_set = FALSE; |
| 93 #if defined(DYNAMIC_FDS) |
| 94 HANDLE fd_update = INVALID_HANDLE_VALUE; // event to notify poll of fd up
date |
| 95 HANDLE new_fd[MAX_FDS]; // overlapped event handles for fds created sinc
e last poll |
| 96 unsigned nb_new_fds = 0; // nb new fds created since last poll |
| 97 usbi_mutex_t new_fd_mutex; // mutex required for the above |
| 98 #endif |
| 99 LONG pipe_number = 0; |
| 100 static volatile LONG compat_spinlock = 0; |
| 101 |
| 102 // CancelIoEx, available on Vista and later only, provides the ability to cancel |
| 103 // a single transfer (OVERLAPPED) when used. As it may not be part of any of the |
| 104 // platform headers, we hook into the Kernel32 system DLL directly to seek it. |
| 105 static BOOL (__stdcall *pCancelIoEx)(HANDLE, LPOVERLAPPED) = NULL; |
| 106 #define CancelIoEx_Available (pCancelIoEx != NULL) |
| 107 static __inline BOOL cancel_io(int _index) |
| 108 { |
| 109 if ((_index < 0) || (_index >= MAX_FDS)) { |
| 110 return FALSE; |
| 111 } |
| 112 |
| 113 if ( (poll_fd[_index].fd < 0) || (poll_fd[_index].handle == INVALID_HAND
LE_VALUE) |
| 114 || (poll_fd[_index].handle == 0) || (poll_fd[_index].overlapped == NUL
L) ) { |
| 115 return TRUE; |
| 116 } |
| 117 if (CancelIoEx_Available) { |
| 118 return (*pCancelIoEx)(poll_fd[_index].handle, poll_fd[_index].ov
erlapped); |
| 119 } |
| 120 if (_poll_fd[_index].thread_id == GetCurrentThreadId()) { |
| 121 return CancelIo(poll_fd[_index].handle); |
| 122 } |
| 123 usbi_warn(NULL, "Unable to cancel I/O that was started from another thre
ad"); |
| 124 return FALSE; |
| 125 } |
| 126 |
| 127 // Init |
| 128 void init_polling(void) |
| 129 { |
| 130 int i; |
| 131 |
| 132 while (InterlockedExchange((LONG *)&compat_spinlock, 1) == 1) { |
| 133 SleepEx(0, TRUE); |
| 134 } |
| 135 if (!is_polling_set) { |
| 136 pCancelIoEx = (BOOL (__stdcall *)(HANDLE,LPOVERLAPPED)) |
| 137 GetProcAddress(GetModuleHandleA("KERNEL32"), "CancelIoEx
"); |
| 138 usbi_dbg("Will use CancelIo%s for I/O cancellation", |
| 139 CancelIoEx_Available?"Ex":""); |
| 140 for (i=0; i<MAX_FDS; i++) { |
| 141 poll_fd[i] = INVALID_WINFD; |
| 142 _poll_fd[i].original_handle = INVALID_HANDLE_VALUE; |
| 143 _poll_fd[i].thread_id = 0; |
| 144 InitializeCriticalSection(&_poll_fd[i].mutex); |
| 145 } |
| 146 #if defined(DYNAMIC_FDS) |
| 147 // We need to create an update event so that poll is warned when
there |
| 148 // are new/deleted fds during a timeout wait operation |
| 149 fd_update = CreateEvent(NULL, TRUE, FALSE, NULL); |
| 150 if (fd_update == NULL) { |
| 151 usbi_err(NULL, "unable to create update event"); |
| 152 } |
| 153 usbi_mutex_init(&new_fd_mutex, NULL); |
| 154 nb_new_fds = 0; |
| 155 #endif |
| 156 is_polling_set = TRUE; |
| 157 } |
| 158 compat_spinlock = 0; |
| 159 } |
| 160 |
| 161 // Internal function to retrieve the table index (and lock the fd mutex) |
| 162 int _fd_to_index_and_lock(int fd) |
| 163 { |
| 164 int i; |
| 165 |
| 166 if (fd <= 0) |
| 167 return -1; |
| 168 |
| 169 for (i=0; i<MAX_FDS; i++) { |
| 170 if (poll_fd[i].fd == fd) { |
| 171 EnterCriticalSection(&_poll_fd[i].mutex); |
| 172 // fd might have changed before we got to critical |
| 173 if (poll_fd[i].fd != fd) { |
| 174 LeaveCriticalSection(&_poll_fd[i].mutex); |
| 175 continue; |
| 176 } |
| 177 return i; |
| 178 } |
| 179 } |
| 180 return -1; |
| 181 } |
| 182 |
| 183 OVERLAPPED *create_overlapped(void) |
| 184 { |
| 185 OVERLAPPED *overlapped = calloc(1, sizeof(OVERLAPPED)); |
| 186 if (overlapped == NULL) { |
| 187 return NULL; |
| 188 } |
| 189 overlapped->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); |
| 190 if(overlapped->hEvent == NULL) { |
| 191 free (overlapped); |
| 192 return NULL; |
| 193 } |
| 194 return overlapped; |
| 195 } |
| 196 |
| 197 void free_overlapped(OVERLAPPED *overlapped) |
| 198 { |
| 199 if (overlapped == NULL) |
| 200 return; |
| 201 |
| 202 if ( (overlapped->hEvent != 0) |
| 203 && (overlapped->hEvent != INVALID_HANDLE_VALUE) ) { |
| 204 CloseHandle(overlapped->hEvent); |
| 205 } |
| 206 free(overlapped); |
| 207 } |
| 208 |
| 209 void reset_overlapped(OVERLAPPED *overlapped) |
| 210 { |
| 211 HANDLE event_handle; |
| 212 if (overlapped == NULL) |
| 213 return; |
| 214 |
| 215 event_handle = overlapped->hEvent; |
| 216 if (event_handle != NULL) { |
| 217 ResetEvent(event_handle); |
| 218 } |
| 219 memset(overlapped, 0, sizeof(OVERLAPPED)); |
| 220 overlapped->hEvent = event_handle; |
| 221 } |
| 222 |
| 223 void exit_polling(void) |
| 224 { |
| 225 int i; |
| 226 |
| 227 while (InterlockedExchange((LONG *)&compat_spinlock, 1) == 1) { |
| 228 SleepEx(0, TRUE); |
| 229 } |
| 230 if (is_polling_set) { |
| 231 is_polling_set = FALSE; |
| 232 |
| 233 for (i=0; i<MAX_FDS; i++) { |
| 234 // Cancel any async I/O (handle can be invalid) |
| 235 cancel_io(i); |
| 236 // If anything was pending on that I/O, it should be |
| 237 // terminating, and we should be able to access the fd |
| 238 // mutex lock before too long |
| 239 EnterCriticalSection(&_poll_fd[i].mutex); |
| 240 if ( (poll_fd[i].fd > 0) && (poll_fd[i].handle != INVALI
D_HANDLE_VALUE) && (poll_fd[i].handle != 0) |
| 241 && (GetFileType(poll_fd[i].handle) == FILE_TYPE_UNKNOW
N) ) { |
| 242 _close(poll_fd[i].fd); |
| 243 } |
| 244 free_overlapped(poll_fd[i].overlapped); |
| 245 if (!CancelIoEx_Available) { |
| 246 // Close duplicate handle |
| 247 if (_poll_fd[i].original_handle != INVALID_HANDL
E_VALUE) { |
| 248 CloseHandle(poll_fd[i].handle); |
| 249 } |
| 250 } |
| 251 poll_fd[i] = INVALID_WINFD; |
| 252 #if defined(DYNAMIC_FDS) |
| 253 usbi_mutex_destroy(&new_fd_mutex); |
| 254 CloseHandle(fd_update); |
| 255 fd_update = INVALID_HANDLE_VALUE; |
| 256 #endif |
| 257 LeaveCriticalSection(&_poll_fd[i].mutex); |
| 258 DeleteCriticalSection(&_poll_fd[i].mutex); |
| 259 } |
| 260 } |
| 261 compat_spinlock = 0; |
| 262 } |
| 263 |
| 264 /* |
| 265 * Create a fake pipe. |
| 266 * As libusb only uses pipes for signaling, all we need from a pipe is an |
| 267 * event. To that extent, we create a single wfd and overlapped as a means |
| 268 * to access that event. |
| 269 */ |
| 270 int usbi_pipe(int filedes[2]) |
| 271 { |
| 272 int i; |
| 273 OVERLAPPED* overlapped; |
| 274 |
| 275 CHECK_INIT_POLLING; |
| 276 |
| 277 overlapped = calloc(1, sizeof(OVERLAPPED)); |
| 278 if (overlapped == NULL) { |
| 279 return -1; |
| 280 } |
| 281 // The overlapped must have status pending for signaling to work in poll |
| 282 overlapped->Internal = STATUS_PENDING; |
| 283 overlapped->InternalHigh = 0; |
| 284 |
| 285 // Read end of the "pipe" |
| 286 filedes[0] = _open(NUL_DEVICE, _O_WRONLY); |
| 287 if (filedes[0] < 0) { |
| 288 usbi_err(NULL, "could not create pipe: errno %d", errno); |
| 289 goto out1; |
| 290 } |
| 291 // We can use the same handle for both ends |
| 292 filedes[1] = filedes[0]; |
| 293 poll_dbg("pipe filedes = %d", filedes[0]); |
| 294 |
| 295 // Note: manual reset must be true (second param) as the reset occurs in
read |
| 296 overlapped->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); |
| 297 if(!overlapped->hEvent) { |
| 298 goto out2; |
| 299 } |
| 300 |
| 301 for (i=0; i<MAX_FDS; i++) { |
| 302 if (poll_fd[i].fd < 0) { |
| 303 EnterCriticalSection(&_poll_fd[i].mutex); |
| 304 // fd might have been allocated before we got to critica
l |
| 305 if (poll_fd[i].fd >= 0) { |
| 306 LeaveCriticalSection(&_poll_fd[i].mutex); |
| 307 continue; |
| 308 } |
| 309 |
| 310 poll_fd[i].fd = filedes[0]; |
| 311 poll_fd[i].handle = DUMMY_HANDLE; |
| 312 poll_fd[i].overlapped = overlapped; |
| 313 // There's no polling on the write end, so we just use R
EAD for our needs |
| 314 poll_fd[i].rw = RW_READ; |
| 315 _poll_fd[i].original_handle = INVALID_HANDLE_VALUE; |
| 316 LeaveCriticalSection(&_poll_fd[i].mutex); |
| 317 return 0; |
| 318 } |
| 319 } |
| 320 |
| 321 CloseHandle(overlapped->hEvent); |
| 322 out2: |
| 323 _close(filedes[0]); |
| 324 out1: |
| 325 free(overlapped); |
| 326 return -1; |
| 327 } |
| 328 |
| 329 /* |
| 330 * Create both an fd and an OVERLAPPED from an open Windows handle, so that |
| 331 * it can be used with our polling function |
| 332 * The handle MUST support overlapped transfers (usually requires CreateFile |
| 333 * with FILE_FLAG_OVERLAPPED) |
| 334 * Return a pollable file descriptor struct, or INVALID_WINFD on error |
| 335 * |
| 336 * Note that the fd returned by this function is a per-transfer fd, rather |
| 337 * than a per-session fd and cannot be used for anything else but our |
| 338 * custom functions (the fd itself points to the NUL: device) |
| 339 * if you plan to do R/W on the same handle, you MUST create 2 fds: one for |
| 340 * read and one for write. Using a single R/W fd is unsupported and will |
| 341 * produce unexpected results |
| 342 */ |
| 343 struct winfd usbi_create_fd(HANDLE handle, int access_mode) |
| 344 { |
| 345 int i, fd; |
| 346 struct winfd wfd = INVALID_WINFD; |
| 347 OVERLAPPED* overlapped = NULL; |
| 348 |
| 349 CHECK_INIT_POLLING; |
| 350 |
| 351 if ((handle == 0) || (handle == INVALID_HANDLE_VALUE)) { |
| 352 return INVALID_WINFD; |
| 353 } |
| 354 |
| 355 if ((access_mode != _O_RDONLY) && (access_mode != _O_WRONLY)) { |
| 356 usbi_warn(NULL, "only one of _O_RDONLY or _O_WRONLY are supporte
d.\n" |
| 357 "If you want to poll for R/W simultaneously, create mult
iple fds from the same handle."); |
| 358 return INVALID_WINFD; |
| 359 } |
| 360 if (access_mode == _O_RDONLY) { |
| 361 wfd.rw = RW_READ; |
| 362 } else { |
| 363 wfd.rw = RW_WRITE; |
| 364 } |
| 365 |
| 366 // Ensure that we get a non system conflicting unique fd, using |
| 367 // the same fd attribution system as the pipe ends |
| 368 fd = _open(NUL_DEVICE, _O_WRONLY); |
| 369 if (fd < 0) { |
| 370 return INVALID_WINFD; |
| 371 } |
| 372 |
| 373 overlapped = create_overlapped(); |
| 374 if(overlapped == NULL) { |
| 375 _close(fd); |
| 376 return INVALID_WINFD; |
| 377 } |
| 378 |
| 379 for (i=0; i<MAX_FDS; i++) { |
| 380 if (poll_fd[i].fd < 0) { |
| 381 EnterCriticalSection(&_poll_fd[i].mutex); |
| 382 // fd might have been removed before we got to critical |
| 383 if (poll_fd[i].fd >= 0) { |
| 384 LeaveCriticalSection(&_poll_fd[i].mutex); |
| 385 continue; |
| 386 } |
| 387 wfd.fd = fd; |
| 388 // Attempt to emulate some of the CancelIoEx behaviour o
n platforms |
| 389 // that don't have it |
| 390 if (!CancelIoEx_Available) { |
| 391 _poll_fd[i].thread_id = GetCurrentThreadId(); |
| 392 if (!DuplicateHandle(GetCurrentProcess(), handle
, GetCurrentProcess(), |
| 393 &wfd.handle, 0, TRUE, DUPLICATE_SAME_ACC
ESS)) { |
| 394 usbi_dbg("could not duplicate handle for
CancelIo - using original one"); |
| 395 wfd.handle = handle; |
| 396 // Make sure we won't close the original
handle on fd deletion then |
| 397 _poll_fd[i].original_handle = INVALID_HA
NDLE_VALUE; |
| 398 } else { |
| 399 _poll_fd[i].original_handle = handle; |
| 400 } |
| 401 } else { |
| 402 wfd.handle = handle; |
| 403 } |
| 404 wfd.overlapped = overlapped; |
| 405 memcpy(&poll_fd[i], &wfd, sizeof(struct winfd)); |
| 406 LeaveCriticalSection(&_poll_fd[i].mutex); |
| 407 #if defined(DYNAMIC_FDS) |
| 408 usbi_mutex_lock(&new_fd_mutex); |
| 409 new_fd[nb_new_fds++] = overlapped->hEvent; |
| 410 usbi_mutex_unlock(&new_fd_mutex); |
| 411 // Notify poll that fds have been updated |
| 412 SetEvent(fd_update); |
| 413 #endif |
| 414 return wfd; |
| 415 } |
| 416 } |
| 417 free_overlapped(overlapped); |
| 418 _close(fd); |
| 419 return INVALID_WINFD; |
| 420 } |
| 421 |
| 422 void _free_index(int _index) |
| 423 { |
| 424 // Cancel any async IO (Don't care about the validity of our handles for
this) |
| 425 cancel_io(_index); |
| 426 // close fake handle for devices |
| 427 if ( (poll_fd[_index].handle != INVALID_HANDLE_VALUE) && (poll_fd[_index
].handle != 0) |
| 428 && (GetFileType(poll_fd[_index].handle) == FILE_TYPE_UNKNOWN) ) { |
| 429 _close(poll_fd[_index].fd); |
| 430 } |
| 431 // close the duplicate handle (if we have an actual duplicate) |
| 432 if (!CancelIoEx_Available) { |
| 433 if (_poll_fd[_index].original_handle != INVALID_HANDLE_VALUE) { |
| 434 CloseHandle(poll_fd[_index].handle); |
| 435 } |
| 436 _poll_fd[_index].original_handle = INVALID_HANDLE_VALUE; |
| 437 _poll_fd[_index].thread_id = 0; |
| 438 } |
| 439 free_overlapped(poll_fd[_index].overlapped); |
| 440 poll_fd[_index] = INVALID_WINFD; |
| 441 } |
| 442 |
| 443 /* |
| 444 * Release a pollable file descriptor. |
| 445 * |
| 446 * Note that the associated Windows handle is not closed by this call |
| 447 */ |
| 448 void usbi_free_fd(int fd) |
| 449 { |
| 450 int _index; |
| 451 |
| 452 CHECK_INIT_POLLING; |
| 453 |
| 454 _index = _fd_to_index_and_lock(fd); |
| 455 if (_index < 0) { |
| 456 return; |
| 457 } |
| 458 _free_index(_index); |
| 459 LeaveCriticalSection(&_poll_fd[_index].mutex); |
| 460 } |
| 461 |
| 462 /* |
| 463 * The functions below perform various conversions between fd, handle and OVERLA
PPED |
| 464 */ |
| 465 struct winfd fd_to_winfd(int fd) |
| 466 { |
| 467 int i; |
| 468 struct winfd wfd; |
| 469 |
| 470 CHECK_INIT_POLLING; |
| 471 |
| 472 if (fd <= 0) |
| 473 return INVALID_WINFD; |
| 474 |
| 475 for (i=0; i<MAX_FDS; i++) { |
| 476 if (poll_fd[i].fd == fd) { |
| 477 EnterCriticalSection(&_poll_fd[i].mutex); |
| 478 // fd might have been deleted before we got to critical |
| 479 if (poll_fd[i].fd != fd) { |
| 480 LeaveCriticalSection(&_poll_fd[i].mutex); |
| 481 continue; |
| 482 } |
| 483 memcpy(&wfd, &poll_fd[i], sizeof(struct winfd)); |
| 484 LeaveCriticalSection(&_poll_fd[i].mutex); |
| 485 return wfd; |
| 486 } |
| 487 } |
| 488 return INVALID_WINFD; |
| 489 } |
| 490 |
| 491 struct winfd handle_to_winfd(HANDLE handle) |
| 492 { |
| 493 int i; |
| 494 struct winfd wfd; |
| 495 |
| 496 CHECK_INIT_POLLING; |
| 497 |
| 498 if ((handle == 0) || (handle == INVALID_HANDLE_VALUE)) |
| 499 return INVALID_WINFD; |
| 500 |
| 501 for (i=0; i<MAX_FDS; i++) { |
| 502 if (poll_fd[i].handle == handle) { |
| 503 EnterCriticalSection(&_poll_fd[i].mutex); |
| 504 // fd might have been deleted before we got to critical |
| 505 if (poll_fd[i].handle != handle) { |
| 506 LeaveCriticalSection(&_poll_fd[i].mutex); |
| 507 continue; |
| 508 } |
| 509 memcpy(&wfd, &poll_fd[i], sizeof(struct winfd)); |
| 510 LeaveCriticalSection(&_poll_fd[i].mutex); |
| 511 return wfd; |
| 512 } |
| 513 } |
| 514 return INVALID_WINFD; |
| 515 } |
| 516 |
| 517 struct winfd overlapped_to_winfd(OVERLAPPED* overlapped) |
| 518 { |
| 519 int i; |
| 520 struct winfd wfd; |
| 521 |
| 522 CHECK_INIT_POLLING; |
| 523 |
| 524 if (overlapped == NULL) |
| 525 return INVALID_WINFD; |
| 526 |
| 527 for (i=0; i<MAX_FDS; i++) { |
| 528 if (poll_fd[i].overlapped == overlapped) { |
| 529 EnterCriticalSection(&_poll_fd[i].mutex); |
| 530 // fd might have been deleted before we got to critical |
| 531 if (poll_fd[i].overlapped != overlapped) { |
| 532 LeaveCriticalSection(&_poll_fd[i].mutex); |
| 533 continue; |
| 534 } |
| 535 memcpy(&wfd, &poll_fd[i], sizeof(struct winfd)); |
| 536 LeaveCriticalSection(&_poll_fd[i].mutex); |
| 537 return wfd; |
| 538 } |
| 539 } |
| 540 return INVALID_WINFD; |
| 541 } |
| 542 |
| 543 /* |
| 544 * POSIX poll equivalent, using Windows OVERLAPPED |
| 545 * Currently, this function only accepts one of POLLIN or POLLOUT per fd |
| 546 * (but you can create multiple fds from the same handle for read and write) |
| 547 */ |
| 548 int usbi_poll(struct pollfd *fds, unsigned int nfds, int timeout) |
| 549 { |
| 550 unsigned i; |
| 551 int _index, object_index, triggered; |
| 552 HANDLE *handles_to_wait_on; |
| 553 int *handle_to_index; |
| 554 DWORD nb_handles_to_wait_on = 0; |
| 555 DWORD ret; |
| 556 |
| 557 #if defined(DYNAMIC_FDS) |
| 558 DWORD nb_extra_handles = 0; |
| 559 unsigned j; |
| 560 |
| 561 // To address the possibility of missing new fds between the time the ne
w |
| 562 // pollable fd set is assembled, and the ResetEvent() call below, an |
| 563 // additional new_fd[] HANDLE table is used for any new fd that was crea
ted |
| 564 // since the last call to poll (see below) |
| 565 ResetEvent(fd_update); |
| 566 |
| 567 // At this stage, any new fd creation will be detected through the fd_up
date |
| 568 // event notification, and any previous creation that we may have missed |
| 569 // will be picked up through the existing new_fd[] table. |
| 570 #endif |
| 571 |
| 572 CHECK_INIT_POLLING; |
| 573 |
| 574 triggered = 0; |
| 575 handles_to_wait_on = malloc((nfds+1)*sizeof(HANDLE)); // +1 for fd_upd
ate |
| 576 handle_to_index = malloc(nfds*sizeof(int)); |
| 577 if ((handles_to_wait_on == NULL) || (handle_to_index == NULL)) { |
| 578 errno = ENOMEM; |
| 579 triggered = -1; |
| 580 goto poll_exit; |
| 581 } |
| 582 |
| 583 for (i = 0; i < nfds; ++i) { |
| 584 fds[i].revents = 0; |
| 585 |
| 586 // Only one of POLLIN or POLLOUT can be selected with this versi
on of poll (not both) |
| 587 if ((fds[i].events & ~POLLIN) && (!(fds[i].events & POLLOUT))) { |
| 588 fds[i].revents |= POLLERR; |
| 589 errno = EACCES; |
| 590 usbi_warn(NULL, "unsupported set of events"); |
| 591 triggered = -1; |
| 592 goto poll_exit; |
| 593 } |
| 594 |
| 595 _index = _fd_to_index_and_lock(fds[i].fd); |
| 596 poll_dbg("fd[%d]=%d: (overlapped=%p) got events %04X", i, poll_f
d[_index].fd, poll_fd[_index].overlapped, fds[i].events); |
| 597 |
| 598 if ( (_index < 0) || (poll_fd[_index].handle == INVALID_HANDLE_V
ALUE) |
| 599 || (poll_fd[_index].handle == 0) || (poll_fd[_index].overlappe
d == NULL)) { |
| 600 fds[i].revents |= POLLNVAL | POLLERR; |
| 601 errno = EBADF; |
| 602 if (_index >= 0) { |
| 603 LeaveCriticalSection(&_poll_fd[_index].mutex); |
| 604 } |
| 605 usbi_warn(NULL, "invalid fd"); |
| 606 triggered = -1; |
| 607 goto poll_exit; |
| 608 } |
| 609 |
| 610 // IN or OUT must match our fd direction |
| 611 if ((fds[i].events & POLLIN) && (poll_fd[_index].rw != RW_READ))
{ |
| 612 fds[i].revents |= POLLNVAL | POLLERR; |
| 613 errno = EBADF; |
| 614 usbi_warn(NULL, "attempted POLLIN on fd without READ acc
ess"); |
| 615 LeaveCriticalSection(&_poll_fd[_index].mutex); |
| 616 triggered = -1; |
| 617 goto poll_exit; |
| 618 } |
| 619 |
| 620 if ((fds[i].events & POLLOUT) && (poll_fd[_index].rw != RW_WRITE
)) { |
| 621 fds[i].revents |= POLLNVAL | POLLERR; |
| 622 errno = EBADF; |
| 623 usbi_warn(NULL, "attempted POLLOUT on fd without WRITE a
ccess"); |
| 624 LeaveCriticalSection(&_poll_fd[_index].mutex); |
| 625 triggered = -1; |
| 626 goto poll_exit; |
| 627 } |
| 628 |
| 629 // The following macro only works if overlapped I/O was reported
pending |
| 630 if ( (HasOverlappedIoCompleted(poll_fd[_index].overlapped)) |
| 631 || (HasOverlappedIoCompletedSync(poll_fd[_index].overlapped))
) { |
| 632 poll_dbg(" completed"); |
| 633 // checks above should ensure this works: |
| 634 fds[i].revents = fds[i].events; |
| 635 triggered++; |
| 636 } else { |
| 637 handles_to_wait_on[nb_handles_to_wait_on] = poll_fd[_ind
ex].overlapped->hEvent; |
| 638 handle_to_index[nb_handles_to_wait_on] = i; |
| 639 #if defined(DYNAMIC_FDS) |
| 640 // If this fd from the poll set is also part of the new_
fd event handle table, remove it |
| 641 usbi_mutex_lock(&new_fd_mutex); |
| 642 for (j=0; j<nb_new_fds; j++) { |
| 643 if (handles_to_wait_on[nb_handles_to_wait_on] ==
new_fd[j]) { |
| 644 new_fd[j] = INVALID_HANDLE_VALUE; |
| 645 break; |
| 646 } |
| 647 } |
| 648 usbi_mutex_unlock(&new_fd_mutex); |
| 649 #endif |
| 650 nb_handles_to_wait_on++; |
| 651 } |
| 652 LeaveCriticalSection(&_poll_fd[_index].mutex); |
| 653 } |
| 654 #if defined(DYNAMIC_FDS) |
| 655 // At this stage, new_fd[] should only contain events from fds that |
| 656 // have been added since the last call to poll, but are not (yet) part |
| 657 // of the pollable fd set. Typically, these would be from fds that have |
| 658 // been created between the construction of the fd set and the calling |
| 659 // of poll. |
| 660 // Event if we won't be able to return usable poll data on these events, |
| 661 // make sure we monitor them to return an EINTR code |
| 662 usbi_mutex_lock(&new_fd_mutex); // We could probably do without |
| 663 for (i=0; i<nb_new_fds; i++) { |
| 664 if (new_fd[i] != INVALID_HANDLE_VALUE) { |
| 665 handles_to_wait_on[nb_handles_to_wait_on++] = new_fd[i]; |
| 666 nb_extra_handles++; |
| 667 } |
| 668 } |
| 669 usbi_mutex_unlock(&new_fd_mutex); |
| 670 poll_dbg("dynamic_fds: added %d extra handles", nb_extra_handles); |
| 671 #endif |
| 672 |
| 673 // If nothing was triggered, wait on all fds that require it |
| 674 if ((timeout != 0) && (triggered == 0) && (nb_handles_to_wait_on != 0))
{ |
| 675 #if defined(DYNAMIC_FDS) |
| 676 // Register for fd update notifications |
| 677 handles_to_wait_on[nb_handles_to_wait_on++] = fd_update; |
| 678 nb_extra_handles++; |
| 679 #endif |
| 680 if (timeout < 0) { |
| 681 poll_dbg("starting infinite wait for %d handles...", (in
t)nb_handles_to_wait_on); |
| 682 } else { |
| 683 poll_dbg("starting %d ms wait for %d handles...", timeou
t, (int)nb_handles_to_wait_on); |
| 684 } |
| 685 ret = WaitForMultipleObjects(nb_handles_to_wait_on, handles_to_w
ait_on, |
| 686 FALSE, (timeout<0)?INFINITE:(DWORD)timeout); |
| 687 object_index = ret-WAIT_OBJECT_0; |
| 688 if ((object_index >= 0) && ((DWORD)object_index < nb_handles_to_
wait_on)) { |
| 689 #if defined(DYNAMIC_FDS) |
| 690 if ((DWORD)object_index >= (nb_handles_to_wait_on-nb_ext
ra_handles)) { |
| 691 // Detected fd update => flag a poll interruptio
n |
| 692 if ((DWORD)object_index == (nb_handles_to_wait_o
n-1)) |
| 693 poll_dbg(" dynamic_fds: fd_update event
"); |
| 694 else |
| 695 poll_dbg(" dynamic_fds: new fd I/O even
t"); |
| 696 errno = EINTR; |
| 697 triggered = -1; |
| 698 goto poll_exit; |
| 699 } |
| 700 #endif |
| 701 poll_dbg(" completed after wait"); |
| 702 i = handle_to_index[object_index]; |
| 703 _index = _fd_to_index_and_lock(fds[i].fd); |
| 704 fds[i].revents = fds[i].events; |
| 705 triggered++; |
| 706 if (_index >= 0) { |
| 707 LeaveCriticalSection(&_poll_fd[_index].mutex); |
| 708 } |
| 709 } else if (ret == WAIT_TIMEOUT) { |
| 710 poll_dbg(" timed out"); |
| 711 triggered = 0; // 0 = timeout |
| 712 } else { |
| 713 errno = EIO; |
| 714 triggered = -1; // error |
| 715 } |
| 716 } |
| 717 |
| 718 poll_exit: |
| 719 if (handles_to_wait_on != NULL) { |
| 720 free(handles_to_wait_on); |
| 721 } |
| 722 if (handle_to_index != NULL) { |
| 723 free(handle_to_index); |
| 724 } |
| 725 #if defined(DYNAMIC_FDS) |
| 726 usbi_mutex_lock(&new_fd_mutex); |
| 727 nb_new_fds = 0; |
| 728 usbi_mutex_unlock(&new_fd_mutex); |
| 729 #endif |
| 730 return triggered; |
| 731 } |
| 732 |
| 733 /* |
| 734 * close a fake pipe fd |
| 735 */ |
| 736 int usbi_close(int fd) |
| 737 { |
| 738 int _index; |
| 739 int r = -1; |
| 740 |
| 741 CHECK_INIT_POLLING; |
| 742 |
| 743 _index = _fd_to_index_and_lock(fd); |
| 744 |
| 745 if (_index < 0) { |
| 746 errno = EBADF; |
| 747 } else { |
| 748 if (poll_fd[_index].overlapped != NULL) { |
| 749 // Must be a different event for each end of the pipe |
| 750 CloseHandle(poll_fd[_index].overlapped->hEvent); |
| 751 free(poll_fd[_index].overlapped); |
| 752 } |
| 753 r = _close(poll_fd[_index].fd); |
| 754 if (r != 0) { |
| 755 errno = EIO; |
| 756 } |
| 757 poll_fd[_index] = INVALID_WINFD; |
| 758 LeaveCriticalSection(&_poll_fd[_index].mutex); |
| 759 } |
| 760 return r; |
| 761 } |
| 762 |
| 763 /* |
| 764 * synchronous write for fake "pipe" signaling |
| 765 */ |
| 766 ssize_t usbi_write(int fd, const void *buf, size_t count) |
| 767 { |
| 768 int _index; |
| 769 |
| 770 CHECK_INIT_POLLING; |
| 771 |
| 772 if (count != sizeof(unsigned char)) { |
| 773 usbi_err(NULL, "this function should only used for signaling"); |
| 774 return -1; |
| 775 } |
| 776 |
| 777 _index = _fd_to_index_and_lock(fd); |
| 778 |
| 779 if ( (_index < 0) || (poll_fd[_index].overlapped == NULL) ) { |
| 780 errno = EBADF; |
| 781 if (_index >= 0) { |
| 782 LeaveCriticalSection(&_poll_fd[_index].mutex); |
| 783 } |
| 784 return -1; |
| 785 } |
| 786 |
| 787 poll_dbg("set pipe event (fd = %d, thread = %08X)", _index, GetCurrentTh
readId()); |
| 788 SetEvent(poll_fd[_index].overlapped->hEvent); |
| 789 poll_fd[_index].overlapped->Internal = STATUS_WAIT_0; |
| 790 // If two threads write on the pipe at the same time, we need to |
| 791 // process two separate reads => use the overlapped as a counter |
| 792 poll_fd[_index].overlapped->InternalHigh++; |
| 793 |
| 794 LeaveCriticalSection(&_poll_fd[_index].mutex); |
| 795 return sizeof(unsigned char); |
| 796 } |
| 797 |
| 798 /* |
| 799 * synchronous read for fake "pipe" signaling |
| 800 */ |
| 801 ssize_t usbi_read(int fd, void *buf, size_t count) |
| 802 { |
| 803 int _index; |
| 804 ssize_t r = -1; |
| 805 |
| 806 CHECK_INIT_POLLING; |
| 807 |
| 808 if (count != sizeof(unsigned char)) { |
| 809 usbi_err(NULL, "this function should only used for signaling"); |
| 810 return -1; |
| 811 } |
| 812 |
| 813 _index = _fd_to_index_and_lock(fd); |
| 814 |
| 815 if (_index < 0) { |
| 816 errno = EBADF; |
| 817 return -1; |
| 818 } |
| 819 |
| 820 if (WaitForSingleObject(poll_fd[_index].overlapped->hEvent, INFINITE) !=
WAIT_OBJECT_0) { |
| 821 usbi_warn(NULL, "waiting for event failed: %d", (int)GetLastErro
r()); |
| 822 errno = EIO; |
| 823 goto out; |
| 824 } |
| 825 |
| 826 poll_dbg("clr pipe event (fd = %d, thread = %08X)", _index, GetCurrentTh
readId()); |
| 827 poll_fd[_index].overlapped->InternalHigh--; |
| 828 // Don't reset unless we don't have any more events to process |
| 829 if (poll_fd[_index].overlapped->InternalHigh <= 0) { |
| 830 ResetEvent(poll_fd[_index].overlapped->hEvent); |
| 831 poll_fd[_index].overlapped->Internal = STATUS_PENDING; |
| 832 } |
| 833 |
| 834 r = sizeof(unsigned char); |
| 835 |
| 836 out: |
| 837 LeaveCriticalSection(&_poll_fd[_index].mutex); |
| 838 return r; |
| 839 } |
OLD | NEW |