linux内核 semaphore,2.4内核里semaphore源码的一个疑问
博主你好, 请教一个问题.
__down()里面有一段代码, 我觉得不那么保险.我先把__down的源码贴出来:
=============================================
void __down(struct semaphore * sem)
{
struct task_struct *tsk = current;
DECLARE_WAITQUEUE(wait, tsk); //定义一个"队列项", 等待者是当前进程
tsk->state = TASK_UNINTERRUPTIBLE;
add_wait_queue_exclusive(&sem->wait, &wait); //把当前进程添加到该信号量的wait queue里.
spin_lock_irq(&semaphore_lock); //抓取"大锁"
sem->sleepers++;
for (;;) {
int sleepers = sem->sleepers;
/*
* Add "everybody else" into it. They aren't
* playing, because we own the spinlock.
*/
if (!atomic_add_negative(sleepers - 1, &sem->count)) { //临睡前最后一次尝试
sem->sleepers = 0;
break;
}
sem->sleepers = 1; /* us - see -1 above */
spin_unlock_irq(&semaphore_lock);
schedule(); //睡眠
tsk->state = TASK_UNINTERRUPTIBLE;
spin_lock_irq(&semaphore_lock);
}
spin_unlock_irq(&semaphore_lock);
remove_wait_queue(&sem->wait, &wait); //取得信号量后, 退出该信号量的等待队列
tsk->state = TASK_RUNNING;
wake_up(&sem->wait);
}
我也是这两天才开始读linux的源码. 我先说说我读到的一点经验. 2.4内核里的semaphore结构体里面没有lock字段, 整个semaphor.c里是共用一个文件域的大锁, 就是semaphore.c里定义的semaphore_lock. 每当要操作semaphore结构体之前, 就先抓取这个"全局锁".
但是up()操作的全程都没有理睬这把锁, 我很好奇, 会不会出现这样一种bug呢:
为了方便分析, 假设除了当前进程, 没有别的进程在竞争这个信号量.
刚才说到up()的全程都没理会"大锁", 所以在整个__down()的过程中, 别的cpu上, 随时可能会有一个up()平行的运行. up()最终调用的是wake_up_process().
=====================================
inline void wake_up_process(struct task_struct * p)
{
unsigned long flags;
/*
* We want the common case fall through straight, thus the goto.
*/
spin_lock_irqsave(&runqueue_lock, flags);
p->state = TASK_RUNNING; if (task_on_runqueue(p)) goto out;
add_to_runqueue(p);
reschedule_idle(p);
out:
spin_unlock_irqrestore(&runqueue_lock, flags);
}
===============================================
那么在__down()里面的这段区间,
add_wait_queue_exclusive(&sem->wait, &wait);
...
...
schedule();
也就是, current进入信号量排队之后, 调用schedule()之前, 我们随时可能遭受"wake_up_process()".
如果在if (!atomic_add_negative(sleepers - 1, &sem->count)) 这句之前被wake_up_process(), 倒也无所谓, 因为反正我们能通过这个if拿到信号量, (既然有人up, 肯定就是有门票了).
但是如果这个if失败, 我们就要睡眠了. 在我们调用schdule入睡之前的这个空隙里, 即执行这几行代码的时候:
sem->sleepers = 1; /* us - see -1 above */
spin_unlock_irq(&semaphore_lock);
schedule();
我们遭到了wake_up_process.
会发生什么呢? 其实看wake_up_process()的源码,它也做不了什么( 因为我们已经在运行队列里了 ), 但它把我们的状态设置成TASK_RUNNING了.
就是说, 接下来, 我们是以"TASK_RUNNING"的身份调用schedule的.
更坏的是, 我们等于说是错过了这次up(), 再没有人来唤醒我们了.
我上面说的很麻烦, 简单的说, 就是, up()为什么不理睬semaphore_lock这个锁? 明明会出bug.
我想是我哪里错了, linux肯定不会有这种bug.
恳请指教.
------------------------------------------------------------------------------
*
为了方便一些, 我把相关的源码都贴上:
== down()和up()的入口函数来自 include/asm-i386/semaphore.h
static inline void down(struct semaphore * sem)
{
#if WAITQUEUE_DEBUG
CHECK_MAGIC(sem->__magic);
#endif
__asm__ __volatile__(
"# atomic down operation\n\t"
LOCK "decl %0\n\t" /* --sem->count */
"js 2f\n"
"1:\n"
".section .text.lock,\"ax\"\n"
"2:\tcall __down_failed\n\t"
"jmp 1b\n"
".previous"
:"=m" (sem->count)
:"c" (sem)
:"memory");
}
static inline void up(struct semaphore * sem)
{
#if WAITQUEUE_DEBUG
CHECK_MAGIC(sem->__magic);
#endif
__asm__ __volatile__(
"# atomic up operation\n\t"
LOCK "incl %0\n\t" /* ++sem->count */
"jle 2f\n"
"1:\n"
".section .text.lock,\"ax\"\n"
"2:\tcall __up_wakeup\n\t"
"jmp 1b\n"
".previous"
:"=m" (sem->count)
:"c" (sem)
:"memory");
}
===fall through失败后的操作, 都在arch/i386/kernel/semaphore.c
asm(
".align 4\n"
".globl __down_failed\n"
"__down_failed:\n\t"
"pushl %eax\n\t"
"pushl %edx\n\t"
"pushl %ecx\n\t"
"call __down\n\t"
"popl %ecx\n\t"
"popl %edx\n\t"
"popl %eax\n\t"
"ret"
);
void __down(struct semaphore * sem)
{
struct task_struct *tsk = current;
DECLARE_WAITQUEUE(wait, tsk);
tsk->state = TASK_UNINTERRUPTIBLE;
add_wait_queue_exclusive(&sem->wait, &wait);
spin_lock_irq(&semaphore_lock);
sem->sleepers++;
for (;;) {
int sleepers = sem->sleepers;
/*
* Add "everybody else" into it. They aren't
* playing, because we own the spinlock.
*/
if (!atomic_add_negative(sleepers - 1, &sem->count)) {
sem->sleepers = 0;
break;
}
sem->sleepers = 1; /* us - see -1 above */
spin_unlock_irq(&semaphore_lock);
schedule();
tsk->state = TASK_UNINTERRUPTIBLE;
spin_lock_irq(&semaphore_lock);
}
spin_unlock_irq(&semaphore_lock);
remove_wait_queue(&sem->wait, &wait);
tsk->state = TASK_RUNNING;
wake_up(&sem->wait);
}
void __up(struct semaphore *sem)
{
wake_up(&sem->wait);
}
asm(
".align 4\n"
".globl __up_wakeup\n"
"__up_wakeup:\n\t"
"pushl %eax\n\t"
"pushl %edx\n\t"
"pushl %ecx\n\t"
"call __up\n\t"
"popl %ecx\n\t"
"popl %edx\n\t"
"popl %eax\n\t"
"ret"
);
*
这部分的内容在403页前后.
相关文章:

