📄 linux设备驱动程序学习(3-补)-linux中的循环缓冲区 - linux设备驱动程序 - tekkaman ninja.htm
字号:
face="Times New Roman, serif"><FONT
face="SimSun, serif"><SPAN
lang=en-US>kfifo_init</SPAN></FONT></FONT>只会接受一个已分配好空间的<FONT
face="Times New Roman, serif"><FONT
face="SimSun, serif"><SPAN
lang=en-US>fifo->buffer</SPAN></FONT></FONT>,不能和<FONT
face="Times New Roman, serif"><FONT
face="SimSun, serif"><SPAN
lang=en-US>kfifo_free</SPAN></FONT></FONT>搭配,用<FONT
face="Times New Roman, serif"><FONT
face="SimSun, serif"><SPAN
lang=en-US>kfifo_init</SPAN></FONT></FONT>分配的<FONT
face="Times New Roman, serif"><FONT
face="SimSun, serif"><SPAN
lang=en-US>kfifo</SPAN></FONT></FONT>只能用<FONT
face="Times New Roman, serif"><FONT
face="SimSun, serif"><SPAN
lang=en-US>kfree</SPAN></FONT></FONT>释放。”
</FONT><FONT color=#ff0000>阅读源码可以得出这样的结论:<FONT
face=宋体><SPAN lang=en-US>kfifo_init和<FONT
face=新宋体>kfifo_alloc分配的<SPAN lang=en-US><FONT
face=宋体>kfifo都</FONT></SPAN><FONT
face="Courier New">能用</FONT><FONT
face="Times New Roman, serif"><FONT
face="SimSun, serif"><SPAN
lang=en-US>kfree</SPAN></FONT></FONT><FONT
face="Courier New">释放。已经用实验证实。</FONT></FONT></SPAN></FONT></FONT></DIV>
<DIV><FONT color=#000000><SPAN lang=en-US>原文链接地址:
<FONT face="Times New Roman, serif"><A
href="http://www.kerneltravel.net/jiaoliu/kern-kfifo.html">http://www.kerneltravel.net/jiaoliu/kern-kfifo.html</A></FONT></SPAN></FONT></DIV>
<DIV>
<HR id=null>
</DIV>
<DIV>在学习到<FONT color=#0000ff>第十章 中断处理</FONT>
时,其中的中断驱动的I/O需要使用缓冲区,我觉得与其自己实现一个缓冲区,不如利用内核已经写好的fifo。内核里有一个通用的循环缓冲区的实现在
<FONT
color=#0000ff><linux/kfifo.h>。</FONT></DIV>
<DIV><FONT
color=#0000ff><STRONG>使用的数据结构如下:</STRONG></FONT></DIV>
<TABLE style="BORDER-COLLAPSE: collapse"
borderColor=#999999 cellSpacing=0 cellPadding=0
width="95%" bgColor=#f1f1f1 border=1>
<TBODY>
<TR>
<TD>
<P
style="MARGIN: 5px; LINE-HEIGHT: 150%"><CODE><SPAN
style="COLOR: #000000"><SPAN
style="COLOR: #0000ff">struct</SPAN> kfifo <SPAN
style="COLOR: #0000cc">{</SPAN><BR> <SPAN
style="COLOR: #0000ff">unsigned</SPAN> <SPAN
style="COLOR: #0000ff">char</SPAN> <SPAN
style="COLOR: #0000cc">*</SPAN>buffer<SPAN
style="COLOR: #0000cc">;</SPAN> <SPAN
style="COLOR: #ff9900">/* 使用的缓冲区头指针
*/</SPAN><BR> <SPAN
style="COLOR: #0000ff">unsigned</SPAN> <SPAN
style="COLOR: #0000ff">int</SPAN> size<SPAN
style="COLOR: #0000cc">;</SPAN> <SPAN
style="COLOR: #ff9900">/* 缓冲区总大小
*/</SPAN><BR> <SPAN
style="COLOR: #0000ff">unsigned</SPAN> <SPAN
style="COLOR: #0000ff">int</SPAN> in<SPAN
style="COLOR: #0000cc">;</SPAN> <SPAN
style="COLOR: #ff9900">/*
已写入缓冲区的数据总量,当前缓冲区写指针的偏移量:(in % size)
*/</SPAN><BR> <SPAN
style="COLOR: #0000ff">unsigned</SPAN> <SPAN
style="COLOR: #0000ff">int</SPAN> out<SPAN
style="COLOR: #0000cc">;</SPAN> <SPAN
style="COLOR: #ff9900">/*
已读出缓冲区的数据总量,当前缓冲区读指针的偏移量:(out % size)
*/</SPAN><BR> spinlock_t
<SPAN style="COLOR: #0000cc">*</SPAN>lock<SPAN
style="COLOR: #0000cc">;</SPAN> <SPAN
style="COLOR: #ff9900">/* 为避免竞态的自旋锁
*/</SPAN><BR><SPAN
style="COLOR: #0000cc">}</SPAN><SPAN
style="COLOR: #0000cc">;</SPAN><SPAN
style="COLOR: #ff9900">/*当in==out时,缓冲区为空;当(in-out)==size时,缓冲区已满*/</SPAN></SPAN></CODE></P></TD></TR></TBODY></TABLE>
<P><FONT face="Times New Roman, serif"><FONT
face="SimSun, serif"><SPAN
lang=en-US>kfifo</SPAN></FONT></FONT>提供的循环缓冲的部分函数分为2类:</P>
<P>(1)以双下划线开头,没有使用自旋锁函数;</P>
<P>(2)没有双下划线开头,需要额外加锁的情况下使用的函数。</P>
<P>其实第二类只是在第一类的基础上进行加锁后,实际的代码如下:
<TABLE style="BORDER-COLLAPSE: collapse"
borderColor=#999999 cellSpacing=0 cellPadding=0
width="95%" bgColor=#f1f1f1 border=1>
<TBODY>
<TR>
<TD>
<P
style="MARGIN: 5px; LINE-HEIGHT: 150%"><CODE><SPAN
style="COLOR: #000000"><FONT
face=新宋体> <SPAN
style="COLOR: #0000ff">unsigned</SPAN> <SPAN
style="COLOR: #0000ff">long</SPAN> flags<SPAN
style="COLOR: #0000cc">;</SPAN><BR> spin_lock_irqsave<SPAN
style="COLOR: #0000cc">(</SPAN>fifo<SPAN
style="COLOR: #0000cc">-</SPAN><SPAN
style="COLOR: #0000cc">></SPAN>lock<SPAN
style="COLOR: #0000cc">,</SPAN> flags<SPAN
style="COLOR: #0000cc">)</SPAN><SPAN
style="COLOR: #0000cc">;</SPAN><BR> <SPAN
style="COLOR: #ff9900">/*第一类函数*/</SPAN><BR> spin_unlock_irqrestore<SPAN
style="COLOR: #0000cc">(</SPAN>fifo<SPAN
style="COLOR: #0000cc">-</SPAN><SPAN
style="COLOR: #0000cc">></SPAN>lock<SPAN
style="COLOR: #0000cc">,</SPAN> flags<SPAN
style="COLOR: #0000cc">)</SPAN><SPAN
style="COLOR: #0000cc">;</SPAN></FONT></SPAN></CODE></P></TD></TR></TBODY></TABLE></P>
<P>以下我按使用的顺序介绍每个函数的使用,部分函数源码在<FONT
face="Times New Roman, serif"><FONT
face="SimSun, serif"><SPAN
lang=en-US>kernel/kfifo.c</SPAN></FONT></FONT>中定义,这些接口是经过精心构造的,可以小心地避免一些边界情况,原理其实很简单,建议去看源码弄清楚实现的原理,可以学到一些编程技巧。</P>
<P>(0)声明循环缓冲数据结构<FONT color=#ff0000>指针</FONT>
<TABLE style="BORDER-COLLAPSE: collapse"
borderColor=#999999 cellSpacing=0 cellPadding=0
width="95%" bgColor=#f1f1f1 border=1>
<TBODY>
<TR>
<TD>
<P
style="MARGIN: 5px; LINE-HEIGHT: 150%"><CODE><SPAN
style="COLOR: #000000"><FONT face=新宋体><SPAN
style="COLOR: #0000ff">struct</SPAN> kfifo
*tekkamanfifo<SPAN
style="COLOR: #0000cc">;</SPAN></FONT></SPAN></CODE></P></TD></TR></TBODY></TABLE></P>
<P>(1)初始化循环缓冲结构体
<TABLE style="BORDER-COLLAPSE: collapse"
borderColor=#999999 cellSpacing=0 cellPadding=0
width="95%" bgColor=#f1f1f1 border=1>
<TBODY>
<TR>
<TD>
<P
style="MARGIN: 5px; LINE-HEIGHT: 150%"><CODE><SPAN
style="COLOR: #000000"><FONT face=新宋体><SPAN
style="COLOR: #0000ff">struct</SPAN> kfifo <SPAN
style="COLOR: #0000cc">*</SPAN>kfifo_init<SPAN
style="COLOR: #0000cc">(</SPAN><SPAN
style="COLOR: #0000ff">unsigned</SPAN> <SPAN
style="COLOR: #0000ff">char</SPAN> <SPAN
style="COLOR: #0000cc">*</SPAN>buffer<SPAN
style="COLOR: #0000cc">,</SPAN> <SPAN
style="COLOR: #0000ff">unsigned</SPAN> <SPAN
style="COLOR: #0000ff">int</SPAN> size<SPAN
style="COLOR: #0000cc">,</SPAN><BR> gfp_t
gfp_mask<SPAN style="COLOR: #0000cc">,</SPAN>
spinlock_t <SPAN
style="COLOR: #0000cc">*</SPAN>lock<SPAN
style="COLOR: #0000cc">)</SPAN><SPAN
style="COLOR: #0000cc">;</SPAN><BR><SPAN
style="COLOR: #ff9900">/*调用kfifo_init必须保证size是2的整数次幂,而且<FONT
color=#000000>buffer</FONT>只接受一个已分配好空间的指针。也就是说之前要使用kmalloc分配好空间,将返回的指针传递到buffer*/</SPAN><BR><SPAN
style="COLOR: #0000ff">struct</SPAN> kfifo <SPAN
style="COLOR: #0000cc">*</SPAN>kfifo_alloc<SPAN
style="COLOR: #0000cc">(</SPAN><SPAN
style="COLOR: #0000ff">unsigned</SPAN> <SPAN
style="COLOR: #0000ff">int</SPAN> size<SPAN
style="COLOR: #0000cc">,</SPAN> gfp_t
gfp_mask<SPAN
style="COLOR: #0000cc">,</SPAN><BR>
spinlock_t <SPAN
style="COLOR: #0000cc">*</SPAN>lock<SPAN
style="COLOR: #0000cc">)</SPAN><SPAN
style="COLOR: #0000cc">;</SPAN><BR><SPAN
style="COLOR: #ff9900">/*调用kfifo_alloc不必保证size是2的幂,它内部会把size向上调整到2的整数次幂。空间分配的内部实现使用kmalloc。函数内部调用kfifo_init/</SPAN></FONT></SPAN></CODE></P></TD></TR></TBODY></TABLE></P>
<P><FONT
face=新宋体>buffer:之前要使用kmalloc分配好的空间指针;</FONT></P>
<P><FONT face=新宋体>size:循环缓冲空间大小;</FONT></P>
<P><FONT
face=新宋体>gfp_mask:和kmalloc使用的分配标志(flags)一样。(参阅<A
title=Linux设备驱动程序学习(8)-分配内存
href="http://blog.chinaunix.net/u1/34474/showart.php?id=428673"
target=_blank><FONT
color=#800080>Linux设备驱动程序学习(8)-分配内存</FONT></A>)</FONT></P>
<P><FONT face=新宋体>lock:是<FONT
color=#ff0000>事先声明并初始化好的</FONT>自旋锁结构体指针;</FONT></P>
<P><FONT face=新宋体><FONT color=#0000ff>返回值</FONT>
为初始化好的</FONT><FONT face="Courier New">循环缓冲数据结构指针
。</FONT></P>
<P><FONT face=新宋体>(2) 向缓冲区里写入数据</FONT>
<TABLE style="BORDER-COLLAPSE: collapse"
borderColor=#999999 cellSpacing=0 cellPadding=0
width="95%" bgColor=#f1f1f1 border=1>
<TBODY>
<TR>
<TD>
<P
style="MARGIN: 5px; LINE-HEIGHT: 150%"><CODE><SPAN
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -