Linux内核的等待队列是以双循环链表为基础数据结构,与进程调度机制紧密结合,能够用于实现核心的异步时间通知机制。在网络编程中,我们发送数据总要在收到反馈信息的时候才能发送下一帧数据,上层应用开发我们使用的iotcl进行读写控制时,底层便是以此开发比较合理。Linux内核休眠唤醒机制,在本文指的是在驱动运行的过程中可以使进程以休眠的方式等待数据,当事件发生的时候将其唤醒。当前在工作过程中主要用到的方式为:
TASK_RUNNING:在Linux中,仅等待 CPU 时间的进程称为就绪进程,它们被放置在一个运行队列中,一个就绪进程的状 态标志位为 TASK_RUNNING。一旦一个运行中的进程时间片用完, Linux 内核的调度器会剥夺这个进程对 CPU 的控制权,并且从运行队列中选择一个合适的进程投入运行。
TASK_INTERRUPTIBLE:可中断的睡眠状态的进程会睡眠直到某个条件变为真,比如说产生一个硬件中断、释放 进程正在等待的系统资源或是传递一个信号都可以是唤醒进程的条件。
TASK_UNINTERRUPTIBLE:不可中断睡眠状态一般较少用到,但在一些特定情况下这种状态还是很有用的,比如说:进程必须等 待,不能被中断,直到某个特定的事件发生。
#include
#include
wait_queue_head_t wait_head;
static inline void init_waitqueue_head(wait_queue_head_t *q)
{
spin_lock_init(&q->lock);
INIT_LIST_HEAD(&q->task_list);
}
#define wake_up_interruptible(x) __wake_up(x, TASK_INTERRUPTIBLE, 1, NULL)
事件唤醒队列(当cond条件是false,则休眠)。等待休眠直到condition的表达式为真,每次唤醒队列都会检查condition,如果函数被中断,函数将返回-ERESTARTSYS信号,condition为真则返回0。
/**
* wait_event_interruptible - sleep until a condition gets true
* @wq: the waitqueue to wait on
* @condition: a C expression for the event to wait for
*
* The process is put to sleep (TASK_INTERRUPTIBLE) until the
* @condition evaluates to true or a signal is received.
* The @condition is checked each time the waitqueue @wq is woken up.
*
* wake_up() has to be called after changing any variable that could
* change the result of the wait condition.
*
* The function will return -ERESTARTSYS if it was interrupted by a
* signal and 0 if @condition evaluated to true.
*/
#define wait_event_interruptible(wq, condition) \
({ \
int __ret = 0; \
if (!(condition)) \
__wait_event_interruptible(wq, condition, __ret); \
__ret; \
})
#define __wait_event_interruptible_timeout(wq, condition, ret)
do {
DEFINE_WAIT(__wait);
for (;;) {
prepare_to_wait(&wq, &__wait, TASK_INTERRUPTIBLE);
if (condition)
break;
if (!signal_pending(current)) {
ret = schedule_timeout(ret);
if (!ret)
break;
continue;
}
ret = -ERESTARTSYS;
break;
}
finish_wait(&wq, &__wait);
} while (0)
/**
* wait_event_interruptible_timeout - sleep until a condition gets true or a timeout elapses
* @wq: the waitqueue to wait on
* @condition: a C expression for the event to wait for
* @timeout: timeout, in jiffies
*
* The process is put to sleep (TASK_INTERRUPTIBLE) until the
* @condition evaluates to true or a signal is received.
* The @condition is checked each time the waitqueue @wq is woken up.
*
* wake_up() has to be called after changing any variable that could
* change the result of the wait condition.
*
* The function returns 0 if the @timeout elapsed, -ERESTARTSYS if it
* was interrupted by a signal, and the remaining jiffies otherwise
* if the condition evaluated to true before the timeout elapsed.
*/
#define wait_event_interruptible_timeout(wq, condition, timeout)
({
long __ret = timeout;
if (!(condition))
__wait_event_interruptible_timeout(wq, condition, __ret);
__ret;
})
ret = wait_event_interruptible_timeout(wait_queue,ev_recv,msecs_to_jiffies(60));
用wake_up_interruptible()唤醒后,wait_event_interruptible(wq, condition)宏,自身再检查“condition”这个条件以决定是返回还是继续休眠,真则返回,假则继续睡眠,不过这个程序中若有中断程序的话,中断来了,还是会继续执行中断函数的。只有当执行wake_up_interruptible()并且condition条件成立时才会把程序从队列中唤醒。
主要使用在某个条件满足执行线程内容进行获取,当用户空间进程读取某一设备时,如果设备此时没有数据则调用wait_event_interruptible
等函数,该进程将进入等待状态, 等待某一事件发生且条件成立; 当某事件发生后,调用wake_up_interruptible
等函数进行唤醒,唤醒后,其会判断条件是否成立, 如果不成立则继续进入休眠状态; 反之条件成立,则立即退出等待状态;此时程序中有中断程序,程序仍会执行中断函数,只有执行wait_event_interruptible
并且condition
条件成立时才会把程序从队列唤醒。
Linux内核之休眠与唤醒
Linux内核驱动休眠和唤醒机制(select系统调用内核驱动poll实现)
Linux时间转换msecs_to_jiffies