等待队列——休眠与唤醒
内核中的休眠是通过等待队列来处理的。等待队列是一个由正在等待某个事件发生的进程组成的一个简单链表。在内核用wait_queue_head_t来表示。
定义:
DECLARE_WAITQUEUE()(静态定义)
或
init_waitqueue_head()(动态定义)
在内核中实现休眠的方法有点复杂,实现的模板如下:
/*‘q’isthewaitqueuewewishtosleepon*/ |
DEFINE_WAIT(wait); |
add_wait_queue(q,&wait);//这个函数调用是可选 |
while(!condition){/*conditionistheeventthatwearewaitingfor*/ |
prepare_to_wait(&q,&wait,TASK_INTERRUPTIBLE); |
if(signal_pending(current)) |
/*handlesignal*/ |
schedule(); |
} |
finish_wait(&q,&wait); |
一个进程执行如下步骤将自己加入到一个等待队列中:
通过宏DEFINE_WAIT()来创建一个等待队列项。
通过函数add_wait_queue()将该项加入到一个等待队列中。当等待的事件(条件)为真时,等待队列会唤醒该进程项。当然,需要在其他地方调用wake_up()函数。
调用prepare_to_wait()函数将进程的状态改为TASK_INTERRUPTIBLE或TASK_UNINTERRUPTIBLE。该函数也会在必要的时候将进程加回到等待队列中,在后续的迭代中会用到(提示:第二个步骤可选,因为该函数在任务列表为空的时候也会将当前任务项加入到等待队列中)。
如果状态设置为TASK_INTERRUPTIBLE,,一个信号会唤醒该进程。这称为伪休眠。因此要检测和处理信号。
当进程被唤醒,它再次检测条件是否为真。如果为真,它会退出循环。否则,再次调用schedule()然后重复上述过程。
当条件为真,该进程会将其状态设为TASK_RUNNING并将自己通过finish_wait()从等待队列中删除。
一个例子:
staticssize_t inotify_read(struct file *file, char __user *buf, size_t count, loff_t *pos) { structfsnotify_group *group; structfsnotify_event *kevent; char__user *start; intret; DEFINE_WAIT(wait); start= buf; group= file->private_data; while(1) { prepare_to_wait(&group->notification_waitq,&wait,TASK_INTERRUPTIBLE); mutex_lock(&group->notification_mutex); kevent= get_one_event(group, count); mutex_unlock(&group->notification_mutex); if(kevent) { ret= PTR_ERR(kevent); if(IS_ERR(kevent)) break; ret= copy_event_to_user(group, kevent, buf); fsnotify_put_event(kevent); if(ret < 0) break; buf+= ret; count-= ret; continue; } ret= -EAGAIN; if(file->f_flags & O_NONBLOCK) break; ret= -EINTR; if(signal_pending(current)) break; if(start != buf) break; schedule(); } finish_wait(&group->notification_waitq,&wait); if(start != buf && ret != -EFAULT) ret= buf - start; returnret; } |
另一种模板:
/*Helper thread */ staticint my_thread(void*unused) { /** * wait_queue_t wait; * init_waitqueue_entry(&wait, current); */ DECLARE_WAITQUEUE(wait,current); daemonize("my_thread"); add_wait_queue(&my_thread_wait,&wait); while(1) { /*Relinquish processor until event occurs */ set_current_state(TASK_INTERRUPTIBLE); if(signal_pending(current)) /*##handlesingalevent##*/ schedule(); /*Control gets here when the thread is woken upfrom the my_thread_wait wait queue */ /*Quit if let go */ if(pink_slip) { break; } /*Do the real work */ /*... */ } /*Bail out of the wait queue */ __set_current_state(TASK_RUNNING); remove_wait_queue(&my_thread_wait,&wait); /*Atomically signal completion and exit */ complete_and_exit(&my_thread_exit,0); } |
唤醒
通过函数wake_up()唤醒,它将唤醒所有在特定等待队列上等待的进程。一般情况下默认的唤醒函数为:default_wake_function()。它会调用try_to_wake_up(),将被唤醒的进程状态设置为TASK_RUNNING,然后调用enqueue_task()将该进程加入到红黑树中,如果被唤醒的进程的优先级大于当前进程的优先级,设置need_resched为1。休眠与唤醒之间的关系如下:
\
伪唤醒是指进程是因为接收到某个信号而被唤醒,而不是等待事件发生而导致其被唤醒。
转载于:https://my.oschina.net/fuyajun1983cn/blog/263905
等待队列——休眠与唤醒相关推荐
- 进程的休眠与唤醒(等待队列)
1.进程休眠 (1)进程有三种基本状态:就绪态.阻塞态.运行态. <1>阻塞态:进程缺少除了CPU之外的某些资源,因此该进程不能被运行,被阻塞住了不能被CPU调度: <2>就绪 ...
- Linux进程休眠和唤醒
当进程以阻塞的方式通信,在得到结果前进程会挂起休眠. 为了将进程以一种安全的方式进入休眠,我们需要牢记两条规则: 一.永远不要在原子上下文中进入休眠. 二.进程休眠后,对环境一无所知.唤醒后,必须再次 ...
- linux待机唤醒_Linux电源管理-休眠与唤醒
1.休眠方式 在内核中,休眠方式有很多种,可以通过下面命令查看 # cat /sys/power/state //来得到内核支持哪几种休眠方式. 常用的休眠方式有freeze,standby, mem ...
- Linux Kernel and Android 休眠与唤醒(中文版)
Linux Kernel and Android 休眠与唤醒(中文版) 四月 18th, 2010 0 Comments/1664 hits Table of Contents 简介 国际化 版本信息 ...
- Linux Kernel and Android休眠与唤醒
版本信息 Linux Kernel: v2.6.28 Android: v2.0 对于休眠(suspend)的简单介绍 在Linux中,休眠主要分三个主要的步骤: 版本信息 Linux Ke ...
- 休眠后gpio状态_1.Linux电源管理-休眠与唤醒
1.休眠方式 在内核中,休眠方式有很多种,可以通过下面命令查看 常用的休眠方式有freeze,standby, mem, disk freeze:冻结I/O设备,将它们置于低功耗状态,使处理器进入空闲 ...
- Win7休眠后唤醒出现黑屏的解决办法
进入睡眠状态可很好地节约电源和延长硬件的使用寿命,很多用户的电脑进入睡眠状态后,唤醒无法正常进入屏幕,而是变成黑屏的故障,怎么回事?其实出现这种情况并非什么系统故障问题,下面小编给大家分享Win7休眠 ...
- 计算机休眠唤醒后 网络受限,Win7系统待机/休眠被唤醒后笔记本WIFI无线网络无法连接解决方法...
有的时候,我们会暂时离开电脑,希望回来的时候又可以快速使用电脑,所以我们经常会使用待机.休眠功能,当我们将系统待机时,不仅可以快速的恢复到之前电脑的工作状态,还可以省电.但是我们使用笔记本的时候,发现 ...
- 2022-06-29 AndroidR 获取接近传感器Proximity Sensor的信号,休眠和唤醒。
一.底层的驱动在这里不提,只关心上层. 二.实现AndroidR 获取接近传感器Proximity Sensor的信号,休眠和唤醒的方法:获取SENSOR_SERVICE服务,侦听Sensor事件. ...
最新文章
- 吵疯了,Pull Request到底是个啥?
- java定时扫描_springmvc 定时扫描
- 刷题总结——生日礼物(bzoj1293单调队列)
- [待总结]高频率vim命令
- (转)如何用U盘创建Linux系统盘
- 排优解难 网上邻居常遇故障解决方法
- 从零开始实现主成分分析(PCA)算法
- 脱发篇-多线程基础(下)来看看你知道多少
- matlab求感知距离的命令,感知机算法(MATLAB)
- C#水晶报表,窗体不显示,闪退
- ASP.NET MVC 过滤器(五)
- dubbox开发rest+json指南【转】
- linux vi文件加密和文件解密
- 单稳态电路和双稳态电路电路详解 CD4013触发器开关电路驱动继电器
- java之等差素数的求法
- Curious Cupid
- 关于mac系统外接键盘的设置
- 7-3 计算平均成绩 (15分)
- jenkins cicd k8s 多分支流水线构建
- 【完整代码】用HTML/CSS制作一个美观的个人简介网页