ringq.c源码解析

一:ring_t类型描述:

    下面的描述在uemf.h和ringq.c中都有:

2011052116454871.jpg

ringq_t类型定义在uemf.h中:

ContractedBlock.gif ExpandedBlockStart.gif View Code
 
   
typedef struct {
unsigned
char * buf; /* Holding buffer for data */
unsigned
char * servp; /* Pointer to start of data */
unsigned
char * endp; /* Pointer to end of data */
unsigned
char * endbuf; /* Pointer to end of buffer */
int buflen; /* Length of ring queue */
int maxsize; /* Maximum size */
int increment; /* Growth increment */
} ringq_t;

二.ringq_t相关的宏:

   在ringq.c文件中包含的对ringq_t操作的宏有如下这些:

   1)RINGQ_LEN(rq)

   功能:返回ringq_t类型对象rq的有效长度。

   定义如下:

ContractedBlock.gif ExpandedBlockStart.gif View Code
 
   
#define RINGQ_LEN(rq) \
((rq
-> servp > rq -> endp) ? \
(rq
-> buflen + (rq -> endp - rq -> servp)) : \
(rq
-> endp - rq -> servp))

解析:ringq_t在内存中开辟一块循环使用的缓冲区,其成员buf指向该缓冲区的起始地址,endbuf指向紧挨该缓冲区的下一个字节(注意:并不是该缓冲区的最后一个字节)。buflen是该缓冲区的长度,即buflen=endbuf-buf. servp指向缓冲区中有效数据的第一个字节(不知道源码中的un-consumed是否有误),endp指向缓冲区中空闲块的第一个字节。那么在一般情况下,endp>serp,且endp-servp即为缓冲区中有效数据的字节数。

ringq_t的特点即是缓冲区循环使用。当endp或servp到达缓冲区的最后一个字节,如果要继续增长(即要到达endbuf所指的位置)时,缓冲区的填充着要负责将它们回卷(wrap)到缓冲区的起始位置。这样循环利用这块缓冲区使得内存利用率得到提高。

宏RINGQ_LEN的功能就是返回ringq_t类型对象中的有效数据的长度。由于缓冲区被循环使用,使得有两种情况会出现:1)endp>servp,这是一般情况,此时有效数据的长度(所占的字节数)即为endp-servp;2)endp<serp,此种情况的产生是由于endp的增长使其回卷到缓冲区的前端继续增长,那么此时的有效数据的长度是从servp到endbuf和从buf到endp这两段长度的和,即endbuf-servp+endp-buf=endbuf-buf+endp-servp=buflen+endp-servp.

      

三.相关的函数:

1)static int    getBinBlockSize(int size)

   功能:如果参数size<2的 B_SHIFT次方(定义在uemf.h中,为4),则返回2的B_SHIFT次方。如果参数size>=2的B_SHIFT次方,则返回大于2的B_SHIFT次方的第一个2的整数次幂。

   作用:程序中申请空间的时候,尽量满足2的N次方的申请值,不然会产生很多碎片,或者造成内存中降低申请到大空间的可能性,这在资源紧缺的嵌入式开发中是非常值得关注的。

   代码:

