From c1cdaa0ce8017b075487e6670f89eb4e715258ea Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Wed, 27 Oct 1999 12:50:33 +0000 Subject: Patch from Emmanuel Raguet and Eric 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 on 26 Oct 1999 about this port and got verbal approval to include it in RTEMS distributions. --- cpukit/httpd/ringq.c | 537 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 537 insertions(+) create mode 100644 cpukit/httpd/ringq.c (limited to 'cpukit/httpd/ringq.c') diff --git a/cpukit/httpd/ringq.c b/cpukit/httpd/ringq.c new file mode 100644 index 0000000000..62c4634eef --- /dev/null +++ b/cpukit/httpd/ringq.c @@ -0,0 +1,537 @@ +/* + * ringq.c -- Ring queue buffering module + * + * Copyright (c) GoAhead Software Inc., 1995-1999. All Rights Reserved. + * + * See the file "license.txt" for usage and redistribution license requirements + */ + +/******************************** Description *********************************/ + +/* + * A ring queue allows maximum utilization of memory for data storage and is + * ideal for input/output buffering. This module provides a highly effecient + * implementation and a vehicle for dynamic strings. + * + * WARNING: This is a public implementation and callers have full access to + * the queue structure and pointers. Change this module very carefully. + * + * This module follows the open/close model. + * + * Operation of a ringq where rq is a pointer to a ringq : + * + * rq->buflen contains the size of the buffer. + * rq->buf will point to the start of the buffer. + * rq->servp will point to the first (un-consumed) data byte. + * rq->endp will point to the next free location to which new data is added + * rq->endbuf will point to one past the end of the buffer. + * + * Eg. If the ringq contains the data "abcdef", it might look like : + * + * +-------------------------------------------------------------------+ + * | | | | | | | | a | b | c | d | e | f | | | | | + * +-------------------------------------------------------------------+ + * ^ ^ ^ ^ + * | | | | + * rq->buf rq->servp rq->endp rq->enduf + * + * The queue is empty when servp == endp. This means that the queue will hold + * at most rq->buflen -1 bytes. It is the fillers responsibility to ensure + * the ringq is never filled such that servp == endp. + * + * It is the fillers responsibility to "wrap" the endp back to point to + * rq->buf when the pointer steps past the end. Correspondingly it is the + * consumers responsibility to "wrap" the servp when it steps to rq->endbuf. + * The ringqPutc and ringqGetc routines will do this automatically. + */ + +/********************************* Includes ***********************************/ + +#if UEMF + #include "uemf.h" +#else + #include "basic/basicInternal.h" +#endif + +/*********************************** Defines **********************************/ +/* + * Faster than a function call + */ + +#define RINGQ_LEN(rq) \ + ((rq->servp > rq->endp) ? \ + (rq->buflen + (rq->endp - rq->servp)) : \ + (rq->endp - rq->servp)) + +/***************************** Forward Declarations ***************************/ + +static int ringq_grow(ringq_t *rq); + +/*********************************** Code *************************************/ +/* + * Create a new ringq. "increment" is the amount to increase the size of the + * ringq should it need to grow to accomodate data being added. "maxsize" is + * an upper limit (sanity level) beyond which the q must not grow. Set maxsize + * to -1 to imply no upper limit. The buffer for the ringq is always + * dynamically allocated. Set maxsize + */ + +int ringqOpen(ringq_t *rq, int increment, int maxsize) +{ + a_assert(rq); + a_assert(increment >= 0); + + if ((rq->buf = balloc(B_L, increment)) == NULL) { + return -1; + } + rq->maxsize = maxsize; + rq->buflen = increment; + rq->increment = increment; + rq->endbuf = &rq->buf[rq->buflen]; + rq->servp = rq->buf; + rq->endp = rq->buf; + *rq->servp = '\0'; + return 0; +} + +/******************************************************************************/ +/* + * Delete a ringq and free the ringq buffer. + */ + +void ringqClose(ringq_t *rq) +{ + a_assert(rq); + a_assert(rq->buflen == (rq->endbuf - rq->buf)); + + if (rq == NULL) { + return; + } + + ringqFlush(rq); + bfree(B_L, (char*) rq->buf); + rq->buf = NULL; +} + +/******************************************************************************/ +/* + * Return the length of the ringq. Users must fill the queue to a high + * water mark of at most one less than the queue size. + */ + +int ringqLen(ringq_t *rq) +{ + a_assert(rq); + a_assert(rq->buflen == (rq->endbuf - rq->buf)); + + if (rq->servp > rq->endp) { + return rq->buflen + rq->endp - rq->servp; + } + else { + return rq->endp - rq->servp; + } +} + +/******************************************************************************/ +/* + * Get a byte from the queue + */ + +int ringqGetc(ringq_t *rq) +{ + char_t c; + char_t* cp; + + a_assert(rq); + a_assert(rq->buflen == (rq->endbuf - rq->buf)); + + if (rq->servp == rq->endp) { + return -1; + } + + cp = (char_t*) rq->servp; + c = *cp++; + rq->servp = (unsigned char *) cp; + if (rq->servp >= rq->endbuf) { + rq->servp = rq->buf; + } + return c; +} + +/******************************************************************************/ +/* + * Add a char to the queue. Note if being used to store wide strings + * this does not add a trailing '\0'. Grow the q as required. + */ + +int ringqPutc(ringq_t *rq, char_t c) +{ + char_t* cp; + + a_assert(rq); + a_assert(rq->buflen == (rq->endbuf - rq->buf)); + + if (ringqPutBlkMax(rq) < (int) sizeof(char_t) && !ringq_grow(rq)) { + return -1; + } + + cp = (char_t*) rq->endp; + *cp++ = (char_t) c; + rq->endp = (unsigned char *) cp; + if (rq->endp >= rq->endbuf) { + rq->endp = rq->buf; + } + return 0; +} + +/******************************************************************************/ +/* + * Insert a wide character at the front of the queue + */ + +int ringqInsertc(ringq_t *rq, char_t c) +{ + char_t* cp; + + a_assert(rq); + a_assert(rq->buflen == (rq->endbuf - rq->buf)); + + if (ringqPutBlkMax(rq) < (int) sizeof(char_t) && !ringq_grow(rq)) { + return -1; + } + if (rq->servp <= rq->buf) { + rq->servp = rq->endbuf; + } + cp = (char_t*) rq->servp; + *--cp = (char_t) c; + rq->servp = (unsigned char *) cp; + return 0; +} + +/******************************************************************************/ +/* + * Add a string to the queue. Add a trailing wide null (two nulls) + */ + +int ringqPutstr(ringq_t *rq, char_t *str) +{ + int rc; + + a_assert(rq); + a_assert(str); + a_assert(rq->buflen == (rq->endbuf - rq->buf)); + + rc = ringqPutBlk(rq, (unsigned char*) str, gstrlen(str) * sizeof(char_t)); + *((char_t*) rq->endp) = (char_t) '\0'; + return rc; +} + +/******************************************************************************/ +#if UNICODE +/* + * Get a byte from the queue + */ + +int ringqGetcA(ringq_t *rq) +{ + unsigned char c; + + a_assert(rq); + a_assert(rq->buflen == (rq->endbuf - rq->buf)); + + if (rq->servp == rq->endp) { + return -1; + } + + c = *rq->servp++; + if (rq->servp >= rq->endbuf) { + rq->servp = rq->buf; + } + return c; +} + +/******************************************************************************/ +/* + * Add a byte to the queue. Note if being used to store strings this does not + * add a trailing '\0'. Grow the q as required. + */ + +int ringqPutcA(ringq_t *rq, char c) +{ + a_assert(rq); + a_assert(rq->buflen == (rq->endbuf - rq->buf)); + + if (ringqPutBlkMax(rq) == 0 && !ringq_grow(rq)) { + return -1; + } + + *rq->endp++ = (unsigned char) c; + if (rq->endp >= rq->endbuf) { + rq->endp = rq->buf; + } + return 0; +} + +/******************************************************************************/ +/* + * Insert a byte at the front of the queue + */ + +int ringqInsertcA(ringq_t *rq, char c) +{ + a_assert(rq); + a_assert(rq->buflen == (rq->endbuf - rq->buf)); + + if (ringqPutBlkMax(rq) == 0 && !ringq_grow(rq)) { + return -1; + } + if (rq->servp <= rq->buf) { + rq->servp = rq->endbuf; + } + *--rq->servp = (unsigned char) c; + return 0; +} + +/******************************************************************************/ +/* + * Add a string to the queue. Add a trailing null (not really in the q). + * ie. beyond the last valid byte. + */ + +int ringqPutstrA(ringq_t *rq, char *str) +{ + int rc; + + a_assert(rq); + a_assert(str); + a_assert(rq->buflen == (rq->endbuf - rq->buf)); + + rc = ringqPutBlk(rq, (unsigned char*) str, strlen(str)); + rq->endp[0] = '\0'; + return rc; +} + +#endif /* UNICODE */ +/******************************************************************************/ +/* + * Add a block of data to the ringq. Return the number of bytes added. + * Grow the q as required. + */ + +int ringqPutBlk(ringq_t *rq, unsigned char *buf, int size) +{ + int this, bytes_put; + + a_assert(rq); + a_assert(rq->buflen == (rq->endbuf - rq->buf)); + a_assert(buf); + a_assert(0 <= size); + +/* + * Loop adding the maximum bytes we can add in a single straight line copy + */ + bytes_put = 0; + while (size > 0) { + this = min(ringqPutBlkMax(rq), size); + if (this <= 0) { + if (! ringq_grow(rq)) { + break; + } + this = min(ringqPutBlkMax(rq), size); + } + + memcpy(rq->endp, buf, this); + buf += this; + rq->endp += this; + size -= this; + bytes_put += this; + + if (rq->endp >= rq->endbuf) { + rq->endp = rq->buf; + } + } + return bytes_put; +} + +/******************************************************************************/ +/* + * Get a block of data from the ringq. Return the number of bytes returned. + */ + +int ringqGetBlk(ringq_t *rq, unsigned char *buf, int size) +{ + int this, bytes_read; + + a_assert(rq); + a_assert(rq->buflen == (rq->endbuf - rq->buf)); + a_assert(buf); + a_assert(0 <= size && size < rq->buflen); + +/* + * Loop getting the maximum bytes we can get in a single straight line copy + */ + bytes_read = 0; + while (size > 0) { + this = ringqGetBlkMax(rq); + this = min(this, size); + if (this <= 0) { + break; + } + + memcpy(buf, rq->servp, this); + buf += this; + rq->servp += this; + size -= this; + bytes_read += this; + + if (rq->servp >= rq->endbuf) { + rq->servp = rq->buf; + } + } + return bytes_read; +} + +/******************************************************************************/ +/* + * Return the maximum number of bytes the ring q can accept via a single + * block copy. Useful if the user is doing their own data insertion. + */ + +int ringqPutBlkMax(ringq_t *rq) +{ + int space, in_a_line; + + a_assert(rq); + a_assert(rq->buflen == (rq->endbuf - rq->buf)); + + space = rq->buflen - RINGQ_LEN(rq) - 1; + in_a_line = rq->endbuf - rq->endp; + + return min(in_a_line, space); +} + +/******************************************************************************/ +/* + * Return the maximum number of bytes the ring q can provide via a single + * block copy. Useful if the user is doing their own data retrieval. + */ + +int ringqGetBlkMax(ringq_t *rq) +{ + int len, in_a_line; + + a_assert(rq); + a_assert(rq->buflen == (rq->endbuf - rq->buf)); + + len = RINGQ_LEN(rq); + in_a_line = rq->endbuf - rq->servp; + + return min(in_a_line, len); +} + +/******************************************************************************/ +/* + * Adjust the endp pointer after the user has copied data into the queue. + */ + +void ringqPutBlkAdj(ringq_t *rq, int size) +{ + a_assert(rq); + a_assert(rq->buflen == (rq->endbuf - rq->buf)); + a_assert(0 <= size && size < rq->buflen); + + rq->endp += size; + if (rq->endp >= rq->endbuf) { + rq->endp -= rq->buflen; + } +/* + * Flush the queue if the endp pointer is corrupted via a bad size + */ + if (rq->endp >= rq->endbuf) { + error(E_L, E_LOG, T("Bad end pointer")); + ringqFlush(rq); + } +} + +/******************************************************************************/ +/* + * Adjust the servp pointer after the user has copied data from the queue. + */ + +void ringqGetBlkAdj(ringq_t *rq, int size) +{ + a_assert(rq); + a_assert(rq->buflen == (rq->endbuf - rq->buf)); + a_assert(0 < size && size < rq->buflen); + + rq->servp += size; + if (rq->servp >= rq->endbuf) { + rq->servp -= rq->buflen; + } +/* + * Flush the queue if the servp pointer is corrupted via a bad size + */ + if (rq->servp >= rq->endbuf) { + error(E_L, E_LOG, T("Bad serv pointer")); + ringqFlush(rq); + } +} + +/******************************************************************************/ +/* + * Flush all data in a ring q. Reset the pointers. + */ + +void ringqFlush(ringq_t *rq) +{ + a_assert(rq); + + rq->servp = rq->buf; + rq->endp = rq->buf; + *rq->servp = '\0'; +} + +/******************************************************************************/ +/* + * Grow the buffer. Return true if the buffer can be grown. Grow using + * the increment size specified when opening the ringq. Don't grow beyond + * the maximum possible size. + */ + +static int ringq_grow(ringq_t *rq) +{ + unsigned char *newbuf; + int len; + + a_assert(rq); + + if (rq->maxsize >= 0 && rq->buflen >= rq->maxsize) { + return 0; + } + + len = ringqLen(rq); + + if ((newbuf = balloc(B_L, rq->buflen + rq->increment)) == NULL) { + return 0; + } + ringqGetBlk(rq, newbuf, ringqLen(rq)); + bfree(B_L, (char*) rq->buf); + +#if OLD + rq->endp = &newbuf[endp]; + rq->servp = &newbuf[servp]; + rq->endbuf = &newbuf[rq->buflen]; + rq->buf = newbuf; +#endif + + rq->buflen += rq->increment; + rq->endp = newbuf; + rq->servp = newbuf; + rq->buf = newbuf; + rq->endbuf = &rq->buf[rq->buflen]; + + ringqPutBlk(rq, newbuf, len); + return 1; +} + +/******************************************************************************/ -- cgit v1.2.3