转自:https://blog.csdn.net/fzubbsc/article/details/37737159

参考:

https://blog.csdn.net/liuxd3000/article/details/17913363

http://blog.chinaunix.net/uid-25845340-id-3017214.html

https://blog.csdn.net/xiao229404041/article/details/7031776

查阅文件:

kernel\linux\linux-4.4.3\kernel\locking\semaphore.c

kernel\linux\linux-4.4.3\include\linux\semaphore.h

DOWN操作:linux内核中,对信号量的DOWN操作有如下几种:

1、void down(struct semaphore *sem); //不可中断

down接口用于请求一个信号量。此函数的调用将会到致调用线程的睡眠,  直到获取到信号。同时,该函数的调用不允许中断。
在此函数中首先进行信号量资源数的查看,如果信号量数据(count)不为0,则把其减1,并返回,调用成功;否则调用__down进行等待,调用者进行睡眠。

2、int down_interruptible(struct semaphore *sem);//可中断

该函数功能和down类似,不同之处为,down不会被信号(signal)打断,但down_interruptible能被信号打断,因此该函数有返回值来区分是正常返回还是被信号中断,如果返回0,表示获得信号量正常返回,如果被信号打断,返回-EINTR。

 

3、int down_killable(struct semaphore *sem);//睡眠的进程可以因为受到致命信号而被唤醒,中断获取信号量的操作。

down_killable与down_interruptible相近,最终传入的__down_common的实参有所不同(TASK_KILLABLE和TASK_INTERRUPTIBLE),所以,在此不再进行分析。

4、int down_trylock(struct semaphore *sem);//试图获取信号量,若无法获得则直接返回1而不睡眠。返回0则 表示获取到了信号量

down_trylock接口用于试着获取一个信号量,但是,此接口不会引起调用者的睡眠。不管有无可用信号量,都马上进行返回,如果返回0,则获取信号量成功,如果返回1,则获取失败。所以,在调用此接口时,必须进行返回的值的查看,看是否获取成功。

5、int down_timeout(struct semaphore *sem,long jiffies);//表示睡眠时间是有限制的,如果在jiffies指明的时间到期时仍然无法获得信号量,则将返回错误码。

down_timeout接口的实现过程与down接口的实现过程差不多,只是此接口 可以自定义超时时间,也就是如果在超时间内不能得到信号量,调用者会因为超时而自行唤醒。其实现过程如下,请注意超时参数的传入。其中TASK_UNINTERRUPTIBLE

在以上五种函数中,驱动程序使用的最频繁的就是down_interruptible函数,以下将对该函数进行分析。

down_interruptible函数的定义如下:

函数分析:函数首先通过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) 有着很重要的作用。

Note:一个进程在调用down_interruptible()之后,如果sem<0,那么就进入到可中断的睡眠状态并调度其它进程运行, 但是一旦该进程收到信号,那么就会从down_interruptible函数中返回。并标记错误号为:-EINTR。一个形象的比喻:传入的信号量为1好比天亮,如果当前信号量为0,进程睡眠,直到(信号量为1)天亮才醒,但是可能中途有个闹铃(信号)把你闹醒。又如:小强下午放学回家,回家了就要开始吃饭嘛,这时就会有两种情况:情况一:饭做好了,可以开始吃;情况二:当他到厨房去的时候发现妈妈还在做,妈妈就对他说:“你先去睡会,待会做好了叫你。”小强就答应去睡会,不过又说了一句:“睡的这段时间要是小红来找我玩,你可以叫醒我。”小强就是down_interruptible,想吃饭就是获取信号量,睡觉对应这里的休眠,而小红来找我玩就是中断休眠。

使用可被中断的信号量版本的意思是,万一出现了semaphore的死锁,还有机会用ctrl+c发出软中断,让等待这个内核驱动返回的用户态进程退出。而不是把整个系统都锁住了。在休眠时,能被中断信号终止,这个进程是可以接受中断信号的!比如你在命令行中输入# sleep 10000,按下ctrl + c,就给上面的进程发送了进程终止信号。信号发送给用户空间,然后通过系统调用,会把这个信号传给递给驱动。信号只能发送给用户空间,无权直接发送给内核的,那1G的内核空间,我们是无法直接去操作的。 --------------------- 本文来自 liuxd3000 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/liuxd3000/article/details/17913363?utm_source=copy

