]>
Commit | Line | Data |
---|---|---|
cb22974d | 1 | /* Copyright (c) 2008, 2009, 2012 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 | ||
23 | /* The queue size must be a power of 2. */ | |
24 | BUILD_ASSERT_DECL(!(BYTEQ_SIZE & (BYTEQ_SIZE - 1))); | |
25 | ||
064af421 BP |
26 | /* Initializes 'q' as empty. */ |
27 | void | |
28 | byteq_init(struct byteq *q) | |
29 | { | |
30 | q->head = q->tail = 0; | |
31 | } | |
32 | ||
33 | /* Returns the number of bytes current queued in 'q'. */ | |
34 | int | |
35 | byteq_used(const struct byteq *q) | |
36 | { | |
37 | return q->head - q->tail; | |
38 | } | |
39 | ||
40 | /* Returns the number of bytes that can be added to 'q' without overflow. */ | |
41 | int | |
42 | byteq_avail(const struct byteq *q) | |
43 | { | |
44 | return BYTEQ_SIZE - byteq_used(q); | |
45 | } | |
46 | ||
47 | /* Returns true if no bytes are queued in 'q', | |
48 | * false if at least one byte is queued. */ | |
49 | bool | |
50 | byteq_is_empty(const struct byteq *q) | |
51 | { | |
52 | return !byteq_used(q); | |
53 | } | |
54 | ||
55 | /* Returns true if 'q' has no room to queue additional bytes, | |
56 | * false if 'q' has room for at least one more byte. */ | |
57 | bool | |
58 | byteq_is_full(const struct byteq *q) | |
59 | { | |
60 | return !byteq_avail(q); | |
61 | } | |
62 | ||
63 | /* Adds 'c' at the head of 'q', which must not be full. */ | |
64 | void | |
65 | byteq_put(struct byteq *q, uint8_t c) | |
66 | { | |
cb22974d | 67 | ovs_assert(!byteq_is_full(q)); |
1c617a49 | 68 | *byteq_head(q) = c; |
064af421 BP |
69 | q->head++; |
70 | } | |
71 | ||
72 | /* Adds the 'n' bytes in 'p' at the head of 'q', which must have at least 'n' | |
73 | * bytes of free space. */ | |
74 | void | |
75 | byteq_putn(struct byteq *q, const void *p_, size_t n) | |
76 | { | |
77 | const uint8_t *p = p_; | |
cb22974d | 78 | ovs_assert(byteq_avail(q) >= n); |
064af421 | 79 | while (n > 0) { |
1c617a49 BP |
80 | size_t chunk = MIN(n, byteq_headroom(q)); |
81 | memcpy(byteq_head(q), p, chunk); | |
82 | byteq_advance_head(q, chunk); | |
064af421 BP |
83 | p += chunk; |
84 | n -= chunk; | |
85 | } | |
86 | } | |
87 | ||
88 | /* Appends null-terminated string 's' to the head of 'q', which must have | |
89 | * enough space. The null terminator is not added to 'q'. */ | |
90 | void | |
91 | byteq_put_string(struct byteq *q, const char *s) | |
92 | { | |
93 | byteq_putn(q, s, strlen(s)); | |
94 | } | |
95 | ||
96 | /* Removes a byte from the tail of 'q' and returns it. 'q' must not be | |
97 | * empty. */ | |
98 | uint8_t | |
99 | byteq_get(struct byteq *q) | |
100 | { | |
101 | uint8_t c; | |
cb22974d | 102 | ovs_assert(!byteq_is_empty(q)); |
1c617a49 | 103 | c = *byteq_tail(q); |
064af421 BP |
104 | q->tail++; |
105 | return c; | |
106 | } | |
107 | ||
108 | /* Writes as much of 'q' as possible to 'fd'. Returns 0 if 'q' is fully | |
109 | * drained by the write, otherwise a positive errno value (e.g. EAGAIN if a | |
110 | * socket or tty buffer filled up). */ | |
111 | int | |
112 | byteq_write(struct byteq *q, int fd) | |
113 | { | |
114 | while (!byteq_is_empty(q)) { | |
1c617a49 | 115 | ssize_t n = write(fd, byteq_tail(q), byteq_tailroom(q)); |
064af421 | 116 | if (n > 0) { |
1c617a49 | 117 | byteq_advance_tail(q, n); |
064af421 | 118 | } else { |
cb22974d | 119 | ovs_assert(n < 0); |
064af421 BP |
120 | return errno; |
121 | } | |
122 | } | |
123 | return 0; | |
124 | } | |
125 | ||
126 | /* Reads as much possible from 'fd' into 'q'. Returns 0 if 'q' is completely | |
127 | * filled up by the read, EOF if end-of-file was reached before 'q' was filled, | |
128 | * and otherwise a positive errno value (e.g. EAGAIN if a socket or tty buffer | |
129 | * was drained). */ | |
130 | int | |
131 | byteq_read(struct byteq *q, int fd) | |
132 | { | |
133 | while (!byteq_is_full(q)) { | |
1c617a49 | 134 | ssize_t n = read(fd, byteq_head(q), byteq_headroom(q)); |
064af421 | 135 | if (n > 0) { |
1c617a49 | 136 | byteq_advance_head(q, n); |
064af421 BP |
137 | } else { |
138 | return !n ? EOF : errno; | |
139 | } | |
140 | } | |
141 | return 0; | |
142 | } | |
1c617a49 | 143 | |
064af421 BP |
144 | /* Returns the number of contiguous bytes of in-use space starting at the tail |
145 | * of 'q'. */ | |
1c617a49 BP |
146 | int |
147 | byteq_tailroom(const struct byteq *q) | |
064af421 BP |
148 | { |
149 | int used = byteq_used(q); | |
150 | int tail_to_end = BYTEQ_SIZE - (q->tail & (BYTEQ_SIZE - 1)); | |
151 | return MIN(used, tail_to_end); | |
152 | } | |
153 | ||
154 | /* Returns the first in-use byte of 'q', the point at which data is removed | |
155 | * from 'q'. */ | |
1c617a49 BP |
156 | const uint8_t * |
157 | byteq_tail(const struct byteq *q) | |
064af421 BP |
158 | { |
159 | return &q->buffer[q->tail & (BYTEQ_SIZE - 1)]; | |
160 | } | |
161 | ||
162 | /* Removes 'n' bytes from the tail of 'q', which must have at least 'n' bytes | |
163 | * of tailroom. */ | |
1c617a49 BP |
164 | void |
165 | byteq_advance_tail(struct byteq *q, unsigned int n) | |
064af421 | 166 | { |
cb22974d | 167 | ovs_assert(byteq_tailroom(q) >= n); |
064af421 BP |
168 | q->tail += n; |
169 | } | |
170 | ||
171 | /* Returns the byte after the last in-use byte of 'q', the point at which new | |
172 | * data will be added to 'q'. */ | |
1c617a49 BP |
173 | uint8_t * |
174 | byteq_head(struct byteq *q) | |
064af421 BP |
175 | { |
176 | return &q->buffer[q->head & (BYTEQ_SIZE - 1)]; | |
177 | } | |
178 | ||
179 | /* Returns the number of contiguous bytes of free space starting at the head | |
180 | * of 'q'. */ | |
1c617a49 BP |
181 | int |
182 | byteq_headroom(const struct byteq *q) | |
064af421 BP |
183 | { |
184 | int avail = byteq_avail(q); | |
185 | int head_to_end = BYTEQ_SIZE - (q->head & (BYTEQ_SIZE - 1)); | |
186 | return MIN(avail, head_to_end); | |
187 | } | |
188 | ||
189 | /* Adds to 'q' the 'n' bytes after the last currently in-use byte of 'q'. 'q' | |
190 | * must have at least 'n' bytes of headroom. */ | |
1c617a49 BP |
191 | void |
192 | byteq_advance_head(struct byteq *q, unsigned int n) | |
064af421 | 193 | { |
cb22974d | 194 | ovs_assert(byteq_headroom(q) >= n); |
064af421 BP |
195 | q->head += n; |
196 | } |