当前位置: 首页 > 图文教程 > 操作系统 > Unix/Linux > 详谈Linux 2_4_x内核信号量机制

Unix/Linux
mysql+httpd+gd+php+zend
automake 小回顾
unix黑客精神的最好诠释
www
sun t3存储的设置
RPM简明中文手册
Linux爱好者入门教程 序章 (持续更新)
第一章 Linux基础知识 (飘心)
linux下进程与线程
浅谈如何学习linux
第二章 Linux安装
硬件安装指南
Windows 2000 的桌面不見了的解決方法
部分的ADSL路由器默认帐号密码
如何设定安全log服务器呢?
iptables 规则速查
网友学习 Linux 的七点忠告
sniffer的含义及原理
Linux编程白皮书 第二章 内存管理
Linux编程白皮书 第二章 内存管理 2.1.1 请求调页 --2.1.5 访问控制

Unix/Linux 中的 详谈Linux 2_4_x内核信号量机制


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-11-01   浏览: 128 ::
收藏到网摘: n/a

信号量作为一种同步机制,在每个成熟的现代操作系统的实现过程中,起着不可替代的作用,对于Linux也不例外,在Linux2_4_x下,实现内核信号量机制的代码虽然不长,但由于涉及到多个进程间的相互干扰,并且在Linux发展过程中,不断进行优化,所以非常难于理解,在讲解Linux源代码的各类文章中,也大都对此语焉不详,本人通过认真阅读,对这部分代码有了一定的了解,这里介绍出来,希望对大家有所帮助。
信号量作为一种同步机制,在每个成熟的现代操作系统的实现过程中,起着不可替代的作用,对于Linux也不例外,在Linux2_4_x下,实现内核信号量机制的代码虽然不长,但由于涉及到多个进程间的相互干扰,并且在Linux发展过程中,不断进行优化,所以非常难于理解,在讲解Linux源代码的各类文章中,也大都对此语焉不详,本人通过认真阅读,对这部分代码有了一定的了解,这里介绍出来,希望对大家有所帮助。 首先看看信号量的概念: 1.信号量的类型定义: 每个信号量至少须记录两个信息:信号量的值和等待该信号量的进程队列。它的类型定义如下:(用类PASCAL语言表述) semaphore = record value: integer; queue: ^PCB; end; 其中PCB是进程控制块,是操作系统为每个进程建立的数据结构。s.value>=0时,s.queue为空; s.value<0时,s.value的绝对值为s.queue中等待进程的个数; 2.PV原语: 对一个信号量变量可以进行两种原语操作:p操作和v操作,定义如下: procedure p(var s:samephore); { s.value=s.value-1; if (s.value<0) asleep(s.queue); } procedure v(var s:samephore); { s.value=s.value+1; if (s.value<=0) wakeup(s.queue); } 其中用到两个标准过程: asleep(s.queue);执行此操作的进程的PCB进入s.queue尾部,进程变成等待状态wakeup(s.queue);将s.queue头进程唤醒插入就绪队列。s.value初值为1时,可以用来实现进程的互斥。p操作和v操作是不可中断的程序段,称为原语。如果将信号量看作共享变量,则pv操作为其临界区,多个进程不能同时执行,一般用硬件方法保证。一个信号量只能置一次初值,以后只能对之进行p操作或v操作。 再来看看在对应的Linux2.4.x具体实现中,信号量的数据结构: struct semaphore { atomic_t count; int sleepers; wait_queue_head_t wait; };可以看到相对于操作系统原理中的定义,数据结构多了一个sleepers成员,这个变量是为使主要分支代码执行速度更快,所作的优化。 其中,count相当于资源计数,为正数或0时表示可用资源数,-1则表示没有空闲资源且有等待进程,而其他的负数仅仅一个中间过程,当所有进程都稳定下来后,将最终变为-1。 sleepers相当于一个状态标志,它仅有0和1两个值,有时会出现2,但也只是中间状态,并没有实际意义。当sleepers为0时,表示没有进程在等待,或等待中的这些进程正在被唤醒过程中。当sleepers为1时,表示至少有一个进程在等待中 wait是等待队列。 在这里可以看到,等待进程的数量并不被关心。 下面我们来看函数,Linux2.4.x具体实现中,down()函数相当于p操作,up()函数相当于v操作。在down()函数中,count做原子减1操作,如果结果不小于0[第4行],则表示成功申请,从down()中返回,如果结果为负(大多数情况是-1,注意判断“结果不小于0”的原因,是因为结果有可能是其他负数),表示需要等待,则调用__down_fail()[第7行],(include/asm-i386/semaphore.h):static inline void down(struct semaphore * sem){1 __asm__ __volatile__(2 # atomic down operation\n\t"3 LOCK "decl %0\n\t" /* --sem->count */4 "js 2f\n"5 "1:\n"6 ".section .text.lock,\"ax\"\n"7 "2:\tcall __down_failed\n\t"8 "jmp 1b\n"9 ".previous"10 :"=m" (sem->count)11 :"c" (sem)12 :"memory");}__down_fail()调用__down(),(arch/i386/kernel/semaphore.c):asm(".text\n"".align 4\n"".globl __down_failed\n""__down_failed:\n\t"13 "pushl %eax\n\t"14 "pushl %edx\n\t"15 "pushl %ecx\n\t"16 "call __down\n\t"17 "popl %ecx\n\t"18 "popl %edx\n\t"19 "popl %eax\n\t"20 "ret");__down()用C代码实现。(arch/i386/kernel/semaphore.c):void __down(struct semaphore * sem){21 struct task_struct *tsk = current;22 DECLARE_WAITQUEUE(wait, tsk);23 tsk->state = TASK_UNINTERRUPTIBLE;24 add_wait_queue_exclusive(&sem->wait, &wait);2526 spin_lock_irq(&semaphore_lock);27 sem->sleepers++;28 for (;;) {29 int sleepers = sem->sleepers;3031 /*32 * Add "everybody else" into it. They aren't33 * playing, because we own the spinlock.34 */35 if (!atomic_add_negative(sleepers - 1, &sem->count)) {36 sem->sleepers = 0;37 break;38 }39 sem->slee