Skip to content

[bug fix] driver_vive: fix timeout-never-resubmits and missing clear_halt-on-STALL bugs - #378

Open
rocketmark wants to merge 1 commit into
collabora:masterfrom
rocketmark:upstream-pr/driver-vive-timeout-stall-fixes
Open

rocketmark wants to merge 1 commit into
collabora:masterfrom
rocketmark:upstream-pr/driver-vive-timeout-stall-fixes

Conversation

@rocketmark

Copy link
Copy Markdown
Contributor

Summary

handle_transfer()'s USB transfer retry logic has two bugs: the timeout path never resubmits below the disconnect threshold, and a STALL is retried without clearing the halt condition first.

(Note: #372, open, fixes two other bugs in this same function — error_count double-incremented, and falling through to disconnect after a successful resubmit instead of returning. This PR deliberately leaves those two lines untouched to avoid overlapping with that PR.)

Demonstration

BEFORE fix:
status = LIBUSB_TRANSFER_TIMED_OUT, consecutive_timeouts = 1 (below the disconnect threshold)
libusb_submit_transfer() never called
Result: endpoint stops producing further completions, permanently

status = LIBUSB_TRANSFER_STALL
libusb_clear_halt() never called
(resubmit proceeds anyway)
Result: the retry is guaranteed to stall again

AFTER fix:
status = LIBUSB_TRANSFER_TIMED_OUT, consecutive_timeouts = 1
libusb_submit_transfer() called
Result: endpoint resubmitted, keeps operating

status = LIBUSB_TRANSFER_STALL
libusb_clear_halt() called
Result: halt condition cleared before the retry is submitted
Impact

Reachable any time a USB transfer doesn't complete cleanly — an ordinary timeout or stall, not an edge case. As it stands, any endpoint that times out even once stops producing further completions permanently, and a stalled endpoint's retry is guaranteed to fail the same way.

Change

One file, src/driver_vive.libusb.h. In handle_transfer(): (1) resubmit the transfer before returning on a sub-threshold timeout, (2) call libusb_clear_halt() before retrying a STALL. Includes a regression test (driver_vive_timeout_stall_test.c) against a fake libusb (mock_libusb.c), reproducing each bug independently and without hardware.

Found via

Found while auditing handle_transfer()'s retry/error-handling logic. Confirmed each bug independently with a deterministic test harness.

…ALL bugs

Two bugs in handle_transfer()'s USB transfer retry logic:

1. On LIBUSB_TRANSFER_TIMED_OUT, below the consecutive-timeout/RF-device
   disconnect threshold, the function returned without resubmitting the
   transfer. Once an endpoint times out even once, nothing resubmits it
   again, so it silently stops producing further transfer completions.

2. LIBUSB_TRANSFER_STALL was retried without calling libusb_clear_halt()
   first, so the retry was guaranteed to stall again.

Both confirmed with a new regression test (driver_vive_timeout_stall_test.c)
that drives the real, unmodified handle_transfer/AttachInterface code
against a fake libusb (mock_libusb.c, no hardware needed).

Before this fix, with the included test:
  consecutive_timeouts: 1, submit calls: 0        (never resubmitted)
  clear_halt calls: 0 (expected 1)                (retry guaranteed to
                                                     stall again)
After: both pass with the expected values.

Note: collabora#372 fixes two related but distinct bugs in the same function
(error_count double-incremented, and falling through to disconnect after
a successful resubmit instead of returning) -- this PR deliberately
leaves those two lines untouched to avoid overlapping with that PR.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant