summaryrefslogtreecommitdiff
path: root/serial/VirtualSerial/ringbuffer.h
diff options
context:
space:
mode:
authorWei Mao <[email protected]>2023-01-11 17:49:06 -0800
committerWei Mao <[email protected]>2023-01-13 00:25:06 -0800
commit5c647868e2f8968e2a490bc02da304020405fcce (patch)
tree55ba978269f447985fe1de794587d0341d29d62d /serial/VirtualSerial/ringbuffer.h
parent5bc6b56aef39e19add03297afe0c36168f370dc4 (diff)
[UMDF v1] Remove serial/VirtualSerial/ComPort/virtualserial, fakemodem
Diffstat (limited to 'serial/VirtualSerial/ringbuffer.h')
-rw-r--r--serial/VirtualSerial/ringbuffer.h223
1 files changed, 0 insertions, 223 deletions
diff --git a/serial/VirtualSerial/ringbuffer.h b/serial/VirtualSerial/ringbuffer.h
deleted file mode 100644
index 130055d9..00000000
--- a/serial/VirtualSerial/ringbuffer.h
+++ /dev/null
@@ -1,223 +0,0 @@
-#pragma once
-
-#include "internal.h"
-
-class CRingBuffer
-{
-private:
-
- //
- // Private local variables.
- //
-
- //
- // The size in bytes of the ring buffer.
- //
- SIZE_T m_Size;
-
- //
- // A pointer to the base of the ring buffer.
- //
- PBYTE m_Base;
-
- //
- // A pointer to the byte beyond the end of the ring buffer. Used for
- // quick comparisons when determining if we need to wrap.
- //
- PBYTE m_End;
-
- //
- // A pointer to the current read point in the ring buffer.
- //
- // Updates to this are not protected by any lock. This is different from
- // the write pointer, which is protected by the "pending read pointer"
- // lock. The reason for this difference is that in this driver, we do not
- // keep write requests pending. If there is not enough space to write all
- // the data that was requested, we write as much as we can and drop the
- // rest (lossy data transfer).
- //
- // If we had multiple threads modifying this pointer, then that would
- // provide yet another reason for protecting updates to the pointer using a
- // lock. However, in this driver, at any given time we have only one thread
- // that modifies this pointer (the thread that runs the read callback).
- // This is true because we use a sequential queue for read requests. If we
- // were to change our read queue to be a parallel queue, this would no
- // longer be true.
- //
- //
- PBYTE m_Head;
-
- //
- // A pointer to the current write point in the ring buffer.
- //
- // Updates to this pointer are protected by the "pending read pointer
- // lock", because we do not want a consumer thread to mark a read request
- // as pending while we are in the process of writing data to the buffer.
- // The reason is that the write that we are currently performing might
- // actually supply enough data to satisfy the read request, in which case
- // it should not be marked pending at all.
- // If the read request were to be marked pending in the situation described
- // above, then we would need some trigger to later retrieve the request and
- // complete it. In our driver, arrival of data is the only event that can
- // trigger this. So if no more data arrives, the request will remain
- // pending forever, even though there is enough data in the buffer to
- // complete it. Hence we do not keep a read request pending in situations
- // where the read buffer contains enough data to satisfy it.
- //
- // If we had multiple threads modifying this pointer, then that would
- // provide yet another reason for protecting updates to the pointer using a
- // lock. However, in this driver, at any given time we have only one thread
- // that modifies this pointer (the thread that runs the write callback).
- // This is true because we use a sequential queue for write requests. If we
- // were to change our write queue to be a parallel queue, this would no
- // longer be true.
- //
- PBYTE m_Tail;
-
-private:
-
- //
- // Private Internal Methods.
- //
- void
- GetAvailableSpace(
- _Out_ SIZE_T *AvailableSpace
- )
- {
- WUDF_TEST_DRIVER_ASSERT(AvailableSpace);
-
- PBYTE headSnapshot = NULL;
- PBYTE tailSnapshot = NULL;
- PBYTE tailPlusOne = NULL;
-
- //
- // Take a snapshot of the head and tail pointers. We will compute the
- // available space based on this snapshot. This is safe to do in a
- // single-producer, single-consumer model, because -
- // * A producer will call GetAvailableSpace() to determine whether
- // there is enough space to write the data it is trying to write.
- // The only other thread that could modify the amount of space
- // available is the consumer thread, which can only increase the
- // amount of space available. Hence it is safe for the producer
- // to write based on this snapshot.
- // * A consumer thread will call GetAvailableSpace() to determine
- // whether there is enough data in the buffer for it to read.
- // (Available data = Buffer size - Available space). The only
- // other thread that could modify the amount of space available
- // is the producer thread, which can only decrease the amount of
- // space available (thereby increasing the amount of data
- // available. Hence it is safe for the consumer to read based on
- // this snapshot.
- //
- headSnapshot = m_Head;
- tailSnapshot = m_Tail;
-
- //
- // In order to distinguish between a full buffer and an empty buffer,
- // we always leave the last byte of the buffer unused. So, an empty
- // buffer is denoted by -
- // tail == head
- // ... and a full buffer is denoted by -
- // (tail+1) == head
- //
- tailPlusOne = ((tailSnapshot+1) == m_End) ? m_Base : (tailSnapshot+1);
-
- if (tailPlusOne == headSnapshot)
- {
- //
- // Buffer full
- //
- *AvailableSpace = 0;
- }
- else if (tailSnapshot == headSnapshot)
- {
- //
- // Buffer empty
- // The -1 in the computation below is to account for the fact that
- // we always leave the last byte of the ring buffer unused in order
- // to distinguish between an empty buffer and a full buffer.
- //
- *AvailableSpace = m_Size - 1;
- }
- else
- {
- if (tailSnapshot > headSnapshot)
- {
- //
- // Data has not wrapped around the end of the buffer
- // The -1 in the computation below is to account for the fact
- // that we always leave the last byte of the ring buffer unused
- // in order to distinguish between an empty buffer and a full
- // buffer.
- //
- *AvailableSpace = m_Size - (tailSnapshot - headSnapshot) - 1;
- }
- else
- {
- //
- // Data has wrapped around the end of the buffer
- // The -1 in the computation below is to account for the fact
- // that we always leave the last byte of the ring buffer unused
- // in order to distinguish between an empty buffer and a full
- // buffer.
- //
- *AvailableSpace = (headSnapshot - tailSnapshot) - 1;
- }
- }
-
- return;
- }
-
-public:
-
- //
- // Public Internal methods.
- //
-
- CRingBuffer(
- VOID
- );
-
- ~CRingBuffer(
- VOID
- );
-
- HRESULT
- Initialize(
- _In_ SIZE_T BufferSize
- );
-
- HRESULT
- Write(
- _In_reads_bytes_(DataSize) PBYTE Data,
- _In_ SIZE_T DataSize
- );
-
- HRESULT
- Read(
- _Out_writes_bytes_to_(DataSize, *BytesCopied) PBYTE Data,
- _In_ SIZE_T DataSize,
- _Out_ SIZE_T *BytesCopied
- );
-
- void
- GetAvailableData(
- _Out_ SIZE_T *AvailableData
- )
- {
- SIZE_T availableSpace;
-
- WUDF_TEST_DRIVER_ASSERT(AvailableData);
-
- GetAvailableSpace(&availableSpace);
-
- //
- // The -1 in the arithmetic below accounts for the fact that we always
- // keep 1 byte of the ring buffer unused in order to distinguish
- // between a full buffer and an empty buffer.
- //
- *AvailableData = m_Size - availableSpace - 1;
-
- return;
- }
-};