summaryrefslogtreecommitdiff
path: root/serial/VirtualSerial2/ringbuffer.h
blob: 8c5e3e393741d3f5561b23c1dcbd6f93a5cea21a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/*++

Copyright (C) Microsoft Corporation, All Rights Reserved

Module Name:

    Ringbuffer.h

--*/

#pragma once

typedef struct _RING_BUFFER
{
    //
    // The size in bytes of the ring buffer.
    //
    size_t          Size;

    //
    // A pointer to the base of the ring buffer.
    //
    BYTE*           Base;

    //
    // A pointer to the byte beyond the end of the ring buffer.  Used for
    // quick comparisons when determining if we need to wrap.
    //
    BYTE*           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.
    //
    //
    BYTE*           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.
    //
    BYTE*           Tail;

} RING_BUFFER, *PRING_BUFFER;


VOID
RingBufferInitialize(
    _In_  PRING_BUFFER      Self,
    _In_reads_bytes_(BufferSize)
          BYTE*             Buffer,
    _In_  size_t            BufferSize
    );

NTSTATUS
RingBufferWrite(
    _In_  PRING_BUFFER      Self,
    _In_reads_bytes_(DataSize)
          BYTE*             Data,
    _In_  size_t            DataSize
    );

NTSTATUS
RingBufferRead(
    _In_  PRING_BUFFER      Self,
    _Out_writes_bytes_to_(DataSize, *BytesCopied)
          BYTE*             Data,
    _In_  size_t            DataSize,
    _Out_ size_t            *BytesCopied
    );

VOID
RingBufferGetAvailableSpace(
    _In_  PRING_BUFFER      Self,
    _Out_ size_t            *AvailableSpace
    );

VOID
RingBufferGetAvailableData(
    _In_  PRING_BUFFER      Self,
    _Out_ size_t            *AvailableData
    );