2 * poll_windows: poll compatibility wrapper for Windows
3 * Copyright © 2017 Chris Dickens <christopher.a.dickens@gmail.com>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 * poll() and pipe() Windows compatibility layer for libusb 1.0
24 * The way this layer works is by using OVERLAPPED with async I/O transfers, as
25 * OVERLAPPED have an associated event which is flagged for I/O completion.
27 * For USB pollable async I/O, you would typically:
28 * - obtain a Windows HANDLE to a file or device that has been opened in
30 * - call usbi_create_fd with this handle to obtain a custom fd.
31 * - leave the core functions call the poll routine and flag POLLIN/POLLOUT
33 * The pipe pollable synchronous I/O works using the overlapped event associated
34 * with a fake pipe. The read/write functions are only meant to be used in that
44 #include "windows_common.h"
47 const struct winfd INVALID_WINFD = { -1, NULL };
50 struct file_descriptor {
51 enum fd_type { FD_TYPE_PIPE, FD_TYPE_TRANSFER } type;
52 OVERLAPPED overlapped;
55 static usbi_mutex_static_t fd_table_lock = USBI_MUTEX_INITIALIZER;
56 static struct file_descriptor *fd_table[MAX_FDS];
58 static struct file_descriptor *create_fd(enum fd_type type)
60 struct file_descriptor *fd = calloc(1, sizeof(*fd));
63 fd->overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
64 if (fd->overlapped.hEvent == NULL) {
72 static void free_fd(struct file_descriptor *fd)
74 CloseHandle(fd->overlapped.hEvent);
79 * Create both an fd and an OVERLAPPED, so that it can be used with our
81 * The handle MUST support overlapped transfers (usually requires CreateFile
82 * with FILE_FLAG_OVERLAPPED)
83 * Return a pollable file descriptor struct, or INVALID_WINFD on error
85 * Note that the fd returned by this function is a per-transfer fd, rather
86 * than a per-session fd and cannot be used for anything else but our
88 * if you plan to do R/W on the same handle, you MUST create 2 fds: one for
89 * read and one for write. Using a single R/W fd is unsupported and will
90 * produce unexpected results
92 struct winfd usbi_create_fd(void)
94 struct file_descriptor *fd;
97 fd = create_fd(FD_TYPE_TRANSFER);
101 usbi_mutex_static_lock(&fd_table_lock);
102 for (wfd.fd = 0; wfd.fd < MAX_FDS; wfd.fd++) {
103 if (fd_table[wfd.fd] != NULL)
105 fd_table[wfd.fd] = fd;
108 usbi_mutex_static_unlock(&fd_table_lock);
110 if (wfd.fd == MAX_FDS) {
112 return INVALID_WINFD;
115 wfd.overlapped = &fd->overlapped;
120 static int check_pollfds(struct pollfd *fds, unsigned int nfds,
121 HANDLE *wait_handles, DWORD *nb_wait_handles)
123 struct file_descriptor *fd;
127 usbi_mutex_static_lock(&fd_table_lock);
129 for (n = 0; n < nfds; ++n) {
132 // Keep it simple - only allow either POLLIN *or* POLLOUT
133 assert((fds[n].events == POLLIN) || (fds[n].events == POLLOUT));
134 if ((fds[n].events != POLLIN) && (fds[n].events != POLLOUT)) {
135 fds[n].revents = POLLNVAL;
140 if ((fds[n].fd >= 0) && (fds[n].fd < MAX_FDS))
141 fd = fd_table[fds[n].fd];
147 fds[n].revents = POLLNVAL;
152 if (HasOverlappedIoCompleted(&fd->overlapped)
153 && (WaitForSingleObject(fd->overlapped.hEvent, 0) == WAIT_OBJECT_0)) {
154 fds[n].revents = fds[n].events;
156 } else if (wait_handles != NULL) {
157 if (*nb_wait_handles == MAXIMUM_WAIT_OBJECTS) {
158 usbi_warn(NULL, "too many HANDLEs to wait on");
161 wait_handles[*nb_wait_handles] = fd->overlapped.hEvent;
162 (*nb_wait_handles)++;
166 usbi_mutex_static_unlock(&fd_table_lock);
171 * POSIX poll equivalent, using Windows OVERLAPPED
172 * Currently, this function only accepts one of POLLIN or POLLOUT per fd
173 * (but you can create multiple fds from the same handle for read and write)
175 int usbi_poll(struct pollfd *fds, unsigned int nfds, int timeout)
177 HANDLE wait_handles[MAXIMUM_WAIT_OBJECTS];
178 DWORD nb_wait_handles = 0;
182 nready = check_pollfds(fds, nfds, wait_handles, &nb_wait_handles);
184 // If nothing was triggered, wait on all fds that require it
185 if ((nready == 0) && (nb_wait_handles != 0) && (timeout != 0)) {
186 ret = WaitForMultipleObjects(nb_wait_handles, wait_handles,
187 FALSE, (timeout < 0) ? INFINITE : (DWORD)timeout);
188 if (ret < (WAIT_OBJECT_0 + nb_wait_handles)) {
189 nready = check_pollfds(fds, nfds, NULL, NULL);
190 } else if (ret != WAIT_TIMEOUT) {
191 if (ret == WAIT_FAILED)
192 usbi_err(NULL, "WaitForMultipleObjects failed: %u", (unsigned int)GetLastError());
201 * close a fake file descriptor
203 int usbi_close(int _fd)
205 struct file_descriptor *fd;
207 if (_fd < 0 || _fd >= MAX_FDS)
210 usbi_mutex_static_lock(&fd_table_lock);
212 fd_table[_fd] = NULL;
213 usbi_mutex_static_unlock(&fd_table_lock);
218 if (fd->type == FD_TYPE_PIPE) {
219 // InternalHigh is our reference count
220 fd->overlapped.InternalHigh--;
221 if (fd->overlapped.InternalHigh == 0)
235 * Create a fake pipe.
236 * As libusb only uses pipes for signaling, all we need from a pipe is an
237 * event. To that extent, we create a single wfd and overlapped as a means
238 * to access that event.
240 int usbi_pipe(int filedes[2])
242 struct file_descriptor *fd;
243 int r_fd = -1, w_fd = -1;
246 fd = create_fd(FD_TYPE_PIPE);
252 // Use InternalHigh as a reference count
253 fd->overlapped.Internal = STATUS_PENDING;
254 fd->overlapped.InternalHigh = 2;
256 usbi_mutex_static_lock(&fd_table_lock);
258 for (i = 0; i < MAX_FDS; i++) {
259 if (fd_table[i] != NULL)
263 } else if (w_fd == -1) {
276 usbi_mutex_static_unlock(&fd_table_lock);
291 * synchronous write for fake "pipe" signaling
293 ssize_t usbi_write(int fd, const void *buf, size_t count)
299 if (fd < 0 || fd >= MAX_FDS)
302 if (count != sizeof(unsigned char)) {
303 usbi_err(NULL, "this function should only used for signaling");
308 usbi_mutex_static_lock(&fd_table_lock);
309 if ((fd_table[fd] != NULL) && (fd_table[fd]->type == FD_TYPE_PIPE)) {
310 assert(fd_table[fd]->overlapped.Internal == STATUS_PENDING);
311 assert(fd_table[fd]->overlapped.InternalHigh == 2);
312 fd_table[fd]->overlapped.Internal = STATUS_WAIT_0;
313 SetEvent(fd_table[fd]->overlapped.hEvent);
316 usbi_mutex_static_unlock(&fd_table_lock);
321 return sizeof(unsigned char);
329 * synchronous read for fake "pipe" signaling
331 ssize_t usbi_read(int fd, void *buf, size_t count)
337 if (fd < 0 || fd >= MAX_FDS)
340 if (count != sizeof(unsigned char)) {
341 usbi_err(NULL, "this function should only used for signaling");
346 usbi_mutex_static_lock(&fd_table_lock);
347 if ((fd_table[fd] != NULL) && (fd_table[fd]->type == FD_TYPE_PIPE)) {
348 assert(fd_table[fd]->overlapped.Internal == STATUS_WAIT_0);
349 assert(fd_table[fd]->overlapped.InternalHigh == 2);
350 fd_table[fd]->overlapped.Internal = STATUS_PENDING;
351 ResetEvent(fd_table[fd]->overlapped.hEvent);
354 usbi_mutex_static_unlock(&fd_table_lock);
359 return sizeof(unsigned char);