Windows: Address MSVC Level 4 & WDK's OACR/Prefast warnings
[platform/upstream/libusb.git] / libusb / os / poll_windows.c
1 /*
2  * poll_windows: poll compatibility wrapper for Windows
3  * Copyright © 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 libusbx 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 ommitted.
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         InterlockedExchange((LONG *)&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         InterlockedExchange((LONG *)&compat_spinlock, 0);
241 }
242
243 /*
244  * Create a fake pipe.
245  * 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
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         UNUSED(buf);
676
677         CHECK_INIT_POLLING;
678
679         if (count != sizeof(unsigned char)) {
680                 usbi_err(NULL, "this function should only used for signaling");
681                 return -1;
682         }
683
684         _index = _fd_to_index_and_lock(fd);
685
686         if ( (_index < 0) || (poll_fd[_index].overlapped == NULL) ) {
687                 errno = EBADF;
688                 if (_index >= 0) {
689                         LeaveCriticalSection(&_poll_fd[_index].mutex);
690                 }
691                 return -1;
692         }
693
694         poll_dbg("set pipe event (fd = %d, thread = %08X)", _index, GetCurrentThreadId());
695         SetEvent(poll_fd[_index].overlapped->hEvent);
696         poll_fd[_index].overlapped->Internal = STATUS_WAIT_0;
697         // If two threads write on the pipe at the same time, we need to
698         // process two separate reads => use the overlapped as a counter
699         poll_fd[_index].overlapped->InternalHigh++;
700
701         LeaveCriticalSection(&_poll_fd[_index].mutex);
702         return sizeof(unsigned char);
703 }
704
705 /*
706  * synchronous read for fake "pipe" signaling
707  */
708 ssize_t usbi_read(int fd, void *buf, size_t count)
709 {
710         int _index;
711         ssize_t r = -1;
712         UNUSED(buf);
713
714         CHECK_INIT_POLLING;
715
716         if (count != sizeof(unsigned char)) {
717                 usbi_err(NULL, "this function should only used for signaling");
718                 return -1;
719         }
720
721         _index = _fd_to_index_and_lock(fd);
722
723         if (_index < 0) {
724                 errno = EBADF;
725                 return -1;
726         }
727
728         if (WaitForSingleObject(poll_fd[_index].overlapped->hEvent, INFINITE) != WAIT_OBJECT_0) {
729                 usbi_warn(NULL, "waiting for event failed: %d", (int)GetLastError());
730                 errno = EIO;
731                 goto out;
732         }
733
734         poll_dbg("clr pipe event (fd = %d, thread = %08X)", _index, GetCurrentThreadId());
735         poll_fd[_index].overlapped->InternalHigh--;
736         // Don't reset unless we don't have any more events to process
737         if (poll_fd[_index].overlapped->InternalHigh <= 0) {
738                 ResetEvent(poll_fd[_index].overlapped->hEvent);
739                 poll_fd[_index].overlapped->Internal = STATUS_PENDING;
740         }
741
742         r = sizeof(unsigned char);
743
744 out:
745         LeaveCriticalSection(&_poll_fd[_index].mutex);
746         return r;
747 }