Commit | Line | Data |
---|---|---|
cde671b6 GM |
1 | /* |
2 | * This defines a structure for a receive or send ring buffer. | |
3 | * | |
4 | * The circular buffer actually has three parts: | |
5 | *((( | |
6 | * full, sent, not acked: [ack, send) | |
7 | * full, not sent: [send, add) | |
8 | * empty: [add, ack) | |
9 | *]]] | |
10 | * | |
11 | * Any given byte will go through "empty" -> "send" -> "ack" -> "empty" | |
12 | * as data is moved through it. The transition from "ack" to "empty" | |
13 | * may occur instantaneously (as in the case of sending data up to another | |
14 | * process). | |
15 | */ | |
16 | ||
17 | #include <stdio.h> | |
18 | #include <errno.h> | |
19 | ||
20 | #ifdef size_t | |
21 | #undef size_t | |
22 | #endif | |
23 | ||
24 | #include <sys/types.h> | |
25 | #include <sys/ioctl.h> | |
26 | #include <sys/socket.h> | |
27 | ||
28 | #include "ring.h" | |
29 | #include "general.h" | |
30 | ||
31 | /* Internal macros */ | |
32 | ||
115a5494 GM |
33 | #if !defined(MIN) |
34 | #define MIN(a,b) (((a)<(b))? (a):(b)) | |
35 | #endif /* !defined(MIN) */ | |
cde671b6 | 36 | |
115a5494 GM |
37 | #define ring_subtract(d,a,b) ((((int)(a))-((int)(b)) >= 0)? \ |
38 | (a)-(b): (((a)-(b))+(d)->size)) | |
cde671b6 GM |
39 | |
40 | #define ring_increment(d,a,c) (((a)+(c) < (d)->top)? \ | |
41 | (a)+(c) : (((a)+(c))-(d)->size)) | |
42 | ||
43 | ||
44 | /* | |
45 | * The following is a clock, used to determine full, empty, etc. | |
46 | * | |
47 | * There is some trickiness here. Since the ring buffers are initialized | |
48 | * to ZERO on allocation, we need to make sure, when interpreting the | |
49 | * clock, that when the times are EQUAL, then the buffer is FULL, all | |
50 | * bytes have been SENT, no bytes are waiting to be ACKED, etc. | |
51 | */ | |
52 | static u_long ring_clock = 0; | |
53 | ||
54 | ||
55 | #define ring_add_all(d) (((d)->ack == (d)->add) && \ | |
56 | ((d)->acktime >= (d)->addtime)) | |
57 | #define ring_send_all(d) (((d)->add == (d)->send) && \ | |
58 | ((d)->addtime > (d)->sendtime)) | |
59 | #define ring_ack_all(d) (((d)->send == (d)->ack) && \ | |
60 | ((d)->sendtime > (d)->acktime)) | |
61 | ||
62 | ||
63 | ||
64 | ||
65 | ||
66 | /* Buffer state transition routines */ | |
67 | ||
115a5494 GM |
68 | ring_init(ring, buffer, count) |
69 | Ring *ring; | |
70 | char *buffer; | |
71 | int count; | |
72 | { | |
73 | memset((char *)ring, 0, sizeof *ring); | |
74 | ||
75 | ring->size = count; | |
76 | ||
77 | ring->add = ring->send = ring->ack = ring->bottom = buffer; | |
78 | ||
79 | ring->top = ring->bottom+ring->size; | |
80 | ||
81 | return 1; | |
82 | } | |
cde671b6 GM |
83 | |
84 | /* | |
85 | * Add characters from current segment to ring buffer. | |
86 | */ | |
87 | void | |
88 | ring_added(ring, count) | |
89 | Ring *ring; | |
90 | int count; | |
91 | { | |
92 | ring->add = ring_increment(ring, ring->add, count); | |
93 | ring->addtime = ++ring_clock; | |
94 | } | |
95 | ||
96 | /* | |
97 | * We have just sent "c" bytes. | |
98 | */ | |
99 | void | |
100 | ring_sent(ring, count) | |
101 | Ring *ring; | |
102 | int count; | |
103 | { | |
104 | ring->send = ring_increment(ring, ring->send, count); | |
105 | ring->sendtime = ++ring_clock; | |
106 | } | |
107 | ||
108 | /* | |
109 | * We have just received an "ack" for "c" bytes. | |
110 | */ | |
111 | void | |
112 | ring_acked(ring, count) | |
113 | Ring *ring; | |
114 | int count; | |
115 | { | |
116 | ring->ack = ring_increment(ring, ring->ack, count); | |
117 | ring->acktime = ++ring_clock; | |
118 | } | |
119 | ||
e8507c1e GM |
120 | /* |
121 | * We just sent and acked some data. | |
122 | */ | |
123 | void | |
124 | ring_sent_acked(ring, count) | |
125 | Ring *ring; | |
126 | int count; | |
127 | { | |
128 | ring_sent(ring, count); | |
129 | ring_acked(ring, count); | |
130 | } | |
131 | ||
cde671b6 GM |
132 | |
133 | /* Buffer state query routines */ | |
134 | ||
135 | ||
136 | /* Number of bytes that may be added */ | |
137 | int | |
138 | ring_empty_count(ring) | |
139 | Ring *ring; | |
140 | { | |
141 | if (ring_add_all(ring)) { /* if empty */ | |
142 | return ring->size; | |
143 | } else { | |
144 | return ring_subtract(ring, ring->ack, ring->add); | |
145 | } | |
146 | } | |
147 | ||
148 | /* number of CONSECUTIVE bytes that may be added */ | |
149 | int | |
150 | ring_empty_consecutive(ring) | |
151 | Ring *ring; | |
152 | { | |
153 | if ((ring->ack < ring->add) || ring_add_all(ring)) { | |
154 | /* | |
155 | * if ack is "below" add, or empty, then | |
156 | * return distance to the top | |
157 | */ | |
158 | return ring_subtract(ring, ring->top, ring->add); | |
159 | } else { | |
160 | /* | |
161 | * else, return what we may. | |
162 | */ | |
163 | return ring_subtract(ring, ring->ack, ring->add); | |
164 | } | |
165 | } | |
166 | ||
167 | /* number of bytes that are available for sending */ | |
168 | int | |
169 | ring_unsent_count(ring) | |
170 | Ring *ring; | |
171 | { | |
172 | if (ring_send_all(ring)) { | |
173 | return ring->size; /* nothing sent, but full */ | |
174 | } else { | |
175 | return ring_subtract(ring, ring->add, ring->send); | |
176 | } | |
177 | } | |
178 | ||
179 | /* number of CONSECUTIVE bytes available for sending */ | |
180 | int | |
181 | ring_unsent_consecutive(ring) | |
182 | Ring *ring; | |
183 | { | |
184 | if ((ring->add < ring->send) || ring_send_all(ring)) { | |
185 | return ring_subtract(ring, ring->top, ring->send); | |
186 | } else { | |
187 | return ring_subtract(ring, ring->add, ring->send); | |
188 | } | |
189 | } | |
190 | ||
191 | /* number of bytes awaiting acking */ | |
192 | int | |
193 | ring_unacked_count(ring) | |
194 | Ring *ring; | |
195 | { | |
196 | if (ring_ack_all(ring)) { | |
197 | return ring->size; /* last operation was a send - nothing done */ | |
198 | } else { | |
199 | return ring_subtract(ring, ring->send, ring->ack); | |
200 | } | |
201 | } | |
202 | ||
203 | ||
204 | /* | |
205 | * Move data into the "add" portion of of the ring buffer. | |
206 | */ | |
207 | void | |
208 | ring_add_data(ring, buffer, count) | |
209 | Ring *ring; | |
210 | char *buffer; | |
211 | int count; | |
212 | { | |
213 | int i; | |
214 | ||
215 | while (count) { | |
115a5494 | 216 | i = MIN(count, ring_empty_consecutive(ring)); |
cde671b6 GM |
217 | memcpy(ring->add, buffer, i); |
218 | ring_added(ring, i); | |
219 | count -= i; | |
220 | buffer += i; | |
221 | } | |
222 | } | |
223 | ||
224 | ||
225 | /* | |
226 | * Move data from the "send" portion of the ring buffer | |
227 | */ | |
228 | void | |
229 | ring_send_data(ring, buffer, count) | |
230 | Ring *ring; | |
231 | char *buffer; | |
232 | int count; | |
233 | { | |
234 | int i; | |
235 | ||
236 | while (count) { | |
115a5494 | 237 | i = MIN(count, ring_unsent_consecutive(ring)); |
cde671b6 GM |
238 | memcpy(buffer, ring->send, i); |
239 | ring_sent(ring, i); | |
240 | count -= i; | |
241 | buffer += i; | |
242 | } | |
243 | } | |
115a5494 GM |
244 | |
245 | /* Mark routines */ | |
246 | ||
247 | /* XXX do something here */ | |
248 | void | |
249 | ring_mark(ring) | |
250 | Ring *ring; | |
251 | { | |
252 | } | |
253 | ||
254 | int | |
255 | ring_at_mark(ring) | |
256 | Ring *ring; | |
257 | { | |
258 | return 0; | |
259 | } | |
260 | ||
261 | void | |
262 | ring_clear_mark(ring) | |
263 | Ring *ring; | |
264 | { | |
265 | } |