⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ringq.c

📁 RTEMS (Real-Time Executive for Multiprocessor Systems) is a free open source real-time operating sys
💻 C
字号:
/* * ringq.c -- Ring queue buffering module * * Copyright (c) GoAhead Software Inc., 1995-2000. 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 efficient *	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 filler's responsibility to ensure *	the ringq is never filled such that servp == endp. * *	It is the filler's 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	ringqGrow(ringq_t *rq);static int	getBinBlockSize(int size);int			ringqGrowCalls = 0;/*********************************** 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 initSize, int maxsize){	int	increment;	a_assert(rq);	a_assert(initSize >= 0);	increment = getBinBlockSize(initSize);	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 data in 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)) && !ringqGrow(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) && !ringqGrow(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 null (maybe 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;}/******************************************************************************//* *	Add a null terminator. This does NOT increase the size of the queue */void ringqAddNull(ringq_t *rq){	a_assert(rq);	a_assert(rq->buflen == (rq->endbuf - rq->buf));	*((char_t*) rq->endp) = (char_t) '\0';}/******************************************************************************/#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 && !ringqGrow(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 && !ringqGrow(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 (! ringqGrow(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);	a_assert(rq->servp);	rq->servp = rq->buf;	rq->endp = rq->buf;	if (rq->servp) {		*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 ringqGrow(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);/* *	Double the increment so the next grow will line up with balloc'ed memory */	rq->increment = getBinBlockSize(2 * rq->increment);	return 1;}/******************************************************************************//* *	Find the smallest binary memory size that "size" will fit into.  This *	makes the ringq and ringqGrow routines much more efficient.  The balloc *	routine likes powers of 2 minus 1. */static int	getBinBlockSize(int size){	int	q;	size = size >> B_SHIFT;	for (q = 0; size; size >>= 1) {		q++;	}	return (1 << (B_SHIFT + q));}/******************************************************************************/

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -