【笔记】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 ...
随机推荐
- Google Colab的一些注意事项
1.执行命令行前面加! 当我们使用python解释器时,我们需要不停地在命令行和IDE 之间切换,当我们需要使用命令行工具时.不过,Jupyter Notebook给了我们在notebook中运行sh ...
- mysql利用binlog恢复数据详细例子
模拟数据恢复的案例 有些时候脑瓜就会短路,难免会出错 场景:在生产环境中,我们搭建了mysql主从,备份操作都是在从备份数据库上 前提:有最近一天或者最近的全备 或者最近一天相关数据库的备份 最重要的 ...
- iphone在jsp显示时间会NAN解决办法
例:2018-12-28 15:00:00 1. var newDate = new Date("2018-12-28 15:00:00") 这种获取的时间在安卓手机上显示是 ...
- Gersgorin 圆盘
将学习到什么 好多. Gersgorin 圆盘定理 对任何 \(A \in M_n\),我们总可以记 \(A=D+B\),其中 \(D=\mathrm{diag}(a_{11},\cdots, ...
- Codeforces Round #275(Div. 2)-C. Diverse Permutation
http://codeforces.com/contest/483/problem/C C. Diverse Permutation time limit per test 1 second memo ...
- 洛谷 P3958 奶酪
谨以此题来纪念我爆炸的NOIp2017 这个题虽然很多人说是并查集,但是搜索也是毫无压力的,考场搜索细节写挂,爆了个不上不下的80分.今天无意看到这道题,终于AC 首先这道题要考虑一下精度问题,虽然出 ...
- ios之UIPopoverController
UIPopoverController是iPad上的iOS开发会常用到的一个组件(在iPhone设备上不允许使用),这个组件上手很简单,因为他的显示方法很少,而且参数简单,但我在使用过程中还常碰到各种 ...
- 更新portage之后 安装 certbot
运行的时候一直报如下的错误: sudo certbot 错误结果: Traceback (most recent call last): File "/usr/lib/python-exec ...
- noip_最后一遍_3-数据结构
noip基础数据结构太多了又太捞了 所以也就那么几个了 单调队列滑动窗口 #include<bits/stdc++.h> using namespace std; #define maxn ...
- python的web框架---Django项目
Django项目之会议室预预订: 界面效果展示: 1.创建超级管理员,实现预定界面功能 2.预定界面: (一)基于pymysql设计数据表结构,理清前后端与用户交互逻辑.(用户表,会议室表,预定内容存 ...