Android UI体验之全屏沉浸式透明状态栏效果
前言: Android 4.4之后谷歌提供了沉浸式全屏体验, 在沉浸式全屏模式下, 状态栏、 虚拟按键动态隐藏, 应用可以使用完整的屏幕空间, 按照 Google 的说法, 给用户一种 身临其境 的体验。而Android 5.0之后谷歌…

html 多项选择,选项标签中的HTML多字段选择
这可以通过switch语句实现,但这不是最好的方法。我建议将以下函数作为change事件的事件处理程序。您还需要在窗口加载时运行它,以初始化它。function updateSel() {var sel document.getElementById(sel);var hidden sel.getElementsByClassName(hidde…

tp5.0 queue 队列操作
检查是否安装redis(没有请自行百度安装): phpinfo: 配置thinkphp-queue,没有请执行 composer require topthink/think-queue 加入: 创建 队列 文件: use think\Queue;class TestQueue {// 测试public function queue()…

java redis管理_优雅时间管理Java轻松做到,想学么?
原标题:优雅时间管理Java轻松做到,想学么?来源 |http://rrd.me/gCQHp前言:需求是这样的,在与第三方对接过程中,对方提供了token进行时效性验证,过一段时间token就会失效.后台有定时任务在获取&a…

jenkins运行日志时间与linux,Jenkins 用户文档(运行多个步骤)
运行多个步骤管道由多个步骤组成,允许你构建、测试和部署应用程序,Jenkins管道允许你以简单的方式组成多个步骤,可以帮助你为任何类型的自动化过程建模。将“步骤”想象成执行单个操作的单个命令,当一个步骤成功时,它将…

HPU组队赛B:问题(二进制枚举)
时间限制1 Second 内存限制 512 Mb 题目描述 你有n个问题,你已经估计了第i个问题的难度为Ci,现在你想使用这些问题去构造一个问题集。比赛的问题集必须包含至少两个问题,而且比赛的总难度必须至少为l至多为r,此外最简单的问题和最难的问题之间的差异至少…

html脱机不显示图片,Python绘图脱机图表嵌入HTML(不工作)
aPlot是绘图文件的文件名。在在您的iframe中,您将.embed?width800&height550添加到文件名中,这将导致一个不存在的文件名。在当您删除这个字符串时,即src" aPlot ",它应该可以工作。在不必嵌入整个HTML文件&…

数据库分库分表(sharding)系列
数据库分库分表(sharding)系列转载于:https://www.cnblogs.com/gotodsp/p/6517478.html

php imagecopy 用法,php使用imagecopymerge()函数创建半透明水印
使用imagecopymerge() 函数创建半透明水印,供大家参考,具体内容如下// 加载要加水印的图像$im imagecreatefromjpeg(photo.jpeg);// 首先我们从 GD 手动创建水印图像$stamp imagecreatetruecolor(100, 70);imagefilledrectangle($stamp, 0, 0, 99, 69,…
linux系统yum源,Linux开启安装EPEL YUM源
我们用yum安装软件时,经常发现我们的yum源里面没有该软件,需要自己去wget,然后configure,make,make install,太折腾了。其实,CentOS还有一个源叫做 EPEL (Extra Packages for Enterprise),里面有1万多个软件࿰…

MATLAB简易验证码识别程序介绍
本推文主要识别的验证码是这种:第一步: 二值化所谓二值化就是把不需要的信息通通去除,比如背景,干扰线,干扰像素等等,只剩下需要识别的文字,让图片变成2进制点阵。第二步: 文字分割为了能识别出字符,需要对…

mac终端命令-----常规操作
OSX 的文件系统 OSX 采用的Unix文件系统,所有文件都挂在跟目录 / 下面,所以不在要有Windows 下的盘符概念。 你在桌面上看到的硬盘都挂在 /Volumes 下。 比如接上个叫做 USBHD的移动硬盘,桌面上会显示出一个硬盘图标,它实际在哪里…

php true true true,php-为什么此评估为true
标签:php乳清这算是真的吗?$val20;//outputs that is an error123if($val2error123){echo that is an error123;}else{echo that is not an error123;}解决方法:您正在将字符串与整数进行比较.为了进行比较,首先将字符串转换为整数.当“ error123”转换为…

一个html文件放到服务器访问,访问云服务器里面的html文件
弹性云服务器 ECS弹性云服务器(Elastic Cloud Server)是一种可随时自助获取、可弹性伸缩的云服务器,帮助用户打造可靠、安全、灵活、高效的应用环境,确保服务持久稳定运行,提升运维效率三年低至5折,多种配置可选了解详情建站入门|…

limbo可以运行linux,这次真的了,安卓手机可以安装 Windows 10 了
原标题:这次真的了,安卓手机可以安装 Windows 10 了上回雷锋哥给大家分享过「安卓可以体验 "Windows 10" 了」实际上就是一个第三方安卓桌面启动器模仿 Windows 10 的主题,所以只能说是美化,并非真的运行 Windows 10 系…

Fedora dnf配置
1、在配置文件/etc/dnf/dnf.conf中加入: fastestmirrortruekeepcachetrue这样下载安装软件就快多了。 2、dnf常用命令 检查并升级可用软件包:$ dnf update删除缓存:$dnf clean all列出可用的软件源:$ dnf repolist搜索软件:$ dnf search $…

2021梧州一中高考成绩查询,2021年广西高考成绩查询网站查分网址:https://www.gxeea.cn/...
【摘要】高考结束后大家最为关心的问题就是在哪里查分,如何查分,高考频道特别整理2021年广西高考成绩查询查分网址,成绩公布时考生可直接点击网址进行查分,预祝大家都能顺利的考上理想的大学!由于,各省级招…

php ip地址地区,PHP查询ip所在地(省份,市)
通过IP获取归属地图1 : 返回数据图2 : 查询成功如果喜欢的话,可以试试,几行代码就能搞定,我觉得还是挺实用的!!

描述一下 Intent 和 IntentFilter?
Android 中通过 Intent 对象来表示一条消息,一个 Intent 对象不仅包含有这个消息的目的地,还可以包含消息的内容,这好比一封 Email,其中不仅应该包含收件地址,还可以包含具体的内容。对于一个 Intent 对象,…

linux字符界面教程,打造字符界面的多媒体Linux系统
打造字符界面的多媒体Linux系统打造字符界面的多媒体Linux系统0 环境与目标硬件:ThinkPad R52笔记本一台。目标:字符界面的LINUX系统,同时可以看图片,听音乐,看视频,无线上网。1 系统安装1.1 最小安装系统官…

Linux 环境 搭建Git 服务器,并且修改SSH端口使用
1.环境配置说明 服务器 CentOS 7 git(git version 1.8.3.1) 客户端 Windows10 SourceTree 2.安装 Git 服务器端安装: sudo yum -y install git 查看安装版本 #git --version git version 1.8.3.1 客户端安装 下载 SourceTree for Window 下…

php发光字体代码,CSS3怎么实现字体发光效果
这次给大家带来CSS3怎么实现字体发光效果,CSS3实现字体发光效果的注意事项有哪些,下面就是实战案例,一起来看一下。博客页面左上角的“猿来是勇者”文字已制作发光效果,分享方法如下:该属性为文本添加阴影效果text-shadow:h-shado…

计算机专业英语chapter012,计算机专业英语 chapter_1.ppt
计算机专业英语 chapter_1Chapter 1 Information Technology, The Internet, and You;Competencies;Competencies能力,要求After you have read this chapter, you should be able to: Explain the five parts of an information system: people, procedures, softw…

C#与C++的区别
1,C#不支持多重继承,这是与C明显区别的地方,说真的多重继承有时候用起来挺麻烦的,可能微软怕你用不好吧,不给你提供了,但我个人觉得没有了多重继承感觉有点可惜。 2.在标准的C#安全代码中不支持指针类型的操作…

黑裙安装linux环境,Linux学习笔记(一) ---- 安装Linux系统
学习Linux的第一件事情,你得先有个Linux系统,才能知道怎么学吧?于是安装Linux是第一部,找网上找了不少教程,自己总结了一下,些一个博文先。我安装的Linux是在VMWare 7.2版本上安装的,安装的是Ret Hat Linux…

mybatis批量更新的两种实现方式
mapper.xml文件,后台传入一个对象集合,另外如果是mysql数据库,一点在配置文件上加上&allowMultiQueriestrue,这样才可以执行多条sql,以下为mysql: <update id"batchUpdate" parameterType…

php常用20函数,PHP常用函数
//PHP设置跨域header("Access-Control-Allow-Origin:*");//PHP设置JSON头 以JSON格式输出header("Content-type:application/json; charsetutf-8");//正则取字符串preg_match_all(/字符串(.*?)字符串/i,$data,$out);// PHP把JSON对象转字符串不转码输出js…

tcpdump保存数据包
1、启动tcpdump tcpdump 2、查看网卡 tcpdump -D 3. 抓取报文后隔指定的时间保存一次 tcpdump -i eth3 -s0 -G 60 -Z root -w %Y_%m%d_%H%M_%S.pcap 这里解释下-G选项 后面接时间 单位为秒 本例中的时间为60秒 4. 抓取报文后达到指定的大小保存一次 tcpdump -i eth3 -s0 -C 1 -…

在线翻译系统属于计算机应用领域中,【单选题】网状物编织物和机件上的滚花部分,可以在轮廓线附件用( )线示意画出...
参考答案如下单选【简答题】我决定明天五点起床。(ことになる・ことにする)题网【单选题】法律的规定:邀请招标,应向()个以上具备承担招标项目能力,资信良好的特定法人发出投标邀请书。状物轮【单选题】描述液体运动的方法不包括( )。编织部分【单选题】Everyone _________ on …

linux进行主机发现,linux – 网络上所有计算机的主机名发现
SSH不关心是否给出了要连接的主机名或IP地址(当有特定于主机的配置时,不确定是否适用).大多数MPI实现也不关心,例如在Open MPI连接中,URI地址都是数字,因此具有IP的主机文件可以正常使用.另一方面,HTTP服务器关心的是虚拟主机事件,其中许多不同站点解析为相同的IP地址,但服务器…