Skip to content

Commit d0732cd

Browse files
authored
hidapi/windows: do not wait in GetOverlappedResult() in hid_read_timeout() (#577)
This is unsafe because the event is auto-reset, therefore the call to WaitForSingleObject() resets the event which GetOverlappedResult() will try to wait on. Even though the overlapped operation is guaranteed to be completed at the point we call GetOverlappedResult(), it will still wait on the event handle for a short time to trigger the reset for auto-reset events. This amounts to roughly a 100 ms sleep each time GetOverlappedResult() is called for a completed I/O with a non-signalled event. In the context of HIDAPI, this extra sleep means that callers that loop on hid_read_timeout() with timeout=0 will loop forever, since the 100 ms sleep each iteration ensures ReadFile() will always have new data. Signed-off-by: Cameron Gutman <[email protected]> Signed-off-by: Sam Lantinga <[email protected]>
1 parent 76462bd commit d0732cd

File tree

1 file changed

+11
-12
lines changed

1 file changed

+11
-12
lines changed

windows/hid.c

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1163,20 +1163,19 @@ int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char
11631163
}
11641164

11651165
if (overlapped) {
1166-
if (milliseconds >= 0) {
1167-
/* See if there is any data yet. */
1168-
res = WaitForSingleObject(ev, milliseconds);
1169-
if (res != WAIT_OBJECT_0) {
1170-
/* There was no data this time. Return zero bytes available,
1171-
but leave the Overlapped I/O running. */
1172-
return 0;
1173-
}
1166+
/* See if there is any data yet. */
1167+
res = WaitForSingleObject(ev, milliseconds >= 0 ? (DWORD)milliseconds : INFINITE);
1168+
if (res != WAIT_OBJECT_0) {
1169+
/* There was no data this time. Return zero bytes available,
1170+
but leave the Overlapped I/O running. */
1171+
return 0;
11741172
}
11751173

1176-
/* Either WaitForSingleObject() told us that ReadFile has completed, or
1177-
we are in non-blocking mode. Get the number of bytes read. The actual
1178-
data has been copied to the data[] array which was passed to ReadFile(). */
1179-
res = GetOverlappedResult(dev->device_handle, &dev->ol, &bytes_read, TRUE/*wait*/);
1174+
/* Get the number of bytes read. The actual data has been copied to the data[]
1175+
array which was passed to ReadFile(). We must not wait here because we've
1176+
already waited on our event above, and since it's auto-reset, it will have
1177+
been reset back to unsignalled by now. */
1178+
res = GetOverlappedResult(dev->device_handle, &dev->ol, &bytes_read, FALSE/*don't wait now - already did on the prev step*/);
11801179
}
11811180
/* Set pending back to false, even if GetOverlappedResult() returned error. */
11821181
dev->read_pending = FALSE;

0 commit comments

Comments
 (0)