ContractedBlock.gif ExpandedBlockStart.gif View Code
 
   
/* **************************************************************************** */
/*
* 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));
}

/* *****************************************************************************

    代码解析:首先我们自己完成这样一个函数,要求该函数返回比输入参数大的第一个2的整数次幂。我们这里把函数原型依然定义为int   getBinBlockSize(int size)。

    代码如下(在VC下测试过):

ContractedBlock.gif ExpandedBlockStart.gif View Code
 
   
#include < iostream.h >

int getBinBlockSize( int size);
void main()
{
int a;
cout
<< " please input a positive integer: " ;
cin
>> a;
cout
<< getBinBlockSize(a) << endl;
}

int getBinBlockSize( int size)
{
for ( int q = 0 ;size > 0 ;size >>= 1 )
{
q
++ ;
}

return 1 << q;
}

其核心思想就是统计输入参数占用了多少个二进制位。这个函数理解了,那么上面的函数就好理解了,只是加了一个比较阈值B_SHIFT而已。

2)int ringqOpen(ringq_t *rq, int initSize, int maxsize)

       功能:新建一个ringq_t类型的对象(准确的说,这种说法有误,因为ring_t对象通过ringq_t rq即可创建,这个函数的实际作用是初始化ringq_t对象相关的缓冲区)。参数initSize是函数调用者希望分配的缓冲区大小,但实际传递给内存分配函数的请求大小是经过函数int getBinBlockSize(int size)调整过的,如果initSize比2的B_SHIFT(在uemf.h中定义为4)次方小,则用2的B_SHIFT次方去调用实际内存分配函数balloc,如果initSize比2的B_SHIFT次幂大,则用大于initSize的第一个2的整数次幂作为参数去调用实际内存分配函数balloc。balloc的解析目前不表。maxsize的作用是设置缓冲区大小的上界,如果设置为-1,则表示缓冲区无上界。

       源码:

ContractedBlock.gif ExpandedBlockStart.gif View Code
 
   
/* ********************************** 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 ;
}

补充:新建了大小经过算法调整后的缓冲区后,代码还把serp、endp都指向缓冲区的起始位置,且填上\0字符。

3)void ringqFlush(ringq_t *rq)

       功能:清空ringq_t类型对象所有的内存缓冲区中的有效数据。使得servp和endp都指向缓冲区中的第一个字节,即buf指针所指处。并将这块内存的内容设置为‘\0’。

       代码:

ContractedBlock.gif ExpandedBlockStart.gif View Code
 
   
/* **************************************************************************** */
/*
* 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 ' ;
}
}

4)void ringqClose(ringq_t *rq)

       功能:删除ring_t对象,并且释放其指向的内存缓冲区。

       代码:

ContractedBlock.gif ExpandedBlockStart.gif View Code
 
   
/* **************************************************************************** */
/*
* 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;
}

解析:该函数在调用了ringqFlush()清空缓冲区有效数据外,还释放了整个缓冲区的内存。

5)int ringqLen(ringq_t *rq)

功能:返回ringq_t对象的内存缓冲区中数据的长度。与RINGQ_LEN(rq)宏功能同。

代码:

ContractedBlock.gif ExpandedBlockStart.gif View Code
 
   
/* **************************************************************************** */
/*
* 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;
}
}

6)int ringqGetc(ringq_t *rq)

       功能:返回ringq_t对象的内存缓冲区中的有效数据区得第一个字节处的内容。也就是返回servp所指的内容,并将servp+1,如果servp+1后到达endbuf,则将其回卷(wrap)到缓冲区的开头即buf处。

       代码:

ContractedBlock.gif ExpandedBlockStart.gif View Code
 
   
/* **************************************************************************** */
/*
* 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;
}
/*
* 17 Sep 03 BgP -- using the implicit conversion from signed char to
* signed int in the return below makes this function work incorrectly when
* dealing with UTF-8 encoded text. UTF-8 may include characters that are >
* 127, which a signed char treats as negative. When we return a 'negative'
* value from this function, it gets converted to a negative
* integer, instead of a small positive integer, which is what we want.
* So, we cast to (unsigned char) before returning, and the problem goes
* away...
*/
return ( int ) ((unsigned char ) c);
}

7)int ringqPutBlkMax(ringq_t *rq)

       功能:返回缓冲区通过一次拷贝操作可以接受的最大字节数。需要考虑到回卷的情况。

       代码:

ContractedBlock.gif ExpandedBlockStart.gif View Code
 
   
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);
}

8)int ringqGetBlkMax(ringq_t *rq)

       功能:与ringqPutBlkMax(ringq_t *rq函数对应,该函数返回缓冲区通过一次拷贝可以提供的有效数据的字节数。同样要考虑两种情况,一种是没有回卷,即endp>servp,另一种是回卷了的,即servp>endp.

       代码:

ContractedBlock.gif ExpandedBlockStart.gif View Code
 
   
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);
}

