void windows_get_overlapped_result(struct usbi_transfer *transfer, struct winfd *pollable_fd, DWORD *io_result, DWORD *io_size) { if (HasOverlappedIoCompletedSync(pollable_fd->overlapped) // Handle async requests that completed synchronously first || GetOverlappedResult(pollable_fd->handle, pollable_fd->overlapped, io_size, false)) { // Regular async overlapped struct libusb_transfer *ltransfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer); struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(transfer); if (ltransfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) { int i; for (i = 0; i < transfer_priv->request.IsochronousPacketsArraySize; i++) { struct libusb_iso_packet_descriptor *lib_desc = <ransfer->iso_packet_desc[i]; switch (transfer_priv->IsochronousResultsArray[i].TransferResult) { case STATUS_SUCCESS: case STATUS_CANCELLED: case STATUS_REQUEST_CANCELED: lib_desc->status = LIBUSB_TRANSFER_COMPLETED; // == ERROR_SUCCESS break; default: lib_desc->status = LIBUSB_TRANSFER_ERROR; // ERROR_UNKNOWN_EXCEPTION; break; } lib_desc->actual_length = (unsigned int)transfer_priv->IsochronousResultsArray[i].ActualLength; } } *io_size = (DWORD) transfer_priv->request.Result.GenResult.BytesTransferred; *io_result = usbdk_translate_usbd_status((USBD_STATUS) transfer_priv->request.Result.GenResult.UsbdStatus); } else { *io_result = GetLastError(); } }
int usbi_poll(struct pollfd *fds, unsigned int nfds, int timeout) { unsigned i; int _index, object_index, triggered; HANDLE *handles_to_wait_on; int *handle_to_index; DWORD nb_handles_to_wait_on = 0; DWORD ret; CHECK_INIT_POLLING; triggered = 0; handles_to_wait_on = (HANDLE*) calloc(nfds+1, sizeof(HANDLE)); handle_to_index = (int*) calloc(nfds, sizeof(int)); if ((handles_to_wait_on == NULL) || (handle_to_index == NULL)) { errno = ENOMEM; triggered = -1; goto poll_exit; } for (i = 0; i < nfds; ++i) { fds[i].revents = 0; if ((fds[i].events & ~POLLIN) && (!(fds[i].events & POLLOUT))) { fds[i].revents |= POLLERR; errno = EACCES; usbi_warn(NULL, "unsupported set of events"); triggered = -1; goto poll_exit; } _index = _fd_to_index_and_lock(fds[i].fd); poll_dbg("fd[%d]=%d: (overlapped=%p) got events %04X", i, poll_fd[_index].fd, poll_fd[_index].overlapped, fds[i].events); if ( (_index < 0) || (poll_fd[_index].handle == INVALID_HANDLE_VALUE) || (poll_fd[_index].handle == 0) || (poll_fd[_index].overlapped == NULL)) { fds[i].revents |= POLLNVAL | POLLERR; errno = EBADF; if (_index >= 0) { LeaveCriticalSection(&_poll_fd[_index].mutex); } usbi_warn(NULL, "invalid fd"); triggered = -1; goto poll_exit; } if ((fds[i].events & POLLIN) && (poll_fd[_index].rw != RW_READ)) { fds[i].revents |= POLLNVAL | POLLERR; errno = EBADF; usbi_warn(NULL, "attempted POLLIN on fd without READ access"); LeaveCriticalSection(&_poll_fd[_index].mutex); triggered = -1; goto poll_exit; } if ((fds[i].events & POLLOUT) && (poll_fd[_index].rw != RW_WRITE)) { fds[i].revents |= POLLNVAL | POLLERR; errno = EBADF; usbi_warn(NULL, "attempted POLLOUT on fd without WRITE access"); LeaveCriticalSection(&_poll_fd[_index].mutex); triggered = -1; goto poll_exit; } if ( (HasOverlappedIoCompleted(poll_fd[_index].overlapped)) || (HasOverlappedIoCompletedSync(poll_fd[_index].overlapped)) ) { poll_dbg(" completed"); fds[i].revents = fds[i].events; triggered++; } else { handles_to_wait_on[nb_handles_to_wait_on] = poll_fd[_index].overlapped->hEvent; handle_to_index[nb_handles_to_wait_on] = i; nb_handles_to_wait_on++; } LeaveCriticalSection(&_poll_fd[_index].mutex); } if ((timeout != 0) && (triggered == 0) && (nb_handles_to_wait_on != 0)) { if (timeout < 0) { poll_dbg("starting infinite wait for %d handles...", (int)nb_handles_to_wait_on); } else { poll_dbg("starting %d ms wait for %d handles...", timeout, (int)nb_handles_to_wait_on); } ret = WaitForMultipleObjects(nb_handles_to_wait_on, handles_to_wait_on, FALSE, (timeout<0)?INFINITE:(DWORD)timeout); object_index = ret-WAIT_OBJECT_0; if ((object_index >= 0) && ((DWORD)object_index < nb_handles_to_wait_on)) { poll_dbg(" completed after wait"); i = handle_to_index[object_index]; _index = _fd_to_index_and_lock(fds[i].fd); fds[i].revents = fds[i].events; triggered++; if (_index >= 0) { LeaveCriticalSection(&_poll_fd[_index].mutex); } } else if (ret == WAIT_TIMEOUT) { poll_dbg(" timed out"); triggered = 0; } else { errno = EIO; triggered = -1; } } poll_exit: if (handles_to_wait_on != NULL) { free(handles_to_wait_on); } if (handle_to_index != NULL) { free(handle_to_index); } return triggered; }
/* Get a list of HANDLE */ void API_EXPORTED libusb_get_handles_to_wait_on(struct libusb_context *ctx, HANDLE **handles_to_wait_on_ret, int *nb_handles_to_wait_on) { int _index; HANDLE *handles_to_wait_on = 0; struct usbi_pollfd *ipollfd; POLL_NFDS_TYPE nfds = 0; CHECK_INIT_POLLING; *nb_handles_to_wait_on = 0; usbi_mutex_lock(&ctx->pollfds_lock); list_for_each_entry(ipollfd, &ctx->pollfds, list, struct usbi_pollfd) nfds++; if (nfds != 0) { handles_to_wait_on = (HANDLE*) calloc(nfds+1, sizeof(HANDLE)); // +1 for fd_update if (handles_to_wait_on == NULL) { errno = ENOMEM; goto libusb_get_handles_to_wait_on_exit; } } else { goto libusb_get_handles_to_wait_on_exit; } list_for_each_entry(ipollfd, &ctx->pollfds, list, struct usbi_pollfd) { struct libusb_pollfd *pollfd_current = &ipollfd->pollfd; // Only one of POLLIN or POLLOUT can be selected with this version of poll (not both) if ((pollfd_current->events & ~POLLIN) && (!(pollfd_current->events & POLLOUT))) { errno = EACCES; usbi_warn(NULL, "unsupported set of events"); *nb_handles_to_wait_on = -1; goto libusb_get_handles_to_wait_on_exit; } _index = _fd_to_index_and_lock(pollfd_current->fd); poll_dbg("fd=%d: (overlapped=%p) got events %04X", poll_fd[_index].fd, poll_fd[_index].overlapped, pollfd_current->events); if ( (_index < 0) || (poll_fd[_index].handle == INVALID_HANDLE_VALUE) || (poll_fd[_index].handle == 0) || (poll_fd[_index].overlapped == NULL)) { errno = EBADF; if (_index >= 0) { LeaveCriticalSection(&_poll_fd[_index].mutex); } usbi_warn(NULL, "invalid fd"); *nb_handles_to_wait_on = -1; goto libusb_get_handles_to_wait_on_exit; } // IN or OUT must match our fd direction if ((pollfd_current->events & POLLIN) && (poll_fd[_index].rw != RW_READ)) { errno = EBADF; usbi_warn(NULL, "attempted POLLIN on fd without READ access"); LeaveCriticalSection(&_poll_fd[_index].mutex); *nb_handles_to_wait_on = -1; goto libusb_get_handles_to_wait_on_exit; } if ((pollfd_current->events & POLLOUT) && (poll_fd[_index].rw != RW_WRITE)) { errno = EBADF; usbi_warn(NULL, "attempted POLLOUT on fd without WRITE access"); LeaveCriticalSection(&_poll_fd[_index].mutex); *nb_handles_to_wait_on = -1; goto libusb_get_handles_to_wait_on_exit; } // The following macro only works if overlapped I/O was reported pending if ( (HasOverlappedIoCompleted(poll_fd[_index].overlapped)) || (HasOverlappedIoCompletedSync(poll_fd[_index].overlapped)) ) { poll_dbg(" completed"); // checks above should ensure this works: } else { handles_to_wait_on[*nb_handles_to_wait_on] = poll_fd[_index].overlapped->hEvent; (*nb_handles_to_wait_on)++; } LeaveCriticalSection(&_poll_fd[_index].mutex); } libusb_get_handles_to_wait_on_exit: usbi_mutex_unlock(&ctx->pollfds_lock); *handles_to_wait_on_ret = handles_to_wait_on; }