内核同步方法之读写信号量

 

   读写信号量在内核中是由rw_semaphore结构表示的:

  1. 在<Rwsem.h(include/asm-i386)>中
  2. /*
  3.  * the semaphore definition
  4.  */
  5. struct rw_semaphore {
  6.     signed long     count;
  7. #define RWSEM_UNLOCKED_VALUE        0x00000000
  8. #define RWSEM_ACTIVE_BIAS       0x00000001
  9. #define RWSEM_ACTIVE_MASK       0x0000ffff
  10. #define RWSEM_WAITING_BIAS      (-0x00010000)
  11. #define RWSEM_ACTIVE_READ_BIAS      RWSEM_ACTIVE_BIAS
  12. #define RWSEM_ACTIVE_WRITE_BIAS     (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
  13.     spinlock_t      wait_lock;
  14.     struct list_head    wait_list;
  15. #ifdef CONFIG_DEBUG_LOCK_ALLOC
  16.     struct lockdep_map dep_map;
  17. #endif
  18. };

静态创建读写信号量:

 

  1. #define __RWSEM_INITIALIZER(name) /
  2. { RWSEM_UNLOCKED_VALUE, __SPIN_LOCK_UNLOCKED((name).wait_lock), /
  3.   LIST_HEAD_INIT((name).wait_list) __RWSEM_DEP_MAP_INIT(name) }
  4. #define DECLARE_RWSEM(name) /
  5.     struct rw_semaphore name = __RWSEM_INITIALIZER(name)

