Linux 内核 up down,信号量机制中的DOWN操作与UP操作详解
DOWN操作:linux内核中,对信号量的DOWN操作有如下几种:
void down(struct semaphore *sem); //不可中断
int down_interruptible(struct semaphore *sem);//可中断
int down_killable(struct semaphore *sem);//睡眠的进程可以因为受到致命信号而被唤醒,中断获取信号量的操作。
int down_trylock(struct semaphore *sem);//试图获取信号量,若无法获得则直接返回1而不睡眠。返回0则 表示获取到了信号量
int down_timeout(struct semaphore *sem,long jiffies);//表示睡眠时间是有限制的,如果在jiffies指明的时间到期时仍然无法获得信号量,则将返回错误码。
在以上四种函数中,驱动程序使用的最频繁的就是down_interruptible函数,以下将对该函数进行分析。
down_interruptible函数的定义如下:
int down_interruptible(struct semaphore *sem)
{
unsigned long flags;
int result = 0;
spin_lock_irqsave(&sem->lock,flags);
if (likely(sem->count> 0))
sem->count--;
else
result =__down_interruptible(sem);
spin_unlock_irqrestore(&sem->lock,flags);
return result;
}
函数分析:函数首先通过spin_lock_irqsave的调用来保证对sem->count操作的原子性。如果count>0,表示当前进程可以获得信号量,将count的值减1然后退出。如果count不大于0,表明当前进程无法获取信号量,则调用__down_interruptible,后者会继续调用__down_common。
__down_common 函数定义如下:
static inline int __sched __down_common(struct semaphore *sem, longstate,
longtimeout)
{
struct task_struct *task= current;
struct semaphore_waiterwaiter;
list_add_tail(&waiter.list,&sem->wait_list);
waiter.task = task;
waiter.up = 0;
for (;;) {
if(signal_pending_state(state, task))
gotointerrupted;
if (timeout <=0)
gototimed_out;
__set_task_state(task,state);
spin_unlock_irq(&sem->lock);
timeout =schedule_timeout(timeout);
spin_lock_irq(&sem->lock);
if (waiter.up)
return 0;
}
timed_out:
list_del(&waiter.list);
return -ETIME;
interrupted:
list_del(&waiter.list);
return -EINTR;
}
函数分析:在__down_common函数数执行了以下操作。
(1)将当前进程放到信号量成员变量wait_list所管理的队列中。
(2)在一个for循环中把当前的进程状态这是为TASK_INTERRUPTIBLE,在调用schedule_timeout使当前进程进入睡眠状态,函数将停留在schedule_timeout调用上,知道再次被调度执行。
(3) 当该进程再一次被调度时,按原因执行相应的操作:如果waiter.up不为0说明进程被该信号量的up操作所唤醒,进程可以获得信号量。如果进程是因为被用户空间的信号所中断或超时信号所引起的唤醒,则返回相应的错误代码。
UP操作:LINUX内核只提供了一个up函数
up函数定义如下:
void up(struct semaphore *sem)
{
unsigned long flags;
spin_lock_irqsave(&sem->lock,flags);
if(likely(list_empty(&sem->wait_list)))
sem->count++;
else
__up(sem);
spin_unlock_irqrestore(&sem->lock,flags);
}
函数分析:如果sem的wait_list队列为空,则表明没有其他进程正在等待该信号量,那么只需要把sem的count加1即可。如果wait_list队列不为空,则说明有其他进程正睡眠在wait_list上等待该信号,此时调用__up(sem)来唤醒进程:
__up()函数定义如下:
static noinline void __sched __up(struct semaphore *sem)
{
struct semaphore_waiter*waiter = list_first_entry(&sem->wait_list,
structsemaphore_waiter, list);
list_del(&waiter->list);
waiter->up = 1;
wake_up_process(waiter->task);
}
函数分析:在函数中,调用了wake_up_process来唤醒进程,这样进程就从之前的__down_interruptible调用中的timeout=schedule_timeout(timeout)处醒来,wait-up=1, __down_interruptible返回0,进程获得了信号量。
up()与down()函数之间的联系:由上面对两个函数的分析可以知道,__down_common函数中timeout=schedule_timeout(timeout) 有着很重要的作用。
原文:http://blog.csdn.net/fzubbsc/article/details/37737159
Linux 内核 up down,信号量机制中的DOWN操作与UP操作详解相关推荐
- Linux内核 eBPF基础:perf(4)perf_event_open系统调用与用户手册详解
Linux内核 eBPF基础 perf(4)perf_event_open系统调用与用户手册详解 荣涛 2021年5月19日 本文相关注释代码:https://github.com/Rtoax/lin ...
- Virtual PC 2007下虚拟机与本机双XP系统实现互联与上网详解
Virtual PC 2007下虚拟机与本机双XP系统实现互联与上网详解 1.在虚拟机安装windowsXP系统 2.为了不影响用来上网的原网卡,所以我们选择在主机上装一个虚拟网卡来与虚拟机进行通信, ...
- Linux Shell脚本入门教程系列之(八)Shell printf命令详解
本文是Linux Shell脚本系列教程的第(八)篇,更多shell教程请看:Linux Shell脚本系列教程 在上一篇:Linux Shell系列教程之(七)Shell输出这篇文章中,已经对She ...
- linux上连接ftp服务器,linux下lftp连接ftp服务器进行上传与下载的方法详解
摘要 腾兴网为您分享:linux下lftp连接ftp服务器进行上传与下载的方法详解,中英翻译,中建在线,掌上看家,银行帮等软件知识,以及微信一键转发工具,小学英语冀教版,正是在下表情包,易问电信,万能 ...
- 信号量机制中的down和up函数
转自:https://blog.csdn.net/fzubbsc/article/details/37737159 参考: https://blog.csdn.net/liuxd3000/articl ...
- linux内核同步之信号量、顺序锁、RCU、完成量、关闭中断【转】
转自:http://blog.csdn.net/goodluckwhh/article/details/9006065 版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[-] 一信号量 ...
- linux查看tcl版本_查看Linux内核版本的方法有几个?你也是这样操作吗?
请关注本头条号,每天坚持更新原创干货技术文章.如需学习视频,请在微信搜索公众号"智传网优"直接开始自助视频学习 1. 前言 内核是操作系统的核心组件. 它管理系统的资源,是计算机硬 ...
- 如何查看docker的内核版本_查看Linux内核版本的方法有几个?你也是这样操作吗?...
请关注本头条号,每天坚持更新原创干货技术文章.如需学习视频,请在微信搜索公众号"智传网优"直接开始自助视频学习 1. 前言 内核是操作系统的核心组件. 它管理系统的资源,是计算机硬 ...
- [入门篇]Linux操作系统fork子进程的创建以及进程的状态 超超超详解!!!我不允许有人错过!!!
目录 0.前言 1.fork()创建子进程讲解 1.1fork()的简单介绍 1.2 创建子进程详解 1.2.1 如何理解fork创建子进程 1.2.2 子进程的PCB以及子进程的代码和数据 1.2. ...
最新文章
- yum源的超级简单配置
- 阿里云OSS搭建移动应用直传服务的.Net C#示例
- 谈及未来的 AI, 也许你已身处其中 —— 记 InfoQ 对青云QingCloud 联合创始人林源的采访...
- xcode3.2.6升级至4.0.2经验加教训总结(转)
- python元胞自动机模拟交通_结构专栏 | 解析DEFORM软件中的元胞自动机法
- Bootstrap 字体图标Glyphicons
- 加密+拜占庭将军_屡屡被提及拜占庭将军问题,究竟和比特币是什么关系?
- 客户端手册_增值税发票管理系统“2.0”版——客户端环境配置问题
- 机器学习基础算法32-隐马尔科夫模型HMM
- 廖雪峰python教程答案
- Java高级工程师面试总结
- NativeWindow_02_DialogBoxParam_VC6
- Linux下点阵汉字的字模读取与显示
- 解决“桌面右键单击文件夹鼠标一直转圈”
- py使用pie绘制饼图或圆环图
- python使用Future、async、await、wait、gather、ensure_future、as_completed
- SUNDIALS中的RTOL和ATOL
- BigDecimal.divide异常 ArithmeticException
- 常用方法——4.JS将yyyy-MM-dd HH-mm-ss格式日期转换成时间戳
- 如何在同一台电脑上保持两个文件夹的内容同步更新?