转自: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. [windows]转帖 windows 版本的含义

    1.N是None的意思,由于欧洲反垄断法不让系统捆绑浏览器ie和播放器.LTSB全称为Long Term Support Branch,意思为长期支持分支,是给Windows 10企业用户的一个更新选 ...

  2. ThinkPHP从零开始(一)安装和配置

    序: 对PHP一无所知的我,将从这里从零开始. 1.下载与安装 ThinkPHP的下载: ThinkPHP中文站下载页面 有 核心版和完整版两种,由于不了解.所以我选择了完整版.    WampSer ...

  3. 本地安装apk后直接打开,按下Home键再重新打开,然后按下返回键时页面展示错误的处理方法

    情景: 1.下载apk到手机本地,点击本地apk开始安装 2.安装完成后,一般会有 “完成” 和 “打开” 两个按钮,点击 “完成” 按钮时是没有问题的,不管它 3.点击 “打开” 按钮,进入到首页( ...

  4. sqlserver2017安装及连接过程中发现的问题

    1.SSMS安装报错,如下图 根据搜索资料发现是防火墙的问题,关闭防火墙就行了. 2.连接用户时报错 这个是因为远程连接相关问题. 首先打开服务器远程连接: 其次点击: SqlServer配置管理器- ...

  5. Vue入门---事件与方法详解

    一. vue方法实现 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> &l ...

  6. requestMapping设置客户端访问地址

  7. IDEA 调试技巧

    转载:http://blog.csdn.net/victor_cindy1/article/details/52336983 1.这里以一个web工程为例,点击图中按钮开始运行web工程. 2.设置断 ...

  8. R vs Python,数据分析中谁与争锋?

    R和Python两者谁更适合数据分析领域?在某些特定情况下谁会更有优势?还是一个天生在各方面都比另一个更好? 当我们想要选择一种编程语言进行数据分析时,相信大多数人都会想到R和Python——但是从这 ...

  9. 【BZOJ4870】组合数问题(动态规划,矩阵快速幂)

    [BZOJ4870]组合数问题(动态规划,矩阵快速幂) 题面 BZOJ 洛谷 题解 显然直接算是没法做的.但是要求的东西的和就是从\(nk\)个物品中选出模\(k\)意义下恰好\(r\)个物品的方案数 ...

  10. CAP定理为什么只能同时满足两个

    Consistency(一致性), 数据一致更新,所有数据变动都是同步的 Availability(可用性), 好的响应性能 Partition tolerance(分区容忍性) 可靠性 在网上看了很 ...