转自:https://blog.csdn.net/eydwyz/article/details/56671023

循环缓冲区在一些竞争问题上提供了一种免锁的机制,免锁的前提是,生产者和消费
 都只有一个的情况下,否则也要加锁。下面就内核中提取出来,而经过修改后的fifo进
 行简要的分析。
 
 先看其只要数据结构:
 struct my_fifo {
 unsignedchar *buffer;/* the
buffer holding the data*/
 unsignedint size;/* the
size of the allocated buffer*/
unsignedint in;/* data is added at offset (in % size)*/
 unsignedint out;/* data
is extracted from off. (out % size)*/

}

也不用多说,一看就明白。size, in, out 都设成无符号型的,因为都不存在负值的情型。

/*
 form kernel/kfifo.c
 */
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <fifo.h>
 
 #define min(a,b) ((a) < (b) ? (a):(b))
 /*

my_fifo_init

*/

struct my_fifo *my_fifo_init(unsignedchar *buffer,unsigned int size)
 {
 struct my_fifo *fifo;
 
 fifo = malloc(sizeof(struct my_fifo));
 if (!fifo)
 returnNULL;

fifo->buffer = buffer;
 fifo->size = size;
 fifo->in = fifo->out = 0;

return fifo;
 }
这个初始化fifo结构的函数一般也不会在应用层里进行调用,而是被下面的fifo_alloc
 调用。依我的观点来看,这两个函数合成一个函数会更加的清晰,但是这一情况只针对

buffer是系统开辟的空间,如果buffer的空间是由其它的函数来提供,就只能用上面的这个函数。

/*
 my_fifo_alloc
*/
 struct my_fifo *my_fifo_alloc(unsignedint size)
 {
 unsignedchar *buffer;
 struct my_fifo *ret;
 /*
 * round up to the next power of 2, since our 'let the indices
 * wrap' tachnique works only in this case.
 */
 
 buffer = malloc(size);
 if (!buffer)
 returnNULL;
 
 ret = my_fifo_init(buffer, size);
 
 if (ret ==NULL)
 free(buffer);
 
 return ret;
 }
 /*
 * my_fifo_free
 */
 void my_fifo_free(struct my_fifo *fifo)
 {
 free(fifo->buffer);
 free(fifo);
 }
 
 这两个函数也不作过多的分析,都很清晰。

/*
 my_fifo_put()
 */
 unsignedint my_fifo_put(struct my_fifo
*fifo,
 unsignedchar *buffer, unsigned int len)
 {
 unsignedint l;
 
 len = min(len, fifo->size - fifo->in + fifo->out);/*可能是缓冲区的空闲长度或者要写长度*/
 
 /* first put the data starting from fifo->in to buffer end*/
 l = min(len, fifo->size - (fifo->in & (fifo->size -1)));
 memcpy(fifo->buffer + (fifo->in & (fifo->size -1)), buffer, l);
 
 /* then put the rest (if any) at the beginning of the buffer*/
 memcpy(fifo->buffer, buffer + l, len - l);
 
 fifo->in += len;
 
 return len;
 }

/*
 my_fifo_get
 */
 unsignedint my_fifo_get(struct my_fifo
*fifo,
 unsignedchar *buffer, unsigned int len)
 {
 unsignedint l;
 
 len = min(len, fifo->in - fifo->out); /*可读数据*/
 
 /* first get the data from fifo->out until the end of the buffer*/
 l = min(len, fifo->size - (fifo->out & (fifo->size -1)));
 memcpy(buffer, fifo->buffer + (fifo->out & (fifo->size -1)), l);
 
 /* then get the rest (if any) from the beginning of the buffer*/
 memcpy(buffer + l, fifo->buffer, len - l);
 
 fifo->out += len;
 
 return len;
 }
 这两个读写结构才是循环缓冲区的重点。在fifo结构中,size是缓冲区的大小,是由用
 户自己定义的,但是在这个设计当中要求它的大小必须是2的幂次。
 当in==out时,表明缓冲区为空的,当(in-out)==size 时,说明缓冲区已满。
 
 我们看下具体实现,在86行处如果size-in+out ==0,也即获得的len值会0,而没有数
 据写入到缓冲区中。所以在设计缓冲区的大小的时候要恰当,读出的速度要比定入的速
 度要快,否则缓冲区满了会使数据丢失,可以通过成功写入的反回值来做判断尝试再次
 写入.
 另一种情况则是缓冲区有足够的空间给要写入的数据,但是试想一下,如果空闲的空间
 在缓冲的首尾两次,这又是如何实现呢?这部分代码实现得非常巧妙。
 我们看fifo->in &(fifo->size-1) 这个表达式是什么意思呢?我们知道size是2的幂次
 项,那么它减1即表示其值的二进制所有位都为1,与in相与的最终结果是in%size,比
 size要小,所以看in及out的值都是不断地增加,但再相与操作后,它们即是以size为
 周期的一个循环。89行就是比较要写入的数据应该是多少,如果缓冲区后面的还有足够
 的空间可写,那么把全部的值写到后面,否则写满后面,再写到前面去93行。
 读数据也可以作类似的分析,108行表示请求的数据要比缓冲区的数据要大时,只
 读取缓冲区中可用的数据。
 
 staticinline void my_fifo_reset(struct my_fifo
*fifo)
 {
 fifo->in = fifo->out = 0;
 }
 
 staticinline unsigned int my_fifo_len(struct my_fifo
*fifo)

