none
EvtUsbTargetPipeReadComplete synchronization RRS feed

  • Question

  • Hey,

    I am working on a KMDF driver that use an usb continuous reader to read data from an interrupt pipe.

    The idea is the EvtUsbTargetPipeReadComplete read and parse the data, then store some in the device's context space.

    On the other hand, EvtIoDeviceControl handle an ioctl that provide these data to user mode applications, so I need some kind of synchronization to avoid data races.

    I dont use WDF automatic synchronization so I created a spin lock (I dont understand IRQL quite well yet, so I guess it was the best choice over a wait lock).

    However when a user mode application send the ioctl I get a very nice deadlock. Any idea what could cause this?

    Here is some code for you guys

    VOID
    my_driverEvtIoDeviceControl(
        _In_ WDFQUEUE Queue,
        _In_ WDFREQUEST Request,
        _In_ size_t OutputBufferLength,
        _In_ size_t InputBufferLength,
        _In_ ULONG IoControlCode
        )
    {
    	WDFDEVICE device = WdfIoQueueGetDevice(Queue);
    	PDEVICE_CONTEXT pDeviceContext = DeviceGetContext(device);
    
    	switch(IoControlCode)
    	{
    	case IOCTL_MYDEVICE_GET_DATA:
    	{
    		//	Get buffer
    		WDFMEMORY hOutMemory = NULL;
    		NTSTATUS status = WdfRequestRetrieveOutputMemory(Request, &hOutMemory);
    		if (!NT_SUCCESS(status))
    		{
    			WdfRequestComplete(Request, status);
    			break;
    		}
    
    		//	Acquire mutex
    		WdfSpinLockAcquire(pDeviceContext->reportBufferLock);
    
    		//	Get ping pong buffer address
    		PREPORT_BUFFER pBuffer = NULL;
    		if (pDeviceContext->useBuffer1)
    			pBuffer = &pDeviceContext->inReportBuffer1;
    		else
    			pBuffer = &pDeviceContext->inReportBuffer2;
    
    		//	Copy buffer content
    		status = WdfMemoryCopyFromBuffer(hOutMemory, 0, pBuffer, sizeof(REPORT_BUFFER));
    
    		//	Release mutex
    		WdfSpinLockRelease(pDeviceContext->reportBufferLock);
    		if (!NT_SUCCESS(status))
    		{
    			WdfRequestComplete(Request, status);
    			break;
    		}
    		
    		//	Complete with number of bytes copied.
    		WdfRequestCompleteWithInformation(Request, STATUS_SUCCESS, sizeof(REPORT_BUFFER));
    		break;
    	}
    	default:
    		WdfRequestComplete(Request, STATUS_INVALID_DEVICE_REQUEST);
    		break;
    	}
    
        return;
    }

    VOID
    my_driverEvtUsbInterruptPipeReadComplete(
    WDFUSBPIPE  Pipe,
    WDFMEMORY   Buffer,
    size_t      NumBytesTransferred,
    WDFCONTEXT  Context
    )
    {
    	UNREFERENCED_PARAMETER(Pipe);
    
    	PDEVICE_CONTEXT pDeviceContext = Context;
    
    	if (NumBytesTransferred == 0)
    	{
    		return;
    	}
    	
    	PUCHAR pBuffer = WdfMemoryGetBuffer(Buffer, NULL);
    	UCHAR reportID = *pBuffer;
    	if (reportID == 1)
    	{
    		if (NumBytesTransferred < sizeof(REPORT_BUFFER) + 1)
    		{
    			//	Error
    			return;
    		}
    
    		PREPORT_BUFFER pReport = (PREPORT_BUFFER)(pBuffer + 1);
    
    		// Get unused buffer address
    		PREPORT_BUFFER pUnusedBuffer = NULL;
    		if (pDeviceContext->useBuffer1 == 1)
    		{
    			pUnusedBuffer = &pDeviceContext->inReportBuffer2;
    		}
    		else
    		{
    			pUnusedBuffer = &pDeviceContext->inReportBuffer1;
    		}
    
    		// acquire lock
    		WdfSpinLockAcquire(pDeviceContext->reportBufferLock);
    
    		// copy data
    		memcpy(pUnusedBuffer, pReport, sizeof(REPORT_BUFFER));
    
    		// exchange ping pong buffers
    		pDeviceContext->useBuffer1 = !pDeviceContext->useBuffer1;
    
    		// release lock
    		WdfSpinLockRelease(pDeviceContext->reportBufferLock);
    	}
    
    
    }




    • Edited by Potatos Monday, May 11, 2015 9:36 AM
    Monday, May 11, 2015 9:33 AM

All replies

  • nothing looks out of place with the spin lock except in the completion routine you should acquire it before the comparison if (pDeviceContext-> useBuffer1 == 1). I also find it a little suspicious that two buffers are enough. What happens if the app doesn't query in time? The common way to do this is with a ring buffer as an array

    d -- This posting is provided "AS IS" with no warranties, and confers no rights.

    Monday, May 11, 2015 2:22 PM