1/*
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.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 *
21 */
22
23/*
24 * poll() and pipe() Windows compatibility layer for libusb 1.0
25 *
26 * The way this layer works is by using OVERLAPPED with async I/O transfers, as
27 * OVERLAPPED have an associated event which is flagged for I/O completion.
28 *
29 * For USB pollable async I/O, you would typically:
30 * - obtain a Windows HANDLE to a file or device that has been opened in
31 *   OVERLAPPED mode
32 * - call usbi_create_fd with this handle to obtain a custom fd.
33 *   Note that if you need simultaneous R/W access, you need to call create_fd
34 *   twice, once in _O_RDONLY and once in _O_WRONLY mode to obtain 2 separate
35 *   pollable fds
36 * - leave the core functions call the poll routine and flag POLLIN/POLLOUT
37 *
38 * The pipe pollable synchronous I/O works using the overlapped event associated
39 * with a fake pipe. The read/write functions are only meant to be used in that
40 * context.
41 */
42#include <errno.h>
43#include <fcntl.h>
44#include <stdio.h>
45#include <stdlib.h>
46#include <io.h>
47
48#include <libusbi.h>
49
50// Uncomment to debug the polling layer
51//#define DEBUG_POLL_WINDOWS
52#if defined(DEBUG_POLL_WINDOWS)
53#define poll_dbg usbi_dbg
54#else
55// MSVC++ < 2005 cannot use a variadic argument and non MSVC
56// compilers produce warnings if parenthesis are omitted.
57#if defined(_MSC_VER) && _MSC_VER < 1400
58#define poll_dbg
59#else
60#define poll_dbg(...)
61#endif
62#endif
63
64#if defined(_PREFAST_)
65#pragma warning(disable:28719)
66#endif
67
68#if defined(__CYGWIN__)
69// cygwin produces a warning unless these prototypes are defined
70extern int _open(char* name, int flags);
71extern int _close(int fd);
72extern 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
81const struct winfd INVALID_WINFD = {-1, INVALID_HANDLE_VALUE, NULL, RW_NONE};
82struct winfd poll_fd[MAX_FDS];
83// internal fd data
84struct {
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
92BOOLEAN is_polling_set = FALSE;
93LONG pipe_number = 0;
94static 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.
99static BOOL (__stdcall *pCancelIoEx)(HANDLE, LPOVERLAPPED) = NULL;
100#define CancelIoEx_Available (pCancelIoEx != NULL)
101static __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
122void init_polling(void)
123{
124	int i;
125
126	while (InterlockedExchange((LONG *)&compat_spinlock, 1) == 1) {
127		SleepEx(0, TRUE);
128	}
129	if (!is_polling_set) {
130		pCancelIoEx = (BOOL (__stdcall *)(HANDLE,LPOVERLAPPED))
131			GetProcAddress(GetModuleHandleA("KERNEL32"), "CancelIoEx");
132		usbi_dbg("Will use CancelIo%s for I/O cancellation",
133			CancelIoEx_Available?"Ex":"");
134		for (i=0; i<MAX_FDS; i++) {
135			poll_fd[i] = INVALID_WINFD;
136			_poll_fd[i].original_handle = INVALID_HANDLE_VALUE;
137			_poll_fd[i].thread_id = 0;
138			InitializeCriticalSection(&_poll_fd[i].mutex);
139		}
140		is_polling_set = TRUE;
141	}
142	compat_spinlock = 0;
143}
144
145// Internal function to retrieve the table index (and lock the fd mutex)
146int _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
167OVERLAPPED *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
181void 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
193void 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
207void exit_polling(void)
208{
209	int i;
210
211	while (InterlockedExchange((LONG *)&compat_spinlock, 1) == 1) {
212		SleepEx(0, TRUE);
213	}
214	if (is_polling_set) {
215		is_polling_set = FALSE;
216
217		for (i=0; i<MAX_FDS; i++) {
218			// Cancel any async I/O (handle can be invalid)
219			cancel_io(i);
220			// If anything was pending on that I/O, it should be
221			// terminating, and we should be able to access the fd
222			// mutex lock before too long
223			EnterCriticalSection(&_poll_fd[i].mutex);
224			if ( (poll_fd[i].fd > 0) && (poll_fd[i].handle != INVALID_HANDLE_VALUE) && (poll_fd[i].handle != 0)
225			  && (GetFileType(poll_fd[i].handle) == FILE_TYPE_UNKNOWN) ) {
226				_close(poll_fd[i].fd);
227			}
228			free_overlapped(poll_fd[i].overlapped);
229			if (!CancelIoEx_Available) {
230				// Close duplicate handle
231				if (_poll_fd[i].original_handle != INVALID_HANDLE_VALUE) {
232					CloseHandle(poll_fd[i].handle);
233				}
234			}
235			poll_fd[i] = INVALID_WINFD;
236			LeaveCriticalSection(&_poll_fd[i].mutex);
237			DeleteCriticalSection(&_poll_fd[i].mutex);
238		}
239	}
240	compat_spinlock = 0;
241}
242
243/*
244 * Create a fake pipe.
245 * As libusb only uses pipes for signaling, all we need from a pipe is an
246 * event. To that extent, we create a single wfd and overlapped as a means
247 * to access that event.
248 */
249int 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);
301out2:
302	_close(filedes[0]);
303out1:
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 */
322struct 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
394void _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 */
420void 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 */
437struct 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
463struct 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
489struct 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 */
520int 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
629poll_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 */
642int 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 */
672ssize_t usbi_write(int fd, const void *buf, size_t count)
673{
674	int _index;
675
676	CHECK_INIT_POLLING;
677
678	if (count != sizeof(unsigned char)) {
679		usbi_err(NULL, "this function should only used for signaling");
680		return -1;
681	}
682
683	_index = _fd_to_index_and_lock(fd);
684
685	if ( (_index < 0) || (poll_fd[_index].overlapped == NULL) ) {
686		errno = EBADF;
687		if (_index >= 0) {
688			LeaveCriticalSection(&_poll_fd[_index].mutex);
689		}
690		return -1;
691	}
692
693	poll_dbg("set pipe event (fd = %d, thread = %08X)", _index, GetCurrentThreadId());
694	SetEvent(poll_fd[_index].overlapped->hEvent);
695	poll_fd[_index].overlapped->Internal = STATUS_WAIT_0;
696	// If two threads write on the pipe at the same time, we need to
697	// process two separate reads => use the overlapped as a counter
698	poll_fd[_index].overlapped->InternalHigh++;
699
700	LeaveCriticalSection(&_poll_fd[_index].mutex);
701	return sizeof(unsigned char);
702}
703
704/*
705 * synchronous read for fake "pipe" signaling
706 */
707ssize_t usbi_read(int fd, void *buf, size_t count)
708{
709	int _index;
710	ssize_t r = -1;
711
712	CHECK_INIT_POLLING;
713
714	if (count != sizeof(unsigned char)) {
715		usbi_err(NULL, "this function should only used for signaling");
716		return -1;
717	}
718
719	_index = _fd_to_index_and_lock(fd);
720
721	if (_index < 0) {
722		errno = EBADF;
723		return -1;
724	}
725
726	if (WaitForSingleObject(poll_fd[_index].overlapped->hEvent, INFINITE) != WAIT_OBJECT_0) {
727		usbi_warn(NULL, "waiting for event failed: %d", (int)GetLastError());
728		errno = EIO;
729		goto out;
730	}
731
732	poll_dbg("clr pipe event (fd = %d, thread = %08X)", _index, GetCurrentThreadId());
733	poll_fd[_index].overlapped->InternalHigh--;
734	// Don't reset unless we don't have any more events to process
735	if (poll_fd[_index].overlapped->InternalHigh <= 0) {
736		ResetEvent(poll_fd[_index].overlapped->hEvent);
737		poll_fd[_index].overlapped->Internal = STATUS_PENDING;
738	}
739
740	r = sizeof(unsigned char);
741
742out:
743	LeaveCriticalSection(&_poll_fd[_index].mutex);
744	return r;
745}
746