<!--[if gte mso 9]><xml>
<w:WordDocument>
<w:View>Normal</w:View>
<w:Zoom>0</w:Zoom>
<w:PunctuationKerning />
<w:DrawingGridVerticalSpacing>7.8 磅</w:DrawingGridVerticalSpacing>
<w:DisplayHorizontalDrawingGridEvery>0</w:DisplayHorizontalDrawingGridEvery>
<w:DisplayVerticalDrawingGridEvery>2</w:DisplayVerticalDrawingGridEvery>
<w:ValidateAgainstSchemas />
<w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid>
<w:IgnoreMixedContent>false</w:IgnoreMixedContent>
<w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText>
<w:Compatibility>
<w:SpaceForUL />
<w:BalanceSingleByteDoubleByteWidth />
<w:DoNotLeaveBackslashAlone />
<w:ULTrailSpace />
<w:DoNotExpandShiftReturn />
<w:AdjustLineHeightInTable />
<w:BreakWrappedTables />
<w:SnapToGridInCell />
<w:WrapTextWithPunct />
<w:UseAsianBreakRules />
<w:DontGrowAutofit />
<w:UseFELayout />
</w:Compatibility>
<w:BrowserLevel>MicrosoftInternetExplorer4</w:BrowserLevel>
</w:WordDocument>
</xml><![endif]--><!--[if gte mso 9]><xml>
<w:LatentStyles DefLockedState="false" LatentStyleCount="156">
</w:LatentStyles>
</xml><![endif]--><!--[if !mso]>
<object
classid="clsid:38481807-CA0E-42D2-BF39-B33AF135CC4D" id=ieooui>
</object>
<mce:style><!
st1/:*{behavior:url(#ieooui) }
-->
在file_operations中有许多的回调函数,正是这些回调函数实现了vfs,vfs提供了一个机制,这些回调函数提供了不同的策略,等于说实现了vfs,照理说这些函数不应该有任何限制,但是唯独一个poll回调函数与众不同,它不能睡眠,这是为何呢?
除了poll以外的回调函数都拥有直接的语义,比如read就是读,write就是写,因此系统调用层可以直接将执行路径交给vfs,比如在sys_read函数中,几乎做了简单的判断之后就马上调用了真正文件系统的file_operations的read函数,但是poll函数比较特殊,它并没有简单的语义,其实它就是轮询,可是它不像read,write那样系统调用层和vfs层那么统一,poll在vfs层的意思就是“看看这个文件是否有动作”,但是在系统调用层的意义就是“看看这些文件中哪个有动作”,这就是不同,为了将系统调用层的语义平滑的过度到vfs层,就必须在系统调用和vfs只见插入机制,这个机制实现了poll,当然还包括select。在poll的实现中,靠的是进程的状态来同步睡眠/唤醒动作的,它并不是在将进程加入睡眠队列后马上睡眠,而是不睡眠等到所有poll的文件描述符均加入队列后再睡眠,其实仅仅是左一个调度罢了,总体框架如下:
for (;;)
set_current_state(TASK_INTERRUPTIBLE)
for each fd to poll
ask driver if I/O can happen
add current process to driver wait queue
if one or more fds are ready
break
schedule_timeout_range(...)
注意,这里是在一开始就将进程的状态设置为TASK_INTERRUPTIBLE但是不睡眠,在中间的for循环中陆续将进程加入到睡眠队列,到了最后才切换进程,等于说就是睡眠了,看看这个糟糕的实现,在设置了进程TASK_INTERRUPTIBLE状态后那么大一会才将进程切换,这很是丑陋,丑陋的本质原因就是vfs实现的poll是poll一个文件描述符,但是系统调用的语义是poll一大堆的文件描述符,在没有必要添加适配机制的情况下,只好用进程状态来实现了,2.6.29内核实在是看不下去这个局面了,于是提出了poll和别的file_operations的回调函数一样,也可以睡眠,并且可以用传统的睡眠唤醒函数来唤醒进程:
+static int pollwake(wait_queue_t
*wait, unsigned mode, int sync, void *key)
+{
+ struct
poll_wqueues *pwq = wait->private;
+ DECLARE_WAITQUEUE(dummy_wait,
pwq->polling_task);
+
+ set_mb(pwq->triggered,
1);
+
+ /*
perform the default wake up operation */
+ return
default_wake_function(&dummy_wait, mode, sync, key);
+}
static void __pollwait(struct file
*filp, wait_queue_head_t *wait_address, poll_table *p)
{
- struct
poll_table_entry *entry = poll_get_entry(p);
+ struct
poll_wqueues *pwq = container_of(p, struct poll_wqueues, pt);
+ struct
poll_table_entry *entry = poll_get_entry(pwq);
if
(!entry)
return;
get_file(filp);
entry->filp
= filp;
entry->wait_address
= wait_address;
- init_waitqueue_entry(&entry->wait,
current);
+ init_waitqueue_func_entry(&entry->wait,
pollwake);
+ entry->wait.private
= pwq;
add_wait_queue(wait_address,
&entry->wait);
}
+int poll_schedule_timeout(struct
poll_wqueues *pwq, int state,
+ ktime_t *expires, unsigned long slack)
+{
+ int
rc = -EINTR;
+
+ set_current_state(state);
+ if
(!pwq->triggered)
+ rc
= schedule_hrtimeout_range(expires, slack, HRTIMER_MODE_ABS);
+ __set_current_state(TASK_RUNNING);
+
+ /*
clear triggered for the next iteration */
+ pwq->triggered
= 0;
+
+ return
rc;
+}
int do_select(int n, fd_set_bits
*fds, s
for
(;;) {
unsigned
long *rinp, *routp, *rexp, *inp, *outp, *exp;
- set_current_state(TASK_INTERRUPTIBLE);
inp
= fds->in; outp = fds->out; exp = fds->ex;
rinp
= fds->res_in; routp = fds->res_out; rexp = fds->res_ex;
@@ -411,10 +436,10 @@ int
do_select(int n, fd_set_bits *fds, s
to
= &expire;
}
- if
(!schedule_hrtimeout_range(to, slack, HRTIMER_MODE_ABS))
+ if
(!poll_schedule_timeout(&table, TASK_INTERRUPTIBLE,
+ to, slack))
timed_out
= 1;
}
- __set_current_state(TASK_RUNNING);
poll_freewait(&table);
我们可以看到在这个可睡眠的poll的补丁中,去掉了刻意为了适配加入的设置进程状态的语句,加入了统一的linux的睡眠/唤醒机制,poll_schedule_timeout是个新加入的函数,实际上它就是poll中的睡眠函数,和wait_event没有本质区别的,这样的话,加入这些函数,poll的实现和别的回调函数变得统一起来的。
实际上,我发现在2.6.29内核中,代码变得更加统一了,内核逻辑变得更加统一了,和前一篇文章我谈到的cred从task_struct中分离一样,poll可睡眠的意义也十分的大,比如将来为了加入新的机制要大改代码,起码file_operations中的回调函数都是统一的,这样就可以将之独立成一个模块而不用和别的模块杂糅。
分享到:
相关推荐
modbus poll工具+Modbus Poll Key.txt
ModbusPoll-v7.0.0 永久使用
它可以帮助用户快速的进行modbus调试,也支持进行主机的模拟,让您的开发、调试变得简单,快捷;软件的用户界面相当的友好,可快速的提升调试的效率,唯一不足就是软件是英文的操作界面,对于英语不好的培育比较的...
Modbus Poll 9.2.2 Build.zip
modbus poll 7 序列号 注册码 32,64通用
破解版ModBusPoll.4.3.4+Slave+破解版虚拟串口助手 破解版ModBusPoll.4.3.4+Slave+破解版虚拟串口助手
select,poll,epoll都是多路复用IO的函数,简单说就是在一个线程里,可以同时处理多个文件描述符的读写。 select/poll的实现很类似,epoll是从select/poll扩展而来,主要是为了解决select/poll天生的缺陷。 epoll在...
Modbus Poll version 10.5.0 Build 1946 self-installing,包含序列号
客户端访问服务器方式使用,包含Ajax原生,long poll,Websocket 客户端访问服务器方式使用,包含Ajax原生,long poll,Websocket 客户端访问服务器方式使用,包含Ajax原生,long poll,Websocket 客户端访问服务器...
ModbusPoll7.0.1 RS485调试神器
详细描述了modbus_poll软件的使用
文档讲解了ModBusPoll 调试modbus仪表设置方法。用于ModBusPoll 调试modbus仪表。
Modbus Poll :Modbus主机仿真器,用于测试和调试Modbus从设备。该软件支持ModbusRTU、ASCII、TCP/IP。用来帮助开发人员测试Modbus从设备,或者其它Modbus协议的测试和仿真。它支持多文档接口,即,可以同时监视多个...
Linux poll 和 epoll源码剖析
modbus poll7.0,需要的童鞋放心下载,解压皆可以用,无毒
资源简介:Modbus Poll是一个模拟Modbus协议主机的上位机软件,主要用于模拟测试跟其他从机设备通信的过程。该软件内部封装标准Modbus协议栈,通过图形化界面使得操作更为简便。目前软件支持01、02、03、04、05、06...
modbuspoll破解版。有需要的朋友可以下载用用。
破解版modbus poll
modbus 主站测试工具 可配合modbus poll从站应用
poll和阻塞驱动程序经典实例 poll和阻塞驱动程序经典实例 poll和阻塞驱动程序经典实例 poll和阻塞驱动程序经典实例