CubieBoard中文论坛

 找回密码
 立即注册
搜索
热搜: unable
查看: 6101|回复: 1

对Linux系统休眠的理解

[复制链接]
发表于 2014-6-6 18:13:15 | 显示全部楼层 |阅读模式
今天遇见了一个bug,中断上下文不能进行休眠,百度一下。
本文转自:http://blog.chinaunix.net/uid-26359109-id-3271119.html
首先必须意识到:休眠是一种进程的特殊状态(即
task->state= TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE

  • 一、休眠的目的
    简单的说,休眠是为在一个当前进程等待暂时无法获得的资源或者一个event的到来时(原因),避免当前进程浪费CPU时间(目的),将自己放入进程等待队列中,同时让出CPU给别的进程(工作)。休眠就是为了更好地利用CPU
     一旦资源可用或event到来,将由内核代码(可能是其他进程通过系统调用)唤醒某个等待队列上的部分或全部进程。从这点来说,休眠也是一种进程间的同步机制。
  • 二、休眠的对象
     休眠是针对进程,也就是拥有task_struct的独立个体。
     当进程执行某个系统调用的时候,暂时无法获得的某种资源或必须等待某event的到来,在这个系统调用的底层实现代码就可以通过让系统调度的手段让出CPU,让当前进程处于休眠状态

  • 进程什么时候会被休眠?
    进程进入休眠状态,必然是他自己的代码中调用了某个系统调用,而这个系统调用中存在休眠代码。这个休眠代码在某种条件下会被激活,从而让改变进程状态,说到底就是以各种方式包含了:
1、条件判断语句
2、进程状态改变语句
3、schedule();

  • 三、休眠操作做了什么
    进程被置为休眠,意味着它被标识为处于一个特殊的状态(TASK_UNINTERRUPTIBLE TASK_INTERRUPTIBLE),并且从调度器的运行队列中移走这个进程将不在任何 CPU 调度,即不会被运行。 直到发生某些事情改变了那个状态(to TASK_WAKING)。这时处理器重新开始执行此进程,此时进程会再次检查是否需要继续休眠(资源是否真的可用?),如果不需要就做清理工作,并将自己的状态调整为TASK_RUNNING。过程如下图所示:

  • 四、谁来唤醒休眠进程
     进程在休眠后,就不再被调度器执行,就不可能由自己唤醒自己,也就是说进程不可能“睡觉睡到自然醒”。唤醒工作必然是由其他进程或者内核本身来完成的。唤醒需要改变进程的task_struct中的状态等,代码必然在内核中,所以唤醒必然是在系统调用的实现代码中(如你驱动中的read、write方法)以及各种形式的中断代码(包括软、硬中断)中。
     如果在系统调用代码中唤醒,则说明是由其他的某个进程来调用了这个系统调用唤醒了休眠的进程。
      如果是中断中唤醒,那么唤醒的任务可以说是内核完成了。
· 如何找到需要唤醒的进程:等待队列
    上面其实已经提到了:休眠代码的一个工作就是将当前进程信息放入一个等待队列中。它其实是一个包含等待某个特定事件的所有进程相关信息的链表。一个等待队列由一个wait_queue_head_t 结构体来管理,其定义在<linux/wait.h>中。
wait_queue_head_t 类型的数据结构如下:

  • struct __wait_queue_head {
  •     spinlock_t lock;
  •     struct list_head task_list;
  • };
  • typedef struct __wait_queue_head wait_queue_head_t;

    它包含一个自旋锁和一个链表。这是一个等待队列链表头,链表中的元素被声明做wait_queue_t。自旋锁用于包含链表操作的原子性。
wait_queue_t包含关于睡眠进程的信息和唤醒函数

  • typedef struct __wait_queue wait_queue_t;
  • typedef int (*wait_queue_func_t)(wait_queue_t *wait, unsigned mode, int flags, void *key);
  • int default_wake_function(wait_queue_t *wait, unsigned mode, int flags, void *key);
  • struct __wait_queue {
  • unsigned int flags;
  • #define WQ_FLAG_EXCLUSIVE 0x01                 /* 表示等待进程想要被独占地唤醒 */
  • void *private;                                 /* 指向等待进程的task_struct结构图 */
  • wait_queue_func_t func;                 /* 用于唤醒等待进程的处理例程,在其中实现了进程状态的改变和将自己从等待队列中删除的工作 */
  • struct list_head task_list;                 /* 双向链表结构体,用于将wait_queue_t链接到wait_queue_head_t */
  • };

他们在内存中的结构大致如下图所示:
等待队列头wait_queue_head_t一般是定义在模块或内核代码中的全局变量,而其中链接的元素 wait_queue_t的定义被包含在了休眠宏中。
休眠和唤醒的过程如下图所示:


回复

使用道具 举报

发表于 2014-8-1 11:37:27 | 显示全部楼层
我又来了
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|粤ICP备13051116号|cubie.cc---深刻的嵌入式技术讨论社区

GMT+8, 2024-5-6 15:00 , Processed in 0.023206 second(s), 15 queries .

Powered by Discuz! X3.4

© 2001-2012 Comsenz Inc. | Style by Coxxs

返回顶部