source: rtems/cpukit/httpd/ringq.c @ 9b05600

4.104.114.84.95
Last change on this file since 9b05600 was c1cdaa0, checked in by Joel Sherrill <joel.sherrill@…>, on 10/27/99 at 12:50:33

Patch from Emmanuel Raguet <raguet@…> and Eric Valette
<valette@…> to add a port of the GoAhead? web server
(httpd) to the RTEMS build tree. They have successfully used
this BSP on i386/pc386 and PowerPC/mcp750.

Mark and Joel spoke with Nick Berliner <nickb@…> on
26 Oct 1999 about this port and got verbal approval to include
it in RTEMS distributions.

  • Property mode set to 100644
File size: 12.4 KB
Line 
1/*
2 * ringq.c -- Ring queue buffering module
3 *
4 * Copyright (c) GoAhead Software Inc., 1995-1999. All Rights Reserved.
5 *
6 * See the file "license.txt" for usage and redistribution license requirements
7 */
8
9/******************************** Description *********************************/
10
11/*
12 *      A ring queue allows maximum utilization of memory for data storage and is
13 *      ideal for input/output buffering.  This module provides a highly effecient
14 *      implementation and a vehicle for dynamic strings.
15 *
16 *      WARNING:  This is a public implementation and callers have full access to
17 *      the queue structure and pointers.  Change this module very carefully.
18 *
19 *      This module follows the open/close model.
20 *
21 *      Operation of a ringq where rq is a pointer to a ringq :
22 *
23 *              rq->buflen contains the size of the buffer.
24 *              rq->buf will point to the start of the buffer.
25 *              rq->servp will point to the first (un-consumed) data byte.
26 *              rq->endp will point to the next free location to which new data is added
27 *              rq->endbuf will point to one past the end of the buffer.
28 *
29 *      Eg. If the ringq contains the data "abcdef", it might look like :
30 *
31 *      +-------------------------------------------------------------------+
32 *  |   |   |   |   |   |   |   | a | b | c | d | e | f |   |   |   |   |
33 *      +-------------------------------------------------------------------+
34 *    ^                           ^                       ^               ^
35 *    |                           |                       |               |
36 *  rq->buf                    rq->servp               rq->endp      rq->enduf
37 *     
38 *      The queue is empty when servp == endp.  This means that the queue will hold
39 *      at most rq->buflen -1 bytes.  It is the fillers responsibility to ensure
40 *      the ringq is never filled such that servp == endp.
41 *
42 *      It is the fillers responsibility to "wrap" the endp back to point to
43 *      rq->buf when the pointer steps past the end.  Correspondingly it is the
44 *      consumers responsibility to "wrap" the servp when it steps to rq->endbuf.
45 *      The ringqPutc and ringqGetc routines will do this automatically.
46 */
47
48/********************************* Includes ***********************************/
49
50#if UEMF
51        #include        "uemf.h"
52#else
53        #include        "basic/basicInternal.h"
54#endif
55
56/*********************************** Defines **********************************/
57/*
58 *      Faster than a function call
59 */
60
61#define RINGQ_LEN(rq) \
62        ((rq->servp > rq->endp) ? \
63                (rq->buflen + (rq->endp - rq->servp)) : \
64                (rq->endp - rq->servp))
65
66/***************************** Forward Declarations ***************************/
67
68static int ringq_grow(ringq_t *rq);
69
70/*********************************** Code *************************************/
71/*
72 *      Create a new ringq. "increment" is the amount to increase the size of the
73 *      ringq should it need to grow to accomodate data being added. "maxsize" is
74 *      an upper limit (sanity level) beyond which the q must not grow. Set maxsize
75 *      to -1 to imply no upper limit. The buffer for the ringq is always
76 *      dynamically allocated. Set maxsize
77 */
78
79int ringqOpen(ringq_t *rq, int increment, int maxsize)
80{
81        a_assert(rq);
82        a_assert(increment >= 0);
83
84        if ((rq->buf = balloc(B_L, increment)) == NULL) {
85                return -1;
86        }
87        rq->maxsize = maxsize;
88        rq->buflen = increment;
89        rq->increment = increment;
90        rq->endbuf = &rq->buf[rq->buflen];
91        rq->servp = rq->buf;
92        rq->endp = rq->buf;
93        *rq->servp = '\0';
94        return 0;
95}
96
97/******************************************************************************/
98/*
99 *      Delete a ringq and free the ringq buffer.
100 */
101
102void ringqClose(ringq_t *rq)
103{
104        a_assert(rq);
105        a_assert(rq->buflen == (rq->endbuf - rq->buf));
106
107        if (rq == NULL) {
108                return;
109        }
110
111        ringqFlush(rq);
112        bfree(B_L, (char*) rq->buf);
113        rq->buf = NULL;
114}
115
116/******************************************************************************/
117/*
118 *      Return the length of the ringq. Users must fill the queue to a high
119 *      water mark of at most one less than the queue size.
120 */
121
122int ringqLen(ringq_t *rq)
123{
124        a_assert(rq);
125        a_assert(rq->buflen == (rq->endbuf - rq->buf));
126
127        if (rq->servp > rq->endp) {
128                return rq->buflen + rq->endp - rq->servp;
129        }
130        else {
131                return rq->endp - rq->servp;
132        }
133}
134
135/******************************************************************************/
136/*
137 *      Get a byte from the queue
138 */
139
140int ringqGetc(ringq_t *rq)
141{
142        char_t  c;
143        char_t* cp;
144
145        a_assert(rq);
146        a_assert(rq->buflen == (rq->endbuf - rq->buf));
147
148        if (rq->servp == rq->endp) {
149                return -1;
150        }
151
152        cp = (char_t*) rq->servp;
153        c = *cp++;
154        rq->servp = (unsigned char *) cp;
155        if (rq->servp >= rq->endbuf) {
156                rq->servp = rq->buf;
157        }
158        return c;
159}
160
161/******************************************************************************/
162/*
163 *      Add a char to the queue. Note if being used to store wide strings
164 *      this does not add a trailing '\0'. Grow the q as required.
165 */
166
167int ringqPutc(ringq_t *rq, char_t c)
168{
169        char_t* cp;
170
171        a_assert(rq);
172        a_assert(rq->buflen == (rq->endbuf - rq->buf));
173
174        if (ringqPutBlkMax(rq) < (int) sizeof(char_t) && !ringq_grow(rq)) {
175                return -1;
176        }
177
178        cp = (char_t*) rq->endp;
179        *cp++ = (char_t) c;
180        rq->endp = (unsigned char *) cp;
181        if (rq->endp >= rq->endbuf) {
182                rq->endp = rq->buf;
183        }
184        return 0;
185}
186
187/******************************************************************************/
188/*
189 *      Insert a wide character at the front of the queue
190 */
191
192int ringqInsertc(ringq_t *rq, char_t c)
193{
194        char_t* cp;
195
196        a_assert(rq);
197        a_assert(rq->buflen == (rq->endbuf - rq->buf));
198
199        if (ringqPutBlkMax(rq) < (int) sizeof(char_t) && !ringq_grow(rq)) {
200                return -1;
201        }
202        if (rq->servp <= rq->buf) {
203                rq->servp = rq->endbuf;
204        }
205        cp = (char_t*) rq->servp;
206        *--cp = (char_t) c;
207        rq->servp = (unsigned char *) cp;
208        return 0;
209}
210
211/******************************************************************************/
212/*
213 *      Add a string to the queue. Add a trailing wide null (two nulls)
214 */
215
216int ringqPutstr(ringq_t *rq, char_t *str)
217{
218        int             rc;
219
220        a_assert(rq);
221        a_assert(str);
222        a_assert(rq->buflen == (rq->endbuf - rq->buf));
223
224        rc = ringqPutBlk(rq, (unsigned char*) str, gstrlen(str) * sizeof(char_t));
225        *((char_t*) rq->endp) = (char_t) '\0';
226        return rc;
227}
228
229/******************************************************************************/
230#if UNICODE
231/*
232 *      Get a byte from the queue
233 */
234
235int ringqGetcA(ringq_t *rq)
236{
237        unsigned char   c;
238
239        a_assert(rq);
240        a_assert(rq->buflen == (rq->endbuf - rq->buf));
241
242        if (rq->servp == rq->endp) {
243                return -1;
244        }
245
246        c = *rq->servp++;
247        if (rq->servp >= rq->endbuf) {
248                rq->servp = rq->buf;
249        }
250        return c;
251}
252
253/******************************************************************************/
254/*
255 *      Add a byte to the queue. Note if being used to store strings this does not
256 *      add a trailing '\0'. Grow the q as required.
257 */
258
259int ringqPutcA(ringq_t *rq, char c)
260{
261        a_assert(rq);
262        a_assert(rq->buflen == (rq->endbuf - rq->buf));
263
264        if (ringqPutBlkMax(rq) == 0 && !ringq_grow(rq)) {
265                return -1;
266        }
267
268        *rq->endp++ = (unsigned char) c;
269        if (rq->endp >= rq->endbuf) {
270                rq->endp = rq->buf;
271        }
272        return 0;
273}
274
275/******************************************************************************/
276/*
277 *      Insert a byte at the front of the queue
278 */
279
280int ringqInsertcA(ringq_t *rq, char c)
281{
282        a_assert(rq);
283        a_assert(rq->buflen == (rq->endbuf - rq->buf));
284
285        if (ringqPutBlkMax(rq) == 0 && !ringq_grow(rq)) {
286                return -1;
287        }
288        if (rq->servp <= rq->buf) {
289                rq->servp = rq->endbuf;
290        }
291        *--rq->servp = (unsigned char) c;
292        return 0;
293}
294
295/******************************************************************************/
296/*
297 *      Add a string to the queue. Add a trailing null (not really in the q).
298 *      ie. beyond the last valid byte.
299 */
300
301int ringqPutstrA(ringq_t *rq, char *str)
302{
303        int             rc;
304
305        a_assert(rq);
306        a_assert(str);
307        a_assert(rq->buflen == (rq->endbuf - rq->buf));
308
309        rc = ringqPutBlk(rq, (unsigned char*) str, strlen(str));
310        rq->endp[0] = '\0';
311        return rc;
312}
313
314#endif /* UNICODE */
315/******************************************************************************/
316/*
317 *      Add a block of data to the ringq. Return the number of bytes added.
318 *      Grow the q as required.
319 */
320
321int ringqPutBlk(ringq_t *rq, unsigned char *buf, int size)
322{
323        int             this, bytes_put;
324
325        a_assert(rq);
326        a_assert(rq->buflen == (rq->endbuf - rq->buf));
327        a_assert(buf);
328        a_assert(0 <= size);
329
330/*
331 *      Loop adding the maximum bytes we can add in a single straight line copy
332 */
333        bytes_put = 0;
334        while (size > 0) {
335                this = min(ringqPutBlkMax(rq), size);
336                if (this <= 0) {
337                        if (! ringq_grow(rq)) {
338                                break;
339                        }
340                        this = min(ringqPutBlkMax(rq), size);
341                }
342
343                memcpy(rq->endp, buf, this);
344                buf += this;
345                rq->endp += this;
346                size -= this;
347                bytes_put += this;
348
349                if (rq->endp >= rq->endbuf) {
350                        rq->endp = rq->buf;
351                }
352        }
353        return bytes_put;
354}
355
356/******************************************************************************/
357/*
358 *      Get a block of data from the ringq. Return the number of bytes returned.
359 */
360
361int ringqGetBlk(ringq_t *rq, unsigned char *buf, int size)
362{
363        int             this, bytes_read;
364
365        a_assert(rq);
366        a_assert(rq->buflen == (rq->endbuf - rq->buf));
367        a_assert(buf);
368        a_assert(0 <= size && size < rq->buflen);
369
370/*
371 *      Loop getting the maximum bytes we can get in a single straight line copy
372 */
373        bytes_read = 0;
374        while (size > 0) {
375                this = ringqGetBlkMax(rq);
376                this = min(this, size);
377                if (this <= 0) {
378                        break;
379                }
380
381                memcpy(buf, rq->servp, this);
382                buf += this;
383                rq->servp += this;
384                size -= this;
385                bytes_read += this;
386
387                if (rq->servp >= rq->endbuf) {
388                        rq->servp = rq->buf;
389                }
390        }
391        return bytes_read;
392}
393
394/******************************************************************************/
395/*
396 *      Return the maximum number of bytes the ring q can accept via a single
397 *      block copy. Useful if the user is doing their own data insertion.
398 */
399
400int ringqPutBlkMax(ringq_t *rq)
401{
402        int             space, in_a_line;
403
404        a_assert(rq);
405        a_assert(rq->buflen == (rq->endbuf - rq->buf));
406       
407        space = rq->buflen - RINGQ_LEN(rq) - 1;
408        in_a_line = rq->endbuf - rq->endp;
409
410        return min(in_a_line, space);
411}
412
413/******************************************************************************/
414/*
415 *      Return the maximum number of bytes the ring q can provide via a single
416 *      block copy. Useful if the user is doing their own data retrieval.
417 */
418
419int ringqGetBlkMax(ringq_t *rq)
420{
421        int             len, in_a_line;
422
423        a_assert(rq);
424        a_assert(rq->buflen == (rq->endbuf - rq->buf));
425
426        len = RINGQ_LEN(rq);
427        in_a_line = rq->endbuf - rq->servp;
428
429        return min(in_a_line, len);
430}
431
432/******************************************************************************/
433/*
434 *      Adjust the endp pointer after the user has copied data into the queue.
435 */
436
437void ringqPutBlkAdj(ringq_t *rq, int size)
438{
439        a_assert(rq);
440        a_assert(rq->buflen == (rq->endbuf - rq->buf));
441        a_assert(0 <= size && size < rq->buflen);
442
443        rq->endp += size;
444        if (rq->endp >= rq->endbuf) {
445                rq->endp -= rq->buflen;
446        }
447/*
448 *      Flush the queue if the endp pointer is corrupted via a bad size
449 */
450        if (rq->endp >= rq->endbuf) {
451                error(E_L, E_LOG, T("Bad end pointer"));
452                ringqFlush(rq);
453        }
454}
455
456/******************************************************************************/
457/*
458 *      Adjust the servp pointer after the user has copied data from the queue.
459 */
460
461void ringqGetBlkAdj(ringq_t *rq, int size)
462{
463        a_assert(rq);
464        a_assert(rq->buflen == (rq->endbuf - rq->buf));
465        a_assert(0 < size && size < rq->buflen);
466
467        rq->servp += size;
468        if (rq->servp >= rq->endbuf) {
469                rq->servp -= rq->buflen;
470        }
471/*
472 *      Flush the queue if the servp pointer is corrupted via a bad size
473 */
474        if (rq->servp >= rq->endbuf) {
475                error(E_L, E_LOG, T("Bad serv pointer"));
476                ringqFlush(rq);
477        }
478}
479
480/******************************************************************************/
481/*
482 *      Flush all data in a ring q.  Reset the pointers.
483 */
484
485void ringqFlush(ringq_t *rq)
486{
487        a_assert(rq);
488
489        rq->servp = rq->buf;
490        rq->endp = rq->buf;
491        *rq->servp = '\0';
492}
493
494/******************************************************************************/
495/*
496 *      Grow the buffer. Return true if the buffer can be grown. Grow using
497 *      the increment size specified when opening the ringq. Don't grow beyond
498 *      the maximum possible size.
499 */
500
501static int ringq_grow(ringq_t *rq)
502{
503        unsigned char   *newbuf;
504        int                     len;
505
506        a_assert(rq);
507
508        if (rq->maxsize >= 0 && rq->buflen >= rq->maxsize) {
509                return 0;
510        }
511
512        len = ringqLen(rq);
513
514        if ((newbuf = balloc(B_L, rq->buflen + rq->increment)) == NULL) {
515                return 0;
516        }
517        ringqGetBlk(rq, newbuf, ringqLen(rq));
518        bfree(B_L, (char*) rq->buf);
519
520#if OLD
521        rq->endp = &newbuf[endp];
522        rq->servp = &newbuf[servp];
523        rq->endbuf = &newbuf[rq->buflen];
524        rq->buf = newbuf;
525#endif
526
527        rq->buflen += rq->increment;
528        rq->endp = newbuf;
529        rq->servp = newbuf;
530        rq->buf = newbuf;
531        rq->endbuf = &rq->buf[rq->buflen];
532
533        ringqPutBlk(rq, newbuf, len);
534        return 1;
535}
536
537/******************************************************************************/
Note: See TracBrowser for help on using the repository browser.