Chinaunix首页 | 论坛 | 博客
  • 博客访问: 19076
  • 博文数量: 15
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 45
  • 用 户 组: 普通用户
  • 注册时间: 2015-06-23 14:19
个人简介

我要成为多面手!

文章分类
文章存档

2015年(15)

我的朋友

分类: LINUX

2015-11-12 17:28:21

Linux内核锁主要有自旋锁和信号量这两种。

自旋锁的概念:
    在执行功能单元之前,如果调用了自旋锁获取函数,并且没有其他功能单元在保持该锁,那么该执行单元则会立即获取该锁;倘若有其他执行单元,正在保持该锁,则该正在获取锁操作的执行单元将会保持自旋的状态,直到锁保持单元释放了该锁为止。另强调一点:所谓自旋,即为忙循环,该操作不会引起调用者睡眠。

自旋锁的目的:
    自旋锁是为了防止多处理器并发而引入的一种锁,它在内核中,大量应用于中断处理部分。而对于单处理器来说,防止中断中的并发,可以简单地采用关闭中断的方式,即在标志寄存器中打开或者关闭中断标志位,不需要自旋锁。 

自旋锁API:
    struct spinlock lock;    //声明一个锁lock

点击(此处)折叠或打开

  1. typedef struct spinlock {
  2.     union {
  3.         struct raw_spinlock rlock;
  4.     };
  5. } spinlock_t;

  6. typedef struct raw_spinlock {
  7.     arch_spinlock_t raw_lock;
  8. } raw_spinlock_t;

  9. typedef struct {
  10.     volatile unsigned int lock;
  11. } arch_spinlock_t
    我把里面的DEBUG预编译都删了,层层剥开spinlock结构体,原来就是一个volatile unsigned int 数据,内核真是千回百转,然而细细去追寻,却也别有一番回味。   

     spin_lock_init(lock)    //该函数用于初始化自旋锁lock

点击(此处)折叠或打开

  1. #define spin_lock_init(_lock) \
  2. do { \
  3.     spinlock_check(_lock); \
  4.     raw_spin_lock_init(&(_lock)->rlock); \
  5. } while (0)
    第一层,可见,原来spin_lock_init()是一个宏定义,“\”是续行符。那么再看do {} while(0)循环,很有意思,while(0)中,0为FALSE,在很多的操作系统内核源码中,都是以  #define FALSE 0   #define TRUE 1  的方式定义的。那么这个循环,就是直接退出循环咯,至于为什么会这样,有可能是历史原因,也有可能是出于对未来的考虑了,哈哈。
    言归正传,spinlock_check(_lock)这一步,就是返回_lock参数,在源码中,暂时没见更大的用处。

点击(此处)折叠或打开

  1. static inline raw_spinlock_t *spinlock_check(spinlock_t *lock)
  2. {
  3.     return &lock->rlock;
  4. }
    那么就运行raw_spin_lock_init();

点击(此处)折叠或打开

  1. # define raw_spin_lock_init(lock)                \
  2.     do { *(lock) = __RAW_SPIN_LOCK_UNLOCKED(lock); } while (0)

  3. #define __RAW_SPIN_LOCK_UNLOCKED(lockname)    \
  4.     (raw_spinlock_t) __RAW_SPIN_LOCK_INITIALIZER(lockname)

  5. #define __RAW_SPIN_LOCK_INITIALIZER(lockname)    \
  6.     {                    \
  7.     .raw_lock = __ARCH_SPIN_LOCK_UNLOCKED,    \
  8.     SPIN_DEBUG_INIT(lockname)        \
  9.     SPIN_DEP_MAP_INIT(lockname) }

  10. # define SPIN_DEBUG_INIT(lockname)
  11. # define SPIN_DEP_MAP_INIT(lockname)

  12. #define __ARCH_SPIN_LOCK_UNLOCKED { }
    观察这段整理后的代码,可见,其实raw_spin_lock_init这个宏,就是在初始化raw_lock为_ARCH_SPIN_LOCK_UNLOCKED,也就是未加锁的状态吗?可是,看到这个宏定义为什么是空的呢?前面说到过,对于单处理器来说,不需要用到自旋锁,那么的话,这个很可能就是传说中的单内核的代码,就是不需要用到自旋锁的。
    这里补充一点,所谓多核处理器就是SMP(Symmetrical Multi-Processing),即为对称多核处理器。而单核处理器是UP(Uni-Processor)。看到这里,我才发现,自己看了UP下的自旋锁代码,不过没关系,既来之则安之,继续往下看。


    spin_lock(lock);         //获得自旋锁lock,只有获得后才会返回,否则自旋

