📄 linux设备驱动程序学习(5)-高级字符驱动程序操作[(2)阻塞型i-o和休眠] - linux设备驱动程序 - tekkaman ninja.htm
字号:
color=#0000ff>如果驱动程序无法立即满足请求,该如何响应?(65865346)</FONT></P>
<P align=center>
<HR id=null>
<P></P>
<P align=left><FONT color=#0000ff
size=5><STRONG>一、休眠</STRONG></FONT></P>
<P>进程被置为休眠,意味着它被标识为处于一个特殊的状态并且从调度器的运行队列中移走。这个进程将不被在任何
CPU 上调度,即将不会运行。 直到发生某些事情改变了那个状态。安全地进入休眠的两条规则:</P>
<P>(1) 永远不要在原子上下文中进入休眠,即<FONT
color=#0000ff>当驱动在持有一个自旋锁、seqlock或者 RCU
锁时不能睡眠;关闭中断也不能睡眠。</FONT>持有一个信号量时休眠是合法的,但你应当仔细查看代码:如果代码在持有一个信号量时睡眠,任何其他的等待这个信号量的线程也会休眠。因此发生在持有信号量时的休眠必须短暂,而且决不能阻塞那个将最终唤醒你的进程。</P>
<P>(2)当进程被唤醒,它并不知道休眠了多长时间以及休眠时发生什么;也不知道是否另有进程也在休眠等待同一事件,且那个进程可能在它之前醒来并获取了所等待的资源。所以不能对唤醒后的系统状态做任何的假设,并<FONT
color=#ff0000>必须重新检查等待条件来确保正确的响应</FONT>。</P>
<P><FONT
size=3>除非确信其他进程会在其他地方唤醒休眠的进程,否则也不能睡眠。使进程可被找到意味着:需要维护一个称为等待队列的数据结构。它是一个进程链表,其中饱含了等待某个特定事件的所有进程。在
Linux 中, 一个等待队列由一个wait_queue_head_t
结构体来管理,其定义在<FONT
color=#0000ff><linux/wait.h></FONT>中。</FONT>wait_queue_head_t
类型的数据结构非常简单: </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: rgb(0,0,0)"><FONT face=新宋体><SPAN
style="COLOR: rgb(0,0,255)">struct</SPAN>
__wait_queue_head <SPAN
style="COLOR: rgb(0,0,204)">{</SPAN><BR> spinlock_t
lock<SPAN
style="COLOR: rgb(0,0,204)">;</SPAN><BR> <SPAN
style="COLOR: rgb(0,0,255)">struct</SPAN>
list_head task_list<SPAN
style="COLOR: rgb(0,0,204)">;</SPAN><BR><SPAN
style="COLOR: rgb(0,0,204)">}</SPAN><SPAN
style="COLOR: rgb(0,0,204)">;</SPAN><BR><SPAN
style="COLOR: rgb(0,0,255)">typedef</SPAN> <SPAN
style="COLOR: rgb(0,0,255)">struct</SPAN>
__wait_queue_head wait_queue_head_t<SPAN
style="COLOR: rgb(0,0,204)">;</SPAN></FONT></SPAN></CODE></P></TD></TR></TBODY></TABLE></P>
<P>它包含一个自旋锁和一个链表。这个链表是一个等待队列入口,它被声明做
wait_queue_t。wait_queue_head_t包含关于睡眠进程的信息和它想怎样被唤醒。
</P>
<P>
<HR id=null>
<P></P>
<P></P>
<P></P>
<P><FONT color=#0000ff
size=4><STRONG>简单休眠(其实是高级休眠的宏)</STRONG></FONT></P>
<P><FONT size=4>Linux 内核中最简单的休眠方式是称为
wait_event的宏</FONT><FONT
size=4>(及其变种),它实现了休眠和进程等待的条件的检查。形式如下:</FONT></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: rgb(0,0,0)">wait_event<SPAN
style="COLOR: rgb(0,0,204)">(</SPAN><SPAN
style="COLOR: rgb(255,0,0)">queue</SPAN><SPAN
style="COLOR: rgb(0,0,204)">,</SPAN>
condition<SPAN
style="COLOR: rgb(0,0,204)">)</SPAN><SPAN
style="COLOR: rgb(255,153,0)">/*不可中断休眠,不推荐*/</SPAN><BR>wait_event_interruptible<SPAN
style="COLOR: rgb(0,0,204)">(</SPAN><SPAN
style="COLOR: rgb(255,0,0)">queue</SPAN><SPAN
style="COLOR: rgb(0,0,204)">,</SPAN>
condition<SPAN
style="COLOR: rgb(0,0,204)">)</SPAN><SPAN
style="COLOR: rgb(255,153,0)">/*推荐,返回非零值意味着休眠被中断,且驱动应返回
-ERESTARTSYS*/</SPAN><BR>wait_event_timeout<SPAN
style="COLOR: rgb(0,0,204)">(</SPAN><SPAN
style="COLOR: rgb(255,0,0)">queue</SPAN><SPAN
style="COLOR: rgb(0,0,204)">,</SPAN>
condition<SPAN
style="COLOR: rgb(0,0,204)">,</SPAN>
timeout<SPAN
style="COLOR: rgb(0,0,204)">)</SPAN><BR>wait_event_interruptible_timeout<SPAN
style="COLOR: rgb(0,0,204)">(</SPAN><SPAN
style="COLOR: rgb(255,0,0)">queue</SPAN><SPAN
style="COLOR: rgb(0,0,204)">,</SPAN>
condition<SPAN
style="COLOR: rgb(0,0,204)">,</SPAN>
timeout<SPAN
style="COLOR: rgb(0,0,204)">)</SPAN><BR><SPAN
style="COLOR: rgb(255,153,0)">/*有限的时间的休眠;若超时,<FONT
face=新宋体>则不管条件为何值</FONT>返回0,*/</SPAN></SPAN></CODE></P></TD></TR></TBODY></TABLE>
<P>唤醒休眠进程的函数称为 wake_up,形式如下:</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: rgb(0,0,0)"><SPAN
style="COLOR: rgb(0,0,255)">void</SPAN>
wake_up<SPAN
style="COLOR: rgb(0,0,204)">(</SPAN>wait_queue_head_t
<SPAN style="COLOR: rgb(0,0,204)">*</SPAN><SPAN
style="COLOR: rgb(255,0,0)">queue</SPAN><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>
wake_up_interruptible<SPAN
style="COLOR: rgb(0,0,204)">(</SPAN>wait_queue_head_t
<SPAN style="COLOR: rgb(0,0,204)">*</SPAN><SPAN
style="COLOR: rgb(255,0,0)">queue</SPAN><SPAN
style="COLOR: rgb(0,0,204)">)</SPAN><SPAN
style="COLOR: rgb(0,0,204)">;</SPAN></SPAN></CODE></P></TD></TR></TBODY></TABLE>
<P>惯例:用 wake_up 唤醒 wait_event ;用
wake_up_interruptible
唤醒wait_event_interruptible。</P>
<P><FONT size=4><SPAN
style="COLOR: rgb(0,1,255)">简单休眠实验</SPAN></FONT><BR> <FONT
color=#ff0000 size=3><FONT face=新宋体><FONT
color=#000000
size=3>模块程序链接:</FONT></FONT></FONT><A
href="http://blogimg.chinaunix.net/blog/upfile2/071102165236.gz"
target=_blank>sleepy</A><BR><FONT
size=3>模块测试程序</FONT><FONT color=#ff0000
size=3><FONT face=新宋体><FONT color=#000000
size=3>链接</FONT></FONT></FONT><FONT
size=3>:</FONT><A
href="http://blogimg.chinaunix.net/blog/upfile2/071102165157.gz"
target=_blank>sleepy-test</A><SPAN
style="TEXT-DECORATION: underline"></SPAN></P>
<P><FONT size=3><SPAN
style="COLOR: rgb(0,1,255)">实验现象:</SPAN></FONT><BR></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: rgb(0,0,0)"><SPAN
style="COLOR: rgb(0,0,204)">[</SPAN>Tekkaman2440@SBC2440V4<SPAN
style="COLOR: rgb(0,0,204)">]</SPAN><SPAN
style="COLOR: rgb(0,0,204)">#</SPAN>cd <SPAN
style="COLOR: rgb(0,0,204)">/</SPAN>lib<SPAN
style="COLOR: rgb(0,0,204)">/</SPAN>modules<SPAN
style="COLOR: rgb(0,0,204)">/</SPAN><BR><SPAN
style="COLOR: rgb(0,0,204)">[</SPAN>Tekkaman2440@SBC2440V4<SPAN
style="COLOR: rgb(0,0,204)">]</SPAN><SPAN
style="COLOR: rgb(0,0,204)">#</SPAN>insmod
sleepy<SPAN
style="COLOR: rgb(0,0,204)">.</SPAN>ko<BR><SPAN
style="COLOR: rgb(0,0,204)">[</SPAN>Tekkaman2440@SBC2440V4<SPAN
style="COLOR: rgb(0,0,204)">]</SPAN><SPAN
style="COLOR: rgb(0,0,204)">#</SPAN>cd <SPAN
style="COLOR: rgb(0,0,204)">/</SPAN>dev<SPAN
style="COLOR: rgb(0,0,204)">/</SPAN><BR><SPAN
style="COLOR: rgb(0,0,204)">[</SPAN>Tekkaman2440@SBC2440V4<SPAN
style="COLOR: rgb(0,0,204)">]</SPAN><SPAN
style="COLOR: rgb(0,0,204)">#</SPAN>cat <SPAN
style="COLOR: rgb(0,0,204)">/</SPAN>proc<SPAN
style="COLOR: rgb(0,0,204)">/</SPAN>devices<BR>Character
devices<SPAN
style="COLOR: rgb(0,0,204)">:</SPAN><BR> 1
mem<BR> 2 pty<BR> 3
ttyp<BR> 4 <SPAN
style="COLOR: rgb(0,0,204)">/</SPAN>dev<SPAN
style="COLOR: rgb(0,0,204)">/</SPAN>vc<SPAN
style="COLOR: rgb(0,0,204)">/</SPAN>0<BR> 4
tty<BR> 4 ttyS<BR> 5 <SPAN
style="COLOR: rgb(0,0,204)">/</SPAN>dev<SPAN
style="COLOR: rgb(0,0,204)">/</SPAN>tty<BR> 5
<SPAN
style="COLOR: rgb(0,0,204)">/</SPAN>dev<SPAN
style="COLOR: rgb(0,0,204)">/</SPAN>console<BR> 5
<SPAN
style="COLOR: rgb(0,0,204)">/</SPAN>dev<SPAN
style="COLOR: rgb(0,0,204)">/</SPAN>ptmx<BR> 7
vcs<BR> 10 misc<BR> 13
input<BR> 14 sound<BR> 81
video4linux<BR> 89 i2c<BR> 90
mtd<BR>116 alsa<BR>128 ptm<BR>136 pts<BR>180
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -