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页前后.
linux内核 semaphore,2.4内核里semaphore源码的一个疑问相关推荐
- 【内核配置】六、修改内核自带的的LCD驱动源码并编译进内核 | 烧写到Mini2440__TD35 完整攻略...
主 机:VMWare--Ubuntu-16.04.2-x64-100ask 开发板:Mini2440--256M NandFlash, 2M NorFlash, 64M SDRAM, LCD-TD ...
- CentOS 升级内核的三种方式(yum/rpm/源码)
CentOS 升级内核的三种方式(yum/rpm/源码) 在 CentOS 使用过程中,难免需要升级内核,但有时候因为源码编译依赖问题,不一定所有程序都支持最新内核版本,所以以下将介绍三种升级内核方式 ...
- Thinkphp内核无限坐席在线客服系统源码
简介: Thinkphp内核无限坐席在线客服系统源码,直接一键安装的,启动两个端口就行了,安装倒是简单 网盘下载地址: http://pan.zijiepan2.xyz/zJsKwfQH7Gb0 图片 ...
- 最新ThinkPHP内核全行业小程序运营管理系统源码 DIY布局 一键生成小程序
介绍: ThinkPHP内核全行业小程序运营管理系统源码 自由DIY布局 一键生成小程序,内附安装说明 无需编程,各行业模版直接套用,一键生成,轻松搭建小程序 界面自由DIY,打造个性小程序 可拖拽式 ...
- 易优CMS内核儿童教育培训机构网站模板源码
正文: 易优cms内核儿童教育培训机构网站模板源码,PC+手机版,带后台.模板基于EyouCMS内核制作,模板编码为UTF8,适合行业:学校教育培训类企业,有兴趣的自行去体验吧. 程序: wwvdd. ...
- Thinkphp内核高仿拼多多拼团源码 完美运营级商城系统
Thinkphp内核高仿拼多多拼团源码 完美运营级商城系统 可封装APP 多用户 完美运营级商城系统支持商家入驻,是目前来说最新微信拼团系统.完美运营版,带详细配置教程! 运行环境:php+mysql ...
- ThinkPHP内核全行业小程序运营管理系统源码免费分享下载
ThinkPHP内核全行业小程序运营管理系统源码 界面自由DIY,打造个性小程序 可拖拽式DIY布局,开启自定义功能新征程,无需繁琐操作,轻松拖拽即可实现界面布局:同步实时预览,可视化操作让您所见即所 ...
- 帝国CMS内核在线听小说听书网源码
红色风格的帝国CMS内核在线听小说听书网源码,有声读物在线收听和下载,带PC+手机WAP端 PC端: 手机端: 下载地址:www.sucaihuo.com/source/1618-
- php内核自动采集电影影视网站系统源码
介绍: ThinkPHP5内核自动采集电影影视网站系统源码 完全放开双手自动采集 网盘下载地址: http://kekewangLuo.cc/mKwFQsP6yzA 图片:
最新文章
- 自己动手写简单的web应用服务器(4)—利用socket实现文件的下载
- HTTP学习笔记(1)
- pytorch的梯度计算以及backward方法
- opengl加载显示3D模型lwx类型文件
- 陕西专科学校王牌计算机专业,陕西省高职专科院校排名+王牌专业
- 前端学习(2252)推送代码
- js原生popup_JavaScript的popup框
- rabbitmq 学习-2-安装
- centos7 搭建keepalived+Nginx+tomcat
- 开源项目面试重要吗_开源是最重要项目的骨干
- 化工原理物性参数_化工原理
- 怎样将GIS图形复制到Windows剪贴板,粘贴到Word中
- python cv2.resize_Python OpenCV 图像缩放 cv2.resize 方法
- 选中一行的快捷键_常用文字编辑快捷键,学会之后,天天可以提前下班
- 八大编程语言之父:爸爸们节日快乐!
- 数字图像处理 冈萨雷斯 资源下载
- warning.js?d96e:34 Warning: You cannot set a form field before rendering a field associated with the
- Jenkins_Docker
- RSA实现对文件的加密解密
- 文件夹批量改名,将文件夹名称小写字母转为大写字母
热门文章
- Linux服务器部署ssl证书教程,linux服务器在wdcp面板安装ssl证书教程
- java udp tcp协议_【java】TCP和UDP传输协议
- html画三个重叠的矩形,html5 实现两个矩形的叠加
- python html解析查找字符串_用python的BeautifulSoup分析html
- signature=680da11b802226668317d65ae7c38eb7,encryption with designated verifiers
- java后台分页插件怎么写_Java分页技术(从后台传json到前台解析显示)
- python dump函数_python中实现php的var_dump函数功能
- u-charts 曲线图中间有部分没数据,导致点和点无法连成线的问题解决
- 样式集(二) 信息填写样式模板
- Xcode可重用代码块code snippets