2006-07-03 15:24:29 +08:00
|
|
|
/* kernel/rwsem.c: R/W semaphores, public implementation
|
|
|
|
*
|
|
|
|
* Written by David Howells (dhowells@redhat.com).
|
|
|
|
* Derived from asm-i386/semaphore.h
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/types.h>
|
|
|
|
#include <linux/kernel.h>
|
2007-12-18 22:21:13 +08:00
|
|
|
#include <linux/sched.h>
|
2006-07-03 15:24:29 +08:00
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/rwsem.h>
|
|
|
|
|
|
|
|
#include <asm/system.h>
|
|
|
|
#include <asm/atomic.h>
|
|
|
|
|
|
|
|
/*
|
|
|
|
* lock for reading
|
|
|
|
*/
|
2007-12-18 22:21:13 +08:00
|
|
|
void __sched down_read(struct rw_semaphore *sem)
|
2006-07-03 15:24:29 +08:00
|
|
|
{
|
|
|
|
might_sleep();
|
|
|
|
rwsem_acquire_read(&sem->dep_map, 0, 0, _RET_IP_);
|
|
|
|
|
2007-07-19 16:48:58 +08:00
|
|
|
LOCK_CONTENDED(sem, __down_read_trylock, __down_read);
|
2006-07-03 15:24:29 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
EXPORT_SYMBOL(down_read);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* trylock for reading -- returns 1 if successful, 0 if contention
|
|
|
|
*/
|
|
|
|
int down_read_trylock(struct rw_semaphore *sem)
|
|
|
|
{
|
|
|
|
int ret = __down_read_trylock(sem);
|
|
|
|
|
|
|
|
if (ret == 1)
|
|
|
|
rwsem_acquire_read(&sem->dep_map, 0, 1, _RET_IP_);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
EXPORT_SYMBOL(down_read_trylock);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* lock for writing
|
|
|
|
*/
|
2007-12-18 22:21:13 +08:00
|
|
|
void __sched down_write(struct rw_semaphore *sem)
|
2006-07-03 15:24:29 +08:00
|
|
|
{
|
|
|
|
might_sleep();
|
|
|
|
rwsem_acquire(&sem->dep_map, 0, 0, _RET_IP_);
|
|
|
|
|
2007-07-19 16:48:58 +08:00
|
|
|
LOCK_CONTENDED(sem, __down_write_trylock, __down_write);
|
2006-07-03 15:24:29 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
EXPORT_SYMBOL(down_write);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* trylock for writing -- returns 1 if successful, 0 if contention
|
|
|
|
*/
|
|
|
|
int down_write_trylock(struct rw_semaphore *sem)
|
|
|
|
{
|
|
|
|
int ret = __down_write_trylock(sem);
|
|
|
|
|
|
|
|
if (ret == 1)
|
2007-05-08 15:29:10 +08:00
|
|
|
rwsem_acquire(&sem->dep_map, 0, 1, _RET_IP_);
|
2006-07-03 15:24:29 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
EXPORT_SYMBOL(down_write_trylock);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* release a read lock
|
|
|
|
*/
|
|
|
|
void up_read(struct rw_semaphore *sem)
|
|
|
|
{
|
|
|
|
rwsem_release(&sem->dep_map, 1, _RET_IP_);
|
|
|
|
|
|
|
|
__up_read(sem);
|
|
|
|
}
|
|
|
|
|
|
|
|
EXPORT_SYMBOL(up_read);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* release a write lock
|
|
|
|
*/
|
|
|
|
void up_write(struct rw_semaphore *sem)
|
|
|
|
{
|
|
|
|
rwsem_release(&sem->dep_map, 1, _RET_IP_);
|
|
|
|
|
|
|
|
__up_write(sem);
|
|
|
|
}
|
|
|
|
|
|
|
|
EXPORT_SYMBOL(up_write);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* downgrade write lock to read lock
|
|
|
|
*/
|
|
|
|
void downgrade_write(struct rw_semaphore *sem)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* lockdep: a downgraded write will live on as a write
|
|
|
|
* dependency.
|
|
|
|
*/
|
|
|
|
__downgrade_write(sem);
|
|
|
|
}
|
|
|
|
|
|
|
|
EXPORT_SYMBOL(downgrade_write);
|
2006-07-03 15:24:53 +08:00
|
|
|
|
|
|
|
#ifdef CONFIG_DEBUG_LOCK_ALLOC
|
|
|
|
|
|
|
|
void down_read_nested(struct rw_semaphore *sem, int subclass)
|
|
|
|
{
|
|
|
|
might_sleep();
|
|
|
|
rwsem_acquire_read(&sem->dep_map, subclass, 0, _RET_IP_);
|
|
|
|
|
2007-07-19 16:48:58 +08:00
|
|
|
LOCK_CONTENDED(sem, __down_read_trylock, __down_read);
|
2006-07-03 15:24:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
EXPORT_SYMBOL(down_read_nested);
|
|
|
|
|
|
|
|
void down_write_nested(struct rw_semaphore *sem, int subclass)
|
|
|
|
{
|
|
|
|
might_sleep();
|
|
|
|
rwsem_acquire(&sem->dep_map, subclass, 0, _RET_IP_);
|
|
|
|
|
2007-07-19 16:48:58 +08:00
|
|
|
LOCK_CONTENDED(sem, __down_write_trylock, __down_write);
|
2006-07-03 15:24:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
EXPORT_SYMBOL(down_write_nested);
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|