LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 2295|回复: 0

关于内核中spinlock的一些个人理解

[复制链接]
发表于 2004-1-11 22:29:59 | 显示全部楼层 |阅读模式
在这里,我主要把自己对内核中spinlock的一些理解写出来,并不是要告诉大家什么(因为我对我所说的也不能确定),而是希望大家对我的这些理解对的地方给我肯定,错误的地方给我指出。

和spinlock相关的文件主要有两个,一个是include/linux/spinlock.h,主要是提供关于和硬件无关的spinlock的几个对外主函数,一个是include/asm-XXX/spinlock.h,用来提供和硬件相关的功能函数。另外,在2.6的内核中,又多了一个文件,include/linux/preempt.h,为新增加的抢占式多任务功能提供一些服务。

spinlock的作用:spinlock系列函数主要用于保护临界数据(非常重要的数据)不被同时访问(给临界数据加锁),用以达到多任务的同步。如果一个数据当前不可访问,那么就一直等,直到可以访问为止。

spinlock函数的使用前提:首先,spinklock函数只能使用在内核中,或者说只能使用在内核状态下,在2.6以前的内核是不可抢占的,也就是说,当运行于内核状态下时,是不容许切换到其他进程的。而在2.6以后的内核中,编译内核的时候多了一个选项,可以配置内核是否可以被抢占,这也就是为什么在2.6的内核中多了一个preempt.h的原因。

spinlock主要包含以下几个函数:
spin_lock
spin_unlock
spin_lock_irqsave
spin_lock_irq
spin_unlock_irqrestore
spin_unlock_irq
另外还有其他很多,如关于读者写者的一套函数,关于bottom half一套函数(关于bottom half的代码我还没有读到),还有还提供了一套用bit实现加锁的函数,由于大概意思都相同,所以我这里就不说了(只想简单说说,没想到东西还挺多,我的手都快冻僵了,江南的冬天真的受不了:)
spinlock函数根据机器的配置分为两套,单CPU和多CPU,先来看看单CPU的情况。
在单CPU的情况下,spin_lock和spin_unlock函数都被定义成空操作(do { } while(0)),这是因为我们上面说的,内核不可以被抢占的原因。所以,在单CPU的情况下,只要你能够保证你要保护的临界数据不会在中断中用到的话,那么你的数据已经是受保护的了,不需要做任何操作。在2.6内核中,这两个函数就不再这么简单了,因为内核也有可能被其他程序中断,所以要保护数据,还要让调度程序暂时不调度此段程序,也就是说,暂时禁止抢占式任务调度功能,所以在上面两个函数中分别多了一个preempt_disable和preempt_enable调用。spin_lock_irq的功能和上面的spin_lock提供的功能差不多,只不过它还多做了一步,就是把中断也关上,主要用于当前保护的数据在可能的中断程序中也要用到的情况。spin_lock_irqsave和spin_lock_irq的功能一样,只不过调用这个函数以后可以把当前的中断状态记下了,以备以后恢复。

在多CPU的环境下情况就比较复杂了,因为同时可能有几个程序在运行(是真正的同时),所以必须要定义一个变量当作锁的功能,linux是这样规定的,当这个变量为1时,那么其保护的变量可以被访问,当其值为0时,那么其保护的临界数据不可以被访问,其中,要改变变量锁的值也很有学问,就是不能让几个CPU同时去改,负责就会出现不同步的情况。如spin_lock在多cpu的时候就被定义成下面的代码
#define spin_lock_string \
        "\n1:\t" \
        "lock ; decb %0\n\t" \
        "js 2f\n" \
        LOCK_SECTION_START("") \
        "2:\t" \
        "rep;nop\n\t" \
        "cmpb $0,%0\n\t" \
        "jle 2b\n\t" \
        "jmp 1b\n" \
        LOCK_SECTION_END
其中,改变变量锁的值通过在decb %0命令前加一个lock前缀以达到禁止其他CPU运行的目的。这段程序的目的就是监测变量锁的值,看其是否为1,如果是,使其为0,加锁成功,不是就一直循环直到条件满足为止(这段代码我也不太清楚,对gas的语法我还学的不是很透彻,不过大概意思应该是这样的)。看明白这个其他的就很好理解了,基本上都和单CPU的情况一样。

spinlock函数的代码还是很简单的,最主要是会用,比如在内核代码中为什么用spin_lock_irqsave而不用spin_lock_irq或spin_lock函数?这其中往往隐藏着很多东西,在读内核代码的时候如果能注意到这些细节的地方,对你看懂内核代码可能会起着事倍功半的作用,对此我身有体会。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表