Add 500ms max wait time for hid_write to complete on Windows
authorSam Lantinga <slouken@libsdl.org>
Tue, 03 Mar 2020 09:22:43 -0800
changeset 13584fcecab4713f7
parent 13583 88068887c25d
child 13585 32a52ab3133c
Add 500ms max wait time for hid_write to complete on Windows
It appears that with some (presumably) flaky drivers or hardware that the WriteFile in hid_write never completes leading to GetOverlappedResult to block forever waiting for it.
src/hidapi/windows/hid.c
     1.1 --- a/src/hidapi/windows/hid.c	Mon Mar 02 17:31:58 2020 -0800
     1.2 +++ b/src/hidapi/windows/hid.c	Tue Mar 03 09:22:43 2020 -0800
     1.3 @@ -63,6 +63,11 @@
     1.4  
     1.5  /*#define HIDAPI_USE_DDK*/
     1.6  
     1.7 +/* The timeout in milliseconds for waiting on WriteFile to 
     1.8 +   complete in hid_write. The longest observed time to do a output
     1.9 +   report that we've seen is ~200-250ms so let's double that */
    1.10 +#define HID_WRITE_TIMEOUT_MILLISECONDS 500
    1.11 +
    1.12  #ifdef __cplusplus
    1.13  extern "C" {
    1.14  #endif
    1.15 @@ -163,6 +168,7 @@
    1.16  		BOOL read_pending;
    1.17  		char *read_buf;
    1.18  		OVERLAPPED ol;
    1.19 +		OVERLAPPED write_ol;
    1.20  };
    1.21  
    1.22  static hid_device *new_hid_device()
    1.23 @@ -178,6 +184,8 @@
    1.24  	dev->read_buf = NULL;
    1.25  	memset(&dev->ol, 0, sizeof(dev->ol));
    1.26  	dev->ol.hEvent = CreateEvent(NULL, FALSE, FALSE /*initial state f=nonsignaled*/, NULL);
    1.27 +	memset(&dev->write_ol, 0, sizeof(dev->write_ol));
    1.28 +	dev->write_ol.hEvent = CreateEvent(NULL, FALSE, FALSE /*initial state f=nonsignaled*/, NULL);
    1.29  
    1.30  	return dev;
    1.31  }
    1.32 @@ -185,6 +193,7 @@
    1.33  static void free_hid_device(hid_device *dev)
    1.34  {
    1.35  	CloseHandle(dev->ol.hEvent);
    1.36 +	CloseHandle(dev->write_ol.hEvent);
    1.37  	CloseHandle(dev->device_handle);
    1.38  	LocalFree(dev->last_error_str);
    1.39  	free(dev->read_buf);
    1.40 @@ -678,14 +687,12 @@
    1.41  		return -1;
    1.42  }
    1.43  
    1.44 -int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char *data, size_t length)
    1.45 +static int hid_write_timeout(hid_device *dev, const unsigned char *data, size_t length, int milliseconds)
    1.46  {
    1.47  	DWORD bytes_written;
    1.48  	BOOL res;
    1.49  	size_t stashed_length = length;
    1.50 -	OVERLAPPED ol;
    1.51  	unsigned char *buf;
    1.52 -	memset(&ol, 0, sizeof(ol));
    1.53  
    1.54  	/* Make sure the right number of bytes are passed to WriteFile. Windows
    1.55  	   expects the number of bytes which are in the _longest_ report (plus
    1.56 @@ -710,7 +717,7 @@
    1.57  	}
    1.58  	else
    1.59  	{
    1.60 -		res = WriteFile( dev->device_handle, buf, ( DWORD ) length, NULL, &ol );
    1.61 +		res = WriteFile( dev->device_handle, buf, ( DWORD ) length, NULL, &dev->write_ol );
    1.62  		if (!res) {
    1.63  			if (GetLastError() != ERROR_IO_PENDING) {
    1.64  				/* WriteFile() failed. Return error. */
    1.65 @@ -722,7 +729,16 @@
    1.66  
    1.67  		/* Wait here until the write is done. This makes
    1.68  		hid_write() synchronous. */
    1.69 -		res = GetOverlappedResult(dev->device_handle, &ol, &bytes_written, TRUE/*wait*/);
    1.70 +		res = WaitForSingleObject(dev->write_ol.hEvent, milliseconds);
    1.71 +		if (res != WAIT_OBJECT_0)
    1.72 +		{
    1.73 +			// There was a Timeout.
    1.74 +			bytes_written = (DWORD) -1;
    1.75 +			register_error(dev, "WriteFile/WaitForSingleObject Timeout");
    1.76 +			goto end_of_function;
    1.77 +		}
    1.78 +
    1.79 +		res = GetOverlappedResult(dev->device_handle, &dev->write_ol, &bytes_written, FALSE/*F=don't_wait*/);
    1.80  		if (!res) {
    1.81  			/* The Write operation failed. */
    1.82  			register_error(dev, "WriteFile");
    1.83 @@ -737,6 +753,10 @@
    1.84  	return bytes_written;
    1.85  }
    1.86  
    1.87 +int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char *data, size_t length)
    1.88 +{
    1.89 +	return hid_write_timeout(dev, data, length, HID_WRITE_TIMEOUT_MILLISECONDS);
    1.90 +}
    1.91  
    1.92  int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds)
    1.93  {