解析Linux内核的同步与互斥机制(7)5.3 手工休眠的具体函数执行流 特殊睡眠要求程序员手动处理所有上面的步骤. 它是一个繁琐的过程, 包含相当多的易出错的样板式的代码. 程序员如果愿意还是可能用那种方式手动睡眠。 (1)创建和初始化一个等待队列。常由宏定义完成: DEFINE_WAIT(my_wait); /*name 是等待队列入口项的名字. 也可以用2步来做:*/ wait_queue_t my_wait; init_wait(&my_wait); /*常用的做法是放一个 DEFINE_WAIT 在循环的顶部,来实现休眠。*/ (2)添加等待队列入口到队列,并设置进程状态: void prepare_to_wait(wait_queue_head_t *queue, wait_queue_t *wait, int state); /*queue 和 wait 分别地是等待队列头和进程入口。state 是进程的新状态:TASK_INTERRUPTIBLE(可中断休眠,推荐)或TASK_UNINTERRUPTIBLE(不可中断休眠,不推荐)。*/ prepare_to_wait_exclusive (3)在检查确认仍然需要休眠之后调用 schedule schedule(); (4)schedule 返回,重新判断等待条件,若为真则退出,否则继续schedule (5)条件满足退出后,确保状态为running,同时将进程从等待队列中删除。 void finish_wait(wait_queue_head_t *queue, wait_queue_t *wait); 5.4 wait_event_interruptible_exclusive 为了避免手工编写上述复杂代码,内核提供了最常见的interruptible类型排他性等待函数。而对于非排他性的可以直接利用等待事件event系列函数。 #define __wait_event_interruptible_exclusive(wq, condition, ret) \ do { \ DEFINE_WAIT(__wait); \ \ for (;;) { \ prepare_to_wait_exclusive(&wq, &__wait, \ TASK_INTERRUPTIBLE); \ if (condition) \ break; \ if (!signal_pending(current)) { \ schedule(); \ continue; \ } \ ret = -ERESTARTSYS; \ break; \ } \ finish_wait(&wq, &__wait); \ } while (0) #define wait_event_interruptible_exclusive(wq, condition) \ ({ \ int __ret = 0; \ if (!(condition)) \ __wait_event_interruptible_exclusive(wq, condition, __ret);\ __ret; \ }) 6 Completion completion是一种轻量级的机制,它允许一个线程告诉另一个线程某个工作已经完成。代码必须包含。使用的代码如下: DECLARE_COMPLETION(my_completion);/* 创建completion(声明+初始化) */ struct completion my_completion;/* 动态声明completion 结构体*/ static inline void init_completion(&my_completion);/*动态初始化completion*/ void wait_for_completion(struct completion *c);/* 等待completion */ void complete(struct completion *c);/*唤醒一个等待completion的线程*/ void complete_all(struct completion *c);/*唤醒所有等待completion的线程*/ /*如果未使用completion_all,completion可重复使用;否则必须使用以下函数重新初始化completion*/ INIT_COMPLETION(struct completion c);/*快速重新初始化completion*/ completion 的典型应用是模块退出时的内核线程终止。在这种模式,某些驱动程序的内部工作有一个内核线程在while(1)循环中完成。当内核准备清除该模块 时,exit函数会告诉该线程退出并等待completion。为此内核包含了用于这种线程的一个特殊函数: void complete_and_exit(struct completion *c, long retval); |
|