int usbi_close(int fd) { int _index; int r = -1; CHECK_INIT_POLLING; _index = _fd_to_index_and_lock(fd); if (_index < 0) { errno = EBADF; } else { if (poll_fd[_index].overlapped != NULL) { CloseHandle(poll_fd[_index].overlapped->hEvent); free(poll_fd[_index].overlapped); } r = _close(poll_fd[_index].fd); if (r != 0) { errno = EIO; } poll_fd[_index] = INVALID_WINFD; LeaveCriticalSection(&_poll_fd[_index].mutex); } return r; }
ssize_t usbi_write(int fd, const void *buf, size_t count) { int _index; CHECK_INIT_POLLING; if (count != sizeof(unsigned char)) { usbi_err(NULL, "this function should only used for signaling"); return -1; } _index = _fd_to_index_and_lock(fd); if ( (_index < 0) || (poll_fd[_index].overlapped == NULL) ) { errno = EBADF; if (_index >= 0) { LeaveCriticalSection(&_poll_fd[_index].mutex); } return -1; } poll_dbg("set pipe event (fd = %d, thread = %08X)", _index, GetCurrentThreadId()); SetEvent(poll_fd[_index].overlapped->hEvent); poll_fd[_index].overlapped->Internal = STATUS_WAIT_0; poll_fd[_index].overlapped->InternalHigh++; LeaveCriticalSection(&_poll_fd[_index].mutex); return sizeof(unsigned char); }
/* * synchronous write for fake "pipe" signaling */ ssize_t usbi_write(int fd, const void *buf, size_t count) { int _index; UNUSED(buf); CHECK_INIT_POLLING; if (count != sizeof(unsigned char)) { usbi_err(NULL, "this function should only used for signaling"); return -1; } _index = _fd_to_index_and_lock(fd); if ( (_index < 0) || (poll_fd[_index].overlapped == NULL) ) { errno = EBADF; if (_index >= 0) { LeaveCriticalSection(&_poll_fd[_index].mutex); } return -1; } poll_dbg("set pipe event (fd = %d, thread = %08X)", _index, (unsigned int)GetCurrentThreadId()); SetEvent(poll_fd[_index].overlapped->hEvent); poll_fd[_index].overlapped->Internal = STATUS_WAIT_0; // If two threads write on the pipe at the same time, we need to // process two separate reads => use the overlapped as a counter poll_fd[_index].overlapped->InternalHigh++; LeaveCriticalSection(&_poll_fd[_index].mutex); return sizeof(unsigned char); }
void usbi_free_fd(int fd) { int _index; CHECK_INIT_POLLING; _index = _fd_to_index_and_lock(fd); if (_index < 0) { return; } _free_index(_index); LeaveCriticalSection(&_poll_fd[_index].mutex); }
/* * Release a pollable file descriptor. * * Note that the associated Windows handle is not closed by this call */ void usbi_free_fd(struct winfd *wfd) { int _index; CHECK_INIT_POLLING; _index = _fd_to_index_and_lock(wfd->fd); if (_index < 0) { return; } _free_index(_index); *wfd = INVALID_WINFD; LeaveCriticalSection(&_poll_fd[_index].mutex); }
/* * close a fake pipe fd */ int usbi_close(int fd) { int _index; int r = -1; CHECK_INIT_POLLING; _index = _fd_to_index_and_lock(fd); if (_index < 0) { errno = EBADF; } else { free_overlapped(poll_fd[_index].overlapped); poll_fd[_index] = INVALID_WINFD; LeaveCriticalSection(&_poll_fd[_index].mutex); } return r; }
/* * synchronous read for fake "pipe" signaling */ ssize_t usbi_read(int fd, void *buf, size_t count) { int _index; ssize_t r = -1; UNUSED(buf); CHECK_INIT_POLLING; if (count != sizeof(unsigned char)) { usbi_err(NULL, "this function should only used for signaling"); return -1; } _index = _fd_to_index_and_lock(fd); if (_index < 0) { errno = EBADF; return -1; } if (WaitForSingleObject(poll_fd[_index].overlapped->hEvent, INFINITE) != WAIT_OBJECT_0) { usbi_warn(NULL, "waiting for event failed: %d", (int)GetLastError()); errno = EIO; goto out; } poll_dbg("clr pipe event (fd = %d, thread = %08X)", _index, GetCurrentThreadId()); poll_fd[_index].overlapped->InternalHigh--; // Don't reset unless we don't have any more events to process if (poll_fd[_index].overlapped->InternalHigh <= 0) { ResetEvent(poll_fd[_index].overlapped->hEvent); poll_fd[_index].overlapped->Internal = STATUS_PENDING; } r = sizeof(unsigned char); out: LeaveCriticalSection(&_poll_fd[_index].mutex); return r; }
/* * synchronous write for fake "pipe" signaling */ ssize_t usbi_write(int fd, const void *buf, size_t count) { int _index, i; struct pipe_data *item; const unsigned char * cbuf = (unsigned char*) buf; CHECK_INIT_POLLING; _index = _fd_to_index_and_lock(fd); if ( (_index < 0) || (poll_fd[_index].overlapped == NULL) ) { errno = EBADF; if (_index >= 0) { LeaveCriticalSection(&_poll_fd[_index].mutex); } return -1; } item = calloc(1, sizeof(*item)); item->data = calloc(sizeof(unsigned char), count+1); item->count = count; for(i = 0; i < count; i++) { item->data[i] = cbuf[i]; } list_add(&item->list, &_poll_fd[_index].list); poll_dbg("set pipe event (fd = %d, thread = %08X)", _index, GetCurrentThreadId()); SetEvent(poll_fd[_index].overlapped->hEvent); poll_fd[_index].overlapped->Internal = STATUS_WAIT_0; // If two threads write on the pipe at the same time, we need to // process two separate reads => use the overlapped as a counter poll_fd[_index].overlapped->InternalHigh++; LeaveCriticalSection(&_poll_fd[_index].mutex); return count; }
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; }
/* * synchronous read for fake "pipe" signaling */ ssize_t usbi_read(int fd, void *buf, size_t count) { struct pipe_data * pdata; int _index; int res; ssize_t r = -1; CHECK_INIT_POLLING; _index = _fd_to_index_and_lock(fd); if (_index < 0) { errno = EBADF; return -1; } res = WaitForSingleObject(poll_fd[_index].overlapped->hEvent, INFINITE); if (res != WAIT_OBJECT_0) { usbi_warn(NULL, "waiting for event failed: %d", (int)GetLastError()); errno = EIO; goto out; } poll_fd[_index].overlapped->InternalHigh--; // Don't reset unless we don't have any more events to process if (poll_fd[_index].overlapped->InternalHigh <= 0) { ResetEvent(poll_fd[_index].overlapped->hEvent); poll_fd[_index].overlapped->Internal = STATUS_PENDING; } poll_dbg("clr pipe event (fd = %d, thread = %08X)", _index, GetCurrentThreadId()); if (list_empty(&_poll_fd[_index].list)) { usbi_warn(NULL, "no data in the poll"); r = 0; } else { int i; ssize_t t; unsigned char* cbuf = (unsigned char*) buf; pdata = list_entry(_poll_fd[_index].list.next, struct pipe_data, list); if (pdata == NULL) { usbi_err(NULL, "no pdata"); r = 0; goto out; } if (pdata->data == NULL){ usbi_err(NULL, "no data"); r = 0; goto out; } t = MIN(pdata->count, count); for(i = 0; i < t; i++) { cbuf[i] = pdata->data[i]; } free(pdata->data); list_del(&(pdata->list)); free(pdata); r = t; } out: LeaveCriticalSection(&_poll_fd[_index].mutex); return r; }
/* 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; }