点击(此处)折叠或打开

  1. static inline void spin_lock(spinlock_t *lock)
  2. {
  3.     raw_spin_lock(&lock->rlock);
  4. }

  5. #define raw_spin_lock(lock)    _raw_spin_lock(lock)

  6. #define _raw_spin_lock(lock)            __LOCK(lock)

  7. #define __LOCK(lock) \
  8.   do { preempt_disable(); __acquire(lock); (void)(lock); } while (0)

  9. /*about preempt_disable()*/
  10. #define preempt_disable()        do { } while (0)

  11. /*about __acquire()*/
  12. # define __acquire(x) (void)0
    在这里,我们可以看到从raw_spin_lock()开始一系列的宏定义中,整个spin_lock的过程中,似乎都没干什么事。然而,在__acquire(lock); (void)(lock); 这两步中,虽然什么都没有做,但是其有一个地方值得我们关注,就是(void)0,这行语句的作用,大概是为了迎合编译器的需要吧,这是个人理解,如果有不对的地方,还请赐教。

    spin_trylock(lock);     //尝试获得自旋锁lock,成功获得返回真,否则返回假
    spin_unlock(lock);     //释放自旋锁lock
    至于以上两个接口,在UP下的内核代码中,也与spinlock大同小异,基本上也是以相似的代码,啥也没干,有兴趣可以自己去看看。这篇blog写到这里,好像啥也没说。。。um,不过,既然写了就不删了,毕竟知道了UP下的自旋锁的代码形式,对我看SMP的代码也是有莫大助益的,哈哈,接下来就继续兴致盎然地真正研究下SMP的自旋锁代码了。

    

点击(此处)折叠或打开

  1. static inline void spin_lock(spinlock_t *lock)
  2. {
  3.     raw_spin_lock(&lock->rlock);
  4. }

  5. #define raw_spin_lock(lock)    _raw_spin_lock(lock)

  6. #define _raw_spin_lock(lock) __raw_spin_lock(lock)

  7. static inline void __raw_spin_lock(raw_spinlock_t *lock)
  8. {
  9.     preempt_disable();
  10.     spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);
  11.     LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock);
  12. }

  13. static inline void do_raw_spin_lock(raw_spinlock_t *lock) __acquires(lock)
  14. {
  15.     __acquire(lock);
  16.     arch_spin_lock(&lock->raw_lock);
  17. }

  18. #define arch_spin_lock(lock) arch_spin_lock_flags(lock, 0)

  19. #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)

  20. static inline void arch_spin_lock(arch_spinlock_t *lock)
  21. {
  22.     unsigned long tmp;

  23.     __asm__ __volatile__(
  24. "1:    ldrex    %0, [%1]\n"
  25. "    teq    %0, #0\n"
  26.     WFE("ne")
  27. "    strexeq    %0, %2, [%1]\n"
  28. "    teqeq    %0, #0\n"
  29. "    bne    1b"
  30.     : "=&r" (tmp)
  31.     : "r" (&lock->lock), "r" (1)
  32.     : "cc");

  33.     smp_mb();
  34. }
    在SMP的环境下,spinlock的运行过程是如上代码所示,主要想高透的,是最后的那一段汇编代码是什么意思。





















                     
阅读(605) | 评论(0) | 转发(0) |
0

上一篇:本地socket通讯

下一篇:Linux之mmap详解

给主人留下些什么吧!~~