]> git.proxmox.com Git - mirror_ovs.git/blame - lib/byteq.c
cirrus: Use FreeBSD 12.2.
[mirror_ovs.git] / lib / byteq.c
CommitLineData
00ecc5ce 1/* Copyright (c) 2008, 2009, 2012, 2013 Nicira, Inc.
064af421 2 *
a14bc59f
BP
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:
064af421 6 *
a14bc59f 7 * http://www.apache.org/licenses/LICENSE-2.0
064af421 8 *
a14bc59f
BP
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.
064af421
BP
14 */
15
16#include <config.h>
1c617a49 17#include "byteq.h"
064af421
BP
18#include <errno.h>
19#include <string.h>
20#include <unistd.h>
21#include "util.h"
22
00ecc5ce
BP
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. */
064af421 28void
00ecc5ce 29byteq_init(struct byteq *q, uint8_t *buffer, size_t size)
064af421 30{
00ecc5ce
BP
31 ovs_assert(is_pow2(size));
32 q->buffer = buffer;
33 q->size = size;
064af421
BP
34 q->head = q->tail = 0;
35}
36
37/* Returns the number of bytes current queued in 'q'. */
38int
39byteq_used(const struct byteq *q)
40{
41 return q->head - q->tail;
42}
43
44/* Returns the number of bytes that can be added to 'q' without overflow. */
45int
46byteq_avail(const struct byteq *q)
47{
00ecc5ce 48 return q->size - byteq_used(q);
064af421
BP
49}
50
51/* Returns true if no bytes are queued in 'q',
52 * false if at least one byte is queued. */
53bool
54byteq_is_empty(const struct byteq *q)
55{
56 return !byteq_used(q);
57}
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. */
61bool
62byteq_is_full(const struct byteq *q)
63{
64 return !byteq_avail(q);
65}
66
67/* Adds 'c' at the head of 'q', which must not be full. */
68void
69byteq_put(struct byteq *q, uint8_t c)
70{
cb22974d 71 ovs_assert(!byteq_is_full(q));
1c617a49 72 *byteq_head(q) = c;
064af421
BP
73 q->head++;
74}
75
76/* Adds the 'n' bytes in 'p' at the head of 'q', which must have at least 'n'
77 * bytes of free space. */
78void
79byteq_putn(struct byteq *q, const void *p_, size_t n)
80{
81 const uint8_t *p = p_;
cb22974d 82 ovs_assert(byteq_avail(q) >= n);
064af421 83 while (n > 0) {
1c617a49
BP
84 size_t chunk = MIN(n, byteq_headroom(q));
85 memcpy(byteq_head(q), p, chunk);
86 byteq_advance_head(q, chunk);
064af421
BP
87 p += chunk;
88 n -= chunk;
89 }
90}
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'. */
94void
95byteq_put_string(struct byteq *q, const char *s)
96{
97 byteq_putn(q, s, strlen(s));
98}
99
100/* Removes a byte from the tail of 'q' and returns it. 'q' must not be
101 * empty. */
102uint8_t
103byteq_get(struct byteq *q)
104{
105 uint8_t c;
cb22974d 106 ovs_assert(!byteq_is_empty(q));
1c617a49 107 c = *byteq_tail(q);
064af421
BP
108 q->tail++;
109 return c;
110}
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). */
115int
116byteq_write(struct byteq *q, int fd)
117{
118 while (!byteq_is_empty(q)) {
1c617a49 119 ssize_t n = write(fd, byteq_tail(q), byteq_tailroom(q));
064af421 120 if (n > 0) {
1c617a49 121 byteq_advance_tail(q, n);
064af421 122 } else {
cb22974d 123 ovs_assert(n < 0);
064af421
BP
124 return errno;
125 }
126 }
127 return 0;
128}
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). */
134int
135byteq_read(struct byteq *q, int fd)
136{
137 while (!byteq_is_full(q)) {
1c617a49 138 ssize_t n = read(fd, byteq_head(q), byteq_headroom(q));
064af421 139 if (n > 0) {
1c617a49 140 byteq_advance_head(q, n);
064af421
BP
141 } else {
142 return !n ? EOF : errno;
143 }
144 }
145 return 0;
146}
1c617a49 147
064af421
BP
148/* Returns the number of contiguous bytes of in-use space starting at the tail
149 * of 'q'. */
1c617a49
BP
150int
151byteq_tailroom(const struct byteq *q)
064af421
BP
152{
153 int used = byteq_used(q);
00ecc5ce 154 int tail_to_end = q->size - (q->tail & (q->size - 1));
064af421
BP
155 return MIN(used, tail_to_end);
156}
157
158/* Returns the first in-use byte of 'q', the point at which data is removed
159 * from 'q'. */
1c617a49
BP
160const uint8_t *
161byteq_tail(const struct byteq *q)
064af421 162{
00ecc5ce 163 return &q->buffer[q->tail & (q->size - 1)];
064af421
BP
164}
165
166/* Removes 'n' bytes from the tail of 'q', which must have at least 'n' bytes
167 * of tailroom. */
1c617a49
BP
168void
169byteq_advance_tail(struct byteq *q, unsigned int n)
064af421 170{
cb22974d 171 ovs_assert(byteq_tailroom(q) >= n);
064af421
BP
172 q->tail += n;
173}
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'. */
1c617a49
BP
177uint8_t *
178byteq_head(struct byteq *q)
064af421 179{
00ecc5ce 180 return &q->buffer[q->head & (q->size - 1)];
064af421
BP
181}
182
183/* Returns the number of contiguous bytes of free space starting at the head
184 * of 'q'. */
1c617a49
BP
185int
186byteq_headroom(const struct byteq *q)
064af421
BP
187{
188 int avail = byteq_avail(q);
00ecc5ce 189 int head_to_end = q->size - (q->head & (q->size - 1));
064af421
BP
190 return MIN(avail, head_to_end);
191}
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. */
1c617a49
BP
195void
196byteq_advance_head(struct byteq *q, unsigned int n)
064af421 197{
cb22974d 198 ovs_assert(byteq_headroom(q) >= n);
064af421
BP
199 q->head += n;
200}