linux中对spin_lock的实现

来源:互联网 发布:在淘宝天猫买药靠谱吗 编辑:程序博客网 时间:2024/04/28 07:26

Spinlock在LINUX中的实现(linux-3.8为源码样本)


 

一、            Uniprocessor & SMP 中Spinlock实现概述

Spinlock在Uniprocessor中的实现比较简单,因为对于进程调度,单CPU不存在多个进程同时处于运行状态,并且同时对某块共享数据进行访问这样一种可能性。因此也就不需要实现“获取不到资源就在原地循环傻等”这样一个操作。对于CPU存在内核抢占机制的,则禁止内核抢占;否则退化为空操作。

Spinlock在SMP(Symmetric Multi-Processing)中的实现,就包括了在Uniprocessor中的“禁止内核抢占”操作,以及“获取不到资源就在原地循环傻等”两个步骤。

我们可以用一张图来做更直观的解释:


 

二、            源码解读

l  Uniprocessor

Ø  层次图。通常情况下,我们会调用spin_lock函数来实现加锁,而spin_lock函数经过几个层次的DEFINE之后,在uniprocessor相关的头文件中给出了实现:



 

在__LOCK中,有两个函数调用,一个是preempt_disable(),用于禁止内核抢占的;一个是__acquire(lock),用于申请一个锁的。第三个实际上是一个空函数,正如我们在第一部分分析的,不需要做循环机制。

 

Ø  Preempt_disable()解读


可以看到,preempt_disable()就是将一个当前线程的某个变量加了一,原因是:

每个进程的thread_info引入了 preempt_count(threadinfo.preemptcount)计数器。该计数器初始值为0,每当使用锁的时候数值加1,释放锁的时候数值减1。当数值为0的时候,内核就可执行抢占。从中断返回内核空间的时候,内核会检查flag和preempt_count的值。如果flag中TIFNEEDRESCHED被设置,并且preempt_count为0的话,这说明有一个更为重要的任务需要执行并且可以安全地抢占,此时,调度程序就会调度(抢占当前进程)。如果preempt_count不为0,说明当前任务持有锁,所以抢占是不安全的。这时,就会像通常那样直接从中断返回当前执行进程。如果当前进程所持有的所有的锁都被释放了。

那么preemp_tcount就会重新为0此时,释放锁的代码会检查needresched

是否被设置。如果是的话,就会调用调度程序。有些内核代码需要允许或禁止内核抢占。

Ø  解锁

解锁过程与加锁过程类似,几乎可以对照以上的内容找到相应的代码,以及给出解释,因此这里就不贴源码了。

l  SMP

Ø  层次图+粗略讲解(由于层次结构比较复杂,就不画简略版了,直接在原图上通过引箭头的方式表明)


可以看到,对于SMP系统,禁止内核抢占部分和Uniprocessor是一样的,DEBUG相关的一些函数可以暂时不看,关注主线函数,对于spinlock的实现,是arch_spin_lock(&lock->raw_lock)函数负责的,这是一个体系结构相关的函数,不同体系结构对其有着各自的写法。接下来以X86为例。

 

Ø  Arch_spin_lock(&lock->raw_lock)X86版本解读


在阅读源码的时候发现,linux-3.13中对这一部分的实现,和linux-3.8有一些差别,但差别不很大。主要是对for循环的时间做出了限制:


0 0
原创粉丝点击