linux内核线程睡眠与唤醒

来源:互联网 发布:造梦西游1装备数据大全 编辑:程序博客网 时间:2024/05/22 08:13

这里以内核usb gadget driver中f_mass_storage驱动为例子进行说明。

static int sleep_thread(struct fsg_common *common){int rc = 0;/* Wait until a signal arrives or we are woken up */for (;;) {    try_to_freeze();    set_current_state(TASK_INTERRUPTIBLE);    if (signal_pending(current)) {        rc = -EINTR;        break;    }    if (common->thread_wakeup_needed)        break;    schedule();}__set_current_state(TASK_RUNNING);common->thread_wakeup_needed = 0;smp_rmb();  /* ensure the latest bh->state is visible */return rc;}

try_to_freeze()

try_to_freeze()函数需要参考Documentation/power/freezing-of-tasks.txt
这里也有这个文档对应的中文翻译:http://blog.csdn.net/arethe/article/details/6069358
内核为每个进程在适当的时候调用try_to_freeze来设置PF_FREEZE标志,当系统要suspend的时候,系统那边会调用freeze_process函数来将所有可冷冻的任务的TIF_FREEZE标志置位,然后所有有TIF_FREEZE标志的进程会睡眠。当系统从suspend状态恢复的时候调用thaw_process函数来清除所有冷冻任务的PF_FREEZE标志。


内核线程睡眠的方式(参考了LDD3这本书 P156)

方式1
step1:通过改变当前的状态,改变了处理器处理该进程的方式,但尚未使进程让出处理器。
set_current_state(TASK_INTERRUPTIBLE)
step2:检查睡眠等待的条件,如果没有任何线程试图唤醒这个线程,那么这个线程可以进行睡眠;否则如果不检查睡眠等待的条件而直接进行睡眠,而这个时候有线程试图唤醒这个线程,那么很容易失去被唤醒的机会。
if (!condition)
schedule();
step3:线程通过上面的步骤一直处在睡眠状态,当有别的线程将睡眠的线程唤醒之后,需要执行:
set_current_state(TASK_RUNNING)

方式2
step1:建立并初始化一个等待队列入口
DEFINE_WAIT(my_wait)
step2:将我们的等待队列入口添加到队列中,并设置进程的状态
prepare_to_wait(wait_queue_head_t *queue, wait_queue_t *wait, int state);
step3
if (!condition)
schedule();
step4:线程通过上面的步骤一直处在睡眠状态,当有别的线程将睡眠的线程唤醒之后,需要执行:
void finish_wait(wait_queue_head_t *queue, wait_queue_t *wait);

可以看出开头贴出的代码睡眠采用了”方式2”,另外以上代码中需要包含头文件< linux/sched.h>


唤醒线程的方法

方式1:通过wake_up_process来唤醒睡眠的线程

static void wakeup_thread(struct fsg_common *common){smp_wmb();  /* ensure the write of bh->state is complete *//* Tell the main thread that something has happened */common->thread_wakeup_needed = 1;if (common->thread_task)    wake_up_process(common->thread_task);}

对于开头给出的代码,由于睡眠的线程收到wake_up_process(common->thread_task),于是便从schedule()函数中退出,继续在for循环中,由于此时if (common->thread_wakeup_needed)成立,所以就此退出了for循环。

方式2:通过发送信号来唤醒睡眠的线程

static void raise_exception(struct fsg_common *common, enum fsg_state new_state){unsigned long       flags;/* * Do nothing if a higher-priority exception is already in progress. * If a lower-or-equal priority exception is in progress, preempt it * and notify the main thread by sending it a signal. */spin_lock_irqsave(&common->lock, flags);if (common->state <= new_state) {    common->exception_req_tag = common->ep0_req_tag;    common->state = new_state;    if (common->thread_task)        send_sig_info(SIGUSR1, SEND_SIG_FORCED,                  common->thread_task);}spin_unlock_irqrestore(&common->lock, flags);}

对于开头给出的代码,由于signal_pending(current)函数相当于是内核安装的信号处理函数,现在由于收到了信号,也就退出了for循环。

0 0
原创粉丝点击