内核同步方法之读写信号量
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");
}
呵呵
相关文章推荐
- linux c 线程间同步(通信)的几种方法--互斥锁,条件变量,信号量,读写锁
- Java Note: 多线程的同步(互斥锁)的方法对比,信号量锁,读写锁的实现,生产者-消费者模式的实现
- 内核同步机制之信号量&读写信号量&完成变量
- Java Note: 多线程的同步(互斥锁)的方法对比,信号量锁,读写锁的实现,生产者-消费者模式的实现
- 内核同步方法之读写自旋锁
- Java Note: 多线程的同步(互斥锁)的方法对比,信号量锁,读写锁的实现,生产者-消费者模式的实现
- 内核同步机制-读写信号量(rw_semaphore)
- Java Note: 多线程的同步(互斥锁)的方法对比,信号量锁,读写锁的实现,生产者-消费者模式的实现
- 9.4 内核同步方法_信号量
- Java Note: 多线程的同步(互斥锁)的方法对比,信号量锁,读写锁的实现,生产者-消费者模式的实现
- Java Note: 多线程的同步(互斥锁)的方法对比,信号量锁,读写锁的实现,生产者-消费者模式的实现
- 9.6 内核同步方法_自旋锁和信号量
- Java Note: 多线程的同步(互斥锁)的方法对比,信号量锁,读写锁的实现,生产者-消费者模式的实现
- Linux 内核同步方法(锁机制)(1)
- 内核中读写文件的方法
- 9.7 内核同步方法_完成变量
- 内核部件之同步机制之信号量
- 信号量实现内核线程同步例子
- 内核同步之自旋锁与读写自旋锁
- 内核同步机制 - 读写锁 read_lock()/write_lock