int linux_udev_stop_event_monitor(void) { char dummy = 1; int r; assert(udev_ctx != NULL); assert(udev_monitor != NULL); assert(udev_monitor_fd != -1); /* Write some dummy data to the control pipe and * wait for the thread to exit */ r = usbi_write(udev_control_pipe[1], &dummy, sizeof(dummy)); if (r <= 0) { usbi_warn(NULL, "udev control pipe signal failed"); } pthread_join(linux_event_thread, NULL); /* Release the udev monitor */ udev_monitor_unref(udev_monitor); udev_monitor = NULL; udev_monitor_fd = -1; /* Clean up the udev context */ udev_unref(udev_ctx); udev_ctx = NULL; /* close and reset control pipe */ close(udev_control_pipe[0]); close(udev_control_pipe[1]); udev_control_pipe[0] = -1; udev_control_pipe[1] = -1; return LIBUSB_SUCCESS; }
void API_EXPORTED libusb_hotplug_deregister_callback (struct libusb_context *ctx, libusb_hotplug_callback_handle handle) { struct libusb_hotplug_callback *hotplug_cb; libusb_hotplug_message message; ssize_t ret; /* check for hotplug support */ if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) { return; } USBI_GET_CONTEXT(ctx); usbi_mutex_lock(&ctx->hotplug_cbs_lock); list_for_each_entry(hotplug_cb, &ctx->hotplug_cbs, list, struct libusb_hotplug_callback) { if (handle == hotplug_cb->handle) { /* Mark this callback for deregistration */ hotplug_cb->needs_free = 1; } } usbi_mutex_unlock(&ctx->hotplug_cbs_lock); /* wakeup handle_events to do the actual free */ memset(&message, 0, sizeof(message)); ret = usbi_write(ctx->hotplug_pipe[1], &message, sizeof(message)); if (sizeof(message) != ret) { usbi_err(ctx, "error writing hotplug message"); } }
int linux_netlink_stop_event_monitor(void) { int r; char dummy = 1; if (-1 == linux_netlink_socket) { /* already closed. nothing to do */ return LIBUSB_SUCCESS; } /* Write some dummy data to the control pipe and * wait for the thread to exit */ r = usbi_write(netlink_control_pipe[1], &dummy, sizeof(dummy)); if (r <= 0) { usbi_warn(NULL, "netlink control pipe signal failed"); } pthread_join(libusb_linux_event_thread, NULL); close(linux_netlink_socket); linux_netlink_socket = -1; /* close and reset control pipe */ close(netlink_control_pipe[0]); close(netlink_control_pipe[1]); netlink_control_pipe[0] = -1; netlink_control_pipe[1] = -1; return LIBUSB_SUCCESS; }
int linux_netlink_stop_event_monitor(void) { int r; char dummy = 1; if (-1 == linux_netlink_socket) { return LIBUSB_SUCCESS; } r = usbi_write(netlink_control_pipe[1], &dummy, sizeof(dummy)); if (r <= 0) { usbi_warn(NULL, "netlink control pipe signal failed"); } pthread_join(libusb_linux_event_thread, NULL); close(linux_netlink_socket); linux_netlink_socket = -1; close(netlink_control_pipe[0]); close(netlink_control_pipe[1]); netlink_control_pipe[0] = -1; netlink_control_pipe[1] = -1; return LIBUSB_SUCCESS; }
void API_EXPORTED libusb_close(libusb_device_handle *dev_handle) { struct libusb_context *ctx; unsigned char dummy = 1; ssize_t r; if (!dev_handle) return; usbi_dbg(""); ctx = HANDLE_CTX(dev_handle); usbi_mutex_lock(&ctx->pollfd_modify_lock); ctx->pollfd_modify++; usbi_mutex_unlock(&ctx->pollfd_modify_lock); r = usbi_write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy)); if (r <= 0) { usbi_warn(ctx, "internal signalling write failed, closing anyway"); do_close(ctx, dev_handle); usbi_mutex_lock(&ctx->pollfd_modify_lock); ctx->pollfd_modify--; usbi_mutex_unlock(&ctx->pollfd_modify_lock); return; } libusb_lock_events(ctx); r = usbi_read(ctx->ctrl_pipe[0], &dummy, sizeof(dummy)); if (r <= 0) usbi_warn(ctx, "internal signalling read failed, closing anyway"); do_close(ctx, dev_handle); usbi_mutex_lock(&ctx->pollfd_modify_lock); ctx->pollfd_modify--; usbi_mutex_unlock(&ctx->pollfd_modify_lock); libusb_unlock_events(ctx); }
void usbi_connect_device(struct libusb_device *dev) { libusb_hotplug_message message; ssize_t ret; memset(&message, 0, sizeof(message)); message.event = LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED; message.device = dev; dev->attached = 1; usbi_mutex_lock(&dev->ctx->usb_devs_lock); list_add(&dev->list, &dev->ctx->usb_devs); usbi_mutex_unlock(&dev->ctx->usb_devs_lock); if (libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG) && dev->ctx->hotplug_pipe[1] > 0) { ret = usbi_write(dev->ctx->hotplug_pipe[1], &message, sizeof(message)); if (sizeof (message) != ret) { usbi_err(DEVICE_CTX(dev), "error writing hotplug message"); } } }
void usbi_fd_notification(struct libusb_context *ctx) { unsigned char dummy = 1; ssize_t r; if (ctx == NULL) return; usbi_mutex_lock(&ctx->pollfd_modify_lock); ctx->pollfd_modify++; usbi_mutex_unlock(&ctx->pollfd_modify_lock); r = usbi_write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy)); if (r <= 0) { usbi_warn(ctx, "internal signalling write failed"); usbi_mutex_lock(&ctx->pollfd_modify_lock); ctx->pollfd_modify--; usbi_mutex_unlock(&ctx->pollfd_modify_lock); return; } libusb_lock_events(ctx); r = usbi_read(ctx->ctrl_pipe[0], &dummy, sizeof(dummy)); if (r <= 0) usbi_warn(ctx, "internal signalling read failed"); usbi_mutex_lock(&ctx->pollfd_modify_lock); ctx->pollfd_modify--; usbi_mutex_unlock(&ctx->pollfd_modify_lock); libusb_unlock_events(ctx); }
int event_run_platform(Array *event_sources, bool *running, EventCleanupFunction cleanup) { int result = -1; int i; EventSource *event_source; fd_set *fd_read_set; fd_set *fd_write_set; fd_set *fd_error_set; int ready; int handled; uint8_t byte = 1; int rc; int event_source_count; uint32_t received_events; if (event_add_source(_usb_poll_ready_pipe.read_end, EVENT_SOURCE_TYPE_GENERIC, EVENT_READ, event_forward_usb_events, event_sources) < 0) { return -1; } *running = true; _usb_poll_running = true; thread_create(&_usb_poll_thread, event_poll_usb_events, event_sources); cleanup(); event_cleanup_sources(); while (*running) { // update SocketSet arrays if (event_reserve_socket_set(&_socket_read_set, // FIXME: this over-allocates event_sources->count) < 0) { log_error("Could not resize socket read set: %s (%d)", get_errno_name(errno), errno); goto cleanup; } if (event_reserve_socket_set(&_socket_write_set, // FIXME: this over-allocates event_sources->count) < 0) { log_error("Could not resize socket write set: %s (%d)", get_errno_name(errno), errno); goto cleanup; } if (event_reserve_socket_set(&_socket_error_set, // FIXME: this over-allocates event_sources->count) < 0) { log_error("Could not resize socket error set: %s (%d)", get_errno_name(errno), errno); goto cleanup; } _socket_read_set->count = 0; _socket_write_set->count = 0; _socket_error_set->count = 0; for (i = 0; i < event_sources->count; ++i) { event_source = array_get(event_sources, i); if (event_source->type != EVENT_SOURCE_TYPE_GENERIC) { continue; } if ((event_source->events & EVENT_READ) != 0) { _socket_read_set->sockets[_socket_read_set->count++] = event_source->handle; } if ((event_source->events & EVENT_WRITE) != 0) { _socket_write_set->sockets[_socket_write_set->count++] = event_source->handle; } if ((event_source->events & EVENT_PRIO) != 0) { log_error("Event prio is not supported"); } if ((event_source->events & EVENT_ERROR) != 0) { _socket_error_set->sockets[_socket_error_set->count++] = event_source->handle; } } // start to select log_event_debug("Starting to select on %d + %d + %d %s event source(s)", _socket_read_set->count, _socket_write_set->count, _socket_error_set->count, event_get_source_type_name(EVENT_SOURCE_TYPE_GENERIC, false)); semaphore_release(&_usb_poll_resume); fd_read_set = event_get_socket_set_as_fd_set(_socket_read_set); fd_write_set = event_get_socket_set_as_fd_set(_socket_write_set); fd_error_set = event_get_socket_set_as_fd_set(_socket_error_set); ready = select(0, fd_read_set, fd_write_set, fd_error_set, NULL); if (_usb_poll_running) { log_event_debug("Sending suspend signal to USB poll thread"); if (usbi_write(_usb_poll_suspend_pipe[1], &byte, 1) < 0) { log_error("Could not write to USB suspend pipe"); _usb_poll_stuck = true; goto cleanup; } semaphore_acquire(&_usb_poll_suspend); if (usbi_read(_usb_poll_suspend_pipe[0], &byte, 1) < 0) { log_error("Could not read from USB suspend pipe"); _usb_poll_stuck = true; goto cleanup; } } if (ready == SOCKET_ERROR) { rc = ERRNO_WINAPI_OFFSET + WSAGetLastError(); if (rc == ERRNO_WINAPI_OFFSET + WSAEINTR) { continue; } log_error("Could not select on %s event sources: %s (%d)", event_get_source_type_name(EVENT_SOURCE_TYPE_GENERIC, false), get_errno_name(rc), rc); goto cleanup; } // handle select result log_event_debug("Select returned %d %s event source(s) as ready", ready, event_get_source_type_name(EVENT_SOURCE_TYPE_GENERIC, false)); handled = 0; // cache event source count here to avoid looking at new event // sources that got added during the event handling event_source_count = event_sources->count; for (i = 0; *running && i < event_source_count && ready > handled; ++i) { event_source = array_get(event_sources, i); received_events = 0; if (event_source->type != EVENT_SOURCE_TYPE_GENERIC) { continue; } if (FD_ISSET(event_source->handle, fd_read_set)) { received_events |= EVENT_READ; } if (FD_ISSET(event_source->handle, fd_write_set)) { received_events |= EVENT_WRITE; } if (FD_ISSET(event_source->handle, fd_error_set)) { received_events |= EVENT_ERROR; } if (received_events == 0) { continue; } event_handle_source(event_source, received_events); ++handled; } if (ready == handled) { log_event_debug("Handled all ready %s event sources", event_get_source_type_name(EVENT_SOURCE_TYPE_GENERIC, false)); } else if (*running) { log_warn("Handled only %d of %d ready %s event source(s)", handled, ready, event_get_source_type_name(EVENT_SOURCE_TYPE_GENERIC, false)); } // now cleanup event sources that got marked as disconnected/removed // during the event handling cleanup(); event_cleanup_sources(); } result = 0; cleanup: *running = false; if (_usb_poll_running && !_usb_poll_stuck) { _usb_poll_running = false; log_debug("Stopping USB poll thread"); if (usbi_write(_usb_poll_suspend_pipe[1], &byte, 1) < 0) { log_error("Could not write to USB suspend pipe"); } else { semaphore_release(&_usb_poll_resume); thread_join(&_usb_poll_thread); } } thread_destroy(&_usb_poll_thread); event_remove_source(_usb_poll_ready_pipe.read_end, EVENT_SOURCE_TYPE_GENERIC); return result; }
int API_EXPORTED libusb_interrupt_handle_event(struct libusb_context* ctx) { unsigned char dummy = 1; USBI_GET_CONTEXT(ctx); return usbi_write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy)); }
int event_run_platform(Array *event_sources, int *running) { int result = -1; int i; EventSource *event_source; fd_set *fd_read_set; fd_set *fd_write_set; int ready; int handled; uint8_t byte = 1; int rc; int event_source_count; int received_events; if (event_add_source(_usb_poller.ready_pipe[0], EVENT_SOURCE_TYPE_GENERIC, EVENT_READ, event_forward_usb_events, event_sources) < 0) { return -1; } *running = 1; _usb_poller.running = 1; thread_create(&_usb_poller.thread, event_poll_usb_events, event_sources); event_cleanup_sources(); while (*running) { // update SocketSet arrays if (event_reserve_socket_set(&_socket_read_set, // FIXME: this over allocates event_sources->count) < 0) { log_error("Could not resize socket read set: %s (%d)", get_errno_name(errno), errno); goto cleanup; } if (event_reserve_socket_set(&_socket_write_set, // FIXME: this over allocates event_sources->count) < 0) { log_error("Could not resize socket write set: %s (%d)", get_errno_name(errno), errno); goto cleanup; } _socket_read_set->count = 0; _socket_write_set->count = 0; for (i = 0; i < event_sources->count; i++) { event_source = array_get(event_sources, i); if (event_source->type != EVENT_SOURCE_TYPE_GENERIC) { continue; } if (event_source->events & EVENT_READ) { _socket_read_set->sockets[_socket_read_set->count++] = event_source->handle; } if (event_source->events & EVENT_WRITE) { _socket_write_set->sockets[_socket_write_set->count++] = event_source->handle; } } // start to select log_debug("Starting to select on %d + %d %s event source(s)", _socket_read_set->count, _socket_write_set->count, event_get_source_type_name(EVENT_SOURCE_TYPE_GENERIC, 0)); semaphore_release(&_usb_poller.resume); fd_read_set = event_get_socket_set_as_fd_set(_socket_read_set); fd_write_set = event_get_socket_set_as_fd_set(_socket_write_set); ready = select(0, fd_read_set, fd_write_set, NULL, NULL); if (_usb_poller.running) { log_debug("Sending suspend signal to USB poll thread"); if (usbi_write(_usb_poller.suspend_pipe[1], &byte, 1) < 0) { log_error("Could not write to USB suspend pipe"); _usb_poller.stuck = 1; *running = 0; goto cleanup; } semaphore_acquire(&_usb_poller.suspend); if (usbi_read(_usb_poller.suspend_pipe[0], &byte, 1) < 0) { log_error("Could not read from USB suspend pipe"); _usb_poller.stuck = 1; *running = 0; goto cleanup; } } if (ready < 0) { rc = ERRNO_WINAPI_OFFSET + WSAGetLastError(); if (rc == ERRNO_WINAPI_OFFSET + WSAEINTR) { continue; } log_error("Could not select on %s event sources: %s (%d)", event_get_source_type_name(EVENT_SOURCE_TYPE_GENERIC, 0), get_errno_name(rc), rc); *running = 0; goto cleanup; } // handle select result log_debug("Select returned %d %s event source(s) as ready", ready, event_get_source_type_name(EVENT_SOURCE_TYPE_GENERIC, 0)); handled = 0; // cache event source count here to avoid looking at new event // sources that got added during the event handling event_source_count = event_sources->count; for (i = 0; i < event_source_count && ready > handled; ++i) { event_source = array_get(event_sources, i); received_events = 0; if (event_source->type != EVENT_SOURCE_TYPE_GENERIC) { continue; } if (FD_ISSET(event_source->handle, fd_read_set)) { received_events |= EVENT_READ; } if (FD_ISSET(event_source->handle, fd_write_set)) { received_events |= EVENT_WRITE; } if (received_events == 0) { continue; } if (event_source->state != EVENT_SOURCE_STATE_NORMAL) { log_debug("Ignoring %s event source (handle: %d, received events: %d) marked as removed at index %d", event_get_source_type_name(event_source->type, 0), event_source->handle, received_events, i); } else { log_debug("Handling %s event source (handle: %d, received events: %d) at index %d", event_get_source_type_name(event_source->type, 0), event_source->handle, received_events, i); if (event_source->function != NULL) { event_source->function(event_source->opaque); } } ++handled; if (!*running) { break; } } if (ready == handled) { log_debug("Handled all ready %s event sources", event_get_source_type_name(EVENT_SOURCE_TYPE_GENERIC, 0)); } else { log_warn("Handled only %d of %d ready %s event source(s)", handled, ready, event_get_source_type_name(EVENT_SOURCE_TYPE_GENERIC, 0)); } // now remove event sources that got marked as removed during the // event handling event_cleanup_sources(); } result = 0; cleanup: if (_usb_poller.running && !_usb_poller.stuck) { _usb_poller.running = 0; log_debug("Stopping USB poll thread"); if (usbi_write(_usb_poller.suspend_pipe[1], &byte, 1) < 0) { log_error("Could not write to USB suspend pipe"); } else { semaphore_release(&_usb_poller.resume); thread_join(&_usb_poller.thread); } } event_remove_source(_usb_poller.ready_pipe[0], EVENT_SOURCE_TYPE_GENERIC); return result; }