Coverage Report

Created: 2025-07-01 06:50

/src/openvswitch/lib/byteq.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (c) 2008, 2009, 2012, 2013 Nicira, Inc.
2
 *
3
 * Licensed under the Apache License, Version 2.0 (the "License");
4
 * you may not use this file except in compliance with the License.
5
 * You may obtain a copy of the License at:
6
 *
7
 *     http://www.apache.org/licenses/LICENSE-2.0
8
 *
9
 * Unless required by applicable law or agreed to in writing, software
10
 * distributed under the License is distributed on an "AS IS" BASIS,
11
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
 * See the License for the specific language governing permissions and
13
 * limitations under the License.
14
 */
15
16
#include <config.h>
17
#include "byteq.h"
18
#include <errno.h>
19
#include <string.h>
20
#include <unistd.h>
21
#include "util.h"
22
23
/* Initializes 'q' as an empty byteq that uses the 'size' bytes of 'buffer' to
24
 * store data.  'size' must be a power of 2.
25
 *
26
 * The caller must ensure that 'buffer' remains available to the byteq as long
27
 * as 'q' is in use. */
28
void
29
byteq_init(struct byteq *q, uint8_t *buffer, size_t size)
30
0
{
31
0
    ovs_assert(is_pow2(size));
32
0
    q->buffer = buffer;
33
0
    q->size = size;
34
0
    q->head = q->tail = 0;
35
0
}
36
37
/* Returns the number of bytes current queued in 'q'. */
38
int
39
byteq_used(const struct byteq *q)
40
0
{
41
0
    return q->head - q->tail;
42
0
}
43
44
/* Returns the number of bytes that can be added to 'q' without overflow. */
45
int
46
byteq_avail(const struct byteq *q)
47
0
{
48
0
    return q->size - byteq_used(q);
49
0
}
50
51
/* Returns true if no bytes are queued in 'q',
52
 * false if at least one byte is queued.  */
53
bool
54
byteq_is_empty(const struct byteq *q)
55
0
{
56
0
    return !byteq_used(q);
57
0
}
58
59
/* Returns true if 'q' has no room to queue additional bytes,
60
 * false if 'q' has room for at least one more byte.  */
61
bool
62
byteq_is_full(const struct byteq *q)
63
0
{
64
0
    return !byteq_avail(q);
65
0
}
66
67
/* Adds 'c' at the head of 'q', which must not be full. */
68
void
69
byteq_put(struct byteq *q, uint8_t c)
70
0
{
71
0
    ovs_assert(!byteq_is_full(q));
72
0
    *byteq_head(q) = c;
73
0
    q->head++;
74
0
}
75
76
/* Adds the 'n' bytes in 'p' at the head of 'q', which must have at least 'n'
77
 * bytes of free space. */
78
void
79
byteq_putn(struct byteq *q, const void *p_, size_t n)
80
0
{
81
0
    const uint8_t *p = p_;
82
0
    ovs_assert(byteq_avail(q) >= n);
83
0
    while (n > 0) {
84
0
        size_t chunk = MIN(n, byteq_headroom(q));
85
0
        memcpy(byteq_head(q), p, chunk);
86
0
        byteq_advance_head(q, chunk);
87
0
        p += chunk;
88
0
        n -= chunk;
89
0
    }
90
0
}
91
92
/* Appends null-terminated string 's' to the head of 'q', which must have
93
 * enough space.  The null terminator is not added to 'q'. */
94
void
95
byteq_put_string(struct byteq *q, const char *s)
96
0
{
97
0
    byteq_putn(q, s, strlen(s));
98
0
}
99
100
/* Removes a byte from the tail of 'q' and returns it.  'q' must not be
101
 * empty. */
102
uint8_t
103
byteq_get(struct byteq *q)
104
0
{
105
0
    uint8_t c;
106
0
    ovs_assert(!byteq_is_empty(q));
107
0
    c = *byteq_tail(q);
108
0
    q->tail++;
109
0
    return c;
110
0
}
111
112
/* Writes as much of 'q' as possible to 'fd'.  Returns 0 if 'q' is fully
113
 * drained by the write, otherwise a positive errno value (e.g. EAGAIN if a
114
 * socket or tty buffer filled up). */
