【笔记】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 ...
随机推荐
- ping 不通。无法访问目标主机
台式机 使用无线网卡 又登录了VPN 有时候访问不了局域网内的主机 解决方案 添加路由即可 window+R 打开运行 输入cmd 然后输入 route add 10.16.1.89 10.13 ...
- QR 分解
将学习到什么 介绍了平面旋转矩阵,Householder 矩阵和 QR 分解以入相关性质. 预备知识 平面旋转与 Householder 矩阵是特殊的酉矩阵,它们在建立某些基本的矩阵分解过程中起着 ...
- spring源码学习之容器的基本实现
最近想拿出一部分时间来学习一下spring的源码,还特意买了一本书结合来看,当然主要是学习并跟着作者的思路来踏上学习spring的源码的道路,特意在此记录一下,<spring源码深度解析> ...
- Bootstrap历练实例:弹出提示信息的样式按钮
<!DOCTYPE html><html><head><meta http-equiv="Content-Type" content=&q ...
- shell脚本,计算学生分数的题目。
1.计算学生平均分数的值是多少? 2.计算每门课都大于80分的学生姓名.3.计算每门课都小于90分的学生姓名.
- java在线聊天项目0.6版 解决客户端关闭后异常问题 dis.readUTF()循环读取已关闭的socket
服务端对try catch finally重新进行了定义,当发生异常,主动提示,或关闭出现异常的socket 服务器端代码修改如下: package com.swift; import java.io ...
- 【搜索 技巧】Letter gaps
需要一定技巧的搜索题 题目描述 记得做过这样一道题 Ponder This Challenge: In the string CABACB, each letter appears exactly t ...
- Python基础:字典(dict)与集合(set)
查找场景下与列表的性能对比 字典与集合之所以高效的原因是:内部结构都是一张哈希表. 平均情况下插入.查找和删除的时间复杂度为 O(1). 假设有数量100,000的产品列表: import time ...
- Python中摘要算法MD5,SHA1讲解
摘要算法又称哈希算法.散列算法.它通过一个函数,把任意长度的数据转换为一个长度固定的数据串(通常用16进制的字符串表示).摘要算法就是通过摘要函数f()对任意长度的数据data计算出固定长度的摘要di ...
- DOM tiny-demo
<script type="text/javascript" language="javascript">var i = 4; function a ...