您的位置:首页 > 其它

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

2008-12-20 15:31 363 查看
 
   读写信号量在内核中是由rw_semaphore结构表示的:

在<Rwsem.h(include/asm-i386)>中

/*

 * the semaphore definition

 */

struct rw_semaphore {

    signed long     count;

#define RWSEM_UNLOCKED_VALUE        0x00000000

#define RWSEM_ACTIVE_BIAS       0x00000001

#define RWSEM_ACTIVE_MASK       0x0000ffff

#define RWSEM_WAITING_BIAS      (-0x00010000)

#define RWSEM_ACTIVE_READ_BIAS      RWSEM_ACTIVE_BIAS

#define RWSEM_ACTIVE_WRITE_BIAS     (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)

    spinlock_t      wait_lock;

    struct list_head    wait_list;

#ifdef CONFIG_DEBUG_LOCK_ALLOC

    struct lockdep_map dep_map;

#endif

};

静态创建读写信号量:

 

#define __RWSEM_INITIALIZER(name) /

{ RWSEM_UNLOCKED_VALUE, __SPIN_LOCK_UNLOCKED((name).wait_lock), /

  LIST_HEAD_INIT((name).wait_list) __RWSEM_DEP_MAP_INIT(name) }

#define DECLARE_RWSEM(name) /

    struct rw_semaphore name = __RWSEM_INITIALIZER(name)

动态创建读写信号量:

extern void __init_rwsem(struct rw_semaphore *sem, const char *name,

             struct lock_class_key *key);

#define init_rwsem(sem)                     /

do {                                /

    static struct lock_class_key __key;         /

                                /

    __init_rwsem((sem), #sem, &__key);          /

} while (0)

/*

 * Initialize an rwsem:

 */

void __init_rwsem(struct rw_semaphore *sem, const char *name,

          struct lock_class_key *key)

{

#ifdef CONFIG_DEBUG_LOCK_ALLOC

    /*

     * Make sure we are not reinitializing a held semaphore:

     */

    debug_check_no_locks_freed((void *)sem, sizeof(*sem));

    lockdep_init_map(&sem->dep_map, name, key, 0);

#endif

    sem->count = RWSEM_UNLOCKED_VALUE;

    spin_lock_init(&sem->wait_lock);

    INIT_LIST_HEAD(&sem->wait_list);

}

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

/*

 * lock for reading

 */

static inline void __down_read(struct rw_semaphore *sem)

{

    __asm__ __volatile__(

        "# beginning down_read/n/t"

LOCK_PREFIX "  incl      (%%eax)/n/t" /* adds 0x00000001, returns the old value */

        "  jns        1f/n"

        "  call call_rwsem_down_read_failed/n"

        "1:/n/t"

        "# ending down_read/n/t"

        : "+m" (sem->count)

        : "a" (sem)

        : "memory", "cc");

}

/*

 * lock for writing

 */

static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)

{

    int tmp;

    tmp = RWSEM_ACTIVE_WRITE_BIAS;

    __asm__ __volatile__(

        "# beginning down_write/n/t"

LOCK_PREFIX "  xadd      %%edx,(%%eax)/n/t" /* subtract 0x0000ffff, returns the old value */

        "  testl     %%edx,%%edx/n/t" /* was the count 0 before? */

        "  jz        1f/n"

        "  call call_rwsem_down_write_failed/n"

        "1:/n"

        "# ending down_write"

        : "+m" (sem->count), "=d" (tmp)

        : "a" (sem), "1" (tmp)

        : "memory", "cc");

}

static inline void __down_write(struct rw_semaphore *sem)

{

    __down_write_nested(sem, 0);

}

/*

 * unlock after reading

 */

static inline void __up_read(struct rw_semaphore *sem)

{

    __s32 tmp = -RWSEM_ACTIVE_READ_BIAS;

    __asm__ __volatile__(

        "# beginning __up_read/n/t"

LOCK_PREFIX "  xadd      %%edx,(%%eax)/n/t" /* subtracts 1, returns the old value */

        "  jns        1f/n/t"

        "  call call_rwsem_wake/n"

        "1:/n"

        "# ending __up_read/n"

        : "+m" (sem->count), "=d" (tmp)

        : "a" (sem), "1" (tmp)

        : "memory", "cc");

}

/*

 * unlock after writing

 */

static inline void __up_write(struct rw_semaphore *sem)

{

    __asm__ __volatile__(

        "# beginning __up_write/n/t"

        "  movl      %2,%%edx/n/t"

LOCK_PREFIX "  xaddl     %%edx,(%%eax)/n/t" /* tries to transition 0xffff0001 -> 0x00000000 */

        "  jz       1f/n"

        "  call call_rwsem_wake/n"

        "1:/n/t"

        "# ending __up_write/n"

        : "+m" (sem->count)

        : "a" (sem), "i" (-RWSEM_ACTIVE_WRITE_BIAS)

        : "memory", "cc", "edx");

}

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

/*

 * trylock for reading -- returns 1 if successful, 0 if contention

 */

static inline int __down_read_trylock(struct rw_semaphore *sem)

{

    __s32 result, tmp;

    __asm__ __volatile__(

        "# beginning __down_read_trylock/n/t"

        "  movl      %0,%1/n/t"

        "1:/n/t"

        "  movl      %1,%2/n/t"

        "  addl      %3,%2/n/t"

        "  jle       2f/n/t"

LOCK_PREFIX "  cmpxchgl  %2,%0/n/t"

        "  jnz       1b/n/t"

        "2:/n/t"

        "# ending __down_read_trylock/n/t"

        : "+m" (sem->count), "=&a" (result), "=&r" (tmp)

        : "i" (RWSEM_ACTIVE_READ_BIAS)

        : "memory", "cc");

    return result>=0 ? 1 : 0;

}

/*

 * trylock for writing -- returns 1 if successful, 0 if contention

 */

static inline int __down_write_trylock(struct rw_semaphore *sem)

{

    signed long ret = cmpxchg(&sem->count,

                  RWSEM_UNLOCKED_VALUE, 

                  RWSEM_ACTIVE_WRITE_BIAS);

    if (ret == RWSEM_UNLOCKED_VALUE)

        return 1;

    return 0;

}

 

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

/*

 * downgrade write lock to read lock

 */

static inline void __downgrade_write(struct rw_semaphore *sem)

{

    __asm__ __volatile__(

        "# beginning __downgrade_write/n/t"

LOCK_PREFIX "  addl      %2,(%%eax)/n/t" /* transitions 0xZZZZ0001 -> 0xYYYY0001 */

        "  jns       1f/n/t"

        "  call call_rwsem_downgrade_wake/n"

        "1:/n/t"

        "# ending __downgrade_write/n"

        : "+m" (sem->count)

        : "a" (sem), "i" (-RWSEM_WAITING_BIAS)

        : "memory", "cc");

}

呵呵
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  semaphore nested list class up
相关文章推荐