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