Skip to content

RFC: Add hid_read_interrupt API for thread-safe read cancellation#799

Open
Youw wants to merge 2 commits intomasterfrom
read-interrupt
Open

RFC: Add hid_read_interrupt API for thread-safe read cancellation#799
Youw wants to merge 2 commits intomasterfrom
read-interrupt

Conversation

@Youw
Copy link
Copy Markdown
Member

@Youw Youw commented Apr 26, 2026

New functions on hid_device, implemented across all five backends (linux, libusb, mac, windows, netbsd):

hid_read_interrupt - asynchronously cancel a blocked read
hid_is_read_interrupted - query the sticky interrupt state
hid_read_clear_interrupt - clear the state, allowing reads to resume

hid_read_interrupt is the only hidapi function safe to call concurrently with another function on the same device. Other device operations (write, feature/output reports, info getters) are unaffected. Allows a dedicated reader thread to be stopped without busy-polling on a short timeout.

New hid_read_test tool, to check new functionality.

Resolves: #146

Assisted-by: Claude:claude-opus-4.7

New functions on hid_device, implemented across all five backends
(linux, libusb, mac, windows, netbsd):

  hid_read_interrupt          - asynchronously cancel a blocked read
  hid_is_read_interrupted     - query the sticky interrupt state
  hid_read_clear_interrupt    - clear the state, allowing reads to resume

hid_read_interrupt is the only hidapi function safe to call concurrently
with another function on the same device. Other device operations (write,
feature/output reports, info getters) are unaffected. Allows a dedicated
reader thread to be stopped without busy-polling on a short timeout.

New hid_read_test tool, to check new functionality.

Resolves: #146

Assisted-by: Claude:claude-opus-4.7
@Youw Youw requested a review from Copilot April 26, 2026 22:28
@Youw Youw changed the title Add hid_read_interrupt API for thread-safe read cancellation RFC: Add hid_read_interrupt API for thread-safe read cancellation Apr 26, 2026
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a new public HIDAPI mechanism to asynchronously interrupt a blocked hid_read()/hid_read_timeout() call in a thread-safe way (intended to allow clean shutdown of dedicated reader threads without short timeouts/busy polling), and introduces a small hid_read_test utility to exercise the behavior.

Changes:

  • Adds hid_read_interrupt(), hid_is_read_interrupted(), and hid_read_clear_interrupt() to the public header and implements them across all backends.
  • Updates backend hid_read_timeout() implementations to return -1 with an “operation interrupted” read error when interruption is requested.
  • Adds a new optional hid_read_test tool and a top-level CMake option to build it.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
windows/hid.c Implements interrupt via a manual-reset event + interlocked flag and integrates it into WaitForMultipleObjects() in hid_read_timeout().
netbsd/hid.c Implements interrupt via a nonblocking pipe added to the poll() fd set, plus a sticky interrupt flag.
mac/hid.c Implements interrupt via a mutex-protected flag + condition broadcast integrated into the read wait loops.
linux/hid.c Implements interrupt via eventfd added to poll() plus a sticky interrupt flag; adjusts failure cleanup path to call hid_close().
libusb/hid.c Implements interrupt via a mutex-protected flag + condition broadcast integrated into the read wait loops.
hidapi/hidapi.h Adds the public API declarations and documents the intended thread-safety/semantics.
hid_read_test/main.cpp New command-line tool that opens a device, runs a blocking read thread, and interrupts on Enter/Ctrl+C.
hid_read_test/CMakeLists.txt Adds build/install rules for the new test tool (standalone or as a subdir).
CMakeLists.txt Adds HIDAPI_BUILD_HID_READ_TEST option to include the new tool in the build.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread windows/hid.c Outdated
Comment thread linux/hid.c
Comment thread linux/hid.c
Comment thread linux/hid.c
Comment thread netbsd/hid.c Outdated
Comment thread hidapi/hidapi.h
Comment thread hid_read_test/main.cpp
Comment thread hid_read_test/CMakeLists.txt Outdated
@mcuee mcuee added the enhancement New feature or request label Apr 27, 2026
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated 8 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread linux/hid.c
Comment on lines 1160 to +1176
@@ -1149,12 +1165,15 @@ int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t
properly report device disconnection through read() when
in non-blocking mode. */
int ret;
struct pollfd fds;

fds.fd = dev->device_handle;
fds.events = POLLIN;
fds.revents = 0;
ret = poll(&fds, 1, milliseconds);
struct pollfd fds[2];

fds[0].fd = dev->device_handle;
fds[0].events = POLLIN;
fds[0].revents = 0;
fds[1].fd = dev->interrupt_efd;
fds[1].events = POLLIN;
fds[1].revents = 0;
ret = poll(fds, 2, milliseconds);
Comment thread windows/hid.c
Comment on lines +1216 to +1219
/* Interrupt fired and no data is ready. The pending ReadFile is
left in flight; it will resume on the next hid_read_timeout()
call after hid_read_clear_interrupt(). */
register_string_error_to_buffer(&dev->last_read_error_str, L"hid_read_timeout: operation interrupted");
Comment thread hid_read_test/main.cpp
Comment on lines +130 to +133
#ifdef _WIN32
std::signal(SIGINT, on_signal);
#ifdef SIGTERM
std::signal(SIGTERM, on_signal);
Comment thread hid_read_test/main.cpp
Comment on lines +55 to +59
extern "C" void on_signal(int)
{
/* async-signal-safe: atomic store only. Main thread will call
hid_read_interrupt() once cin.get() returns from EINTR. */
g_terminate.store(true, std::memory_order_release);
Comment thread CMakeLists.txt
Comment on lines +95 to +98
option(HIDAPI_BUILD_HID_READ_TEST "Build hid_read_test cmd-line tool" OFF)
if(HIDAPI_BUILD_HID_READ_TEST)
add_subdirectory(hid_read_test)
endif()
Comment thread hidapi/hidapi.h
Comment on lines +448 to +450
This is the only function on hid_device that may be called concurrently
with another function operating on the same device. The call is
idempotent and is safe to invoke when no read is in flight.
Comment thread CMakeLists.txt
Comment on lines +95 to +97
option(HIDAPI_BUILD_HID_READ_TEST "Build hid_read_test cmd-line tool" OFF)
if(HIDAPI_BUILD_HID_READ_TEST)
add_subdirectory(hid_read_test)
Comment thread hidapi/hidapi.h
Comment on lines +480 to +481
1 if the read pipeline is interrupted, 0 if not, -1 on error.
Call hid_error(dev) to get the failure reason.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

add hid_interrupt_read

3 participants