return fifo->in - fifo->out;
 }
 在头文件里还有缓冲区置位及返回缓冲区中数据大小两个函数,很简单,不必解释

linux内核环形缓冲区【转】的更多相关文章

  1. Linux驱动开发10——内核环形双向链表

    Linux内核环形双向链表本身不实现锁机制,需要驱动本身完成锁机制实现. 1.1.list_head结构体 #include <linux/list.h> struct list_head ...

  2. Linux内核结构体--kfifo 环状缓冲区

    转载链接:http://blog.csdn.net/yusiguyuan/article/details/41985907 1.前言 最近项目中用到一个环形缓冲区(ring buffer),代码是由L ...

  3. Linux 内核:匠心独运之无锁环形队列kfifo

    Linux 内核:匠心独运之无锁环形队列 Kernel version Linux 2.6.12   Author Toney   Email vip_13031075266@163.com   Da ...

  4. linux device driver —— 环形缓冲区的实现

    还是没有接触到怎么控制硬件,但是在书里看到了一个挺巧妙的环形缓冲区实现. 此环形缓冲区实际为一个大小为bufsize的一维数组,有一个rp的读指针,一个wp的写指针. 在数据满时写进程会等待读进程读取 ...

  5. 用于阻止缓冲区溢出攻击的 Linux 内核参数与 gcc 编译选项

    先来看看基于 Red Hat 与 Fedora 衍生版(例如 CentOS)系统用于阻止栈溢出攻击的内核参数,主要包含两项: kernel.exec-shield 可执行栈保护,字面含义比较“绕”, ...

  6. dmesg---检查和控制内核的环形缓冲区

    dmesg命令被用于检查和控制内核的环形缓冲区.kernel会将开机信息存储在ring buffer中.您若是开机时来不及查看信息,可利用dmesg来查看.开机信息保存在/var/log/dmesg文 ...

  7. 环形缓冲区-模仿linux kfifo【转】

    转自:https://blog.csdn.net/vertor11/article/details/53741681 struct kfifo{ uint8_t *buffer; uint32_t i ...

  8. linux网络编程--Circular Buffer(Ring Buffer) 环形缓冲区的设计与实现【转】

    转自:https://blog.csdn.net/yusiguyuan/article/details/18368095 1. 应用场景 网络编程中有这样一种场景:需要应用程序代码一边从TCP/IP协 ...

  9. linux下C语言实现多线程通信—环形缓冲区,可用于生产者(producer)/消费者(consumer)【转】

    转自:http://blog.chinaunix.net/uid-28458801-id-4262445.html 操作系统:ubuntu10.04 前言:     在嵌入式开发中,只要是带操作系统的 ...

随机推荐

  1. 第一个spring,总结!

    陈志棚:界面跳转与框架 李天麟:游戏界面ui 徐侃:算法代码的设计 经过五天的时间,开会时候分配的任务,已经全部完成,在这期间中,我们遇到了一些问题.但是,经过android老师的指导后,app成功的 ...

  2. 04-java学习-选择结构

    if if else 多重if switch

  3. Beta阶段冲刺四

    Beta阶段冲刺四 Task1:团队TSP 团队任务 预估时间 实际时间 完成日期 新增其他学院的爬虫 180 130 11.30 新增其他学院的数据库字段修改 180 160 12.1 新增其他学院 ...

  4. Alpha冲刺第6天

    Alpha第六天 1.团队成员 郑西坤 031602542 (队长) 陈俊杰 031602504 陈顺兴 031602505 张胜男 031602540 廖钰萍 031602323 雷光游 03160 ...

  5. PHP的魔术方法

    PHP中把以两个下划线__开头的方法称为魔术方法(Magic methods) 魔术方法包括: __construct(),类的构造函数 __destruct(),类的析构函数 __call(),在对 ...

  6. asp、asp.net、.aspx、.ascx、.ashx的简单说明

    ASP是动态server页面(Active Server Page)的英文缩写.[1]是微软公司开发的取代CGI脚本程序的一种应用.它能够与数据库和其他程序进行交互,是一种简单.方便的编程工具.ASP ...

  7. Java超类-java.lang.object

    Java是面向对象的,Object是所有对象的超类(不是继承,也不是实现接口) Object类是所有Java类的祖先.每个类都使用 Object 作为超类.所有对象(包括数组)都实现这个类的方法. 如 ...

  8. 【刷题】BZOJ 4391 [Usaco2015 dec]High Card Low Card

    Description Bessie the cow is a huge fan of card games, which is quite surprising, given her lack of ...

  9. 洛谷P3960 列队(NOIP2017)(Splay)

    洛谷题目传送门 最弱的Splay...... 暴力模拟30分(NOIP2017实际得分,因为那时连Splay都不会)...... 发现只是一个点从序列里搬到了另一个位置,其它点的相对位置都没变,可以想 ...

  10. Nexus Repository Manager 3(CVE-2019-7238) 远程代码执行漏洞分析和复现

    0x00 漏洞背景 Nexus Repository Manager 3是一款软件仓库,可以用来存储和分发Maven,NuGET等软件源仓库.其3.14.0及之前版本中,存在一处基于OrientDB自 ...