Skip to content

Commit

Permalink
Handle empty queue after K_CF_RUN_LOOP_RUN_HANDLED_SOURCE
Browse files Browse the repository at this point in the history
Occassionally CFRunLoopInMode() returns K_CF_RUN_LOOP_RUN_HANDLED_SOURCE
even though the _hid_read_callback() has not been invoked, resulting
in reading from an empty queue. We can handle this by re-running the run
loop with a retry mechanism.
  • Loading branch information
elibon99 committed Jan 7, 2025
1 parent 8b5939a commit 49192f3
Showing 1 changed file with 22 additions and 8 deletions.
30 changes: 22 additions & 8 deletions fido2/hid/macos.py
Original file line number Diff line number Diff line change
Expand Up @@ -253,14 +253,28 @@ def _dev_read_thread(hid_device):
hid_device.handle, REMOVAL_CALLBACK, ctypes.py_object(hid_device)
)

# Run the run loop
run_loop_run_result = cf.CFRunLoopRunInMode(
K_CF_RUNLOOP_DEFAULT_MODE, 4, True # Timeout in seconds
) # Return after source handled

# log any unexpected run loop exit
if run_loop_run_result != K_CF_RUN_LOOP_RUN_HANDLED_SOURCE:
logger.error("Unexpected run loop exit code: %d", run_loop_run_result)
max_retries = 2 # Maximum number of run loop retries
retries = 0

while retries < max_retries:
# Run the run loop
run_loop_run_result = cf.CFRunLoopRunInMode(
K_CF_RUNLOOP_DEFAULT_MODE, 4, True # Timeout in seconds
) # Return after source handled

received_data = not hid_device.read_queue.empty()
if run_loop_run_result == K_CF_RUN_LOOP_RUN_HANDLED_SOURCE:
if received_data:
# Return when data has been received
break
else:
# Retry running the run loop if data has not been received yet
logger.debug("Read queue empty after HANDLE_SOURCE, attempting retry")
retries += 1
else:
# log any unexpected run loop exit
logger.error("Unexpected run loop exit code: %d", run_loop_run_result)
break

# Unschedule from run loop
iokit.IOHIDDeviceUnscheduleFromRunLoop(
Expand Down

0 comments on commit 49192f3

Please sign in to comment.