我对内核模块加载到内核后的工作方式有些困惑,主要是因为调用了sleep函数。
以字符设备驱动程序为例,我在read()函数中看到了类似于以下代码的代码,该代码试图使用set_current_state()
(有时是wait_event_interruptible()
等)使“进程”进入休眠状态。 :
set_current_state(TASK_INTERRUPTIBLE);
task = current;
for(;;)
{
if(condition)
break;
schedule();
}
set_current_state(TASK_RUNNING);
在写函数或中断处理程序中,他们试图通过将条件设置为true来唤醒read(),
condition = true;
wake_up_process(task); // -> task was stored inside read() function
我的问题是:
set_current_state()
或wait_event_interruptible()
哪个睡眠在这里?是用户空间进程调用系统调用read()还是为了映射用户空间进程而创建的某个内核进程?
假定通过在open()函数中设置原子计数,此设备驱动程序访问仅限于一个进程,并且该设备驱动程序未启用中断,如果read()调用wait_event()会发生什么情况真的没有其他进程可以唤醒它吗?它会永远卡住(因为没有中断)吗?
使用set_current_state()
和wait_event()
API有什么区别?我已经看到了相应地使用这些函数的不同代码段...我应该考虑一个相对于另一个的偏好吗?
答案 0 :(得分:0)
内核代码在发出系统调用的用户空间线程的“内核侧”上下文中执行。每个用户空间线程都有相应的内核空间。从调度程序的角度来看,线程的用户部分和内核部分是同一实体,因此在调度内核线程时,用户线程也是如此。
“可中断”和“不可中断”等待的不同之处在于信号的处理方式。当进程处于TASK_INTERRUPTIBLE状态并获取信号时,系统确保它尽快从schedule()唤醒。之后,如果signal_pending()返回true,则进程本身必须离开等待循环。在问题文本的示例代码中,除非“ condition”是包含signal_pending()检查的表达式,否则无法正确实现。
set_current_state()是当前进程状态的setter调用,它仅设置一个标志,不执行其他任何操作。它只能与对schedule()的正确调用一起使用。 wait_event()是一个实用程序,可实现所有等待的技术细节。通常,驱动程序使用wait_event *()风格,仅在特殊情况下才需要直接使用set_current_state()和schedule()。