ring.c revision 1.7 1 /* $NetBSD: ring.c,v 1.7 1996/02/28 21:04:07 thorpej Exp $ */
2
3 /*
4 * Copyright (c) 1988, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #ifndef lint
37 #if 0
38 static char sccsid[] = "@(#)ring.c 8.2 (Berkeley) 5/30/95";
39 #else
40 static char rcsid[] = "$NetBSD: ring.c,v 1.7 1996/02/28 21:04:07 thorpej Exp $";
41 #endif
42 #endif /* not lint */
43
44 /*
45 * This defines a structure for a ring buffer.
46 *
47 * The circular buffer has two parts:
48 *(((
49 * full: [consume, supply)
50 * empty: [supply, consume)
51 *]]]
52 *
53 */
54
55 #include <stdio.h>
56 #ifndef NO_STRING_H
57 #include <string.h>
58 #endif
59 #include <strings.h>
60 #include <errno.h>
61
62 #ifdef size_t
63 #undef size_t
64 #endif
65
66 #include <sys/types.h>
67 #ifndef FILIO_H
68 #include <sys/ioctl.h>
69 #endif
70 #include <sys/socket.h>
71
72 #include "ring.h"
73 #include "general.h"
74
75 /* Internal macros */
76
77 #if !defined(MIN)
78 #define MIN(a,b) (((a)<(b))? (a):(b))
79 #endif /* !defined(MIN) */
80
81 #define ring_subtract(d,a,b) (((a)-(b) >= 0)? \
82 (a)-(b): (((a)-(b))+(d)->size))
83
84 #define ring_increment(d,a,c) (((a)+(c) < (d)->top)? \
85 (a)+(c) : (((a)+(c))-(d)->size))
86
87 #define ring_decrement(d,a,c) (((a)-(c) >= (d)->bottom)? \
88 (a)-(c) : (((a)-(c))-(d)->size))
89
90
91 /*
92 * The following is a clock, used to determine full, empty, etc.
93 *
94 * There is some trickiness here. Since the ring buffers are initialized
95 * to ZERO on allocation, we need to make sure, when interpreting the
96 * clock, that when the times are EQUAL, then the buffer is FULL.
97 */
98 static u_long ring_clock = 0;
99
100
101 #define ring_empty(d) (((d)->consume == (d)->supply) && \
102 ((d)->consumetime >= (d)->supplytime))
103 #define ring_full(d) (((d)->supply == (d)->consume) && \
104 ((d)->supplytime > (d)->consumetime))
105
106
107
108
109
110 /* Buffer state transition routines */
111
112 ring_init(ring, buffer, count)
113 Ring *ring;
114 unsigned char *buffer;
115 int count;
116 {
117 memset((char *)ring, 0, sizeof *ring);
118
119 ring->size = count;
120
121 ring->supply = ring->consume = ring->bottom = buffer;
122
123 ring->top = ring->bottom+ring->size;
124
125
126 return 1;
127 }
128
129 /* Mark routines */
130
131 /*
132 * Mark the most recently supplied byte.
133 */
134
135 void
136 ring_mark(ring)
137 Ring *ring;
138 {
139 ring->mark = ring_decrement(ring, ring->supply, 1);
140 }
141
142 /*
143 * Is the ring pointing to the mark?
144 */
145
146 int
147 ring_at_mark(ring)
148 Ring *ring;
149 {
150 if (ring->mark == ring->consume) {
151 return 1;
152 } else {
153 return 0;
154 }
155 }
156
157 /*
158 * Clear any mark set on the ring.
159 */
160
161 void
162 ring_clear_mark(ring)
163 Ring *ring;
164 {
165 ring->mark = 0;
166 }
167
168 /*
169 * Add characters from current segment to ring buffer.
170 */
171 void
172 ring_supplied(ring, count)
173 Ring *ring;
174 int count;
175 {
176 ring->supply = ring_increment(ring, ring->supply, count);
177 ring->supplytime = ++ring_clock;
178 }
179
180 /*
181 * We have just consumed "c" bytes.
182 */
183 void
184 ring_consumed(ring, count)
185 Ring *ring;
186 int count;
187 {
188 if (count == 0) /* don't update anything */
189 return;
190
191 if (ring->mark &&
192 (ring_subtract(ring, ring->mark, ring->consume) < count)) {
193 ring->mark = 0;
194 }
195 ring->consume = ring_increment(ring, ring->consume, count);
196 ring->consumetime = ++ring_clock;
197 /*
198 * Try to encourage "ring_empty_consecutive()" to be large.
199 */
200 if (ring_empty(ring)) {
201 ring->consume = ring->supply = ring->bottom;
202 }
203 }
204
205
206
207 /* Buffer state query routines */
208
209
210 /* Number of bytes that may be supplied */
211 int
212 ring_empty_count(ring)
213 Ring *ring;
214 {
215 if (ring_empty(ring)) { /* if empty */
216 return ring->size;
217 } else {
218 return ring_subtract(ring, ring->consume, ring->supply);
219 }
220 }
221
222 /* number of CONSECUTIVE bytes that may be supplied */
223 int
224 ring_empty_consecutive(ring)
225 Ring *ring;
226 {
227 if ((ring->consume < ring->supply) || ring_empty(ring)) {
228 /*
229 * if consume is "below" supply, or empty, then
230 * return distance to the top
231 */
232 return ring_subtract(ring, ring->top, ring->supply);
233 } else {
234 /*
235 * else, return what we may.
236 */
237 return ring_subtract(ring, ring->consume, ring->supply);
238 }
239 }
240
241 /* Return the number of bytes that are available for consuming
242 * (but don't give more than enough to get to cross over set mark)
243 */
244
245 int
246 ring_full_count(ring)
247 Ring *ring;
248 {
249 if ((ring->mark == 0) || (ring->mark == ring->consume)) {
250 if (ring_full(ring)) {
251 return ring->size; /* nothing consumed, but full */
252 } else {
253 return ring_subtract(ring, ring->supply, ring->consume);
254 }
255 } else {
256 return ring_subtract(ring, ring->mark, ring->consume);
257 }
258 }
259
260 /*
261 * Return the number of CONSECUTIVE bytes available for consuming.
262 * However, don't return more than enough to cross over set mark.
263 */
264 int
265 ring_full_consecutive(ring)
266 Ring *ring;
267 {
268 if ((ring->mark == 0) || (ring->mark == ring->consume)) {
269 if ((ring->supply < ring->consume) || ring_full(ring)) {
270 return ring_subtract(ring, ring->top, ring->consume);
271 } else {
272 return ring_subtract(ring, ring->supply, ring->consume);
273 }
274 } else {
275 if (ring->mark < ring->consume) {
276 return ring_subtract(ring, ring->top, ring->consume);
277 } else { /* Else, distance to mark */
278 return ring_subtract(ring, ring->mark, ring->consume);
279 }
280 }
281 }
282
283 /*
284 * Move data into the "supply" portion of of the ring buffer.
285 */
286 void
287 ring_supply_data(ring, buffer, count)
288 Ring *ring;
289 unsigned char *buffer;
290 int count;
291 {
292 int i;
293
294 while (count) {
295 i = MIN(count, ring_empty_consecutive(ring));
296 memmove(ring->supply, buffer, i);
297 ring_supplied(ring, i);
298 count -= i;
299 buffer += i;
300 }
301 }
302
303 #ifdef notdef
304
305 /*
306 * Move data from the "consume" portion of the ring buffer
307 */
308 void
309 ring_consume_data(ring, buffer, count)
310 Ring *ring;
311 unsigned char *buffer;
312 int count;
313 {
314 int i;
315
316 while (count) {
317 i = MIN(count, ring_full_consecutive(ring));
318 memmove(buffer, ring->consume, i);
319 ring_consumed(ring, i);
320 count -= i;
321 buffer += i;
322 }
323 }
324 #endif
325
326