115
int
116
byteq_write(struct byteq *q, int fd)
117
0
{
118
0
    while (!byteq_is_empty(q)) {
119
0
        ssize_t n = write(fd, byteq_tail(q), byteq_tailroom(q));
120
0
        if (n > 0) {
121
0
            byteq_advance_tail(q, n);
122
0
        } else {
123
0
            ovs_assert(n < 0);
124
0
            return errno;
125
0
        }
126
0
    }
127
0
    return 0;
128
0
}
129
130
/* Reads as much possible from 'fd' into 'q'.  Returns 0 if 'q' is completely
131
 * filled up by the read, EOF if end-of-file was reached before 'q' was filled,
132
 * and otherwise a positive errno value (e.g. EAGAIN if a socket or tty buffer
133
 * was drained). */
134
int
135
byteq_read(struct byteq *q, int fd)
136
0
{
137
0
    while (!byteq_is_full(q)) {
138
0
        ssize_t n = read(fd, byteq_head(q), byteq_headroom(q));
139
0
        if (n > 0) {
140
0
            byteq_advance_head(q, n);
141
0
        } else {
142
0
            return !n ? EOF : errno;
143
0
        }
144
0
    }
145
0
    return 0;
146
0
}
147
148
/* Returns the number of contiguous bytes of in-use space starting at the tail
149
 * of 'q'. */
150
int
151
byteq_tailroom(const struct byteq *q)
152
0
{
153
0
    int used = byteq_used(q);
154
0
    int tail_to_end = q->size - (q->tail & (q->size - 1));
155
0
    return MIN(used, tail_to_end);
156
0
}
157
158
/* Returns the first in-use byte of 'q', the point at which data is removed
159
 * from 'q'. */
160
const uint8_t *
161
byteq_tail(const struct byteq *q)
162
0
{
163
0
    return &q->buffer[q->tail & (q->size - 1)];
164
0
}
165
166
/* Removes 'n' bytes from the tail of 'q', which must have at least 'n' bytes
167
 * of tailroom. */
168
void
169
byteq_advance_tail(struct byteq *q, unsigned int n)
170
0
{
171
0
    ovs_assert(byteq_tailroom(q) >= n);
172
0
    q->tail += n;
173
0
}
174
175
/* Returns the byte after the last in-use byte of 'q', the point at which new
176
 * data will be added to 'q'. */
177
uint8_t *
178
byteq_head(struct byteq *q)
179
0
{
180
0
    return &q->buffer[q->head & (q->size - 1)];
181
0
}
182
183
/* Returns the number of contiguous bytes of free space starting at the head
184
 * of 'q'. */
185
int
186
byteq_headroom(const struct byteq *q)
187
0
{
188
0
    int avail = byteq_avail(q);
189
0
    int head_to_end = q->size - (q->head & (q->size - 1));
190
0
    return MIN(avail, head_to_end);
191
0
}
192
193
/* Adds to 'q' the 'n' bytes after the last currently in-use byte of 'q'.  'q'
194
 * must have at least 'n' bytes of headroom. */
195
void
196
byteq_advance_head(struct byteq *q, unsigned int n)
197
0
{
198
0
    ovs_assert(byteq_headroom(q) >= n);
199
0
    q->head += n;
200
0
}
201
202
/* Move the head and tail pointers forward to have the most headroom available.
203
 * Can only be used on an empty byteq.  This is equivalent to advancing both
204
 * head and tail by the current headroom size.
205
 * Previous pointers returned by byteq_tail() or byteq_head() are potentially
206
 * invalid afterwards. */
207
void
208
byteq_fast_forward(struct byteq *q)
209
0
{
210
0
    ovs_assert(byteq_is_empty(q));
211
0
    unsigned int pos = q->head & (q->size - 1);
212
213
0
    if (pos) {
214
        /* Only advance head if we are not already at a multiple of size. */
215
0
        q->head += q->size - pos;
216
0
        q->tail = q->head;
217
0
    }
218
0
}