source: rtems/cpukit/httpd/ringq.c @ dc2a1750

4.104.114.84.95
Last change on this file since dc2a1750 was ee3afa2, checked in by Joel Sherrill <joel.sherrill@…>, on 04/11/03 at 14:46:55

2002-04-10 Mike Siers <mikes@…>

  • rtems_webserver/NOTES, rtems_webserver/asp.c, rtems_webserver/balloc.c, rtems_webserver/default.c, rtems_webserver/ej.h, rtems_webserver/ejIntrn.h, rtems_webserver/ejlex.c, rtems_webserver/ejparse.c, rtems_webserver/emfdb.c, rtems_webserver/emfdb.h, rtems_webserver/form.c, rtems_webserver/h.c, rtems_webserver/handler.c, rtems_webserver/license.txt, rtems_webserver/md5.h, rtems_webserver/md5c.c, rtems_webserver/mime.c, rtems_webserver/misc.c, rtems_webserver/ringq.c, rtems_webserver/rom.c, rtems_webserver/security.c, rtems_webserver/sock.c, rtems_webserver/sym.c, rtems_webserver/uemf.c, rtems_webserver/uemf.h, rtems_webserver/um.c, rtems_webserver/um.h, rtems_webserver/url.c, rtems_webserver/value.c, rtems_webserver/wbase64.c, rtems_webserver/webcomp.c, rtems_webserver/webpage.c, rtems_webserver/webrom.c, rtems_webserver/webs.c, rtems_webserver/webs.h, rtems_webserver/websuemf.c, rtems_webserver/wsIntrn.h: Update to GoAhead? Webserver 2.1.4. The following URL is the release notes from GoAhead?.

http://data.goahead.com/Software/Webserver/2.1.4/release.htm

I have only done a minimal amount of testing (i.e. the network
demo program works fine). Please try this out and let me know
if it works. The patch needs to be applied on the
c/src/libnetworking/rtems_webserver directory.

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