goahead源码分析(2.5)

ringq.c源码解析

一:ring_t类型描述:

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

ringq_t类型定义在uemf.h中:

View Code

二.ringq_t相关的宏:

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

   1)RINGQ_LEN(rq)

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

   定义如下:

View Code

解析: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次方的申请值,不然会产生很多碎片,或者造成内存中降低申请到大空间的可能性,这在资源紧缺的嵌入式开发中是非常值得关注的。

   代码:

View Code

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

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

View Code

其核心思想就是统计输入参数占用了多少个二进制位。这个函数理解了,那么上面的函数就好理解了,只是加了一个比较阈值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,则表示缓冲区无上界。

       源码:

View Code

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

3)void ringqFlush(ringq_t *rq)

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

       代码:

View Code

4)void ringqClose(ringq_t *rq)

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

       代码:

View Code

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

5)int ringqLen(ringq_t *rq)

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

代码:

View Code

6)int ringqGetc(ringq_t *rq)

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

       代码:

View Code

7)int ringqPutBlkMax(ringq_t *rq)

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

       代码:

View Code

8)int ringqGetBlkMax(ringq_t *rq)

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

       代码:

View Code

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

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

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

       代码:

View Code

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

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

       代码:

View Code

11)static int ringqGrow(ringq_t *rq)

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

       代码:

View Code

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

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

       代码:

View Code

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

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

       代码:  

View Code

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

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

       代码:

 

View Code

15)void ringqAddNull(ringq_t *rq)

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

       代码:

View Code

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函数,感觉这个函数有些多余,以后用到了再体会。

       代码:

View Code

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

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

       代码:

View Code
\
【转】https://www.cnblogs.com/strider/articles/2052858.html

posted on   lydstory  阅读(191)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
历史上的今天:
2021-06-19 名人传记-李宗盛
2021-06-19 cnblogs邀请我写书了,说明啥那
2020-06-19 /etc/rc.local 添加 自启动thttpd服务
2020-06-19 naigos 网络监控工具c php
2020-06-19 试用GNUGettext开源多语组件包
2020-06-19 c语言gnu gettext实现本地化
2020-06-19 centos root登录

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

统计

点击右上角即可分享
微信分享提示