📄 linux设备驱动程序学习(3)-并发和竞态 - linux设备驱动程序 - tekkaman ninja.htm
字号:
style="COLOR: rgb(255,153,0)">/* 等待completion
*/</SPAN><BR><SPAN
style="COLOR: rgb(0,0,255)">void</SPAN>
complete<SPAN
style="COLOR: rgb(0,0,204)">(</SPAN><SPAN
style="COLOR: rgb(0,0,255)">struct</SPAN>
completion <SPAN
style="COLOR: rgb(0,0,204)">*</SPAN>c<SPAN
style="COLOR: rgb(0,0,204)">)</SPAN><SPAN
style="COLOR: rgb(0,0,204)">;</SPAN><SPAN
style="COLOR: rgb(255,153,0)">/*唤醒一个等待completion的线程*/</SPAN><BR><SPAN
style="COLOR: rgb(0,0,255)">void</SPAN>
complete_all<SPAN
style="COLOR: rgb(0,0,204)">(</SPAN><SPAN
style="COLOR: rgb(0,0,255)">struct</SPAN>
completion <SPAN
style="COLOR: rgb(0,0,204)">*</SPAN>c<SPAN
style="COLOR: rgb(0,0,204)">)</SPAN><SPAN
style="COLOR: rgb(0,0,204)">;</SPAN><SPAN
style="COLOR: rgb(255,153,0)">/*唤醒所有等待completion的线程*/</SPAN><BR><BR><SPAN
style="COLOR: rgb(255,153,0)">/*如果未使用completion_all,completion可重复使用;否则必须使用以下函数重新初始化completion*/</SPAN><BR>INIT_COMPLETION<SPAN
style="COLOR: rgb(0,0,204)">(</SPAN><SPAN
style="COLOR: rgb(0,0,255)">struct</SPAN>
completion c<SPAN
style="COLOR: rgb(0,0,204)">)</SPAN><SPAN
style="COLOR: rgb(0,0,204)">;</SPAN><SPAN
style="COLOR: rgb(255,153,0)">/*快速重新初始化completion*/</SPAN></SPAN></CODE></P></TD></TR></TBODY></TABLE><BR></DIV>
<DIV> completion的典型应用是模块退出时的内核线程终止。在这种远行中,某些驱动程序的内部工作有一个内核线程在while(1)循环中完成。当内核准备清楚该模块时,exit函数会告诉该线程退出并等待completion。为此内核包含了用于这种线程的一个特殊函数:<BR>
<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: rgb(0,0,0)"><SPAN
style="COLOR: rgb(0,0,255)">void</SPAN>
complete_and_exit<SPAN
style="COLOR: rgb(0,0,204)">(</SPAN><SPAN
style="COLOR: rgb(0,0,255)">struct</SPAN>
completion <SPAN
style="COLOR: rgb(0,0,204)">*</SPAN>c<SPAN
style="COLOR: rgb(0,0,204)">,</SPAN> <SPAN
style="COLOR: rgb(0,0,255)">long</SPAN>
retval<SPAN
style="COLOR: rgb(0,0,204)">)</SPAN><SPAN
style="COLOR: rgb(0,0,204)">;</SPAN></SPAN></CODE></P></TD></TR></TBODY></TABLE><BR></DIV>
<DIV>
<HR id=null>
</DIV>
<DIV><FONT color=#0000ff
size=4><STRONG>三、自旋锁</STRONG></FONT></DIV>
<DIV><FONT color=#ff0000
size=4>其实上面介绍的几种信号量和互斥机制,其底层源码都是使用自旋锁,可以理解为自旋锁的再包装。</FONT>所以从这里就可以理解为什么自旋锁通常可以提供比信号量更高的性能。<BR>自旋锁是一个互斥设备,他只能会两个值:“锁定”和“解锁”。它通常实现为某个整数之中的单个位。<BR>“测试并设置”的操作必须以原子方式完成。<BR>任何时候,只要内核代码拥有自旋锁,在相关CPU上的抢占就会被禁止。</DIV>
<DIV><FONT
color=#0000ff>适用于自旋锁的核心规则:<BR>(1)任何拥有自旋锁的代码都必须使原子的,除服务中断外(某些情况下也不能放弃CPU,如中断服务也要获得自旋锁。为了避免这种锁陷阱,需要在拥有自旋锁时禁止中断),不能放弃CPU(如休眠,休眠可发生在许多无法预期的地方)。否则CPU将有可能永远自旋下去(死机)。<BR>(2)拥有自旋锁的时间越短越好。</FONT></DIV>
<DIV>自旋锁原语所需包含的文件是<linux/spinlock.h>
,以下是自旋锁的内核API:
<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: rgb(0,0,0)"><FONT
face=新宋体>spinlock_t my_lock <SPAN
style="COLOR: rgb(0,0,204)">=</SPAN>
SPIN_LOCK_UNLOCKED<SPAN
style="COLOR: rgb(0,0,204)">;</SPAN><SPAN
style="COLOR: rgb(255,153,0)">/*
编译时初始化spinlock*/</SPAN><BR><SPAN
style="COLOR: rgb(0,0,255)">void</SPAN>
spin_lock_init<SPAN
style="COLOR: rgb(0,0,204)">(</SPAN>spinlock_t
<SPAN
style="COLOR: rgb(0,0,204)">*</SPAN>lock<SPAN
style="COLOR: rgb(0,0,204)">)</SPAN><SPAN
style="COLOR: rgb(0,0,204)">;</SPAN><SPAN
style="COLOR: rgb(255,153,0)">/*
运行时初始化spinlock*/</SPAN><BR><BR><SPAN
style="COLOR: rgb(255,153,0)">/*
所有spinlock等待本质上是不可中断的,一旦调用spin_lock,在获得锁之前一直处于自旋状态*/</SPAN><BR><SPAN
style="COLOR: rgb(0,0,255)">void</SPAN>
spin_lock<SPAN
style="COLOR: rgb(0,0,204)">(</SPAN>spinlock_t
<SPAN
style="COLOR: rgb(0,0,204)">*</SPAN>lock<SPAN
style="COLOR: rgb(0,0,204)">)</SPAN><SPAN
style="COLOR: rgb(0,0,204)">;</SPAN><SPAN
style="COLOR: rgb(255,153,0)">/*
获得spinlock*/</SPAN><BR><SPAN
style="COLOR: rgb(0,0,255)">void</SPAN>
spin_lock_irqsave<SPAN
style="COLOR: rgb(0,0,204)">(</SPAN>spinlock_t
<SPAN
style="COLOR: rgb(0,0,204)">*</SPAN>lock<SPAN
style="COLOR: rgb(0,0,204)">,</SPAN> <SPAN
style="COLOR: rgb(0,0,255)">unsigned</SPAN>
<SPAN style="COLOR: rgb(0,0,255)">long</SPAN>
flags<SPAN
style="COLOR: rgb(0,0,204)">)</SPAN><SPAN
style="COLOR: rgb(0,0,204)">;</SPAN><SPAN
style="COLOR: rgb(255,153,0)">/*
获得spinlock,禁止本地cpu中断,保存中断标志于flags*/</SPAN><BR><SPAN
style="COLOR: rgb(0,0,255)">void</SPAN>
spin_lock_irq<SPAN
style="COLOR: rgb(0,0,204)">(</SPAN>spinlock_t
<SPAN
style="COLOR: rgb(0,0,204)">*</SPAN>lock<SPAN
style="COLOR: rgb(0,0,204)">)</SPAN><SPAN
style="COLOR: rgb(0,0,204)">;</SPAN><SPAN
style="COLOR: rgb(255,153,0)">/*
获得spinlock,禁止本地cpu中断*/</SPAN><BR><SPAN
style="COLOR: rgb(0,0,255)">void</SPAN>
spin_lock_bh<SPAN
style="COLOR: rgb(0,0,204)">(</SPAN>spinlock_t
<SPAN
style="COLOR: rgb(0,0,204)">*</SPAN>lock<SPAN
style="COLOR: rgb(0,0,204)">)</SPAN><SPAN
style="COLOR: rgb(255,153,0)">/*
获得spinlock,禁止软件中断,保持硬件中断打开*/</SPAN><BR><BR><SPAN
style="COLOR: rgb(255,153,0)">/*
以下是对应的锁释放函数*/</SPAN><BR><SPAN
style="COLOR: rgb(0,0,255)">void</SPAN>
spin_unlock<SPAN
style="COLOR: rgb(0,0,204)">(</SPAN>spinlock_t
<SPAN
style="COLOR: rgb(0,0,204)">*</SPAN>lock<SPAN
style="COLOR: rgb(0,0,204)">)</SPAN><SPAN
style="COLOR: rgb(0,0,204)">;</SPAN><BR><SPAN
style="COLOR: rgb(0,0,255)">void</SPAN>
spin_unlock_irqrestore<SPAN
style="COLOR: rgb(0,0,204)">(</SPAN>spinlock_t
<SPAN
style="COLOR: rgb(0,0,204)">*</SPAN>lock<SPAN
style="COLOR: rgb(0,0,204)">,</SPAN> <SPAN
style="COLOR: rgb(0,0,255)">unsigned</SPAN>
<SPAN style="COLOR: rgb(0,0,255)">long</SPAN>
flags<SPAN
style="COLOR: rgb(0,0,204)">)</SPAN><SPAN
style="COLOR: rgb(0,0,204)">;</SPAN><BR><SPAN
style="COLOR: rgb(0,0,255)">void</SPAN>
spin_unlock_irq<SPAN
style="COLOR: rgb(0,0,204)">(</SPAN>spinlock_t
<SPAN
style="COLOR: rgb(0,0,204)">*</SPAN>lock<SPAN
style="COLOR: rgb(0,0,204)">)</SPAN><SPAN
style="COLOR: rgb(0,0,204)">;</SPAN><BR><SPAN
style="COLOR: rgb(0,0,255)">void</SPAN>
spin_unlock_bh<SPAN
style="COLOR: rgb(0,0,204)">(</SPAN>spinlock_t
<SPAN
style="COLOR: rgb(0,0,204)">*</SPAN>lock<SPAN
style="COLOR: rgb(0,0,204)">)</SPAN><SPAN
style="COLOR: rgb(0,0,204)">;</SPAN><BR><BR><SPAN
style="COLOR: rgb(255,153,0)">/*
以下非阻塞自旋锁函数,成功获得,返回非零值;否则返回零*/</SPAN><BR><SPAN
style="COLOR: rgb(0,0,255)">int</SPAN>
spin_trylock<SPAN
style="COLOR: rgb(0,0,204)">(</SPAN>spinlock_t
<SPAN
style="COLOR: rgb(0,0,204)">*</SPAN>lock<SPAN
style="COLOR: rgb(0,0,204)">)</SPAN><SPAN
style="COLOR: rgb(0,0,204)">;</SPAN><BR><SPAN
style="COLOR: rgb(0,0,255)">int</SPAN>
spin_trylock_bh<SPAN
style="COLOR: rgb(0,0,204)">(</SPAN>spinlock_t
<SPAN
style="COLOR: rgb(0,0,204)">*</SPAN>lock<SPAN
style="COLOR: rgb(0,0,204)">)</SPAN><SPAN
style="COLOR: rgb(0,0,204)">;</SPAN></FONT></SPAN></CODE></P>
<P
style="MARGIN: 5px; LINE-HEIGHT: 150%"><CODE><SPAN
style="COLOR: rgb(0,0,0)"><FONT face=新宋体><SPAN
style="COLOR: rgb(0,0,204)"></SPAN><BR><SPAN
style="COLOR: rgb(255,153,0)">/*新内核的<linux/spinlock.h>包含了更多函数*/</SPAN></FONT></SPAN></CODE><CODE><SPAN
style="COLOR: rgb(0,0,0)"></SPAN></CODE></P></TD></TR></TBODY></TABLE></DIV>
<DIV> </DIV>
<DIV><FONT face=新宋体 color=#0000ff size=4>读取者<SPAN
st
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -