1 /* 2 * poll_windows: poll compatibility wrapper for Windows 3 * Copyright (C) 2009-2010 Pete Batard <pbatard (at) 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 // MSVC++ < 2005 cannot use a variadic argument and non MSVC 56 // compilers produce warnings if parenthesis are omitted. 57 #if defined(_MSC_VER) && _MSC_VER < 1400 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 LONG pipe_number = 0; 94 static volatile LONG compat_spinlock = 0; 95 96 // 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 98 // platform headers, we hook into the Kernel32 system DLL directly to seek it. 99 static BOOL (__stdcall *pCancelIoEx)(HANDLE, LPOVERLAPPED) = NULL; 100 #define CancelIoEx_Available (pCancelIoEx != NULL) 101 static __inline BOOL cancel_io(int _index) 102 { 103 if ((_index < 0) || (_index >= MAX_FDS)) { 104 return FALSE; 105 } 106 107 if ( (poll_fd[_index].fd < 0) || (poll_fd[_index].handle == INVALID_HANDLE_VALUE) 108 || (poll_fd[_index].handle == 0) || (poll_fd[_index].overlapped == NULL) ) { 109 return TRUE; 110 } 111 if (CancelIoEx_Available) { 112 return (*pCancelIoEx)(poll_fd[_index].handle, poll_fd[_index].overlapped); 113 } 114 if (_poll_fd[_index].thread_id == GetCurrentThreadId()) { 115 return CancelIo(poll_fd[_index].handle); 116 } 117 usbi_warn(NULL, "Unable to cancel I/O that was started from another thread"); 118 return FALSE; 119 } 120 121 // Init 122 void init_polling(void) 123 { 124 int i; 125 126 while (InterlockedExchange((LONG *)&compat_spinlock, 1) == 1) { 127 SleepEx(0, TRUE); 128 } 129 if (!is_polling_set) { 130 pCancelIoEx = (BOOL (__stdcall *)(HANDLE,LPOVERLAPPED)) 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++) { 135 poll_fd[i] = INVALID_WINFD; 136 _poll_fd[i].original_handle = INVALID_HANDLE_VALUE; 137 _poll_fd[i].thread_id = 0; 138 InitializeCriticalSection(&_poll_fd[i].mutex); 139 } 140 is_polling_set = TRUE; 141 } 142 compat_spinlock = 0; 143 } 144 145 // Internal function to retrieve the table index (and lock the fd mutex) 146 int _fd_to_index_and_lock(int fd) 147 { 148 int i; 149 150 if (fd <= 0) 151 return -1; 152 153 for (i=0; i<MAX_FDS; i++) { 154 if (poll_fd[i].fd == fd) { 155 EnterCriticalSection(&_poll_fd[i].mutex); 156 // fd might have changed before we got to critical 157 if (poll_fd[i].fd != fd) { 158 LeaveCriticalSection(&_poll_fd[i].mutex); 159 continue; 160 } 161 return i; 162 } 163 } 164 return -1; 165 } 166 167 OVERLAPPED *create_overlapped(void) 168 { 169 OVERLAPPED *overlapped = (OVERLAPPED*) calloc(1, sizeof(OVERLAPPED)); 170 if (overlapped == NULL) { 171 return NULL; 172 } 173 overlapped->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); 174 if(overlapped->hEvent == NULL) { 175 free (overlapped); 176 return NULL; 177 } 178 return overlapped; 179 } 180 181 void free_overlapped(OVERLAPPED *overlapped) 182 { 183 if (overlapped == NULL) 184 return; 185 186 if ( (overlapped->hEvent != 0) 187 && (overlapped->hEvent != INVALID_HANDLE_VALUE) ) { 188 CloseHandle(overlapped->hEvent); 189 } 190 free(overlapped); 191 } 192 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) 208 { 209 int i; 210 211 while (InterlockedExchange((LONG *)&compat_spinlock, 1) == 1) { 212 SleepEx(0, TRUE); 213 } 214 if (is_polling_set) { 215 is_polling_set = FALSE; 216 217 for (i=0; i<MAX_FDS; i++) { 218 // Cancel any async I/O (handle can be invalid) 219 cancel_io(i); 220 // If anything was pending on that I/O, it should be 221 // terminating, and we should be able to access the fd 222 // mutex lock before too long 223 EnterCriticalSection(&_poll_fd[i].mutex); 224 if ( (poll_fd[i].fd > 0) && (poll_fd[i].handle != INVALID_HANDLE_VALUE) && (poll_fd[i].handle != 0) 225 && (GetFileType(poll_fd[i].handle) == FILE_TYPE_UNKNOWN) ) { 226 _close(poll_fd[i].fd); 227 } 228 free_overlapped(poll_fd[i].overlapped); 229 if (!CancelIoEx_Available) { 230 // Close duplicate handle 231 if (_poll_fd[i].original_handle != INVALID_HANDLE_VALUE) { 232 CloseHandle(poll_fd[i].handle); 233 } 234 } 235 poll_fd[i] = INVALID_WINFD; 236 LeaveCriticalSection(&_poll_fd[i].mutex); 237 DeleteCriticalSection(&_poll_fd[i].mutex); 238 } 239 } 240 compat_spinlock = 0; 241 } 242 243 /* 244 * Create a fake pipe. 245 * As libusb 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 247 * to access that event. 248 */ 249 int usbi_pipe(int filedes[2]) 250 { 251 int i; 252 OVERLAPPED* overlapped; 253 254 CHECK_INIT_POLLING; 255 256 overlapped = (OVERLAPPED*) calloc(1, sizeof(OVERLAPPED)); 257 if (overlapped == NULL) { 258 return -1; 259 } 260 // The overlapped must have status pending for signaling to work in poll 261 overlapped->Internal = STATUS_PENDING; 262 overlapped->InternalHigh = 0; 263 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++) { 281 if (poll_fd[i].fd < 0) { 282 EnterCriticalSection(&_poll_fd[i].mutex); 283 // fd might have been allocated before we got to critical 284 if (poll_fd[i].fd >= 0) { 285 LeaveCriticalSection(&_poll_fd[i].mutex); 286 continue; 287 } 288 289 poll_fd[i].fd = filedes[0]; 290 poll_fd[i].handle = DUMMY_HANDLE; 291 poll_fd[i].overlapped = overlapped; 292 // There's no polling on the write end, so we just use READ for our needs 293 poll_fd[i].rw = RW_READ; 294 _poll_fd[i].original_handle = INVALID_HANDLE_VALUE; 295 LeaveCriticalSection(&_poll_fd[i].mutex); 296 return 0; 297 } 298 } 299 300 CloseHandle(overlapped->hEvent); 301 out2: 302 _close(filedes[0]); 303 out1: 304 free(overlapped); 305 return -1; 306 } 307 308 /* 309 * Create both an fd and an OVERLAPPED from an open Windows handle, so that 310 * it can be used with our polling function 311 * The handle MUST support overlapped transfers (usually requires CreateFile 312 * with FILE_FLAG_OVERLAPPED) 313 * Return a pollable file descriptor struct, or INVALID_WINFD on error 314 * 315 * 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 317 * 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 319 * read and one for write. Using a single R/W fd is unsupported and will 320 * produce unexpected results 321 */ 322 struct winfd usbi_create_fd(HANDLE handle, int access_mode) 323 { 324 int i, fd; 325 struct winfd wfd = INVALID_WINFD; 326 OVERLAPPED* overlapped = NULL; 327 328 CHECK_INIT_POLLING; 329 330 if ((handle == 0) || (handle == INVALID_HANDLE_VALUE)) { 331 return INVALID_WINFD; 332 } 333 334 if ((access_mode != _O_RDONLY) && (access_mode != _O_WRONLY)) { 335 usbi_warn(NULL, "only one of _O_RDONLY or _O_WRONLY are supported.\n" 336 "If you want to poll for R/W simultaneously, create multiple fds from the same handle."); 337 return INVALID_WINFD; 338 } 339 if (access_mode == _O_RDONLY) { 340 wfd.rw = RW_READ; 341 } else { 342 wfd.rw = RW_WRITE; 343 } 344 345 // Ensure that we get a non system conflicting unique fd, using 346 // the same fd attribution system as the pipe ends 347 fd = _open(NUL_DEVICE, _O_WRONLY); 348 if (fd < 0) { 349 return INVALID_WINFD; 350 } 351 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++) { 359 if (poll_fd[i].fd < 0) { 360 EnterCriticalSection(&_poll_fd[i].mutex); 361 // fd might have been removed before we got to critical 362 if (poll_fd[i].fd >= 0) { 363 LeaveCriticalSection(&_poll_fd[i].mutex); 364 continue; 365 } 366 wfd.fd = fd; 367 // Attempt to emulate some of the CancelIoEx behaviour on platforms 368 // that don't have it 369 if (!CancelIoEx_Available) { 370 _poll_fd[i].thread_id = GetCurrentThreadId(); 371 if (!DuplicateHandle(GetCurrentProcess(), handle, GetCurrentProcess(), 372 &wfd.handle, 0, TRUE, DUPLICATE_SAME_ACCESS)) { 373 usbi_dbg("could not duplicate handle for CancelIo - using original one"); 374 wfd.handle = handle; 375 // Make sure we won't close the original handle on fd deletion then 376 _poll_fd[i].original_handle = INVALID_HANDLE_VALUE; 377 } else { 378 _poll_fd[i].original_handle = handle; 379 } 380 } else { 381 wfd.handle = handle; 382 } 383 wfd.overlapped = overlapped; 384 memcpy(&poll_fd[i], &wfd, sizeof(struct winfd)); 385 LeaveCriticalSection(&_poll_fd[i].mutex); 386 return wfd; 387 } 388 } 389 free_overlapped(overlapped); 390 _close(fd); 391 return INVALID_WINFD; 392 } 393 394 void _free_index(int _index) 395 { 396 // Cancel any async IO (Don't care about the validity of our handles for this) 397 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) 404 if (!CancelIoEx_Available) { 405 if (_poll_fd[_index].original_handle != INVALID_HANDLE_VALUE) { 406 CloseHandle(poll_fd[_index].handle); 407 } 408 _poll_fd[_index].original_handle = INVALID_HANDLE_VALUE; 409 _poll_fd[_index].thread_id = 0; 410 } 411 free_overlapped(poll_fd[_index].overlapped); 412 poll_fd[_index] = INVALID_WINFD; 413 } 414 415 /* 416 * Release a pollable file descriptor. 417 * 418 * Note that the associated Windows handle is not closed by this call 419 */ 420 void usbi_free_fd(int fd) 421 { 422 int _index; 423 424 CHECK_INIT_POLLING; 425 426 _index = _fd_to_index_and_lock(fd); 427 if (_index < 0) { 428 return; 429 } 430 _free_index(_index); 431 LeaveCriticalSection(&_poll_fd[_index].mutex); 432 } 433 434 /* 435 * The functions below perform various conversions between fd, handle and OVERLAPPED 436 */ 437 struct winfd fd_to_winfd(int fd) 438 { 439 int i; 440 struct winfd wfd; 441 442 CHECK_INIT_POLLING; 443 444 if (fd <= 0) 445 return INVALID_WINFD; 446 447 for (i=0; i<MAX_FDS; i++) { 448 if (poll_fd[i].fd == fd) { 449 EnterCriticalSection(&_poll_fd[i].mutex); 450 // fd might have been deleted before we got to critical 451 if (poll_fd[i].fd != fd) { 452 LeaveCriticalSection(&_poll_fd[i].mutex); 453 continue; 454 } 455 memcpy(&wfd, &poll_fd[i], sizeof(struct winfd)); 456 LeaveCriticalSection(&_poll_fd[i].mutex); 457 return wfd; 458 } 459 } 460 return INVALID_WINFD; 461 } 462 463 struct winfd handle_to_winfd(HANDLE handle) 464 { 465 int i; 466 struct winfd wfd; 467 468 CHECK_INIT_POLLING; 469 470 if ((handle == 0) || (handle == INVALID_HANDLE_VALUE)) 471 return INVALID_WINFD; 472 473 for (i=0; i<MAX_FDS; i++) { 474 if (poll_fd[i].handle == handle) { 475 EnterCriticalSection(&_poll_fd[i].mutex); 476 // fd might have been deleted before we got to critical 477 if (poll_fd[i].handle != handle) { 478 LeaveCriticalSection(&_poll_fd[i].mutex); 479 continue; 480 } 481 memcpy(&wfd, &poll_fd[i], sizeof(struct winfd)); 482 LeaveCriticalSection(&_poll_fd[i].mutex); 483 return wfd; 484 } 485 } 486 return INVALID_WINFD; 487 } 488 489 struct winfd overlapped_to_winfd(OVERLAPPED* overlapped) 490 { 491 int i; 492 struct winfd wfd; 493 494 CHECK_INIT_POLLING; 495 496 if (overlapped == NULL) 497 return INVALID_WINFD; 498 499 for (i=0; i<MAX_FDS; i++) { 500 if (poll_fd[i].overlapped == overlapped) { 501 EnterCriticalSection(&_poll_fd[i].mutex); 502 // fd might have been deleted before we got to critical 503 if (poll_fd[i].overlapped != overlapped) { 504 LeaveCriticalSection(&_poll_fd[i].mutex); 505 continue; 506 } 507 memcpy(&wfd, &poll_fd[i], sizeof(struct winfd)); 508 LeaveCriticalSection(&_poll_fd[i].mutex); 509 return wfd; 510 } 511 } 512 return INVALID_WINFD; 513 } 514 515 /* 516 * POSIX poll equivalent, using Windows OVERLAPPED 517 * Currently, this function only accepts one of POLLIN or POLLOUT per fd 518 * (but you can create multiple fds from the same handle for read and write) 519 */ 520 int usbi_poll(struct pollfd *fds, unsigned int nfds, int timeout) 521 { 522 unsigned i; 523 int _index, object_index, triggered; 524 HANDLE *handles_to_wait_on; 525 int *handle_to_index; 526 DWORD nb_handles_to_wait_on = 0; 527 DWORD ret; 528 529 CHECK_INIT_POLLING; 530 531 triggered = 0; 532 handles_to_wait_on = (HANDLE*) calloc(nfds+1, sizeof(HANDLE)); // +1 for fd_update 533 handle_to_index = (int*) calloc(nfds, sizeof(int)); 534 if ((handles_to_wait_on == NULL) || (handle_to_index == NULL)) { 535 errno = ENOMEM; 536 triggered = -1; 537 goto poll_exit; 538 } 539 540 for (i = 0; i < nfds; ++i) { 541 fds[i].revents = 0; 542 543 // Only one of POLLIN or POLLOUT can be selected with this version of poll (not both) 544 if ((fds[i].events & ~POLLIN) && (!(fds[i].events & POLLOUT))) { 545 fds[i].revents |= POLLERR; 546 errno = EACCES; 547 usbi_warn(NULL, "unsupported set of events"); 548 triggered = -1; 549 goto poll_exit; 550 } 551 552 _index = _fd_to_index_and_lock(fds[i].fd); 553 poll_dbg("fd[%d]=%d: (overlapped=%p) got events %04X", i, poll_fd[_index].fd, poll_fd[_index].overlapped, fds[i].events); 554 555 if ( (_index < 0) || (poll_fd[_index].handle == INVALID_HANDLE_VALUE) 556 || (poll_fd[_index].handle == 0) || (poll_fd[_index].overlapped == NULL)) { 557 fds[i].revents |= POLLNVAL | POLLERR; 558 errno = EBADF; 559 if (_index >= 0) { 560 LeaveCriticalSection(&_poll_fd[_index].mutex); 561 } 562 usbi_warn(NULL, "invalid fd"); 563 triggered = -1; 564 goto poll_exit; 565 } 566 567 // IN or OUT must match our fd direction 568 if ((fds[i].events & POLLIN) && (poll_fd[_index].rw != RW_READ)) { 569 fds[i].revents |= POLLNVAL | POLLERR; 570 errno = EBADF; 571 usbi_warn(NULL, "attempted POLLIN on fd without READ access"); 572 LeaveCriticalSection(&_poll_fd[_index].mutex); 573 triggered = -1; 574 goto poll_exit; 575 } 576 577 if ((fds[i].events & POLLOUT) && (poll_fd[_index].rw != RW_WRITE)) { 578 fds[i].revents |= POLLNVAL | POLLERR; 579 errno = EBADF; 580 usbi_warn(NULL, "attempted POLLOUT on fd without WRITE access"); 581 LeaveCriticalSection(&_poll_fd[_index].mutex); 582 triggered = -1; 583 goto poll_exit; 584 } 585 586 // The following macro only works if overlapped I/O was reported pending 587 if ( (HasOverlappedIoCompleted(poll_fd[_index].overlapped)) 588 || (HasOverlappedIoCompletedSync(poll_fd[_index].overlapped)) ) { 589 poll_dbg(" completed"); 590 // checks above should ensure this works: 591 fds[i].revents = fds[i].events; 592 triggered++; 593 } else { 594 handles_to_wait_on[nb_handles_to_wait_on] = poll_fd[_index].overlapped->hEvent; 595 handle_to_index[nb_handles_to_wait_on] = i; 596 nb_handles_to_wait_on++; 597 } 598 LeaveCriticalSection(&_poll_fd[_index].mutex); 599 } 600 601 // If nothing was triggered, wait on all fds that require it 602 if ((timeout != 0) && (triggered == 0) && (nb_handles_to_wait_on != 0)) { 603 if (timeout < 0) { 604 poll_dbg("starting infinite wait for %d handles...", (int)nb_handles_to_wait_on); 605 } else { 606 poll_dbg("starting %d ms wait for %d handles...", timeout, (int)nb_handles_to_wait_on); 607 } 608 ret = WaitForMultipleObjects(nb_handles_to_wait_on, handles_to_wait_on, 609 FALSE, (timeout<0)?INFINITE:(DWORD)timeout); 610 object_index = ret-WAIT_OBJECT_0; 611 if ((object_index >= 0) && ((DWORD)object_index < nb_handles_to_wait_on)) { 612 poll_dbg(" completed after wait"); 613 i = handle_to_index[object_index]; 614 _index = _fd_to_index_and_lock(fds[i].fd); 615 fds[i].revents = fds[i].events; 616 triggered++; 617 if (_index >= 0) { 618 LeaveCriticalSection(&_poll_fd[_index].mutex); 619 } 620 } else if (ret == WAIT_TIMEOUT) { 621 poll_dbg(" timed out"); 622 triggered = 0; // 0 = timeout 623 } else { 624 errno = EIO; 625 triggered = -1; // error 626 } 627 } 628 629 poll_exit: 630 if (handles_to_wait_on != NULL) { 631 free(handles_to_wait_on); 632 } 633 if (handle_to_index != NULL) { 634 free(handle_to_index); 635 } 636 return triggered; 637 } 638 639 /* 640 * close a fake pipe fd 641 */ 642 int usbi_close(int fd) 643 { 644 int _index; 645 int r = -1; 646 647 CHECK_INIT_POLLING; 648 649 _index = _fd_to_index_and_lock(fd); 650 651 if (_index < 0) { 652 errno = EBADF; 653 } else { 654 if (poll_fd[_index].overlapped != NULL) { 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; 664 LeaveCriticalSection(&_poll_fd[_index].mutex); 665 } 666 return r; 667 } 668 669 /* 670 * synchronous write for fake "pipe" signaling 671 */ 672 ssize_t usbi_write(int fd, const void *buf, size_t count) 673 { 674 int _index; 675 676 CHECK_INIT_POLLING; 677 678 if (count != sizeof(unsigned char)) { 679 usbi_err(NULL, "this function should only used for signaling"); 680 return -1; 681 } 682 683 _index = _fd_to_index_and_lock(fd); 684 685 if ( (_index < 0) || (poll_fd[_index].overlapped == NULL) ) { 686 errno = EBADF; 687 if (_index >= 0) { 688 LeaveCriticalSection(&_poll_fd[_index].mutex); 689 } 690 return -1; 691 } 692 693 poll_dbg("set pipe event (fd = %d, thread = %08X)", _index, GetCurrentThreadId()); 694 SetEvent(poll_fd[_index].overlapped->hEvent); 695 poll_fd[_index].overlapped->Internal = STATUS_WAIT_0; 696 // If two threads write on the pipe at the same time, we need to 697 // process two separate reads => use the overlapped as a counter 698 poll_fd[_index].overlapped->InternalHigh++; 699 700 LeaveCriticalSection(&_poll_fd[_index].mutex); 701 return sizeof(unsigned char); 702 } 703 704 /* 705 * synchronous read for fake "pipe" signaling 706 */ 707 ssize_t usbi_read(int fd, void *buf, size_t count) 708 { 709 int _index; 710 ssize_t r = -1; 711 712 CHECK_INIT_POLLING; 713 714 if (count != sizeof(unsigned char)) { 715 usbi_err(NULL, "this function should only used for signaling"); 716 return -1; 717 } 718 719 _index = _fd_to_index_and_lock(fd); 720 721 if (_index < 0) { 722 errno = EBADF; 723 return -1; 724 } 725 726 if (WaitForSingleObject(poll_fd[_index].overlapped->hEvent, INFINITE) != WAIT_OBJECT_0) { 727 usbi_warn(NULL, "waiting for event failed: %d", (int)GetLastError()); 728 errno = EIO; 729 goto out; 730 } 731 732 poll_dbg("clr pipe event (fd = %d, thread = %08X)", _index, GetCurrentThreadId()); 733 poll_fd[_index].overlapped->InternalHigh--; 734 // Don't reset unless we don't have any more events to process 735 if (poll_fd[_index].overlapped->InternalHigh <= 0) { 736 ResetEvent(poll_fd[_index].overlapped->hEvent); 737 poll_fd[_index].overlapped->Internal = STATUS_PENDING; 738 } 739 740 r = sizeof(unsigned char); 741 742 out: 743 LeaveCriticalSection(&_poll_fd[_index].mutex); 744 return r; 745 } 746