信号量机制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) 它具有非常重要的数据。
版权声明:本文博主原创文章,博客,未经同意不得转载。
信号量机制DOWN操作和UP操作的详细说明的更多相关文章
- 【转】进程同步之信号量机制(pv操作)及三个经典同步问题
原文地址:http://blog.csdn.net/speedme/article/details/17597373 上篇博客中(进程同步之临界区域问题及Peterson算法),我们对临界区,临界资源 ...
- 锁机制(Lock) 信号量机制(Semaphore) 事件机制(Event)
IPC 进程间通信(inter-Process Communicate) 锁机制(Lock) l = Lock() 开启一个锁机制(实例化) 一把锁配一个钥匙 l.acquire() 获得钥匙 ...
- Linux高级调试与优化——信号量机制与应用程序崩溃
背景介绍 Linux分为内核态和用户态,用户态通过系统调用(syscall)进入内核态执行. 用户空间的glibc库将Linux内核系统调用封装成GNU C Library库文件(兼容ANSI &am ...
- RapidIO 逻辑层IO操作与Message操作的原理和区别
接上一篇 SRIO RapidIO (SRIO)协议介绍(一) 1 说明 查看协议手册时会发现,逻辑层的操作分成了IO和Message 2类动作,那么为什么要分成2类操作?从原理和应用角度来看 ...
- Python之路-(Django(csrf,中间件,缓存,信号,Model操作,Form操作))
csrf 中间件 缓存 信号 Model操作 Form操作 csrf: 用 django 有多久,我跟 csrf 这个概念打交道就有久了. 每次初始化一个项目时都能看到 django.middlewa ...
- python基础操作以及hdfs操作
目录 前言 基础操作 hdfs操作 总结 一.前言 作为一个全栈工程师,必须要熟练掌握各种语言...HelloWorld.最近就被"逼着"走向了python开发之路, ...
- [WCF编程]10.操作:单向操作
一.单向操作概述 WCF提供了单向操作,一旦客户端调用,WCF会生成一个请求,但没有相关的应答信息返回给客户端.所以,单向操作是不能有返回值,服务抛出的任何异常都不会传递给客户端. 理想情况下,一旦客 ...
- Linq查询操作之聚合操作(count,max,min,sum,average,aggregate,longcount)
在Linq中有一些这样的操作,根据集合计算某一单一值,比如集合的最大值,最小值,平均值等等.Linq中包含7种操作,这7种操作被称作聚合操作. 1.Count操作,计算序列中元素的个数,或者计算满足一 ...
- Linq查询操作之排序操作
在Linq中排序操作可以按照一个或多个关键字对序列进行排序.其中第一个排序关键字为主要关键字,第二个排序关键字为次要关键字.Linq排序操作共包含以下5个基本的操作. 1.OrderBy操作,根据排序 ...
- Linq查询操作之投影操作
投影操作,乍一看不知道在说啥.那么什么是投影操作呢?其实就是Select操作,名字起的怪怪的.和Linq查询表达式中的select操作是一样的.它能够选择数据源中的元素,并指定元素的表现形式.投影操作 ...
随机推荐
- main thread starting…
例的结果,下面的: main thread starting- Thrad 2 staring- Thrad 2 end- Thrad 4 staring- Thrad 4 end- Thrad 1 ...
- SQLSERVER PRINT语句的换行
原文:SQLSERVER PRINT语句的换行 SQLSERVER PRINT语句的换行 想在输出的PRINT语句里面换行,可以这样做 /* SQL的换行 制表符 CHAR(9) 换行符 CHAR( ...
- 举例说,Linux核心名单(两)
使用列表 我认为最好的方式,成为熟悉的核心列表功能是看一些简单的例子,素材去更好的理解链表. 以下是一个样例.包括创建.加入.删除和遍历链表. <span style="font-si ...
- 摆弄【Nhibernate 协会制图--导乐陪伴分娩】
现有两个实体,Dog和 Master,映射到数据库表中如上图所看到的.一个Dog仅仅同意相应一个Master,但一个Master能够有多个Dog.我们在查询Dog的时候.往往还须要知道其主人Maste ...
- Flex入门(三)——微架构之Cairngorm
大家都知道我们在开发后台的时候,都会使用MVC,三层等分层架构,使后台代码达到职责更为分明单一,高内聚低耦合,比如,Dao层仅仅是进行和数据库打交道,负责处理数据:Service(B层)仅仅是进行逻辑 ...
- POJ3581:Sequence(后缀数组)
Description Given a sequence, {A1, A2, ..., An} which is guaranteed A1 > A2, ..., An, you are to ...
- Android L SDK -- 一些有趣的新功能
一些普通的就不提了,自己查看最新的文档就可以 文档地址 Task locking 功能:让我们在使用一个应用时,能够免受通知(消息)的打搅. 怎样使用:当我们在应用中激活任务锁模式.我们接收到的通知( ...
- Java 理论与实践: 正确使用 Volatile 变量(转)
Java 语言中的 volatile 变量可以被看作是一种 “程度较轻的 synchronized”:与 synchronized 块相比,volatile 变量所需的编码较少,并且运行时开销也较少, ...
- poj 1456 Supermarket(并查集维护区间)
题意:有一些货物,每一个货物有价值和卖出的截至日期,每天能够卖一个货物,问能卖出的最大价值是多少. 思路:算法不难想到,按价值降序排列.对于每一件货物,从deadline那天開始考虑.假设哪天空 ...
- 一个关于Linux Bridge配置的吐嘈
话说有些事情十分适合在放假前的一天折腾一天,但绝对不适合在你准备去吃饭前多看一眼...我上周就碰到了这么一件揪心的事,终于以低血糖收场.十分狼狈地四处觅食,却觅到了一包超级辣的鸡爪.吃完后感觉症状加重 ...