动态创建读写信号量:

  1. extern void __init_rwsem(struct rw_semaphore *sem, const char *name,
  2.              struct lock_class_key *key);
  3. #define init_rwsem(sem)                     /
  4. do {                                /
  5.     static struct lock_class_key __key;         /
  6.                                 /
  7.     __init_rwsem((sem), #sem, &__key);          /
  8. while (0)
  9. /*
  10.  * Initialize an rwsem:
  11.  */
  12. void __init_rwsem(struct rw_semaphore *sem, const char *name,
  13.           struct lock_class_key *key)
  14. {
  15. #ifdef CONFIG_DEBUG_LOCK_ALLOC
  16.     /*
  17.      * Make sure we are not reinitializing a held semaphore:
  18.      */
  19.     debug_check_no_locks_freed((void *)sem, sizeof(*sem));
  20.     lockdep_init_map(&sem->dep_map, name, key, 0);
  21. #endif
  22.     sem->count = RWSEM_UNLOCKED_VALUE;
  23.     spin_lock_init(&sem->wait_lock);
  24.     INIT_LIST_HEAD(&sem->wait_list);
  25. }

所有读写信号量都是互斥信号量。只要没有写者,并发持有读锁的读者数不限。没有读者时,只有唯一的写者可以获得写锁。所有读写锁的睡眠都不会被信号打断,所以它只有一个版本的down()操作。

  1. /*
  2.  * lock for reading
  3.  */
  4. static inline void __down_read(struct rw_semaphore *sem)
  5. {
  6.     __asm__ __volatile__(
  7.         "# beginning down_read/n/t"
  8. LOCK_PREFIX "  incl      (%%eax)/n/t" /* adds 0x00000001, returns the old value */
  9.         "  jns        1f/n"
  10.         "  call call_rwsem_down_read_failed/n"
  11.         "1:/n/t"
  12.         "# ending down_read/n/t"
  13.         : "+m" (sem->count)
  14.         : "a" (sem)
  15.         : "memory""cc");
  16. }
  1. /*
  2.  * lock for writing
  3.  */
  4. static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
  5. {
  6.     int tmp;
  7.     tmp = RWSEM_ACTIVE_WRITE_BIAS;
  8.     __asm__ __volatile__(
  9.         "# beginning down_write/n/t"
  10. LOCK_PREFIX "  xadd      %%edx,(%%eax)/n/t" /* subtract 0x0000ffff, returns the old value */
  11.         "  testl     %%edx,%%edx/n/t" /* was the count 0 before? */
  12.         "  jz        1f/n"
  13.         "  call call_rwsem_down_write_failed/n"
  14.         "1:/n"
  15.         "# ending down_write"
  16.         : "+m" (sem->count), "=d" (tmp)
  17.         : "a" (sem), "1" (tmp)
  18.         : "memory""cc");
  19. }
  20. static inline void __down_write(struct rw_semaphore *sem)
  21. {
  22.     __down_write_nested(sem, 0);
  23. }

  1. /*
  2.  * unlock after reading
  3.  */
  4. static inline void __up_read(struct rw_semaphore *sem)
  5. {
  6.     __s32 tmp = -RWSEM_ACTIVE_READ_BIAS;
  7.     __asm__ __volatile__(
  8.         "# beginning __up_read/n/t"
  9. LOCK_PREFIX "  xadd      %%edx,(%%eax)/n/t" /* subtracts 1, returns the old value */
  10.         "  jns        1f/n/t"
  11.         "  call call_rwsem_wake/n"
  12.         "1:/n"
  13.         "# ending __up_read/n"
  14.         : "+m" (sem->count), "=d" (tmp)
  15.         : "a" (sem), "1" (tmp)
  16.         : "memory""cc");
  17. }
  18. /*
  19.  * unlock after writing
  20.  */
  21. static inline void __up_write(struct rw_semaphore *sem)
  22. {
  23.     __asm__ __volatile__(
  24.         "# beginning __up_write/n/t"
  25.         "  movl      %2,%%edx/n/t"
  26. LOCK_PREFIX "  xaddl     %%edx,(%%eax)/n/t" /* tries to transition 0xffff0001 -> 0x00000000 */
  27.         "  jz       1f/n"
  28.         "  call call_rwsem_wake/n"
  29.         "1:/n/t"
  30.         "# ending __up_write/n"
  31.         : "+m" (sem->count)
  32.         : "a" (sem), "i" (-RWSEM_ACTIVE_WRITE_BIAS)
  33.         : "memory""cc""edx");
  34. }

与标准信号量一样,读写信号量也提供了down_read_trylock()和down_write_trylock()方法。

  1. /*
  2.  * trylock for reading -- returns 1 if successful, 0 if contention
  3.  */
  4. static inline int __down_read_trylock(struct rw_semaphore *sem)
  5. {
  6.     __s32 result, tmp;
  7.     __asm__ __volatile__(
  8.         "# beginning __down_read_trylock/n/t"
  9.         "  movl      %0,%1/n/t"
  10.         "1:/n/t"
  11.         "  movl      %1,%2/n/t"
  12.         "  addl      %3,%2/n/t"
  13.         "  jle       2f/n/t"
  14. LOCK_PREFIX "  cmpxchgl  %2,%0/n/t"
  15.         "  jnz       1b/n/t"
  16.         "2:/n/t"
  17.         "# ending __down_read_trylock/n/t"
  18.         : "+m" (sem->count), "=&a" (result), "=&r" (tmp)
  19.         : "i" (RWSEM_ACTIVE_READ_BIAS)
  20.         : "memory""cc");
  21.     return result>=0 ? 1 : 0;
  22. }
  23. /*
  24.  * trylock for writing -- returns 1 if successful, 0 if contention
  25.  */
  26. static inline int __down_write_trylock(struct rw_semaphore *sem)
  27. {
  28.     signed long ret = cmpxchg(&sem->count,
  29.                   RWSEM_UNLOCKED_VALUE, 
  30.                   RWSEM_ACTIVE_WRITE_BIAS);
  31.     if (ret == RWSEM_UNLOCKED_VALUE)
  32.         return 1;
  33.     return 0;
  34. }

 

读写信号量相比读写自旋锁多一种特有的操作:downgrade_writer(),这个函数可以动态地将获取的写锁转换为读锁。

  1. /*
  2.  * downgrade write lock to read lock
  3.  */
  4. static inline void __downgrade_write(struct rw_semaphore *sem)
  5. {
  6.     __asm__ __volatile__(
  7.         "# beginning __downgrade_write/n/t"
  8. LOCK_PREFIX "  addl      %2,(%%eax)/n/t" /* transitions 0xZZZZ0001 -> 0xYYYY0001 */
  9.         "  jns       1f/n/t"
  10.         "  call call_rwsem_downgrade_wake/n"
  11.         "1:/n/t"
  12.         "# ending __downgrade_write/n"
  13.         : "+m" (sem->count)
  14.         : "a" (sem), "i" (-RWSEM_WAITING_BIAS)
  15.         : "memory""cc");
  16. }

呵呵

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值