linux内核循环,循环缓冲区(参考linux内核Kfifo)
1 循环缓冲区在一些竞争问题上提供了一种免锁的机制,免锁的前提是,生产者和消费 2 都只有一个的情况下,否则也要加锁。下面就内核中提取出来,而经过修改后的fifo进 3 行简要的分析。 4 5 先看其只要数据结构: 6 struct my_fifo { 7 unsigned char *buffe
1循环缓冲区在一些竞争问题上提供了一种免锁的机制,免锁的前提是,生产者和消费
2都只有一个的情况下,否则也要加锁。下面就内核中提取出来,而经过修改后的fifo进
3行简要的分析。
4
5先看其只要数据结构:
6struct my_fifo {
7unsignedchar *buffer;/*the buffer holding the data*/
8unsignedint size;/*the size of the allocated buffer*/
9unsignedint in;/*data is added at offset (in % size)*/
10unsignedint out;/*data is extracted from off. (out
% size)*/
11};
12也不用多说,一看就明白。size, in, out 都设成无符号型的,因为都不存在负值的情
13型。
14
15/*
16form kernel/kfifo.c
17*/
18
19#include
20#include
21#include
22
23#define min(a,b) ((a) < (b) ? (a):(b))
24/*
25my_fifo_init
26*/
27struct my_fifo *my_fifo_init(unsignedchar *buffer,unsigned
int size)
28{
29struct my_fifo *fifo;
30
31
32fifo = malloc(sizeof(struct my_fifo));
33if (!fifo)
34returnNULL;
35
36fifo->buffer = buffer;
37fifo->size = size;
38fifo->in = fifo->out = 0;
39
40return fifo;
41}
42这个初始化fifo结构的函数一般也不会在应用层里进行调用,而是被下面的fifo_alloc
43调用。依我的观点来看,这两个函数合成一个函数会更加的清晰,但是这一情况只针对
buffer是系统开辟的空间,如果buffer的空间是由其它的函数来提供,就只能用上面的这个函数。
44/*
45my_fifo_alloc
46*/
47struct my_fifo *my_fifo_alloc(unsignedint size)
48{
49unsignedchar *buffer;
50struct my_fifo *ret;
51
52/*
53* round up to the next power of 2, since our 'let the indices
54* wrap' tachnique works only in this case.
55*/
56
57buffer = malloc(size);
58if (!buffer)
59returnNULL;
60
61ret = my_fifo_init(buffer, size);
62
63if (ret ==NULL)
64free(buffer);
65
66return ret;
67}
68/*
69* my_fifo_free
70*/
71void my_fifo_free(struct my_fifo *fifo)
72{
73free(fifo->buffer);
74free(fifo);
75}
76
77这两个函数也不作过多的分析,都很清晰。
78/*
79my_fifo_put()
80*/
81unsignedint my_fifo_put(struct my_fifo *fifo,
82unsignedchar *buffer,
unsigned int len)
83{
84unsignedint l;
85
86len = min(len, fifo->size - fifo->in + fifo->out);/*可能是缓冲区的空闲长度或者要写长度*/
87
88/*first put the data starting from fifo->in to buffer end*/
89l = min(len, fifo->size - (fifo->in & (fifo->size -1)));
90memcpy(fifo->buffer + (fifo->in & (fifo->size -1)), buffer, l);
91
92/*then put the rest (if any) at the beginning of the buffer*/
93memcpy(fifo->buffer, buffer + l, len - l);
94
95fifo->in += len;
96
97return len;
98}
99
100/*
101my_fifo_get
102*/
103unsignedint my_fifo_get(struct my_fifo *fifo,
104unsignedchar *buffer,
unsigned int len)
105{
106unsignedint l;
107
108len = min(len, fifo->in - fifo->out); /*可读数据*/
109
110/*first get the data from fifo->out until the end of the buffer*/
111l = min(len, fifo->size - (fifo->out & (fifo->size -1)));
112memcpy(buffer, fifo->buffer + (fifo->out & (fifo->size -1)), l);
113
114/*then get the rest (if any) from the beginning of the buffer*/
115memcpy(buffer + l, fifo->buffer, len - l);
116
117fifo->out += len;
118
119return len;
120}
121这两个读写结构才是循环缓冲区的重点。在fifo结构中,size是缓冲区的大小,是由用
122户自己定义的,但是在这个设计当中要求它的大小必须是2的幂次。
123当in==out时,表明缓冲区为空的,当(in-out)==size 时,说明缓冲区已满。
124
125我们看下具体实现,在86行处如果size-in+out ==0,也即获得的len值会0,而没有数
126据写入到缓冲区中。所以在设计缓冲区的大小的时候要恰当,读出的速度要比定入的速
127度要快,否则缓冲区满了会使数据丢失,可以通过成功写入的反回值来做判断尝试再次
128写入.
129另一种情况则是缓冲区有足够的空间给要写入的数据,但是试想一下,如果空闲的空间
130在缓冲的首尾两次,这又是如何实现呢?这部分代码实现得非常巧妙。
131我们看fifo->in &(fifo->size-1) 这个表达式是什么意思呢?我们知道size是2的幂次
132项,那么它减1即表示其值的二进制所有位都为1,与in相与的最终结果是in%size,比
133size要小,所以看in及out的值都是不断地增加,但再相与操作后,它们即是以size为
134周期的一个循环。89行就是比较要写入的数据应该是多少,如果缓冲区后面的还有足够
135的空间可写,那么把全部的值写到后面,否则写满后面,再写到前面去93行。
136读数据也可以作类似的分析,108行表示请求的数据要比缓冲区的数据要大时,只
137读取缓冲区中可用的数据。
138
139staticinline
void my_fifo_reset(struct my_fifo *fifo)
140{
141fifo->in = fifo->out = 0;
142}
143
144staticinline
unsigned int my_fifo_len(struct my_fifo *fifo)
145{
146return fifo->in - fifo->out;
147}
148
149在头文件里还有缓冲区置位及返回缓冲区中数据大小两个函数,很简单,不必解释。
linux内核循环,循环缓冲区(参考linux内核Kfifo)相关推荐
- linux没有可用的缓冲区空间,linux – 连接时“没有可用的缓冲区空间”
在3.6之前的内核中,您可能已经被ENOBUFS用于常规IPv4 / v6流量, 当net.ipv4.route.max_size或net.ipv6.route.max_size limit was ...
- linux 下查看应用版本信息,Linux下查看版本信息
Linux下如何查看版本信息, 包括位数.版本信息以及CPU内核信息.CPU具体型号等. 1.# uname -a (Linux查看版本当前操作系统内核信息) 2.# cat /proc/vers ...
- linux内核双向循环队列,读书笔记之linux内核设计与实现(2)进程调度
调度程序是内核的组成部分,它负责选择下一个要运行的进程.进程调度程序可看作在可运行态进程之间分配有限的处理器时间资源的内核子系统. 多任务操作系统就是能够同时并发的交互执行多个进程的操作系统.多任务系 ...
- linux 循环缓冲区 源码,Linux中的循环缓冲区
在学习到 并发和竞态 时,其中的提到了缓冲区,用于实现免锁算法,这里转载的是大神有关循环缓冲区做的一些操作. 其中源代码在最下面的附件中,有关作者的讲解感觉很清晰,很好,不过这里说一下自己的见解: 点 ...
- 怎么分析linux的内核程序,Linux内核分析(供参考)
Linux的内核源代码可以从很多途径得到,我一般常常去kernel.org看看.一般来讲,在安装的linux系统下,usr/src/linux目录下的东西就是内核源代码.源码的版本号有一个非常简单的编 ...
- 修改Linux内核的printk缓冲区(log缓冲区)大小
点击打开链接 我们可以用printk打印kernel的日志信息(即log信息),根据时间戳可以判断内核新打印的log会覆盖掉以前打印的log.原因是内核用环形缓冲区存放打印的log信息.那么如何增大缓 ...
- [奔跑吧 Linux内核][学习记录]编译内核-实验1-2-[环境以及参考]
1.下载的版本 VMware workstation player v16.2.4 Ubuntu v22.04.1 Linux kernel v5.19 2.参考的文章 环境安装 [干货]win10 ...
- linux 各用户内存_Linux用户空间与内核空间(理解高端内存)
Linux 操作系统和驱动程序运行在内核空间,应用程序运行在用户空间,两者不能简单地使用指针传递数据,因为Linux使用的虚拟内存机制,用户空间的数据可能被换出,当内核空间使用用户空间指针时,对应的数 ...
- linux内核中锁有哪些,Linux内核中有哪些锁
Linux内核中的各种锁 在LInux操作系统里,同一时间可能有多个内核执行流在执行,因此内核其实象多进程多线程编程一样也需要一些同步机制来同步各执行单元对共享数据的访问.尤其是在多处理器系统上,更需 ...
- Linux Malloc分析-从用户空间到内核空间
Linux Malloc分析-从用户空间到内核空间 本文介绍malloc的实现及其malloc在进行堆扩展操作,并分析了虚拟地址到物理地址是如何实现映射关系. ordeder原创,原文链接: http ...
最新文章
- 数据结构—什么叫满K叉树?
- 盘古分词-关键字搜索没有结果(关键字由未收录词组成)
- 【java】swing编写窗体
- elasticsearch.net search入门使用指南中文版(翻译)
- 自适应图片九宫格 css,高度自适应的九宫格效果
- 【优化求解】基于matlab遗传算法求解多城市多应急物流中心选址问题【含Matlab源码 1724期】
- linux的cd命名返回上级目录,返回根目录
- 奥运五环(一键复制)
- PHP动态网站开发期末试卷,《PHP动态网站开发实例教程》课程考核方案
- 分支-07. 比较大小(10)
- android ios通讯录权限设置,IOS 通讯录的访问和修改的实现
- asp.net905-二次元网站系统#毕业设计
- 【Python + selenium】在浏览器打开新页签,打开方式
- 黎曼流形学习的学习笔记(2):Neural Ordinary Differential Equations(来源:NIPS 2018 oral) (未完待续)
- 健身耳机哪个好、最好的健身耳机推荐
- 妥妥的去面试之数据结构与算法(一)
- 基于骨骼的动作识别:DD-Net
- java邮件模板_java创建邮件模板
- LPG绘画软件测试自学,排放测量(自学内容)
- softmax激活函数_深度学习中的激活函数,从softmax到sparsemax数学证明