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
46 #include "windows_common.h"
49 const struct winfd INVALID_WINFD = { -1, NULL };
52 struct file_descriptor {
53 enum fd_type { FD_TYPE_PIPE, FD_TYPE_TRANSFER } type;
55 OVERLAPPED overlapped;
58 static usbi_mutex_static_t fd_table_lock = USBI_MUTEX_INITIALIZER;
60 #define BITS_PER_BYTE 8
61 #define BITMAP_BITS_PER_WORD (sizeof(unsigned long) * BITS_PER_BYTE)
62 #define FD_TABLE_INCR_SIZE 64
64 static struct file_descriptor **fd_table;
65 static unsigned long *fd_table_bitmap;
66 static unsigned int fd_table_size;
67 static unsigned int fd_count;
69 #define return_with_errno(err) \
75 static struct file_descriptor *alloc_fd(enum fd_type type, LONG refcount)
77 struct file_descriptor *fd = calloc(1, sizeof(*fd));
81 fd->overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
82 if (fd->overlapped.hEvent == NULL) {
87 fd->refcount = refcount;
91 static struct file_descriptor *get_fd(unsigned int _fd, bool ref)
93 struct file_descriptor *fd = NULL;
95 if (_fd < fd_table_size)
97 if (fd != NULL && ref)
98 InterlockedIncrement(&fd->refcount);
103 static void put_fd(struct file_descriptor *fd)
105 if (InterlockedDecrement(&fd->refcount) == 0L) {
106 CloseHandle(fd->overlapped.hEvent);
111 static int install_fd(struct file_descriptor *fd)
115 if (fd_count == fd_table_size) {
116 struct file_descriptor **new_table;
117 unsigned long* new_bitmap;
119 // Need to expand the fd table and bitmap
120 new_table = realloc(fd_table, (fd_table_size + FD_TABLE_INCR_SIZE) * sizeof(*new_table));
121 if (new_table == NULL)
123 memset(new_table + fd_table_size, 0, FD_TABLE_INCR_SIZE * sizeof(*new_table));
124 fd_table = new_table;
126 new_bitmap = realloc(fd_table_bitmap, (fd_table_size + FD_TABLE_INCR_SIZE) / BITS_PER_BYTE);
127 if (new_bitmap == NULL)
129 memset(new_bitmap + (fd_table_size / BITMAP_BITS_PER_WORD), 0, FD_TABLE_INCR_SIZE / BITS_PER_BYTE);
130 fd_table_bitmap = new_bitmap;
132 fd_table_size += FD_TABLE_INCR_SIZE;
133 assert(fd_table_size < (unsigned int)INT_MAX);
136 for (n = 0; n < fd_table_size; n += BITMAP_BITS_PER_WORD) {
137 unsigned int idx = n / BITMAP_BITS_PER_WORD;
138 unsigned long mask, pos;
140 mask = ~fd_table_bitmap[idx];
144 assert(_BitScanForward(&pos, mask));
145 fd_table_bitmap[idx] |= 1UL << pos;
150 assert(n < fd_table_size);
151 assert(fd_table[n] == NULL);
158 static void remove_fd(unsigned int pos)
160 assert(fd_table[pos] != NULL);
161 fd_table[pos] = NULL;
162 fd_table_bitmap[pos / BITMAP_BITS_PER_WORD] &= ~(1UL << (pos % BITMAP_BITS_PER_WORD));
166 free(fd_table_bitmap);
168 fd_table_bitmap = NULL;
174 * Create both an fd and an OVERLAPPED, so that it can be used with our
176 * The handle MUST support overlapped transfers (usually requires CreateFile
177 * with FILE_FLAG_OVERLAPPED)
178 * Return a pollable file descriptor struct, or INVALID_WINFD on error
180 * Note that the fd returned by this function is a per-transfer fd, rather
181 * than a per-session fd and cannot be used for anything else but our
183 * if you plan to do R/W on the same handle, you MUST create 2 fds: one for
184 * read and one for write. Using a single R/W fd is unsupported and will
185 * produce unexpected results
187 struct winfd usbi_create_fd(void)
189 struct file_descriptor *fd;
192 fd = alloc_fd(FD_TYPE_TRANSFER, 1);
194 return INVALID_WINFD;
196 usbi_mutex_static_lock(&fd_table_lock);
197 wfd.fd = install_fd(fd);
198 usbi_mutex_static_unlock(&fd_table_lock);
202 return INVALID_WINFD;
205 wfd.overlapped = &fd->overlapped;
210 struct wait_thread_data {
212 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
217 static DWORD WINAPI WaitThread(LPVOID lpParam)
219 struct wait_thread_data *thread_data = lpParam;
220 HANDLE notify_event = thread_data->handles[0];
223 status = WaitForMultipleObjects(thread_data->num_handles, thread_data->handles, FALSE, INFINITE);
224 if ((status >= WAIT_OBJECT_0) && (status < (WAIT_OBJECT_0 + thread_data->num_handles))) {
225 if (status > WAIT_OBJECT_0) {
226 // This will wake up all the other waiting threads
227 SetEvent(notify_event);
229 thread_data->error = 0;
231 assert(status == WAIT_FAILED);
232 thread_data->error = (status == WAIT_FAILED) ? GetLastError() : ERROR_CAN_NOT_COMPLETE;
238 static DWORD poll_wait(const HANDLE *wait_handles, DWORD num_wait_handles, DWORD timeout)
240 struct wait_thread_data *thread_data;
246 if (num_wait_handles <= MAXIMUM_WAIT_OBJECTS)
247 return WaitForMultipleObjects(num_wait_handles, wait_handles, FALSE, timeout);
249 // To wait on more than MAXIMUM_WAIT_OBJECTS, each thread (including the
250 // current thread) will wait on an event and (MAXIMUM_WAIT_OBJECTS - 1)
251 // HANDLEs. The event is shared amongst all threads so that any thread
252 // that returns from a WaitForMultipleObjects() call will set the event
253 // and wake up all the other threads.
254 notify_event = CreateEvent(NULL, FALSE, FALSE, NULL);
255 if (notify_event == NULL)
258 num_threads = 1 + (num_wait_handles - MAXIMUM_WAIT_OBJECTS - 1) / (MAXIMUM_WAIT_OBJECTS - 1);
259 thread_data = malloc(num_threads * sizeof(*thread_data));
260 if (thread_data == NULL) {
261 CloseHandle(notify_event);
262 SetLastError(ERROR_OUTOFMEMORY);
266 handles = _alloca(MAXIMUM_WAIT_OBJECTS * sizeof(HANDLE));
267 handles[0] = notify_event;
268 memcpy(handles + 1, wait_handles, (MAXIMUM_WAIT_OBJECTS - 1) * sizeof(HANDLE));
269 wait_handles += MAXIMUM_WAIT_OBJECTS - 1;
270 num_wait_handles -= MAXIMUM_WAIT_OBJECTS - 1;
272 for (n = 0; n < num_threads; n++) {
273 DWORD copy_size = MIN(num_wait_handles, MAXIMUM_WAIT_OBJECTS - 1);
275 thread_data[n].handles[0] = notify_event;
276 memcpy(thread_data[n].handles + 1, wait_handles, copy_size * sizeof(HANDLE));
277 thread_data[n].num_handles = copy_size + 1;
279 // Create the thread that will wait on these HANDLEs
280 thread_data[n].thread = CreateThread(NULL, 0, WaitThread, &thread_data[n], 0, NULL);
281 if (thread_data[n].thread == NULL) {
282 thread_data[n].error = GetLastError();
283 SetEvent(notify_event);
288 wait_handles += copy_size;
289 num_wait_handles -= copy_size;
292 status = WaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, handles, FALSE, timeout);
293 if ((status >= WAIT_OBJECT_0) && (status < (WAIT_OBJECT_0 + MAXIMUM_WAIT_OBJECTS))) {
294 if (status > WAIT_OBJECT_0) {
295 // Wake up all the waiting threads
296 SetEvent(notify_event);
297 status = WAIT_OBJECT_0;
300 } else if (status == WAIT_TIMEOUT) {
301 // Wake up all the waiting threads
302 SetEvent(notify_event);
305 assert(status == WAIT_FAILED);
306 error = (status == WAIT_FAILED) ? GetLastError() : ERROR_CAN_NOT_COMPLETE;
309 for (n = 0; n < num_threads; n++) {
310 if (thread_data[n].thread != NULL) {
311 if (WaitForSingleObject(thread_data[n].thread, INFINITE) != WAIT_OBJECT_0)
312 usbi_err(NULL, "WaitForSingleObject() failed: %lu", GetLastError());
313 CloseHandle(thread_data[n].thread);
315 if (thread_data[n].error) {
316 usbi_err(NULL, "wait thread %d had error %lu\n", n, thread_data[n].error);
317 error = thread_data[n].error;
318 status = WAIT_FAILED;
324 CloseHandle(notify_event);
326 if (status == WAIT_FAILED)
333 * POSIX poll equivalent, using Windows OVERLAPPED
334 * Currently, this function only accepts one of POLLIN or POLLOUT per fd
335 * (but you can create multiple fds from the same handle for read and write)
337 int usbi_poll(struct pollfd *fds, unsigned int nfds, int timeout)
339 struct file_descriptor **fds_array;
340 HANDLE *handles_array;
341 struct file_descriptor *fd;
345 if (nfds <= MAXIMUM_WAIT_OBJECTS) {
346 fds_array = _alloca(nfds * sizeof(*fds_array));
347 handles_array = _alloca(nfds * sizeof(*handles_array));
349 fds_array = malloc(nfds * sizeof(*fds_array));
350 if (fds_array == NULL)
351 return_with_errno(ENOMEM);
352 handles_array = malloc(nfds * sizeof(*handles_array));
353 if (handles_array == NULL) {
355 return_with_errno(ENOMEM);
359 usbi_mutex_static_lock(&fd_table_lock);
360 for (n = 0; n < nfds; n++) {
361 struct pollfd *pfd = &fds[n];
363 // Keep it simple - only allow either POLLIN *or* POLLOUT
364 assert((pfd->events == POLLIN) || (pfd->events == POLLOUT));
365 if ((pfd->events != POLLIN) && (pfd->events != POLLOUT)) {
370 // All file descriptors must be valid
371 fd = get_fd(pfd->fd, true);
378 // We hold a reference to fd for the duration of usbi_poll()
380 handles_array[n] = fd->overlapped.hEvent;
382 usbi_mutex_static_unlock(&fd_table_lock);
385 while (nready == 0) {
388 // Check all fds for events
389 for (n = 0; n < nfds; n++) {
392 fds[n].revents = POLLNVAL;
394 } else if (HasOverlappedIoCompleted(&fd->overlapped) &&
395 (WaitForSingleObject(fd->overlapped.hEvent, 0) == WAIT_OBJECT_0)) {
396 fds[n].revents = fds[n].events;
403 if ((nready != 0) || (timeout == 0))
406 // Wait for any of the events to trigger
407 ret = poll_wait(handles_array, nfds, (timeout < 0) ? INFINITE : (DWORD)timeout);
408 if (ret == WAIT_TIMEOUT) {
411 } else if (ret == WAIT_FAILED) {
412 usbi_err(NULL, "WaitForMultipleObjects failed: %lu", GetLastError());
418 for (n = 0; n < nfds; n++) {
419 if (fds_array[n] != NULL)
420 put_fd(fds_array[n]);
423 if (nfds > MAXIMUM_WAIT_OBJECTS) {
432 * close a fake file descriptor
434 int usbi_close(int _fd)
436 struct file_descriptor *fd;
438 usbi_mutex_static_lock(&fd_table_lock);
439 fd = get_fd(_fd, false);
442 usbi_mutex_static_unlock(&fd_table_lock);
445 return_with_errno(EBADF);
453 * Create a fake pipe.
454 * As libusb only uses pipes for signaling, all we need from a pipe is an
455 * event. To that extent, we create a single wfd and overlapped as a means
456 * to access that event.
458 int usbi_pipe(int filedes[2])
460 struct file_descriptor *fd;
464 fd = alloc_fd(FD_TYPE_PIPE, 2);
466 return_with_errno(ENOMEM);
468 fd->overlapped.Internal = STATUS_PENDING;
470 usbi_mutex_static_lock(&fd_table_lock);
471 r_fd = install_fd(fd);
473 w_fd = install_fd(fd);
480 w_fd = -1; // Keep compiler happy
482 usbi_mutex_static_unlock(&fd_table_lock);
485 CloseHandle(fd->overlapped.hEvent);
487 return_with_errno(error);
497 * synchronous write for fake "pipe" signaling
499 ssize_t usbi_write(int _fd, const void *buf, size_t count)
501 struct file_descriptor *fd;
505 if (count != sizeof(unsigned char)) {
506 usbi_err(NULL, "this function should only used for signaling");
507 return_with_errno(EINVAL);
510 usbi_mutex_static_lock(&fd_table_lock);
511 fd = get_fd(_fd, false);
512 if (fd && fd->type == FD_TYPE_PIPE) {
513 assert(fd->overlapped.Internal == STATUS_PENDING);
514 fd->overlapped.Internal = STATUS_WAIT_0;
515 SetEvent(fd->overlapped.hEvent);
519 usbi_mutex_static_unlock(&fd_table_lock);
522 return_with_errno(EBADF);
524 return sizeof(unsigned char);
528 * synchronous read for fake "pipe" signaling
530 ssize_t usbi_read(int _fd, void *buf, size_t count)
532 struct file_descriptor *fd;
536 if (count != sizeof(unsigned char)) {
537 usbi_err(NULL, "this function should only used for signaling");
538 return_with_errno(EINVAL);
541 usbi_mutex_static_lock(&fd_table_lock);
542 fd = get_fd(_fd, false);
543 if (fd && fd->type == FD_TYPE_PIPE) {
544 assert(fd->overlapped.Internal == STATUS_WAIT_0);
545 fd->overlapped.Internal = STATUS_PENDING;
546 ResetEvent(fd->overlapped.hEvent);
550 usbi_mutex_static_unlock(&fd_table_lock);
553 return_with_errno(EBADF);
555 return sizeof(unsigned char);