[PATCH] hidclass.sys: When processing reads fill all the buffers

Aric Stewart aric at codeweavers.com
Thu Jan 26 08:12:17 CST 2017


Hi Sebastian,


On 1/26/17 8:03 AM, Sebastian Lackner wrote:
> On 26.01.2017 13:57, Aric Stewart wrote:
>> This is a follow-up fix for continuing work on bug 42225
>>
>> Signed-off-by: Aric Stewart <aric at codeweavers.com>
>> ---
>>  dlls/hidclass.sys/buffer.c | 34 +++++++++++++++++++++++++++++++++-
>>  dlls/hidclass.sys/device.c |  2 +-
>>  dlls/hidclass.sys/hid.h    |  3 ++-
>>  3 files changed, 36 insertions(+), 3 deletions(-)
>>
>>
>>
>> 0001-hidclass.sys-When-processing-reads-fill-all-the-buffer.txt
>>
>>
>> diff --git a/dlls/hidclass.sys/buffer.c b/dlls/hidclass.sys/buffer.c
>> index 0b29f97b69..41bbb8e241 100644
>> --- a/dlls/hidclass.sys/buffer.c
>> +++ b/dlls/hidclass.sys/buffer.c
>> @@ -127,7 +127,7 @@ NTSTATUS RingBuffer_SetSize(struct ReportRingBuffer *ring, UINT size)
>>      return STATUS_SUCCESS;
>>  }
>>  
>> -void RingBuffer_Read(struct ReportRingBuffer *ring, UINT index, void *output, UINT *size)
>> +void RingBuffer_ReadNew(struct ReportRingBuffer *ring, UINT index, void *output, UINT *size)
>>  {
>>      void *ret = NULL;
>>  
>> @@ -155,6 +155,38 @@ void RingBuffer_Read(struct ReportRingBuffer *ring, UINT index, void *output, UI
>>      }
>>  }
>>  
>> +void RingBuffer_Read(struct ReportRingBuffer *ring, UINT index, void *output, UINT *size)
>> +{
>> +    int pointer = ring->pointers[index];
>> +    void *ret = NULL;
>> +
>> +    EnterCriticalSection(&ring->lock);
>> +    if (index >= ring->pointer_alloc || ring->pointers[index] == POINTER_UNUSED
>> +        || ring->end == ring->start)
>> +    {
>> +        LeaveCriticalSection(&ring->lock);
>> +        *size = 0;
>> +        return;
>> +    }
>> +
>> +    if (pointer == ring->end)
>> +        pointer--;
>> +
>> +    if (pointer < 0)
>> +        pointer = ring->size - 1;
>> +
>> +    ret = &ring->buffer[pointer * ring->buffer_size];
>> +    memcpy(output, ret, ring->buffer_size);
>> +    if (pointer == ring->pointers[index])
>> +    {
>> +        ring->pointers[index]++;
>> +        if (ring->pointers[index] == ring->size)
>> +            ring->pointers[index] = 0;
>> +    }
>> +    LeaveCriticalSection(&ring->lock);
>> +    *size = ring->buffer_size;
> 
> Have you been able to reproduce a similar behavior on Windows? The new code

Yes, I have a test case that produces behavior similar to bug 42225, But I have not been successful at getting even the start of the testing framework in place to be able to put in more tests.

> looks very suspicious and I'm not sure if this is the right approach to fix

Ok, suggestions? 

> it. Also please note that this will effectively disable any asynchronous
> Read requests - HID_Device_read() will always use the first code path when
> there is at least one package in the ring buffer and never return
> STATUS_PENDING.
> 

Nope, it will not. HID_Device_read uses RingBuffer_ReadNew. So the behavior there will be unchanged. This only affects HID_Device_processQueue, which is only called when the device has received a report and has pending IRP requests.  The trick is that if a single FileOpen makes multiple asynchronous FileRead requests all of them should be fulfilled not just the first one. 

-aric


>> +}
>> +
>>  UINT RingBuffer_AddPointer(struct ReportRingBuffer *ring)
>>  {
>>      UINT idx;
>> diff --git a/dlls/hidclass.sys/device.c b/dlls/hidclass.sys/device.c
>> index b241016e72..d6a0a358e3 100644
>> --- a/dlls/hidclass.sys/device.c
>> +++ b/dlls/hidclass.sys/device.c
>> @@ -662,7 +662,7 @@ NTSTATUS WINAPI HID_Device_read(DEVICE_OBJECT *device, IRP *irp)
>>      ptr = PtrToUlong( irp->Tail.Overlay.OriginalFileObject->FsContext );
>>  
>>      irp->IoStatus.Information = 0;
>> -    RingBuffer_Read(ext->ring_buffer, ptr, packet, &buffer_size);
>> +    RingBuffer_ReadNew(ext->ring_buffer, ptr, packet, &buffer_size);
>>  
>>      if (buffer_size)
>>      {
>> diff --git a/dlls/hidclass.sys/hid.h b/dlls/hidclass.sys/hid.h
>> index adc547cc43..1829319ccf 100644
>> --- a/dlls/hidclass.sys/hid.h
>> +++ b/dlls/hidclass.sys/hid.h
>> @@ -62,7 +62,8 @@ typedef struct _BASE_DEVICE_EXTENSION {
>>  void RingBuffer_Write(struct ReportRingBuffer *buffer, void *data) DECLSPEC_HIDDEN;
>>  UINT RingBuffer_AddPointer(struct ReportRingBuffer *buffer) DECLSPEC_HIDDEN;
>>  void RingBuffer_RemovePointer(struct ReportRingBuffer *ring, UINT index) DECLSPEC_HIDDEN;
>> -void RingBuffer_Read(struct ReportRingBuffer *buffer, UINT index, void *output, UINT *size) DECLSPEC_HIDDEN;
>> +void RingBuffer_Read(struct ReportRingBuffer *ring, UINT index, void *output, UINT *size) DECLSPEC_HIDDEN;
>> +void RingBuffer_ReadNew(struct ReportRingBuffer *buffer, UINT index, void *output, UINT *size) DECLSPEC_HIDDEN;
>>  UINT RingBuffer_GetBufferSize(struct ReportRingBuffer *buffer) DECLSPEC_HIDDEN;
>>  UINT RingBuffer_GetSize(struct ReportRingBuffer *buffer) DECLSPEC_HIDDEN;
>>  void RingBuffer_Destroy(struct ReportRingBuffer *buffer) DECLSPEC_HIDDEN;
>>
>>
>>
> 



More information about the wine-devel mailing list