9)int ringqGetBlk(ringq_t *rq, unsigned char *buf, int size)

       功能:从rq的缓冲区的数据区的起始位置起,取出连续的一块数据放到参数buf所指的内存处。参数size是请求的数据块大小,但实际拷贝的大小由size即ringqGetBlkMax()函数共同确定。

       副作用:拷贝完成后,循环缓冲区servp将增大实际拷贝的字节数,若起到达endbuf则要回卷。返回值是实际拷贝成功的字节数。

       代码:

ContractedBlock.gif ExpandedBlockStart.gif View Code
 
   
/* **************************************************************************** */
/*
* 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;
}

10)int ringqPutBlk(ringq_t *rq, unsigned char *buf, int size)

       功能:与ringqGetBlk函数对应理解。

       代码:

ContractedBlock.gif ExpandedBlockStart.gif View Code
 
   
/* **************************************************************************** */
/*
* 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;
}

11)static int ringqGrow(ringq_t *rq)

       功能:扩充rq的循环缓冲区的大小。扩充的大小为ringq_t对象中的increament成员。如果该循环缓冲区能够被扩充,则返回true。需要调用者自己保证扩充后的缓冲区长度不要超过该ringq_t对象的maxsize成员规定的上限值。

       代码:

ContractedBlock.gif ExpandedBlockStart.gif View Code
 
   
/* **************************************************************************** */
/*
* 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);


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 ;
}

12)int ringqPutc(ringq_t *rq, char_t c)

       功能:与ringqGetc函数功能对应,该函数向缓冲区中添加一个字符,使添加后的字符存放于有效数据区的最后一个存储单元。主要代码很简单,重要的是检错,自动调整缓冲区大小与回卷判断部分。

       代码:

ContractedBlock.gif ExpandedBlockStart.gif View Code
 
   
/* **************************************************************************** */
/*
* 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 ;
}

13)int ringqInsertc(ringq_t *rq, char_t c)

       功能:与ringq_Putc相反,前者是往缓冲区数据部分的尾部添加数据,而这个函数是是使得添加后的字符是数据缓冲区的第一个字符。同样重要的部分在于检错机制和回卷的判断以及能否根据现有数据缓冲区的大小自动调整整个缓冲区大小。

       代码:  

ContractedBlock.gif ExpandedBlockStart.gif View Code
 
   
/* **************************************************************************** */
/*
* 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 ;
}

14)int ringqPutStr(ringq_t *rq, char_t *str)

       功能:向ringq_t玄幻缓冲区的数据部分的尾部添加一个字符串。并将endp所指的内存单元置为/0结束符。

       代码:

 

ContractedBlock.gif ExpandedBlockStart.gif View Code
 
   
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;
}

15)void ringqAddNull(ringq_t *rq)

       功能:把ringq_t缓冲区的endp指向的位置设置为\0结束符。

       代码:

ContractedBlock.gif ExpandedBlockStart.gif View Code
 
   
void ringqAddNull(ringq_t * rq)
{
a_assert(rq);
a_assert(rq
-> buflen == (rq -> endbuf - rq -> buf));

* ((char_t * ) rq -> endp) = (char_t) ' \0 ' ;
}

16)int ringqGetcA(ringq_t *rq)

       int ringqPutcA(ringq_t *rq, char c)

       int ringqInsertcA(ringq_t *rq, char c)

       int ringqPutStrA(ringq_t *rq, char *str)

       功能:上述四个函数是在定义了unicode格式时实现与ringqGetc、ringqPutc、ringqInsertc、ringqPutstr对应的功能。

17)void ringqPutBlkAdj(ringq_t *rq, int size)

       功能:当用户往缓冲区中传递数据了后,调整缓冲区中endp指针的位置。但是因为有了ringqPutBlk函数,感觉这个函数有些多余,以后用到了再体会。

       代码:

ContractedBlock.gif ExpandedBlockStart.gif View Code
 
   
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);
}
}

18)void ringqGetBlkAdj(ringq_t *rq, int size)

       功能:当用户从缓冲区中取走数据后,调整数据缓冲区的起始指针servp。同上因为有函数ringqGetBlk的存在,感觉这个函数有些多余。

       代码:

ContractedBlock.gif ExpandedBlockStart.gif View Code
 
   
/* **************************************************************************** */
/*
* 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);
}
}

转载于:https://www.cnblogs.com/strider/articles/2052858.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值