【笔记】Linux内核中的循环缓冲区
1. 有关ring buffer的理解
1) ring buffer位首尾相接的buffer,即类似生活中的圆形跑道;
2) 空闲空间+数据空间=ring buffer大小
3) ring buffer的读写,类似生活中在圆形跑道上的追赶游戏,领跑者位write,追赶着为read
4) 如果read跑的太快,追上write,追赶者read要停下来,否则游戏结束。即保证没有数据空间时,不再从ring buffer中读取数据;
5) 如果write跑的太快,反过来套圈要超过read,此时领跑者write也要停下来。即保证没有空闲空间时,不再往ring buffer中写入数据;
6) 所以,read和write之间的距离总是介于开区间(0, buffer大小)
2. linux2.6内核,kfifo的理解
假设buffer的大小为size,读指针为in,写指针为out
1) 在计算机中,整型数据加到最大值后溢出会回卷到0,从头开始)
2)buffer的长度必须是2的n次幂
3) buffer空闲空间和数据空间的大小
1> 空闲空间的大小=size-in+out
2> 空闲空间的大小=in-out
2.2 对数据空间大小计算的理解
本设计总能保证in前out前面的,in跑出unsigned int边界溢出后回卷。
因为buffer的大小是2的n次幂,而unsigned int也是2的n次幂(32位机器上,n=32),一般buffer大小不会超过unsigned int大小,即unsigned int被分成m个整块(m>=1)
空闲空间=size-数据控件=size-(in-out)=size-in+out
第2种情况:(in跑到unsigned int的边界后,溢出了)
out+数据空间=in,这个等式仍然成立。
所以:空闲空间=size-in+out,亦成立
2.3 写操作分析(读操作类似,不再赘述)

