From b2be32bfce7c9b5caa124ce07cf3906d608ae3f4 Mon Sep 17 00:00:00 2001 From: Ludvig Michaelsson Date: Thu, 21 Dec 2023 17:09:36 +0100 Subject: [PATCH] osx: handle report_callback() firing multiple times One invocation of CFRunLoopRunInMode() may fire report_callback() multiple times. In such a case, the next call to fido_hid_read() may block for the full duration of the timeout. We can handle this by querying the (non-blocking) pipe for any readily available data on entering fido_hid_read() and fall back to executing the run loop if it was empty. Debugged with @elibon99 and @martelletto. --- src/hid_osx.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/hid_osx.c b/src/hid_osx.c index bd2e1c60..f57d2dbe 100644 --- a/src/hid_osx.c +++ b/src/hid_osx.c @@ -552,11 +552,19 @@ fido_hid_read(void *handle, unsigned char *buf, size_t len, int ms) return (-1); } - schedule_io_loop(ctx, ms); - + /* check for pending frame */ if ((r = read(ctx->report_pipe[0], buf, len)) == -1) { - fido_log_error(errno, "%s: read", __func__); - return (-1); + if (errno != EAGAIN && errno != EWOULDBLOCK) { + fido_log_error(errno, "%s: read", __func__); + return (-1); + } + + schedule_io_loop(ctx, ms); + + if ((r = read(ctx->report_pipe[0], buf, len)) == -1) { + fido_log_error(errno, "%s: read", __func__); + return (-1); + } } if (r < 0 || (size_t)r != len) {