博主你好, 请教一个问题.

__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源码的一个疑问相关推荐

  1. 【内核配置】六、修改内核自带的的LCD驱动源码并编译进内核 | 烧写到Mini2440__TD35 完整攻略...

    主   机:VMWare--Ubuntu-16.04.2-x64-100ask 开发板:Mini2440--256M NandFlash, 2M NorFlash, 64M SDRAM, LCD-TD ...

  2. CentOS 升级内核的三种方式(yum/rpm/源码)

    CentOS 升级内核的三种方式(yum/rpm/源码) 在 CentOS 使用过程中,难免需要升级内核,但有时候因为源码编译依赖问题,不一定所有程序都支持最新内核版本,所以以下将介绍三种升级内核方式 ...

  3. Thinkphp内核无限坐席在线客服系统源码

    简介: Thinkphp内核无限坐席在线客服系统源码,直接一键安装的,启动两个端口就行了,安装倒是简单 网盘下载地址: http://pan.zijiepan2.xyz/zJsKwfQH7Gb0 图片 ...

  4. 最新ThinkPHP内核全行业小程序运营管理系统源码 DIY布局 一键生成小程序

    介绍: ThinkPHP内核全行业小程序运营管理系统源码 自由DIY布局 一键生成小程序,内附安装说明 无需编程,各行业模版直接套用,一键生成,轻松搭建小程序 界面自由DIY,打造个性小程序 可拖拽式 ...

  5. 易优CMS内核儿童教育培训机构网站模板源码

    正文: 易优cms内核儿童教育培训机构网站模板源码,PC+手机版,带后台.模板基于EyouCMS内核制作,模板编码为UTF8,适合行业:学校教育培训类企业,有兴趣的自行去体验吧. 程序: wwvdd. ...

  6. Thinkphp内核高仿拼多多拼团源码 完美运营级商城系统

    Thinkphp内核高仿拼多多拼团源码 完美运营级商城系统 可封装APP 多用户 完美运营级商城系统支持商家入驻,是目前来说最新微信拼团系统.完美运营版,带详细配置教程! 运行环境:php+mysql ...

  7. ThinkPHP内核全行业小程序运营管理系统源码免费分享下载

    ThinkPHP内核全行业小程序运营管理系统源码 界面自由DIY,打造个性小程序 可拖拽式DIY布局,开启自定义功能新征程,无需繁琐操作,轻松拖拽即可实现界面布局:同步实时预览,可视化操作让您所见即所 ...

  8. 帝国CMS内核在线听小说听书网源码

    红色风格的帝国CMS内核在线听小说听书网源码,有声读物在线收听和下载,带PC+手机WAP端 PC端: 手机端: 下载地址:www.sucaihuo.com/source/1618-

  9. php内核自动采集电影影视网站系统源码

    介绍: ThinkPHP5内核自动采集电影影视网站系统源码 完全放开双手自动采集 网盘下载地址: http://kekewangLuo.cc/mKwFQsP6yzA 图片:

最新文章

  1. 自己动手写简单的web应用服务器(4)—利用socket实现文件的下载
  2. HTTP学习笔记(1)
  3. pytorch的梯度计算以及backward方法
  4. opengl加载显示3D模型lwx类型文件
  5. 陕西专科学校王牌计算机专业,陕西省高职专科院校排名+王牌专业
  6. 前端学习(2252)推送代码
  7. js原生popup_JavaScript的popup框
  8. rabbitmq 学习-2-安装
  9. centos7 搭建keepalived+Nginx+tomcat
  10. 开源项目面试重要吗_开源是最重要项目的骨干
  11. 化工原理物性参数_化工原理
  12. 怎样将GIS图形复制到Windows剪贴板,粘贴到Word中
  13. python cv2.resize_Python OpenCV 图像缩放 cv2.resize 方法
  14. 选中一行的快捷键_常用文字编辑快捷键,学会之后,天天可以提前下班
  15. 八大编程语言之父:爸爸们节日快乐!
  16. 数字图像处理 冈萨雷斯 资源下载
  17. warning.js?d96e:34 Warning: You cannot set a form field before rendering a field associated with the
  18. Jenkins_Docker
  19. RSA实现对文件的加密解密
  20. 文件夹批量改名,将文件夹名称小写字母转为大写字母

热门文章

  1. Linux服务器部署ssl证书教程,linux服务器在wdcp面板安装ssl证书教程
  2. java udp tcp协议_【java】TCP和UDP传输协议
  3. html画三个重叠的矩形,html5 实现两个矩形的叠加
  4. python html解析查找字符串_用python的BeautifulSoup分析html
  5. signature=680da11b802226668317d65ae7c38eb7,encryption with designated verifiers
  6. java后台分页插件怎么写_Java分页技术(从后台传json到前台解析显示)
  7. python dump函数_python中实现php的var_dump函数功能
  8. u-charts 曲线图中间有部分没数据,导致点和点无法连成线的问题解决
  9. 样式集(二) 信息填写样式模板
  10. Xcode可重用代码块code snippets