2.3.1 基本情况
设落在ring buffer内写指针为__in,读指针为__out,需要写入的空间大小为len, 其中
1. __in = fifo->in % (fifo->size - 1) (读写指针都是从0开始算起)
2. __out = fifo->out % (fifo->size - 1)
3. __size = fifo->size
4. len <= 空闲空间大小
2.3.2 写指针没有回卷
这种情况下,需要写两块buffer,做两次拷贝动作,设需要写入的大小为len,第一块空闲空间大小为left1,第二块为left2,需要第一次拷贝的大小为len1,第二次拷贝的大小为len2,len1 + len2 = len:
1. left1 = _size-__in;
2. len1 = min(len, left1) = min(len, _size-__in);
3. left2 = __out;
4. len2 = len - len1
2.3.3 写指针回卷
这种情况下,需要写一块buffer,做一次拷贝动作:
1. left1 = __out - __in <= __size - __in;
2. 而写入长度len <= 空闲空间大小,所以len <= left1 <= __size - __in,所以len1 = len, len1 = min(len, __size - __in)仍然成立
3. left2 = 0;
4. len2 = 0 = len -len1
2.3.4 两种特殊情况一般化
总结以上两种情形,第一块空闲空间大小为left1,第二块为left2,需要第一次拷贝的大小为len1,第二次拷贝的大小为len2,len1 + len2 = len,则通用情况如下:
1. len <= 空闲空间大小
2. len1 = min(len, _size-__in);
3. len2 = len -len1
附:linux2.6内核,kfifo的实现代码
点击(此处)折叠或打开
- unsigned int __kfifo_put(struct kfifo *fifo,
- unsigned char *buffer, unsigned int len)
- {
- unsigned int l;
- len = min(len, fifo->size - fifo->in + fifo->out);
- /* 前提条件写入大小len不超过空闲空间大小 */
- smp_mb();
- /* 第一块写入空闲空间,大小为min(len, size-in) */
- l = min(len, fifo->size - (fifo->in & (fifo->size - 1)));
- memcpy(fifo->buffer + (fifo->in & (fifo->size - 1)), buffer, l);
- /* 第二块写入空闲空间,大小为len-min(len, size-in) */
- memcpy(fifo->buffer, buffer + l, len - l);
- /*
- * Ensure that we add the bytes to the kfifo -before-
- * we update the fifo->in index.
- */
- smp_wmb();
- fifo->in += len;
- return len;
- }
- unsigned int __kfifo_get(struct kfifo *fifo,
- unsigned char *buffer, unsigned int len)
- {
- unsigned int l;
- len = min(len, fifo->in - fifo->out);
- /*
- * Ensure that we sample the fifo->in index -before- we
- * start removing bytes from the kfifo.
- */
- smp_rmb();
- /* 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);
- /*
- * Ensure that we remove the bytes from the kfifo -before-
- * we update the fifo->out index.
- */
- smp_mb();
- fifo->out += len;
- return len;
- }
【笔记】Linux内核中的循环缓冲区的更多相关文章
- (笔记)Linux内核中内存相关的操作函数
linux内核中内存相关的操作函数 1.kmalloc()/kfree() static __always_inline void *kmalloc(size_t size, gfp_t flags) ...
- (笔记)Linux内核中ioremap映射的透彻理解
几乎每一种外设都是通过读写设备上的寄存器来进行的,通常包括控制寄存器.状态寄存器和数据寄存器三大类,外设的寄存器通常被连续地编址.根据CPU体系结构的不同,CPU对IO端口的编址方式有两种: (1)I ...
- Linux内核中流量控制
linux内核中提供了流量控制的相关处理功能,相关代码在net/sched目录下:而应用层上的控制是通过iproute2软件包中的tc来实现, tc和sched的关系就好象iptables和netfi ...
- Linux内核中内存cache的实现【转】
Linux内核中内存cache的实现 转自:http://blog.chinaunix.net/uid-127037-id-2919545.html 本文档的Copyleft归yfydz所有,使用 ...
- TCP/IP协议栈在Linux内核中的运行时序分析
网络程序设计调研报告 TCP/IP协议栈在Linux内核中的运行时序分析 姓名:柴浩宇 学号:SA20225105 班级:软设1班 2021年1月 调研要求 在深入理解Linux内核任务调度(中断处理 ...
- 【转】在linux内核中读写文件 -- 不错
原文网址:http://blog.csdn.net/tommy_wxie/article/details/8194276 1. 序曲 在用户态,读写文件可以通过read和write这两个系统调用来完成 ...
- Linux内核中常见内存分配函数(一)
linux内核中采 用了一种同时适用于32位和64位系统的内存分页模型,对于32位系统来说,两级页表足够用了,而在x86_64系 统中,用到了四级页表. * 页全局目录(Page Global Dir ...
- Linux内核中的list用法和实现分析
这些天在思考知识体系的完整性,发现总是对消息队列的实现不满意,索性看看内核里面的链表实现形式,这篇文章就当做是学习的i笔记吧.. 内核代码中有很多的地方使用了list,而这个list的用法又跟我们平时 ...
- Linux内核中链表实现
关于双链表实现,一般教科书上定义一个双向链表节点的方法如下: struct list_node{ stuct list_node *pre; stuct list_node *next; ElemTy ...
随机推荐
- docker安装Tensorflow并使用jupyter notebook
目前网上提供的大多数的方法都是如下: docker pull tensorflow/tensorflow docker run -it -p : tensorflow/tensorflow 但是按照步 ...
- RMQ求区间最大最小值
#include<iostream> #include<cmath> #include<cstdio> #define N 50005 using namespac ...
- MFC:AfxParseURL
BOOL AFXAPI AfxParseURL( LPCTSTR pstrURL, DWORD& dwServiceType, CString& strServ ...
- Codeforces Round #277.5 (Div. 2)-B. BerSU Ball
http://codeforces.com/problemset/problem/489/B B. BerSU Ball time limit per test 1 second memory lim ...
- 题解 P1189 SEARCH
(传送门)[https://www.luogu.org/problemnew/show/P1189] 先反省一波:我以后再也不用getchar()+scanf了(日常爆零) 算是比较裸的搜索吧,在下用 ...
- shell脚本,如何破解字符串对应的md5sum前的RANDOM对应数字?
已知下面的字符串是通过RANDOM随机数变量md5sum|cut-c 1-8截取后的结果,请破解这些字符串对应的md5sum前的RANDOM对应数字?[root@localhost md5]# cat ...
- postgresql+pgadmin3安装
检查5432端口是否被占用,如果占用则释放 1.运行postgresql-9.3.1.xxx.run 安装好postgresql和pgadmin III 2.创建数据库目录和日志目录 [roo ...
- js事件(事件冒泡与事件捕获)
事件冒泡和事件捕获分别由微软和网景公司提出,这两个概念都是为了解决页面中事件流(事件发生顺序)的问题. <div id='aa' click='po'> <p id='bb' cli ...
- JavaScript设计模式基础之闭包(终)
对于前端程序员来说闭包还是比较难以理解的, 闭包的形成与变量的作用域以及变量的生产周期密切相关,所以要先弄懂变量的作用域和生存周期. 1.变量作用域 变量的作用域,就是指变量的有效范围,通常我们指的作 ...
- C\C++对于字符串输入处理
1.scanf scanf以%s格式符读入字符串,会以空格为结束,也就是无法将空格读入.如果换成%c就可以读入,但是无法一次性读入一整行字符. 2.fgets 显然,fgets是一个读取带空格字符串的 ...
