linux内核环形缓冲区【转】
转自: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内核环形缓冲区【转】的更多相关文章
- Linux驱动开发10——内核环形双向链表
Linux内核环形双向链表本身不实现锁机制,需要驱动本身完成锁机制实现. 1.1.list_head结构体 #include <linux/list.h> struct list_head ...
- Linux内核结构体--kfifo 环状缓冲区
转载链接:http://blog.csdn.net/yusiguyuan/article/details/41985907 1.前言 最近项目中用到一个环形缓冲区(ring buffer),代码是由L ...
- Linux 内核:匠心独运之无锁环形队列kfifo
Linux 内核:匠心独运之无锁环形队列 Kernel version Linux 2.6.12 Author Toney Email vip_13031075266@163.com Da ...
- linux device driver —— 环形缓冲区的实现
还是没有接触到怎么控制硬件,但是在书里看到了一个挺巧妙的环形缓冲区实现. 此环形缓冲区实际为一个大小为bufsize的一维数组,有一个rp的读指针,一个wp的写指针. 在数据满时写进程会等待读进程读取 ...
- 用于阻止缓冲区溢出攻击的 Linux 内核参数与 gcc 编译选项
先来看看基于 Red Hat 与 Fedora 衍生版(例如 CentOS)系统用于阻止栈溢出攻击的内核参数,主要包含两项: kernel.exec-shield 可执行栈保护,字面含义比较“绕”, ...
- dmesg---检查和控制内核的环形缓冲区
dmesg命令被用于检查和控制内核的环形缓冲区.kernel会将开机信息存储在ring buffer中.您若是开机时来不及查看信息,可利用dmesg来查看.开机信息保存在/var/log/dmesg文 ...
- 环形缓冲区-模仿linux kfifo【转】
转自:https://blog.csdn.net/vertor11/article/details/53741681 struct kfifo{ uint8_t *buffer; uint32_t i ...
- linux网络编程--Circular Buffer(Ring Buffer) 环形缓冲区的设计与实现【转】
转自:https://blog.csdn.net/yusiguyuan/article/details/18368095 1. 应用场景 网络编程中有这样一种场景:需要应用程序代码一边从TCP/IP协 ...
- linux下C语言实现多线程通信—环形缓冲区,可用于生产者(producer)/消费者(consumer)【转】
转自:http://blog.chinaunix.net/uid-28458801-id-4262445.html 操作系统:ubuntu10.04 前言: 在嵌入式开发中,只要是带操作系统的 ...
随机推荐
- 派生类&简单工厂模式
派生类&简单工厂模式 git链接: Operation3.1.1 题目描述的代码部分的解释 首先是声明一个Rand类作为父类,然后两个子类RandNumber类和RandOperation类, ...
- jmeter 获取执行脚本的路径
需求:向jmeter.jmx 的路径下 写日志 : import org.apache.jmeter.services.FileServer; import com.bzj.utils.*; Stri ...
- Docker(八)-Docker创建Nginx容器
获取Nginx镜像 最简单的方法就是通过 docker pull nginx 命令来创建 Nginx容器. $ sudo docker pull nginx 或者: $ sudo docker pul ...
- 【设计模式】—— 职责链模式ChainOfResponsibility
前言:[模式总览]——————————by xingoo 模式意图 避免请求的发送者,和接受者过度的耦合在一起.一个请求者只需要发送一个请求即可,它的请求具体由后面哪个对象进行响应,并不需要关心.而请 ...
- pgm4
这部分 cover 两个比较特殊的情形,一个是 Gaussian networks,一个是 exponential family. 正态分布常见的参数化策略是均值 和协方差矩阵 ,另一种是使用 inf ...
- 修改MyEclipse取消默认工作空间
使用MyEclipse,在最开始Workspace Launcher中选择工作空间时,勾选了默认选择,以后启动程序的时候,就不会弹出这个选择工作空间的对话框了.如下图: 但后来又新增一个工作空间,需要 ...
- Effective Java -- 对于所有对象都通用的方法
覆盖equb时请遵循通用约定: 自反性.对于任何非null的引用值x,xequals(x)必须返回true. 对称性.对于任何非null的引用值x和y,当且晋档y.equals(x)返回true的时候 ...
- 解题:HAOI 2015 按位或
题面 Min-Max容斥:对于集合S $min(S)=\sum_{s∈S}(-1)^{|s|+1}max(s)$ $max(S)=\sum_{s∈S}(-1)^{|s|+1}min(s)$ 那么这个题 ...
- 洛谷P2469 星际竞速
上下界费用流比较无脑,提供一种更巧妙的费用流,无需上下界. #include <cstdio> #include <algorithm> #include <queue& ...
- 界面编程之QT的文件操作20180729
/*******************************************************************************************/ 一.QT文件 ...