Skip to content

Instantly share code, notes, and snippets.

@maxtruxa
Last active August 29, 2015 13:57
Show Gist options
  • Save maxtruxa/9386345 to your computer and use it in GitHub Desktop.
Save maxtruxa/9386345 to your computer and use it in GitHub Desktop.
WDF ring buffer object #windows #driver
//
// The MIT License (MIT)
//
// Copyright (c) 2013-2014 Max Truxa
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
/*
Module Name:
RingBuffer.c
Abstract:
This file contains functions to work with ring buffer objects.
Environment:
Kernel-mode Driver Framework
*/
#include "Driver.h"
typedef struct _RINGBUFFER_CONTEXT
{
WDFMEMORY Buffer;
size_t Offset;
size_t Length;
} RINGBUFFER_CONTEXT, * PRINGBUFFER_CONTEXT;
//
// Inline function to get a pointer to the ring buffer context memory in a type safe manner.
//
WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(RINGBUFFER_CONTEXT, RingBufferGetContext)
NTSTATUS
RingBufferCreate(
_In_opt_ PWDF_OBJECT_ATTRIBUTES Attributes,
_In_ POOL_TYPE PoolType,
_In_ size_t BufferSize,
_Out_ RINGBUFFER* RingBuffer
)
{
NTSTATUS status;
RINGBUFFER ringBuffer;
PRINGBUFFER_CONTEXT context;
WDF_OBJECT_ATTRIBUTES attributes;
if (!RingBuffer)
WdfVerifierKeBugCheck(WDF_REQUIRED_PARAMETER_IS_NULL, 0x4, 0, (ULONG_PTR)&RingBufferCreate, 0);
if (Attributes)
{
attributes = *Attributes;
WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(&attributes, RINGBUFFER_CONTEXT);
}
else
{
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, RINGBUFFER_CONTEXT);
}
status = WdfObjectCreate(&attributes, &ringBuffer);
if (!NT_SUCCESS(status))
return status;
context = RingBufferGetContext(ringBuffer);
WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
attributes.ParentObject = ringBuffer;
status = WdfMemoryCreate(
&attributes,
PoolType,
'GNIR',
BufferSize,
&context->Buffer,
NULL
);
if (!NT_SUCCESS(status))
{
WdfObjectDelete(ringBuffer);
return status;
}
*RingBuffer = ringBuffer;
return STATUS_SUCCESS;
}
VOID
RingBufferClear(
_In_ RINGBUFFER RingBuffer
)
{
PRINGBUFFER_CONTEXT context;
context = RingBufferGetContext(RingBuffer);
context->Offset = 0;
context->Length = 0;
}
NTSTATUS
RingBufferAppend(
_In_ RINGBUFFER RingBuffer,
_In_ WDFMEMORY SourceMemory,
_In_ size_t SourceOffset,
_In_ size_t NumberOfBytesToAppend,
_In_ BOOLEAN Overwrite
)
{
PRINGBUFFER_CONTEXT context;
PUCHAR source;
size_t sourceSize;
PUCHAR buffer;
size_t bufferSize;
size_t offset;
size_t length;
if (Overwrite)
return STATUS_NOT_IMPLEMENTED;
context = RingBufferGetContext(RingBuffer);
source = (PUCHAR)WdfMemoryGetBuffer(SourceMemory, &sourceSize);
buffer = (PUCHAR)WdfMemoryGetBuffer(context->Buffer, &bufferSize);
// Validate source offset
if (SourceOffset > sourceSize)
return STATUS_BUFFER_OVERFLOW;
// Apply source offset
source += SourceOffset;
sourceSize -= SourceOffset;
// Validate number of bytes to copy
if (NumberOfBytesToAppend > sourceSize)
return STATUS_BUFFER_OVERFLOW;
if (NumberOfBytesToAppend > (bufferSize - context->Length))
return STATUS_BUFFER_TOO_SMALL;
while (NumberOfBytesToAppend)
{
offset = (context->Offset + context->Length) % bufferSize;
length = min(bufferSize - offset, NumberOfBytesToAppend);
RtlCopyMemory(buffer + offset, source, length);
context->Length += length;
NumberOfBytesToAppend -= length;
source += length;
}
return STATUS_SUCCESS;
}
NTSTATUS
RingBufferRemove(
_In_ RINGBUFFER RingBuffer,
_Out_ WDFMEMORY DestinationMemory,
_In_ size_t DestinationOffset,
_In_ size_t NumberOfBytesToRemove,
_Out_ size_t* NumberOfBytesRemoved
)
{
PRINGBUFFER_CONTEXT context;
PUCHAR destination;
size_t destinationSize;
PUCHAR buffer;
size_t bufferSize;
size_t length;
size_t numberOfBytesRemoved;
if (NumberOfBytesRemoved)
*NumberOfBytesRemoved = 0;
context = RingBufferGetContext(RingBuffer);
destination = (PUCHAR)WdfMemoryGetBuffer(DestinationMemory, &destinationSize);
buffer = (PUCHAR)WdfMemoryGetBuffer(context->Buffer, &bufferSize);
// Validate destination offset
if (DestinationOffset > destinationSize)
return STATUS_BUFFER_TOO_SMALL;
// Apply destination offset
destination += DestinationOffset;
destinationSize -= DestinationOffset;
// Validate number of bytes to copy
if (NumberOfBytesToRemove > destinationSize)
return STATUS_BUFFER_TOO_SMALL;
numberOfBytesRemoved = 0;
while (NumberOfBytesToRemove && context->Length)
{
length = min(bufferSize - context->Offset, NumberOfBytesToRemove);
if (length > context->Length)
length = context->Length;
RtlCopyMemory(destination, buffer + context->Offset, length);
context->Offset = (context->Offset + length) % bufferSize;
context->Length -= length;
NumberOfBytesToRemove -= length;
destination += length;
numberOfBytesRemoved += length;
}
if (NumberOfBytesRemoved)
*NumberOfBytesRemoved = numberOfBytesRemoved;
return STATUS_SUCCESS;
}
size_t
RingBufferGetLength(
_In_ RINGBUFFER RingBuffer
)
{
return RingBufferGetContext(RingBuffer)->Length;
}
//
// The MIT License (MIT)
//
// Copyright (c) 2013-2014 Max Truxa
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
/*
Module Name:
RingBuffer.h
Abstract:
This file contains the definitions for ring buffer objects.
Environment:
Kernel-mode Driver Framework
*/
DECLARE_HANDLE(RINGBUFFER);
NTSTATUS
RingBufferCreate(
_In_opt_ PWDF_OBJECT_ATTRIBUTES Attributes,
_In_ POOL_TYPE PoolType,
_In_ size_t BufferSize,
_Out_ RINGBUFFER* RingBuffer
);
VOID
RingBufferClear(
_In_ RINGBUFFER RingBuffer
);
NTSTATUS
RingBufferAppend(
_In_ RINGBUFFER RingBuffer,
_In_ WDFMEMORY SourceMemory,
_In_ size_t SourceOffset,
_In_ size_t NumberOfBytesToAppend,
_In_ BOOLEAN Overwrite
);
NTSTATUS
RingBufferRemove(
_In_ RINGBUFFER RingBuffer,
_Out_ WDFMEMORY DestinationMemory,
_In_ size_t DestinationOffset,
_In_ size_t NumberOfBytesToRemove,
_Out_ size_t* NumberOfBytesRemoved
);
size_t
RingBufferGetLength(
_In_ RINGBUFFER RingBuffer
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment