Windows: Fix multiple warnings
[platform/upstream/libusb.git] / libusb / os / poll_windows.c
1 /*
2  * poll_windows: poll compatibility wrapper for Windows
3  * Copyright © 2012-2013 RealVNC Ltd.
4  * Copyright © 2009-2010 Pete Batard <pete@akeo.ie>
5  * With contributions from Michael Plante, Orin Eman et al.
6  * Parts of poll implementation from libusb-win32, by Stephan Meyer et al.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  *
22  */
23
24 /*
25  * poll() and pipe() Windows compatibility layer for libusbx 1.0
26  *
27  * The way this layer works is by using OVERLAPPED with async I/O transfers, as
28  * OVERLAPPED have an associated event which is flagged for I/O completion.
29  *
30  * For USB pollable async I/O, you would typically:
31  * - obtain a Windows HANDLE to a file or device that has been opened in
32  *   OVERLAPPED mode
33  * - call usbi_create_fd with this handle to obtain a custom fd.
34  *   Note that if you need simultaneous R/W access, you need to call create_fd
35  *   twice, once in RW_READ and once in RW_WRITE mode to obtain 2 separate
36  *   pollable fds
37  * - leave the core functions call the poll routine and flag POLLIN/POLLOUT
38  *
39  * The pipe pollable synchronous I/O works using the overlapped event associated
40  * with a fake pipe. The read/write functions are only meant to be used in that
41  * context.
42  */
43 #include <errno.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46
47 #include "libusbi.h"
48
49 // Uncomment to debug the polling layer
50 //#define DEBUG_POLL_WINDOWS
51 #if defined(DEBUG_POLL_WINDOWS)
52 #define poll_dbg usbi_dbg
53 #else
54 // MSVC++ < 2005 cannot use a variadic argument and non MSVC
55 // compilers produce warnings if parenthesis are ommitted.
56 #if defined(_MSC_VER) && (_MSC_VER < 1400)
57 #define poll_dbg
58 #else
59 #define poll_dbg(...)
60 #endif
61 #endif
62
63 #if defined(_PREFAST_)
64 #pragma warning(disable:28719)
65 #endif
66
67 #define CHECK_INIT_POLLING do {if(!is_polling_set) init_polling();} while(0)
68
69 // public fd data
70 const struct winfd INVALID_WINFD = {-1, INVALID_HANDLE_VALUE, NULL, NULL, NULL, RW_NONE};
71 struct winfd poll_fd[MAX_FDS];
72 // internal fd data
73 struct {
74         CRITICAL_SECTION mutex; // lock for fds
75         // Additional variables for XP CancelIoEx partial emulation
76         HANDLE original_handle;
77         DWORD thread_id;
78 } _poll_fd[MAX_FDS];
79
80 // globals
81 BOOLEAN is_polling_set = FALSE;
82 LONG pipe_number = 0;
83 static volatile LONG compat_spinlock = 0;
84
85 #if !defined(_WIN32_WCE)
86 // CancelIoEx, available on Vista and later only, provides the ability to cancel
87 // a single transfer (OVERLAPPED) when used. As it may not be part of any of the
88 // platform headers, we hook into the Kernel32 system DLL directly to seek it.
89 static BOOL (__stdcall *pCancelIoEx)(HANDLE, LPOVERLAPPED) = NULL;
90 #define Use_Duplicate_Handles (pCancelIoEx == NULL)
91
92 static inline void setup_cancel_io(void)
93 {
94         HMODULE hKernel32 = GetModuleHandleA("KERNEL32");
95         if (hKernel32 != NULL) {
96                 pCancelIoEx = (BOOL (__stdcall *)(HANDLE,LPOVERLAPPED))
97                         GetProcAddress(hKernel32, "CancelIoEx");
98         }
99         usbi_dbg("Will use CancelIo%s for I/O cancellation",
100                 Use_Duplicate_Handles?"":"Ex");
101 }
102
103 static inline BOOL cancel_io(int _index)
104 {
105         if ((_index < 0) || (_index >= MAX_FDS)) {
106                 return FALSE;
107         }
108
109         if ( (poll_fd[_index].fd < 0) || (poll_fd[_index].handle == INVALID_HANDLE_VALUE)
110           || (poll_fd[_index].handle == 0) || (poll_fd[_index].overlapped == NULL) ) {
111                 return TRUE;
112         }
113         if (poll_fd[_index].itransfer && poll_fd[_index].cancel_fn) {
114                 // Cancel outstanding transfer via the specific callback
115                 (*poll_fd[_index].cancel_fn)(poll_fd[_index].itransfer);
116                 return TRUE;
117         }
118         if (pCancelIoEx != NULL) {
119                 return (*pCancelIoEx)(poll_fd[_index].handle, poll_fd[_index].overlapped);
120         }
121         if (_poll_fd[_index].thread_id == GetCurrentThreadId()) {
122                 return CancelIo(poll_fd[_index].handle);
123         }
124         usbi_warn(NULL, "Unable to cancel I/O that was started from another thread");
125         return FALSE;
126 }
127 #else
128 #define Use_Duplicate_Handles FALSE
129
130 static __inline void setup_cancel_io()
131 {
132         // No setup needed on WinCE
133 }
134
135 static __inline BOOL cancel_io(int _index)
136 {
137         if ((_index < 0) || (_index >= MAX_FDS)) {
138                 return FALSE;
139         }
140         if ( (poll_fd[_index].fd < 0) || (poll_fd[_index].handle == INVALID_HANDLE_VALUE)
141           || (poll_fd[_index].handle == 0) || (poll_fd[_index].overlapped == NULL) ) {
142                 return TRUE;
143         }
144         if (poll_fd[_index].itransfer && poll_fd[_index].cancel_fn) {
145                 // Cancel outstanding transfer via the specific callback
146                 (*poll_fd[_index].cancel_fn)(poll_fd[_index].itransfer);
147         }
148         return TRUE;
149 }
150 #endif
151
152 // Init
153 void init_polling(void)
154 {
155         int i;
156
157         while (InterlockedExchange((LONG *)&compat_spinlock, 1) == 1) {
158                 SleepEx(0, TRUE);
159         }
160         if (!is_polling_set) {
161                 setup_cancel_io();
162                 for (i=0; i<MAX_FDS; i++) {
163                         poll_fd[i] = INVALID_WINFD;
164                         _poll_fd[i].original_handle = INVALID_HANDLE_VALUE;
165                         _poll_fd[i].thread_id = 0;
166                         InitializeCriticalSection(&_poll_fd[i].mutex);
167                 }
168                 is_polling_set = TRUE;
169         }
170         InterlockedExchange((LONG *)&compat_spinlock, 0);
171 }
172
173 // Internal function to retrieve the table index (and lock the fd mutex)
174 static int _fd_to_index_and_lock(int fd)
175 {
176         int i;
177
178         if (fd < 0)
179                 return -1;
180
181         for (i=0; i<MAX_FDS; i++) {
182                 if (poll_fd[i].fd == fd) {
183                         EnterCriticalSection(&_poll_fd[i].mutex);
184                         // fd might have changed before we got to critical
185                         if (poll_fd[i].fd != fd) {
186                                 LeaveCriticalSection(&_poll_fd[i].mutex);
187                                 continue;
188                         }
189                         return i;
190                 }
191         }
192         return -1;
193 }
194
195 static OVERLAPPED *create_overlapped(void)
196 {
197         OVERLAPPED *overlapped = (OVERLAPPED*) calloc(1, sizeof(OVERLAPPED));
198         if (overlapped == NULL) {
199                 return NULL;
200         }
201         overlapped->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
202         if(overlapped->hEvent == NULL) {
203                 free (overlapped);
204                 return NULL;
205         }
206         return overlapped;
207 }
208
209 static void free_overlapped(OVERLAPPED *overlapped)
210 {
211         if (overlapped == NULL)
212                 return;
213
214         if ( (overlapped->hEvent != 0)
215           && (overlapped->hEvent != INVALID_HANDLE_VALUE) ) {
216                 CloseHandle(overlapped->hEvent);
217         }
218         free(overlapped);
219 }
220
221 void exit_polling(void)
222 {
223         int i;
224
225         while (InterlockedExchange((LONG *)&compat_spinlock, 1) == 1) {
226                 SleepEx(0, TRUE);
227         }
228         if (is_polling_set) {
229                 is_polling_set = FALSE;
230
231                 for (i=0; i<MAX_FDS; i++) {
232                         // Cancel any async I/O (handle can be invalid)
233                         cancel_io(i);
234                         // If anything was pending on that I/O, it should be
235                         // terminating, and we should be able to access the fd
236                         // mutex lock before too long
237                         EnterCriticalSection(&_poll_fd[i].mutex);
238                         free_overlapped(poll_fd[i].overlapped);
239                         if (Use_Duplicate_Handles) {
240                                 // Close duplicate handle
241                                 if (_poll_fd[i].original_handle != INVALID_HANDLE_VALUE) {
242                                         CloseHandle(poll_fd[i].handle);
243                                 }
244                         }
245                         poll_fd[i] = INVALID_WINFD;
246                         LeaveCriticalSection(&_poll_fd[i].mutex);
247                         DeleteCriticalSection(&_poll_fd[i].mutex);
248                 }
249         }
250         InterlockedExchange((LONG *)&compat_spinlock, 0);
251 }
252
253 /*
254  * Create a fake pipe.
255  * As libusbx only uses pipes for signaling, all we need from a pipe is an
256  * event. To that extent, we create a single wfd and overlapped as a means
257  * to access that event.
258  */
259 int usbi_pipe(int filedes[2])
260 {
261         int i;
262         OVERLAPPED* overlapped;
263
264         CHECK_INIT_POLLING;
265
266         overlapped = create_overlapped();
267
268         if (overlapped == NULL) {
269                 return -1;
270         }
271         // The overlapped must have status pending for signaling to work in poll
272         overlapped->Internal = STATUS_PENDING;
273         overlapped->InternalHigh = 0;
274
275         for (i=0; i<MAX_FDS; i++) {
276                 if (poll_fd[i].fd < 0) {
277                         EnterCriticalSection(&_poll_fd[i].mutex);
278                         // fd might have been allocated before we got to critical
279                         if (poll_fd[i].fd >= 0) {
280                                 LeaveCriticalSection(&_poll_fd[i].mutex);
281                                 continue;
282                         }
283
284                         // Use index as the unique fd number
285                         poll_fd[i].fd = i;
286                         // Read end of the "pipe"
287                         filedes[0] = poll_fd[i].fd;
288                         // We can use the same handle for both ends
289                         filedes[1] = filedes[0];
290
291                         poll_fd[i].handle = DUMMY_HANDLE;
292                         poll_fd[i].overlapped = overlapped;
293                         // There's no polling on the write end, so we just use READ for our needs
294                         poll_fd[i].rw = RW_READ;
295                         _poll_fd[i].original_handle = INVALID_HANDLE_VALUE;
296                         LeaveCriticalSection(&_poll_fd[i].mutex);
297                         return 0;
298                 }
299         }
300         free_overlapped(overlapped);
301         return -1;
302 }
303
304 /*
305  * Create both an fd and an OVERLAPPED from an open Windows handle, so that
306  * it can be used with our polling function
307  * The handle MUST support overlapped transfers (usually requires CreateFile
308  * with FILE_FLAG_OVERLAPPED)
309  * Return a pollable file descriptor struct, or INVALID_WINFD on error
310  *
311  * Note that the fd returned by this function is a per-transfer fd, rather
312  * than a per-session fd and cannot be used for anything else but our
313  * custom functions (the fd itself points to the NUL: device)
314  * if you plan to do R/W on the same handle, you MUST create 2 fds: one for
315  * read and one for write. Using a single R/W fd is unsupported and will
316  * produce unexpected results
317  */
318 struct winfd usbi_create_fd(HANDLE handle, int access_mode, struct usbi_transfer *itransfer, cancel_transfer *cancel_fn)
319 {
320         int i;
321         struct winfd wfd = INVALID_WINFD;
322         OVERLAPPED* overlapped = NULL;
323
324         CHECK_INIT_POLLING;
325
326         if ((handle == 0) || (handle == INVALID_HANDLE_VALUE)) {
327                 return INVALID_WINFD;
328         }
329
330         wfd.itransfer = itransfer;
331         wfd.cancel_fn = cancel_fn;
332
333         if ((access_mode != RW_READ) && (access_mode != RW_WRITE)) {
334                 usbi_warn(NULL, "only one of RW_READ or RW_WRITE are supported.\n"
335                         "If you want to poll for R/W simultaneously, create multiple fds from the same handle.");
336                 return INVALID_WINFD;
337         }
338         if (access_mode == RW_READ) {
339                 wfd.rw = RW_READ;
340         } else {
341                 wfd.rw = RW_WRITE;
342         }
343
344         overlapped = create_overlapped();
345         if(overlapped == NULL) {
346                 return INVALID_WINFD;
347         }
348
349         for (i=0; i<MAX_FDS; i++) {
350                 if (poll_fd[i].fd < 0) {
351                         EnterCriticalSection(&_poll_fd[i].mutex);
352                         // fd might have been removed before we got to critical
353                         if (poll_fd[i].fd >= 0) {
354                                 LeaveCriticalSection(&_poll_fd[i].mutex);
355                                 continue;
356                         }
357                         // Use index as the unique fd number
358                         wfd.fd = i;
359                         // Attempt to emulate some of the CancelIoEx behaviour on platforms
360                         // that don't have it
361                         if (Use_Duplicate_Handles) {
362                                 _poll_fd[i].thread_id = GetCurrentThreadId();
363                                 if (!DuplicateHandle(GetCurrentProcess(), handle, GetCurrentProcess(),
364                                         &wfd.handle, 0, TRUE, DUPLICATE_SAME_ACCESS)) {
365                                         usbi_dbg("could not duplicate handle for CancelIo - using original one");
366                                         wfd.handle = handle;
367                                         // Make sure we won't close the original handle on fd deletion then
368                                         _poll_fd[i].original_handle = INVALID_HANDLE_VALUE;
369                                 } else {
370                                         _poll_fd[i].original_handle = handle;
371                                 }
372                         } else {
373                                 wfd.handle = handle;
374                         }
375                         wfd.overlapped = overlapped;
376                         memcpy(&poll_fd[i], &wfd, sizeof(struct winfd));
377                         LeaveCriticalSection(&_poll_fd[i].mutex);
378                         return wfd;
379                 }
380         }
381         free_overlapped(overlapped);
382         return INVALID_WINFD;
383 }
384
385 static void _free_index(int _index)
386 {
387         // Cancel any async IO (Don't care about the validity of our handles for this)
388         cancel_io(_index);
389         // close the duplicate handle (if we have an actual duplicate)
390         if (Use_Duplicate_Handles) {
391                 if (_poll_fd[_index].original_handle != INVALID_HANDLE_VALUE) {
392                         CloseHandle(poll_fd[_index].handle);
393                 }
394                 _poll_fd[_index].original_handle = INVALID_HANDLE_VALUE;
395                 _poll_fd[_index].thread_id = 0;
396         }
397         free_overlapped(poll_fd[_index].overlapped);
398         poll_fd[_index] = INVALID_WINFD;
399 }
400
401 /*
402  * Release a pollable file descriptor.
403  *
404  * Note that the associated Windows handle is not closed by this call
405  */
406 void usbi_free_fd(int fd)
407 {
408         int _index;
409
410         CHECK_INIT_POLLING;
411
412         _index = _fd_to_index_and_lock(fd);
413         if (_index < 0) {
414                 return;
415         }
416         _free_index(_index);
417         LeaveCriticalSection(&_poll_fd[_index].mutex);
418 }
419
420 /*
421  * The functions below perform various conversions between fd, handle and OVERLAPPED
422  */
423 struct winfd fd_to_winfd(int fd)
424 {
425         int i;
426         struct winfd wfd;
427
428         CHECK_INIT_POLLING;
429
430         if (fd <= 0)
431                 return INVALID_WINFD;
432
433         for (i=0; i<MAX_FDS; i++) {
434                 if (poll_fd[i].fd == fd) {
435                         EnterCriticalSection(&_poll_fd[i].mutex);
436                         // fd might have been deleted before we got to critical
437                         if (poll_fd[i].fd != fd) {
438                                 LeaveCriticalSection(&_poll_fd[i].mutex);
439                                 continue;
440                         }
441                         memcpy(&wfd, &poll_fd[i], sizeof(struct winfd));
442                         LeaveCriticalSection(&_poll_fd[i].mutex);
443                         return wfd;
444                 }
445         }
446         return INVALID_WINFD;
447 }
448
449 struct winfd handle_to_winfd(HANDLE handle)
450 {
451         int i;
452         struct winfd wfd;
453
454         CHECK_INIT_POLLING;
455
456         if ((handle == 0) || (handle == INVALID_HANDLE_VALUE))
457                 return INVALID_WINFD;
458
459         for (i=0; i<MAX_FDS; i++) {
460                 if (poll_fd[i].handle == handle) {
461                         EnterCriticalSection(&_poll_fd[i].mutex);
462                         // fd might have been deleted before we got to critical
463                         if (poll_fd[i].handle != handle) {
464                                 LeaveCriticalSection(&_poll_fd[i].mutex);
465                                 continue;
466                         }
467                         memcpy(&wfd, &poll_fd[i], sizeof(struct winfd));
468                         LeaveCriticalSection(&_poll_fd[i].mutex);
469                         return wfd;
470                 }
471         }
472         return INVALID_WINFD;
473 }
474
475 struct winfd overlapped_to_winfd(OVERLAPPED* overlapped)
476 {
477         int i;
478         struct winfd wfd;
479
480         CHECK_INIT_POLLING;
481
482         if (overlapped == NULL)
483                 return INVALID_WINFD;
484
485         for (i=0; i<MAX_FDS; i++) {
486                 if (poll_fd[i].overlapped == overlapped) {
487                         EnterCriticalSection(&_poll_fd[i].mutex);
488                         // fd might have been deleted before we got to critical
489                         if (poll_fd[i].overlapped != overlapped) {
490                                 LeaveCriticalSection(&_poll_fd[i].mutex);
491                                 continue;
492                         }
493                         memcpy(&wfd, &poll_fd[i], sizeof(struct winfd));
494                         LeaveCriticalSection(&_poll_fd[i].mutex);
495                         return wfd;
496                 }
497         }
498         return INVALID_WINFD;
499 }
500
501 /*
502  * POSIX poll equivalent, using Windows OVERLAPPED
503  * Currently, this function only accepts one of POLLIN or POLLOUT per fd
504  * (but you can create multiple fds from the same handle for read and write)
505  */
506 int usbi_poll(struct pollfd *fds, unsigned int nfds, int timeout)
507 {
508         unsigned i;
509         int _index, object_index, triggered;
510         HANDLE *handles_to_wait_on;
511         int *handle_to_index;
512         DWORD nb_handles_to_wait_on = 0;
513         DWORD ret;
514
515         CHECK_INIT_POLLING;
516
517         triggered = 0;
518         handles_to_wait_on = (HANDLE*) calloc(nfds+1, sizeof(HANDLE));  // +1 for fd_update
519         handle_to_index = (int*) calloc(nfds, sizeof(int));
520         if ((handles_to_wait_on == NULL) || (handle_to_index == NULL)) {
521                 errno = ENOMEM;
522                 triggered = -1;
523                 goto poll_exit;
524         }
525
526         for (i = 0; i < nfds; ++i) {
527                 fds[i].revents = 0;
528
529                 // Only one of POLLIN or POLLOUT can be selected with this version of poll (not both)
530                 if ((fds[i].events & ~POLLIN) && (!(fds[i].events & POLLOUT))) {
531                         fds[i].revents |= POLLERR;
532                         errno = EACCES;
533                         usbi_warn(NULL, "unsupported set of events");
534                         triggered = -1;
535                         goto poll_exit;
536                 }
537
538                 _index = _fd_to_index_and_lock(fds[i].fd);
539                 poll_dbg("fd[%d]=%d: (overlapped=%p) got events %04X", i, poll_fd[_index].fd, poll_fd[_index].overlapped, fds[i].events);
540
541                 if ( (_index < 0) || (poll_fd[_index].handle == INVALID_HANDLE_VALUE)
542                   || (poll_fd[_index].handle == 0) || (poll_fd[_index].overlapped == NULL)) {
543                         fds[i].revents |= POLLNVAL | POLLERR;
544                         errno = EBADF;
545                         if (_index >= 0) {
546                                 LeaveCriticalSection(&_poll_fd[_index].mutex);
547                         }
548                         usbi_warn(NULL, "invalid fd");
549                         triggered = -1;
550                         goto poll_exit;
551                 }
552
553                 // IN or OUT must match our fd direction
554                 if ((fds[i].events & POLLIN) && (poll_fd[_index].rw != RW_READ)) {
555                         fds[i].revents |= POLLNVAL | POLLERR;
556                         errno = EBADF;
557                         usbi_warn(NULL, "attempted POLLIN on fd without READ access");
558                         LeaveCriticalSection(&_poll_fd[_index].mutex);
559                         triggered = -1;
560                         goto poll_exit;
561                 }
562
563                 if ((fds[i].events & POLLOUT) && (poll_fd[_index].rw != RW_WRITE)) {
564                         fds[i].revents |= POLLNVAL | POLLERR;
565                         errno = EBADF;
566                         usbi_warn(NULL, "attempted POLLOUT on fd without WRITE access");
567                         LeaveCriticalSection(&_poll_fd[_index].mutex);
568                         triggered = -1;
569                         goto poll_exit;
570                 }
571
572                 // The following macro only works if overlapped I/O was reported pending
573                 if ( (HasOverlappedIoCompleted(poll_fd[_index].overlapped))
574                   || (HasOverlappedIoCompletedSync(poll_fd[_index].overlapped)) ) {
575                         poll_dbg("  completed");
576                         // checks above should ensure this works:
577                         fds[i].revents = fds[i].events;
578                         triggered++;
579                 } else {
580                         handles_to_wait_on[nb_handles_to_wait_on] = poll_fd[_index].overlapped->hEvent;
581                         handle_to_index[nb_handles_to_wait_on] = i;
582                         nb_handles_to_wait_on++;
583                 }
584                 LeaveCriticalSection(&_poll_fd[_index].mutex);
585         }
586
587         // If nothing was triggered, wait on all fds that require it
588         if ((timeout != 0) && (triggered == 0) && (nb_handles_to_wait_on != 0)) {
589                 if (timeout < 0) {
590                         poll_dbg("starting infinite wait for %d handles...", (int)nb_handles_to_wait_on);
591                 } else {
592                         poll_dbg("starting %d ms wait for %d handles...", timeout, (int)nb_handles_to_wait_on);
593                 }
594                 ret = WaitForMultipleObjects(nb_handles_to_wait_on, handles_to_wait_on,
595                         FALSE, (timeout<0)?INFINITE:(DWORD)timeout);
596                 object_index = ret-WAIT_OBJECT_0;
597                 if ((object_index >= 0) && ((DWORD)object_index < nb_handles_to_wait_on)) {
598                         poll_dbg("  completed after wait");
599                         i = handle_to_index[object_index];
600                         _index = _fd_to_index_and_lock(fds[i].fd);
601                         fds[i].revents = fds[i].events;
602                         triggered++;
603                         if (_index >= 0) {
604                                 LeaveCriticalSection(&_poll_fd[_index].mutex);
605                         }
606                 } else if (ret == WAIT_TIMEOUT) {
607                         poll_dbg("  timed out");
608                         triggered = 0;  // 0 = timeout
609                 } else {
610                         errno = EIO;
611                         triggered = -1; // error
612                 }
613         }
614
615 poll_exit:
616         if (handles_to_wait_on != NULL) {
617                 free(handles_to_wait_on);
618         }
619         if (handle_to_index != NULL) {
620                 free(handle_to_index);
621         }
622         return triggered;
623 }
624
625 /*
626  * close a fake pipe fd
627  */
628 int usbi_close(int fd)
629 {
630         int _index;
631         int r = -1;
632
633         CHECK_INIT_POLLING;
634
635         _index = _fd_to_index_and_lock(fd);
636
637         if (_index < 0) {
638                 errno = EBADF;
639         } else {
640                 free_overlapped(poll_fd[_index].overlapped);
641                 poll_fd[_index] = INVALID_WINFD;
642                 LeaveCriticalSection(&_poll_fd[_index].mutex);
643         }
644         return r;
645 }
646
647 /*
648  * synchronous write for fake "pipe" signaling
649  */
650 ssize_t usbi_write(int fd, const void *buf, size_t count)
651 {
652         int _index;
653         UNUSED(buf);
654
655         CHECK_INIT_POLLING;
656
657         if (count != sizeof(unsigned char)) {
658                 usbi_err(NULL, "this function should only used for signaling");
659                 return -1;
660         }
661
662         _index = _fd_to_index_and_lock(fd);
663
664         if ( (_index < 0) || (poll_fd[_index].overlapped == NULL) ) {
665                 errno = EBADF;
666                 if (_index >= 0) {
667                         LeaveCriticalSection(&_poll_fd[_index].mutex);
668                 }
669                 return -1;
670         }
671
672         poll_dbg("set pipe event (fd = %d, thread = %08X)", _index, GetCurrentThreadId());
673         SetEvent(poll_fd[_index].overlapped->hEvent);
674         poll_fd[_index].overlapped->Internal = STATUS_WAIT_0;
675         // If two threads write on the pipe at the same time, we need to
676         // process two separate reads => use the overlapped as a counter
677         poll_fd[_index].overlapped->InternalHigh++;
678
679         LeaveCriticalSection(&_poll_fd[_index].mutex);
680         return sizeof(unsigned char);
681 }
682
683 /*
684  * synchronous read for fake "pipe" signaling
685  */
686 ssize_t usbi_read(int fd, void *buf, size_t count)
687 {
688         int _index;
689         ssize_t r = -1;
690         UNUSED(buf);
691
692         CHECK_INIT_POLLING;
693
694         if (count != sizeof(unsigned char)) {
695                 usbi_err(NULL, "this function should only used for signaling");
696                 return -1;
697         }
698
699         _index = _fd_to_index_and_lock(fd);
700
701         if (_index < 0) {
702                 errno = EBADF;
703                 return -1;
704         }
705
706         if (WaitForSingleObject(poll_fd[_index].overlapped->hEvent, INFINITE) != WAIT_OBJECT_0) {
707                 usbi_warn(NULL, "waiting for event failed: %d", (int)GetLastError());
708                 errno = EIO;
709                 goto out;
710         }
711
712         poll_dbg("clr pipe event (fd = %d, thread = %08X)", _index, GetCurrentThreadId());
713         poll_fd[_index].overlapped->InternalHigh--;
714         // Don't reset unless we don't have any more events to process
715         if (poll_fd[_index].overlapped->InternalHigh <= 0) {
716                 ResetEvent(poll_fd[_index].overlapped->hEvent);
717                 poll_fd[_index].overlapped->Internal = STATUS_PENDING;
718         }
719
720         r = sizeof(unsigned char);
721
722 out:
723         LeaveCriticalSection(&_poll_fd[_index].mutex);
724         return r;
725 }