]>
Commit | Line | Data |
---|---|---|
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 | 28 | void |
00ecc5ce | 29 | byteq_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'. */ | |
38 | int | |
39 | byteq_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. */ | |
45 | int | |
46 | byteq_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. */ | |
53 | bool | |
54 | byteq_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. */ | |
61 | bool | |
62 | byteq_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. */ | |
68 | void | |
69 | byteq_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. */ | |
78 | void | |
79 | byteq_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'. */ | |
94 | void | |
95 | byteq_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. */ | |
102 | uint8_t | |
103 | byteq_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). */ | |
115 | int | |
116 | byteq_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). */ | |
134 | int | |
135 | byteq_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 |
150 | int |
151 | byteq_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 |
160 | const uint8_t * |
161 | byteq_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 |
168 | void |
169 | byteq_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 |
177 | uint8_t * |
178 | byteq_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 |
185 | int |
186 | byteq_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 |
195 | void |
196 | byteq_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 | } |