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.
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.
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.
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
24 * poll() and pipe() Windows compatibility layer for libusb 1.0
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.
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
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
36 * - leave the core functions call the poll routine and flag POLLIN/POLLOUT
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
50 // Uncomment to debug the polling layer
51 //#define DEBUG_POLL_WINDOWS
52 #if defined(DEBUG_POLL_WINDOWS)
53 #define poll_dbg usbi_dbg
55 // MSVC6 cannot use a variadic argument and non MSVC
56 // compilers produce warnings if parenthesis are ommitted.
64 #if defined(_PREFAST_)
65 #pragma warning(disable:28719)
68 #if defined(__CYGWIN__)
69 // cygwin produces a warning unless these prototypes are defined
70 extern int _close(int fd);
71 extern int _snprintf(char *buffer, size_t count, const char *format, ...);
72 extern int cygwin_attach_handle_to_fd(char *name, int fd, HANDLE handle, int bin, int access_mode);
73 // _open_osfhandle() is not available on cygwin, but we can emulate
74 // it for our needs with cygwin_attach_handle_to_fd()
75 static inline int _open_osfhandle(intptr_t osfhandle, int flags)
80 access_mode = GENERIC_READ;
83 access_mode = GENERIC_WRITE;
86 access_mode = GENERIC_READ|GENERIC_WRITE;
89 usbi_err(NULL, "unsupported access mode");
92 return cygwin_attach_handle_to_fd("/dev/null", -1, (HANDLE)osfhandle, -1, access_mode);
96 #define CHECK_INIT_POLLING do {if(!is_polling_set) init_polling();} while(0)
99 const struct winfd INVALID_WINFD = {-1, INVALID_HANDLE_VALUE, NULL, RW_NONE};
100 struct winfd poll_fd[MAX_FDS];
103 CRITICAL_SECTION mutex; // lock for fds
104 // Additional variables for XP CancelIoEx partial emulation
105 HANDLE original_handle;
110 BOOLEAN is_polling_set = FALSE;
111 #if defined(DYNAMIC_FDS)
112 HANDLE fd_update = INVALID_HANDLE_VALUE; // event to notify poll of fd update
113 HANDLE new_fd[MAX_FDS]; // overlapped event handles for fds created since last poll
114 unsigned nb_new_fds = 0; // nb new fds created since last poll
115 usbi_mutex_t new_fd_mutex; // mutex required for the above
117 LONG pipe_number = 0;
118 static volatile LONG compat_spinlock = 0;
120 // CancelIoEx, available on Vista and later only, provides the ability to cancel
121 // a single transfer (OVERLAPPED) when used. As it may not be part of any of the
122 // platform headers, we hook into the Kernel32 system DLL directly to seek it.
123 static BOOL (__stdcall *pCancelIoEx)(HANDLE, LPOVERLAPPED) = NULL;
124 #define CancelIoEx_Available (pCancelIoEx != NULL)
125 __inline BOOL cancel_io(int _index)
127 if ((_index < 0) || (_index >= MAX_FDS)) {
131 if ( (poll_fd[_index].fd < 0) || (poll_fd[_index].handle == INVALID_HANDLE_VALUE)
132 || (poll_fd[_index].handle == 0) || (poll_fd[_index].overlapped == NULL) ) {
135 if (CancelIoEx_Available) {
136 return (*pCancelIoEx)(poll_fd[_index].handle, poll_fd[_index].overlapped);
138 if (_poll_fd[_index].thread_id == GetCurrentThreadId()) {
139 return CancelIo(poll_fd[_index].handle);
141 usbi_warn(NULL, "Unable to cancel I/O that was started from another thread");
146 void init_polling(void)
150 while (InterlockedExchange((LONG *)&compat_spinlock, 1) == 1) {
153 if (!is_polling_set) {
154 pCancelIoEx = (BOOL (__stdcall *)(HANDLE,LPOVERLAPPED))
155 GetProcAddress(GetModuleHandle("KERNEL32"), "CancelIoEx");
156 usbi_dbg("Will use CancelIo%s for I/O cancellation",
157 CancelIoEx_Available?"Ex":"");
158 for (i=0; i<MAX_FDS; i++) {
159 poll_fd[i] = INVALID_WINFD;
160 _poll_fd[i].original_handle = INVALID_HANDLE_VALUE;
161 _poll_fd[i].thread_id = 0;
162 InitializeCriticalSection(&_poll_fd[i].mutex);
164 #if defined(DYNAMIC_FDS)
165 // We need to create an update event so that poll is warned when there
166 // are new/deleted fds during a timeout wait operation
167 fd_update = CreateEvent(NULL, TRUE, FALSE, NULL);
168 if (fd_update == NULL) {
169 usbi_err(NULL, "unable to create update event");
171 usbi_mutex_init(&new_fd_mutex, NULL);
174 is_polling_set = TRUE;
179 // Internal function to retrieve the table index (and lock the fd mutex)
180 int _fd_to_index_and_lock(int fd)
187 for (i=0; i<MAX_FDS; i++) {
188 if (poll_fd[i].fd == fd) {
189 EnterCriticalSection(&_poll_fd[i].mutex);
190 // fd might have changed before we got to critical
191 if (poll_fd[i].fd != fd) {
192 LeaveCriticalSection(&_poll_fd[i].mutex);
201 OVERLAPPED *create_overlapped(void)
203 OVERLAPPED *overlapped = calloc(1, sizeof(OVERLAPPED));
204 if (overlapped == NULL) {
207 overlapped->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
208 if(overlapped->hEvent == NULL) {
215 void free_overlapped(OVERLAPPED *overlapped)
217 if (overlapped == NULL)
220 if ( (overlapped->hEvent != 0)
221 && (overlapped->hEvent != INVALID_HANDLE_VALUE) ) {
222 CloseHandle(overlapped->hEvent);
227 void reset_overlapped(OVERLAPPED *overlapped)
230 if (overlapped == NULL)
233 event_handle = overlapped->hEvent;
234 if (event_handle != NULL) {
235 ResetEvent(event_handle);
237 memset(overlapped, 0, sizeof(OVERLAPPED));
238 overlapped->hEvent = event_handle;
241 void exit_polling(void)
245 while (InterlockedExchange((LONG *)&compat_spinlock, 1) == 1) {
248 if (is_polling_set) {
249 is_polling_set = FALSE;
251 for (i=0; i<MAX_FDS; i++) {
252 // Cancel any async I/O (handle can be invalid)
254 // If anything was pending on that I/O, it should be
255 // terminating, and we should be able to access the fd
256 // mutex lock before too long
257 EnterCriticalSection(&_poll_fd[i].mutex);
258 if ( (poll_fd[i].fd > 0) && (poll_fd[i].handle != INVALID_HANDLE_VALUE) && (poll_fd[i].handle != 0)
259 && (GetFileType(poll_fd[i].handle) == FILE_TYPE_UNKNOWN) ) {
260 _close(poll_fd[i].fd);
262 free_overlapped(poll_fd[i].overlapped);
263 if (!CancelIoEx_Available) {
264 // Close duplicate handle
265 if (_poll_fd[i].original_handle != INVALID_HANDLE_VALUE) {
266 CloseHandle(poll_fd[i].handle);
269 poll_fd[i] = INVALID_WINFD;
270 #if defined(DYNAMIC_FDS)
271 usbi_mutex_destroy(&new_fd_mutex);
272 CloseHandle(fd_update);
273 fd_update = INVALID_HANDLE_VALUE;
275 LeaveCriticalSection(&_poll_fd[i].mutex);
276 DeleteCriticalSection(&_poll_fd[i].mutex);
283 * Create a fake pipe.
284 * As libusb only uses pipes for signaling, all we need from a pipe is an
285 * event. To that extent, we create a single wfd and overlapped as a means
286 * to access that event.
288 int usbi_pipe(int filedes[2])
292 OVERLAPPED* overlapped;
296 overlapped = calloc(1, sizeof(OVERLAPPED));
297 if (overlapped == NULL) {
300 // The overlapped must have status pending for signaling to work in poll
301 overlapped->Internal = STATUS_PENDING;
302 overlapped->InternalHigh = 0;
304 // Read end of the "pipe"
305 handle = CreateFileA("NUL", 0, 0, NULL, OPEN_EXISTING, 0, NULL);
306 if (handle == INVALID_HANDLE_VALUE) {
307 usbi_err(NULL, "could not create pipe: errcode %d", (int)GetLastError());
310 filedes[0] = _open_osfhandle((intptr_t)handle, _O_RDONLY);
311 // We can use the same handle for both ends
312 filedes[1] = filedes[0];
313 poll_dbg("pipe filedes = %d", filedes[0]);
315 // Note: manual reset must be true (second param) as the reset occurs in read
316 overlapped->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
317 if(!overlapped->hEvent) {
321 for (i=0; i<MAX_FDS; i++) {
322 if (poll_fd[i].fd < 0) {
323 EnterCriticalSection(&_poll_fd[i].mutex);
324 // fd might have been allocated before we got to critical
325 if (poll_fd[i].fd >= 0) {
326 LeaveCriticalSection(&_poll_fd[i].mutex);
330 poll_fd[i].fd = filedes[0];
331 poll_fd[i].handle = handle;
332 poll_fd[i].overlapped = overlapped;
333 // There's no polling on the write end, so we just use READ for our needs
334 poll_fd[i].rw = RW_READ;
335 _poll_fd[i].original_handle = INVALID_HANDLE_VALUE;
336 LeaveCriticalSection(&_poll_fd[i].mutex);
341 CloseHandle(overlapped->hEvent);
350 * Create both an fd and an OVERLAPPED from an open Windows handle, so that
351 * it can be used with our polling function
352 * The handle MUST support overlapped transfers (usually requires CreateFile
353 * with FILE_FLAG_OVERLAPPED)
354 * Return a pollable file descriptor struct, or INVALID_WINFD on error
356 * Note that the fd returned by this function is a per-transfer fd, rather
357 * than a per-session fd and cannot be used for anything else but our
358 * custom functions (the fd itself points to the NUL: device)
359 * if you plan to do R/W on the same handle, you MUST create 2 fds: one for
360 * read and one for write. Using a single R/W fd is unsupported and will
361 * produce unexpected results
363 struct winfd usbi_create_fd(HANDLE handle, int access_mode)
366 struct winfd wfd = INVALID_WINFD;
367 OVERLAPPED* overlapped = NULL;
371 if ((handle == 0) || (handle == INVALID_HANDLE_VALUE)) {
372 return INVALID_WINFD;
375 if ((access_mode != _O_RDONLY) && (access_mode != _O_WRONLY)) {
376 usbi_warn(NULL, "only one of _O_RDONLY or _O_WRONLY are supported.\n"
377 "If you want to poll for R/W simultaneously, create multiple fds from the same handle.");
378 return INVALID_WINFD;
380 if (access_mode == _O_RDONLY) {
386 // Ensure that we get a non system conflicting unique fd
387 fd = _open_osfhandle((intptr_t)CreateFileA("NUL", 0, 0,
388 NULL, OPEN_EXISTING, 0, NULL), _O_RDWR);
390 return INVALID_WINFD;
393 overlapped = create_overlapped();
394 if(overlapped == NULL) {
396 return INVALID_WINFD;
399 for (i=0; i<MAX_FDS; i++) {
400 if (poll_fd[i].fd < 0) {
401 EnterCriticalSection(&_poll_fd[i].mutex);
402 // fd might have been removed before we got to critical
403 if (poll_fd[i].fd >= 0) {
404 LeaveCriticalSection(&_poll_fd[i].mutex);
408 // Attempt to emulate some of the CancelIoEx behaviour on platforms
409 // that don't have it
410 if (!CancelIoEx_Available) {
411 _poll_fd[i].thread_id = GetCurrentThreadId();
412 if (!DuplicateHandle(GetCurrentProcess(), handle, GetCurrentProcess(),
413 &wfd.handle, 0, TRUE, DUPLICATE_SAME_ACCESS)) {
414 usbi_dbg("could not duplicate handle for CancelIo - using original one");
416 // Make sure we won't close the original handle on fd deletion then
417 _poll_fd[i].original_handle = INVALID_HANDLE_VALUE;
419 _poll_fd[i].original_handle = handle;
424 wfd.overlapped = overlapped;
425 memcpy(&poll_fd[i], &wfd, sizeof(struct winfd));
426 LeaveCriticalSection(&_poll_fd[i].mutex);
427 #if defined(DYNAMIC_FDS)
428 usbi_mutex_lock(&new_fd_mutex);
429 new_fd[nb_new_fds++] = overlapped->hEvent;
430 usbi_mutex_unlock(&new_fd_mutex);
431 // Notify poll that fds have been updated
437 free_overlapped(overlapped);
439 return INVALID_WINFD;
442 void _free_index(int _index)
444 // Cancel any async IO (Don't care about the validity of our handles for this)
446 // close fake handle for devices
447 if ( (poll_fd[_index].handle != INVALID_HANDLE_VALUE) && (poll_fd[_index].handle != 0)
448 && (GetFileType(poll_fd[_index].handle) == FILE_TYPE_UNKNOWN) ) {
449 _close(poll_fd[_index].fd);
451 // close the duplicate handle (if we have an actual duplicate)
452 if (!CancelIoEx_Available) {
453 if (_poll_fd[_index].original_handle != INVALID_HANDLE_VALUE) {
454 CloseHandle(poll_fd[_index].handle);
456 _poll_fd[_index].original_handle = INVALID_HANDLE_VALUE;
457 _poll_fd[_index].thread_id = 0;
459 free_overlapped(poll_fd[_index].overlapped);
460 poll_fd[_index] = INVALID_WINFD;
464 * Release a pollable file descriptor.
466 * Note that the associated Windows handle is not closed by this call
468 void usbi_free_fd(int fd)
474 _index = _fd_to_index_and_lock(fd);
479 LeaveCriticalSection(&_poll_fd[_index].mutex);
483 * The functions below perform various conversions between fd, handle and OVERLAPPED
485 struct winfd fd_to_winfd(int fd)
493 return INVALID_WINFD;
495 for (i=0; i<MAX_FDS; i++) {
496 if (poll_fd[i].fd == fd) {
497 EnterCriticalSection(&_poll_fd[i].mutex);
498 // fd might have been deleted before we got to critical
499 if (poll_fd[i].fd != fd) {
500 LeaveCriticalSection(&_poll_fd[i].mutex);
503 memcpy(&wfd, &poll_fd[i], sizeof(struct winfd));
504 LeaveCriticalSection(&_poll_fd[i].mutex);
508 return INVALID_WINFD;
511 struct winfd handle_to_winfd(HANDLE handle)
518 if ((handle == 0) || (handle == INVALID_HANDLE_VALUE))
519 return INVALID_WINFD;
521 for (i=0; i<MAX_FDS; i++) {
522 if (poll_fd[i].handle == handle) {
523 EnterCriticalSection(&_poll_fd[i].mutex);
524 // fd might have been deleted before we got to critical
525 if (poll_fd[i].handle != handle) {
526 LeaveCriticalSection(&_poll_fd[i].mutex);
529 memcpy(&wfd, &poll_fd[i], sizeof(struct winfd));
530 LeaveCriticalSection(&_poll_fd[i].mutex);
534 return INVALID_WINFD;
537 struct winfd overlapped_to_winfd(OVERLAPPED* overlapped)
544 if (overlapped == NULL)
545 return INVALID_WINFD;
547 for (i=0; i<MAX_FDS; i++) {
548 if (poll_fd[i].overlapped == overlapped) {
549 EnterCriticalSection(&_poll_fd[i].mutex);
550 // fd might have been deleted before we got to critical
551 if (poll_fd[i].overlapped != overlapped) {
552 LeaveCriticalSection(&_poll_fd[i].mutex);
555 memcpy(&wfd, &poll_fd[i], sizeof(struct winfd));
556 LeaveCriticalSection(&_poll_fd[i].mutex);
560 return INVALID_WINFD;
564 * POSIX poll equivalent, using Windows OVERLAPPED
565 * Currently, this function only accepts one of POLLIN or POLLOUT per fd
566 * (but you can create multiple fds from the same handle for read and write)
568 int usbi_poll(struct pollfd *fds, unsigned int nfds, int timeout)
571 int _index, object_index, triggered;
572 HANDLE *handles_to_wait_on;
573 int *handle_to_index;
574 DWORD nb_handles_to_wait_on = 0;
577 #if defined(DYNAMIC_FDS)
578 DWORD nb_extra_handles = 0;
581 // To address the possibility of missing new fds between the time the new
582 // pollable fd set is assembled, and the ResetEvent() call below, an
583 // additional new_fd[] HANDLE table is used for any new fd that was created
584 // since the last call to poll (see below)
585 ResetEvent(fd_update);
587 // At this stage, any new fd creation will be detected through the fd_update
588 // event notification, and any previous creation that we may have missed
589 // will be picked up through the existing new_fd[] table.
595 handles_to_wait_on = malloc((nfds+1)*sizeof(HANDLE)); // +1 for fd_update
596 handle_to_index = malloc(nfds*sizeof(int));
597 if ((handles_to_wait_on == NULL) || (handle_to_index == NULL)) {
603 for (i = 0; i < nfds; ++i) {
606 // Only one of POLLIN or POLLOUT can be selected with this version of poll (not both)
607 if ((fds[i].events & ~POLLIN) && (!(fds[i].events & POLLOUT))) {
608 fds[i].revents |= POLLERR;
610 usbi_warn(NULL, "unsupported set of events");
615 _index = _fd_to_index_and_lock(fds[i].fd);
616 poll_dbg("fd[%d]=%d: (overlapped=%p) got events %04X", i, poll_fd[_index].fd, poll_fd[_index].overlapped, fds[i].events);
618 if ( (_index < 0) || (poll_fd[_index].handle == INVALID_HANDLE_VALUE)
619 || (poll_fd[_index].handle == 0) || (poll_fd[_index].overlapped == NULL)) {
620 fds[i].revents |= POLLNVAL | POLLERR;
623 LeaveCriticalSection(&_poll_fd[_index].mutex);
625 usbi_warn(NULL, "invalid fd");
630 // IN or OUT must match our fd direction
631 if ((fds[i].events & POLLIN) && (poll_fd[_index].rw != RW_READ)) {
632 fds[i].revents |= POLLNVAL | POLLERR;
634 usbi_warn(NULL, "attempted POLLIN on fd without READ access");
635 LeaveCriticalSection(&_poll_fd[_index].mutex);
640 if ((fds[i].events & POLLOUT) && (poll_fd[_index].rw != RW_WRITE)) {
641 fds[i].revents |= POLLNVAL | POLLERR;
643 usbi_warn(NULL, "attempted POLLOUT on fd without WRITE access");
644 LeaveCriticalSection(&_poll_fd[_index].mutex);
649 // The following macro only works if overlapped I/O was reported pending
650 if ( (HasOverlappedIoCompleted(poll_fd[_index].overlapped))
651 || (HasOverlappedIoCompletedSync(poll_fd[_index].overlapped)) ) {
652 poll_dbg(" completed");
653 // checks above should ensure this works:
654 fds[i].revents = fds[i].events;
657 handles_to_wait_on[nb_handles_to_wait_on] = poll_fd[_index].overlapped->hEvent;
658 handle_to_index[nb_handles_to_wait_on] = i;
659 #if defined(DYNAMIC_FDS)
660 // If this fd from the poll set is also part of the new_fd event handle table, remove it
661 usbi_mutex_lock(&new_fd_mutex);
662 for (j=0; j<nb_new_fds; j++) {
663 if (handles_to_wait_on[nb_handles_to_wait_on] == new_fd[j]) {
664 new_fd[j] = INVALID_HANDLE_VALUE;
668 usbi_mutex_unlock(&new_fd_mutex);
670 nb_handles_to_wait_on++;
672 LeaveCriticalSection(&_poll_fd[_index].mutex);
674 #if defined(DYNAMIC_FDS)
675 // At this stage, new_fd[] should only contain events from fds that
676 // have been added since the last call to poll, but are not (yet) part
677 // of the pollable fd set. Typically, these would be from fds that have
678 // been created between the construction of the fd set and the calling
680 // Event if we won't be able to return usable poll data on these events,
681 // make sure we monitor them to return an EINTR code
682 usbi_mutex_lock(&new_fd_mutex); // We could probably do without
683 for (i=0; i<nb_new_fds; i++) {
684 if (new_fd[i] != INVALID_HANDLE_VALUE) {
685 handles_to_wait_on[nb_handles_to_wait_on++] = new_fd[i];
689 usbi_mutex_unlock(&new_fd_mutex);
690 poll_dbg("dynamic_fds: added %d extra handles", nb_extra_handles);
693 // If nothing was triggered, wait on all fds that require it
694 if ((timeout != 0) && (triggered == 0) && (nb_handles_to_wait_on != 0)) {
695 #if defined(DYNAMIC_FDS)
696 // Register for fd update notifications
697 handles_to_wait_on[nb_handles_to_wait_on++] = fd_update;
701 poll_dbg("starting infinite wait for %d handles...", (int)nb_handles_to_wait_on);
703 poll_dbg("starting %d ms wait for %d handles...", timeout, (int)nb_handles_to_wait_on);
705 ret = WaitForMultipleObjects(nb_handles_to_wait_on, handles_to_wait_on,
706 FALSE, (timeout<0)?INFINITE:(DWORD)timeout);
707 object_index = ret-WAIT_OBJECT_0;
708 if ((object_index >= 0) && ((DWORD)object_index < nb_handles_to_wait_on)) {
709 #if defined(DYNAMIC_FDS)
710 if ((DWORD)object_index >= (nb_handles_to_wait_on-nb_extra_handles)) {
711 // Detected fd update => flag a poll interruption
712 if ((DWORD)object_index == (nb_handles_to_wait_on-1))
713 poll_dbg(" dynamic_fds: fd_update event");
715 poll_dbg(" dynamic_fds: new fd I/O event");
721 poll_dbg(" completed after wait");
722 i = handle_to_index[object_index];
723 _index = _fd_to_index_and_lock(fds[i].fd);
724 fds[i].revents = fds[i].events;
727 LeaveCriticalSection(&_poll_fd[_index].mutex);
729 } else if (ret == WAIT_TIMEOUT) {
730 poll_dbg(" timed out");
731 triggered = 0; // 0 = timeout
734 triggered = -1; // error
739 if (handles_to_wait_on != NULL) {
740 free(handles_to_wait_on);
742 if (handle_to_index != NULL) {
743 free(handle_to_index);
745 #if defined(DYNAMIC_FDS)
746 usbi_mutex_lock(&new_fd_mutex);
748 usbi_mutex_unlock(&new_fd_mutex);
754 * close a fake pipe fd
756 int usbi_close(int fd)
763 _index = _fd_to_index_and_lock(fd);
768 if (poll_fd[_index].overlapped != NULL) {
769 // Must be a different event for each end of the pipe
770 CloseHandle(poll_fd[_index].overlapped->hEvent);
771 free(poll_fd[_index].overlapped);
773 if (CloseHandle(poll_fd[_index].handle) == 0) {
778 poll_fd[_index] = INVALID_WINFD;
779 LeaveCriticalSection(&_poll_fd[_index].mutex);
785 * synchronous write for fake "pipe" signaling
787 ssize_t usbi_write(int fd, const void *buf, size_t count)
793 if (count != sizeof(unsigned char)) {
794 usbi_err(NULL, "this function should only used for signaling");
798 _index = _fd_to_index_and_lock(fd);
800 if ( (_index < 0) || (poll_fd[_index].overlapped == NULL) ) {
803 LeaveCriticalSection(&_poll_fd[_index].mutex);
808 poll_dbg("set pipe event (fd = %d, thread = %08X)", _index, GetCurrentThreadId());
809 SetEvent(poll_fd[_index].overlapped->hEvent);
810 poll_fd[_index].overlapped->Internal = STATUS_WAIT_0;
811 // If two threads write on the pipe at the same time, we need to
812 // process two separate reads => use the overlapped as a counter
813 poll_fd[_index].overlapped->InternalHigh++;
815 LeaveCriticalSection(&_poll_fd[_index].mutex);
816 return sizeof(unsigned char);
820 * synchronous read for fake "pipe" signaling
822 ssize_t usbi_read(int fd, void *buf, size_t count)
829 if (count != sizeof(unsigned char)) {
830 usbi_err(NULL, "this function should only used for signaling");
834 _index = _fd_to_index_and_lock(fd);
841 if (WaitForSingleObject(poll_fd[_index].overlapped->hEvent, INFINITE) != WAIT_OBJECT_0) {
842 usbi_warn(NULL, "waiting for event failed: %d", (int)GetLastError());
847 poll_dbg("clr pipe event (fd = %d, thread = %08X)", _index, GetCurrentThreadId());
848 poll_fd[_index].overlapped->InternalHigh--;
849 // Don't reset unless we don't have any more events to process
850 if (poll_fd[_index].overlapped->InternalHigh <= 0) {
851 ResetEvent(poll_fd[_index].overlapped->hEvent);
852 poll_fd[_index].overlapped->Internal = STATUS_PENDING;
855 r = sizeof(unsigned char);
858 LeaveCriticalSection(&_poll_fd[_index].mutex);