内核态休眠与唤醒
休眠与唤醒
在中断的简介里面,介绍了四种模式:查询,休眠-唤醒,poll机制,异步通知机制。本节主要说休眠-唤醒机制。
举例:我们在等待按键被按下,可以使用“休眠-唤醒”机制。在应用程序中,等待按键事件发生。
1.APP使用read等操作函数尝试读取硬件底层数据。
2.APP调用read等函数,进入内核态,执行驱动中的对应的函数(file_operatons),发现有数据,复制数据到用户空间并返回。
3.如果在驱动程序中没有数据,进行休眠状态
4.按键按下,休眠的程序(内核态)被唤醒。
5.继续运行内核态代码,复制数据到用户空间并返回。
函数调用流程
驱动中如果没有程序,程序在执行drv_read函数时,在内核态进入会休眠,这样内核调度器不会调度执行它。当按下按键,
驱动程序被唤醒,记录按键数据。唤醒休眠的内核态程序,等待调度器调度执行它。等再次执行,执行drv_read剩下的代码,把数据复制到用户空间。
根据上图的历程,涉及两个app。由于休眠,导致其它app被执行。在按下被按下的中断中,唤醒被休眠的程序。
备注:中断程序不能被休眠,中断如果休眠,由哪些来唤醒呢?因此,在中断函数中不能使用会导致休眠的函数。
内核函数
休眠函数
Function |
说明 |
wait_event (wq, condition) |
休眠,直到condition为真; 休眠期间是可被打断的,可以被信号打断 |
wait_event_interruptible(wq, condition) |
休眠,直到condition为真; 退出的唯一条件是condition为真,信号也不好使 |
wait_event_interruptible_timeout(wq, condition, timeout) |
休眠,直到condition为真或超时; 休眠期间是可被打断的,可以被信号打断 |
wait_event_timeout(wq, condition, timeout) |
休眠,直到condition为真; 退出的唯一条件是condition为真,信号也不好使 |
Wq:是一个队列,等待队列。内核态的程序一旦休眠,将其进程放置在该队列,等待后续被唤醒。
如果没有该等待队列变量,无法定位休眠的程序。
Condition:条件变量为真之后,才唤醒休眠的程序。
唤醒函数
函数 |
说明 |
wake_up_interruptible(x) |
唤醒x队列中状态为“TASK_INTERRUPTIBLE”的线程,只唤醒其中的一个线程 |
wake_up_interruptible_nr(x, nr) |
唤醒x队列中状态为“TASK_INTERRUPTIBLE”的线程,只唤醒其中的nr个线程 |
wake_up_interruptible_all(x) |
唤醒x队列中状态为“TASK_INTERRUPTIBLE”的线程,唤醒其中的所有线程 |
wake_up(x) |
唤醒x队列中状态为“TASK_INTERRUPTIBLE”或“TASK_UNINTERRUPTIBLE”的线程,只唤醒其中的一个线程 |
wake_up_nr(x, nr) |
唤醒x队列中状态为“TASK_INTERRUPTIBLE”或“TASK_UNINTERRUPTIBLE”的线程,只唤醒其中nr个线程 |
wake_up_all(x) |
唤醒x队列中状态为“TASK_INTERRUPTIBLE”或“TASK_UNINTERRUPTIBLE”的线程,唤醒其中的所有线程 |
驱动框架