1 /* 2 * Copyright (c) 1988 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)ring.c 1.12 (Berkeley) 06/01/90"; 10 #endif /* not lint */ 11 12 /* 13 * This defines a structure for a ring buffer. 14 * 15 * The circular buffer has two parts: 16 *((( 17 * full: [consume, supply) 18 * empty: [supply, consume) 19 *]]] 20 * 21 */ 22 23 #include <stdio.h> 24 #include <errno.h> 25 26 #ifdef size_t 27 #undef size_t 28 #endif 29 30 #include <sys/types.h> 31 #include <sys/ioctl.h> 32 #include <sys/socket.h> 33 34 #include "ring.h" 35 #include "general.h" 36 37 /* Internal macros */ 38 39 #if !defined(MIN) 40 #define MIN(a,b) (((a)<(b))? (a):(b)) 41 #endif /* !defined(MIN) */ 42 43 #define ring_subtract(d,a,b) (((a)-(b) >= 0)? \ 44 (a)-(b): (((a)-(b))+(d)->size)) 45 46 #define ring_increment(d,a,c) (((a)+(c) < (d)->top)? \ 47 (a)+(c) : (((a)+(c))-(d)->size)) 48 49 #define ring_decrement(d,a,c) (((a)-(c) >= (d)->bottom)? \ 50 (a)-(c) : (((a)-(c))-(d)->size)) 51 52 53 /* 54 * The following is a clock, used to determine full, empty, etc. 55 * 56 * There is some trickiness here. Since the ring buffers are initialized 57 * to ZERO on allocation, we need to make sure, when interpreting the 58 * clock, that when the times are EQUAL, then the buffer is FULL. 59 */ 60 static u_long ring_clock = 0; 61 62 63 #define ring_empty(d) (((d)->consume == (d)->supply) && \ 64 ((d)->consumetime >= (d)->supplytime)) 65 #define ring_full(d) (((d)->supply == (d)->consume) && \ 66 ((d)->supplytime > (d)->consumetime)) 67 68 69 70 71 72 /* Buffer state transition routines */ 73 74 ring_init(ring, buffer, count) 75 Ring *ring; 76 char *buffer; 77 int count; 78 { 79 memset((char *)ring, 0, sizeof *ring); 80 81 ring->size = count; 82 83 ring->supply = ring->consume = ring->bottom = buffer; 84 85 ring->top = ring->bottom+ring->size; 86 87 return 1; 88 } 89 90 /* Mark routines */ 91 92 /* 93 * Mark the most recently supplied byte. 94 */ 95 96 void 97 ring_mark(ring) 98 Ring *ring; 99 { 100 ring->mark = ring_decrement(ring, ring->supply, 1); 101 } 102 103 /* 104 * Is the ring pointing to the mark? 105 */ 106 107 int 108 ring_at_mark(ring) 109 Ring *ring; 110 { 111 if (ring->mark == ring->consume) { 112 return 1; 113 } else { 114 return 0; 115 } 116 } 117 118 /* 119 * Clear any mark set on the ring. 120 */ 121 122 void 123 ring_clear_mark(ring) 124 Ring *ring; 125 { 126 ring->mark = 0; 127 } 128 129 /* 130 * Add characters from current segment to ring buffer. 131 */ 132 void 133 ring_supplied(ring, count) 134 Ring *ring; 135 int count; 136 { 137 ring->supply = ring_increment(ring, ring->supply, count); 138 ring->supplytime = ++ring_clock; 139 } 140 141 /* 142 * We have just consumed "c" bytes. 143 */ 144 void 145 ring_consumed(ring, count) 146 Ring *ring; 147 int count; 148 { 149 if (count == 0) /* don't update anything */ 150 return; 151 152 if (ring->mark && 153 (ring_subtract(ring, ring->mark, ring->consume) < count)) { 154 ring->mark = 0; 155 } 156 ring->consume = ring_increment(ring, ring->consume, count); 157 ring->consumetime = ++ring_clock; 158 /* 159 * Try to encourage "ring_empty_consecutive()" to be large. 160 */ 161 if (ring_empty(ring)) { 162 ring->consume = ring->supply = ring->bottom; 163 } 164 } 165 166 167 168 /* Buffer state query routines */ 169 170 171 /* Number of bytes that may be supplied */ 172 int 173 ring_empty_count(ring) 174 Ring *ring; 175 { 176 if (ring_empty(ring)) { /* if empty */ 177 return ring->size; 178 } else { 179 return ring_subtract(ring, ring->consume, ring->supply); 180 } 181 } 182 183 /* number of CONSECUTIVE bytes that may be supplied */ 184 int 185 ring_empty_consecutive(ring) 186 Ring *ring; 187 { 188 if ((ring->consume < ring->supply) || ring_empty(ring)) { 189 /* 190 * if consume is "below" supply, or empty, then 191 * return distance to the top 192 */ 193 return ring_subtract(ring, ring->top, ring->supply); 194 } else { 195 /* 196 * else, return what we may. 197 */ 198 return ring_subtract(ring, ring->consume, ring->supply); 199 } 200 } 201 202 /* Return the number of bytes that are available for consuming 203 * (but don't give more than enough to get to cross over set mark) 204 */ 205 206 int 207 ring_full_count(ring) 208 Ring *ring; 209 { 210 if ((ring->mark == 0) || (ring->mark == ring->consume)) { 211 if (ring_full(ring)) { 212 return ring->size; /* nothing consumed, but full */ 213 } else { 214 return ring_subtract(ring, ring->supply, ring->consume); 215 } 216 } else { 217 return ring_subtract(ring, ring->mark, ring->consume); 218 } 219 } 220 221 /* 222 * Return the number of CONSECUTIVE bytes available for consuming. 223 * However, don't return more than enough to cross over set mark. 224 */ 225 int 226 ring_full_consecutive(ring) 227 Ring *ring; 228 { 229 if ((ring->mark == 0) || (ring->mark == ring->consume)) { 230 if ((ring->supply < ring->consume) || ring_full(ring)) { 231 return ring_subtract(ring, ring->top, ring->consume); 232 } else { 233 return ring_subtract(ring, ring->supply, ring->consume); 234 } 235 } else { 236 if (ring->mark < ring->consume) { 237 return ring_subtract(ring, ring->top, ring->consume); 238 } else { /* Else, distance to mark */ 239 return ring_subtract(ring, ring->mark, ring->consume); 240 } 241 } 242 } 243 244 /* 245 * Move data into the "supply" portion of of the ring buffer. 246 */ 247 void 248 ring_supply_data(ring, buffer, count) 249 Ring *ring; 250 char *buffer; 251 int count; 252 { 253 int i; 254 255 while (count) { 256 i = MIN(count, ring_empty_consecutive(ring)); 257 memcpy(ring->supply, buffer, i); 258 ring_supplied(ring, i); 259 count -= i; 260 buffer += i; 261 } 262 } 263 264 265 /* 266 * Move data from the "consume" portion of the ring buffer 267 */ 268 void 269 ring_consume_data(ring, buffer, count) 270 Ring *ring; 271 char *buffer; 272 int count; 273 { 274 int i; 275 276 while (count) { 277 i = MIN(count, ring_full_consecutive(ring)); 278 memcpy(buffer, ring->consume, i); 279 ring_consumed(ring, i); 280 count -= i; 281 buffer += i; 282 } 283 } 284