信号量机制中的down和up函数相关推荐

  1. Linux 内核 up down,信号量机制中的DOWN操作与UP操作详解

    DOWN操作:linux内核中,对信号量的DOWN操作有如下几种: void down(struct semaphore *sem); //不可中断 int down_interruptible(st ...

  2. aba问题mysql_解决CAS机制中ABA问题的AtomicStampedReference详解

    AtomicStampedReference是一个带有时间戳的对象引用,能很好的解决CAS机制中的ABA问题,这篇文章将通过案例对其介绍分析. 一.ABA问题 ABA问题是CAS机制中出现的一个问题, ...

  3. linux gpio信号量,执行完? OSIntExit(); 后,再进行任务调度,可是那两个任务都是在等待信号量啊,难道执行完中断函数后会释放一个信号量吗?...

    [mw_shl_code=c,true]/* ***************************************************************************** ...

  4. mysql数据刷盘_MySQL InnoDB 日志管理机制中的MTR和日志刷盘

    1.MTR(mini-transaction) 在MySQL的 InnoDB日志管理机制中,有一个很重要的概念就是MTR.MTR是InnoDB存储擎中一个很重要的用来保证物理写的完整性和持久性的机制. ...

  5. Neutrino追问AMA第20期 | Ultrain 郭睿:在RPoS共识机制中,核心是随机数和 BFT 算法

    在4月10日晚举行第的19期 Neutrino 追问 AMA中 ,我们邀请到了 Ultrain 联合创始人& CEO 郭睿.在社群交流中,郭睿表示,创新的共识机制随机可信证明机制(R-PoS) ...

  6. Attention机制中 Q、K、V分别从哪里来?

    在深度学习中,尤其是自然语言处理领域,Attention 机制已经成为一种非常重要的方法.它的核心思想是根据输入序列中的每个元素与当前元素的相关性来分配不同的权重,从而实现对输入序列的动态聚焦.在 A ...

  7. java 反射 getclass_JAVA反射机制中getClass和class对比分析

    搜索热词 java有两个获得类名的方法getClass()和class(),这两个方法看似一样,实则不然.这两个方法涉及到了java中的反射. 所谓反射,可以理解为在运行时期获取对象类型信息的操作.传 ...

  8. 通俗理解注意力机制中的Q、K和V表示的具体含义

    https://www.jianshu.com/p/7a61533fd73b 通俗理解讲解一 以翻译为例 source:我 是 中国人 target: I am Chinese 比如翻译目标单词为 I ...

  9. 注意力机制中的Q、K和V的意义

    以翻译为例: source:我 是 中国人 target: I  am Chinese 比如翻译目标单词为 I 的时候,Q为I 而source中的 "我"   "是&qu ...

最新文章

  1. spring实现listener(转)
  2. C# 控制台 模拟时间一秒一秒走动,直到按Esc键,时间静止,退出!
  3. rest 怎么发送html,docusignapi - 是否可以使用REST API中的HTML创建Docusign模板? - 堆栈内存溢出...
  4. 如何用 200 行 JavaScript 代码实现人脸检测?
  5. 强大的SqlCacheDependency【转】
  6. 【数据结构与算法】内部排序之一:插入排序和希尔排序的N中实现(不断优化,附完整源码)...
  7. params.c:Parameter() - Ignoring badly formed line in configuration file: ignore errors 解决方法
  8. Android图片拼接
  9. 3500元计算机基本硬件配置清单,电脑硬件中配配置清单
  10. Java从入门到精通章节练习题——第六章
  11. 公安专网与视频专网内使用离线互联网百度高德地图
  12. Nim游戏入门+SG函数
  13. dd指令打包iso文件 linux_Linux_如何在Linux操作系统下创建ISO镜像文件,1、用dd命令#dd if=/dev/cdrom - phpStudy...
  14. 【测试工具】如何制作指定大小的文件(包含可播放的视频或图片)
  15. Android系统版本与代号
  16. Crowd Counting by Adaptively Fusing Predictions from an Image Pyramid (BMVC2018)
  17. Unable to allocate xxx GiB for an array with shape (xxxx, xxxx)
  18. Knights CodeForces - 1221B
  19. matlab 生成plc程序,利用MATLABsimulink的自动代码生成工具开发PLC程序..docx
  20. Unity学习过程中的问题解答汇总(一)

热门文章

  1. 8.中学班级管理与教师心理
  2. 服务容错 - Hystrix
  3. 云崽部署问题解决贴:关于Yunzai-Bot部署后可能遇到的QQ版本过低问题||和一个puppeteer Chromium启动失效问题
  4. Nginx服务器启停命令
  5. 对C++库链接的认识
  6. 程序设计我爱你_如何用爱设计
  7. 计算机信息技术对医院医疗服务工作的影响,医院计算机信息化建设的发展与讨论...
  8. 新年促销扎堆,8个邮件营销方法打动你的客户
  9. J2ee学习流程(zz)
  10. 微信与支付宝钱包的竞争分析