new version; (Chris Torek)
[unix-history] / usr / src / usr.bin / telnet / ring.c
CommitLineData
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 */
52static 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
68ring_init(ring, buffer, count)
69Ring *ring;
70char *buffer;
71int 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 */
87void
88ring_added(ring, count)
89Ring *ring;
90int 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 */
99void
100ring_sent(ring, count)
101Ring *ring;
102int 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 */
111void
112ring_acked(ring, count)
113Ring *ring;
114int 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 */
123void
124ring_sent_acked(ring, count)
125Ring *ring;
126int 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 */
137int
138ring_empty_count(ring)
139Ring *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 */
149int
150ring_empty_consecutive(ring)
151Ring *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 */
168int
169ring_unsent_count(ring)
170Ring *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 */
180int
181ring_unsent_consecutive(ring)
182Ring *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 */
192int
193ring_unacked_count(ring)
194Ring *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 */
207void
208ring_add_data(ring, buffer, count)
209Ring *ring;
210char *buffer;
211int 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 */
228void
229ring_send_data(ring, buffer, count)
230Ring *ring;
231char *buffer;
232int 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 */
248void
249ring_mark(ring)
250Ring *ring;
251{
252}
253
254int
255ring_at_mark(ring)
256Ring *ring;
257{
258 return 0;
259}
260
261void
262ring_clear_mark(ring)
263Ring *ring;
264{
265}