diff options
Diffstat (limited to 'lib/rwsem-spinlock.c')
| -rw-r--r-- | lib/rwsem-spinlock.c | 323 | 
1 files changed, 0 insertions, 323 deletions
diff --git a/lib/rwsem-spinlock.c b/lib/rwsem-spinlock.c deleted file mode 100644 index ffc9fc7f3b0..00000000000 --- a/lib/rwsem-spinlock.c +++ /dev/null @@ -1,323 +0,0 @@ -/* rwsem-spinlock.c: R/W semaphores: contention handling functions for - * generic spinlock implementation - * - * Copyright (c) 2001   David Howells (dhowells@redhat.com). - * - Derived partially from idea by Andrea Arcangeli <andrea@suse.de> - * - Derived also from comments by Linus - */ -#include <linux/rwsem.h> -#include <linux/sched.h> -#include <linux/module.h> - -struct rwsem_waiter { -	struct list_head list; -	struct task_struct *task; -	unsigned int flags; -#define RWSEM_WAITING_FOR_READ	0x00000001 -#define RWSEM_WAITING_FOR_WRITE	0x00000002 -}; - -int rwsem_is_locked(struct rw_semaphore *sem) -{ -	int ret = 1; -	unsigned long flags; - -	if (spin_trylock_irqsave(&sem->wait_lock, flags)) { -		ret = (sem->activity != 0); -		spin_unlock_irqrestore(&sem->wait_lock, flags); -	} -	return ret; -} -EXPORT_SYMBOL(rwsem_is_locked); - -/* - * initialise the semaphore - */ -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->activity = 0; -	spin_lock_init(&sem->wait_lock); -	INIT_LIST_HEAD(&sem->wait_list); -} -EXPORT_SYMBOL(__init_rwsem); - -/* - * handle the lock release when processes blocked on it that can now run - * - if we come here, then: - *   - the 'active count' _reached_ zero - *   - the 'waiting count' is non-zero - * - the spinlock must be held by the caller - * - woken process blocks are discarded from the list after having task zeroed - * - writers are only woken if wakewrite is non-zero - */ -static inline struct rw_semaphore * -__rwsem_do_wake(struct rw_semaphore *sem, int wakewrite) -{ -	struct rwsem_waiter *waiter; -	struct task_struct *tsk; -	int woken; - -	waiter = list_entry(sem->wait_list.next, struct rwsem_waiter, list); - -	if (!wakewrite) { -		if (waiter->flags & RWSEM_WAITING_FOR_WRITE) -			goto out; -		goto dont_wake_writers; -	} - -	/* if we are allowed to wake writers try to grant a single write lock -	 * if there's a writer at the front of the queue -	 * - we leave the 'waiting count' incremented to signify potential -	 *   contention -	 */ -	if (waiter->flags & RWSEM_WAITING_FOR_WRITE) { -		sem->activity = -1; -		list_del(&waiter->list); -		tsk = waiter->task; -		/* Don't touch waiter after ->task has been NULLed */ -		smp_mb(); -		waiter->task = NULL; -		wake_up_process(tsk); -		put_task_struct(tsk); -		goto out; -	} - -	/* grant an infinite number of read locks to the front of the queue */ - dont_wake_writers: -	woken = 0; -	while (waiter->flags & RWSEM_WAITING_FOR_READ) { -		struct list_head *next = waiter->list.next; - -		list_del(&waiter->list); -		tsk = waiter->task; -		smp_mb(); -		waiter->task = NULL; -		wake_up_process(tsk); -		put_task_struct(tsk); -		woken++; -		if (list_empty(&sem->wait_list)) -			break; -		waiter = list_entry(next, struct rwsem_waiter, list); -	} - -	sem->activity += woken; - - out: -	return sem; -} - -/* - * wake a single writer - */ -static inline struct rw_semaphore * -__rwsem_wake_one_writer(struct rw_semaphore *sem) -{ -	struct rwsem_waiter *waiter; -	struct task_struct *tsk; - -	sem->activity = -1; - -	waiter = list_entry(sem->wait_list.next, struct rwsem_waiter, list); -	list_del(&waiter->list); - -	tsk = waiter->task; -	smp_mb(); -	waiter->task = NULL; -	wake_up_process(tsk); -	put_task_struct(tsk); -	return sem; -} - -/* - * get a read lock on the semaphore - */ -void __sched __down_read(struct rw_semaphore *sem) -{ -	struct rwsem_waiter waiter; -	struct task_struct *tsk; -	unsigned long flags; - -	spin_lock_irqsave(&sem->wait_lock, flags); - -	if (sem->activity >= 0 && list_empty(&sem->wait_list)) { -		/* granted */ -		sem->activity++; -		spin_unlock_irqrestore(&sem->wait_lock, flags); -		goto out; -	} - -	tsk = current; -	set_task_state(tsk, TASK_UNINTERRUPTIBLE); - -	/* set up my own style of waitqueue */ -	waiter.task = tsk; -	waiter.flags = RWSEM_WAITING_FOR_READ; -	get_task_struct(tsk); - -	list_add_tail(&waiter.list, &sem->wait_list); - -	/* we don't need to touch the semaphore struct anymore */ -	spin_unlock_irqrestore(&sem->wait_lock, flags); - -	/* wait to be given the lock */ -	for (;;) { -		if (!waiter.task) -			break; -		schedule(); -		set_task_state(tsk, TASK_UNINTERRUPTIBLE); -	} - -	tsk->state = TASK_RUNNING; - out: -	; -} - -/* - * trylock for reading -- returns 1 if successful, 0 if contention - */ -int __down_read_trylock(struct rw_semaphore *sem) -{ -	unsigned long flags; -	int ret = 0; - - -	spin_lock_irqsave(&sem->wait_lock, flags); - -	if (sem->activity >= 0 && list_empty(&sem->wait_list)) { -		/* granted */ -		sem->activity++; -		ret = 1; -	} - -	spin_unlock_irqrestore(&sem->wait_lock, flags); - -	return ret; -} - -/* - * get a write lock on the semaphore - * - we increment the waiting count anyway to indicate an exclusive lock - */ -void __sched __down_write_nested(struct rw_semaphore *sem, int subclass) -{ -	struct rwsem_waiter waiter; -	struct task_struct *tsk; -	unsigned long flags; - -	spin_lock_irqsave(&sem->wait_lock, flags); - -	if (sem->activity == 0 && list_empty(&sem->wait_list)) { -		/* granted */ -		sem->activity = -1; -		spin_unlock_irqrestore(&sem->wait_lock, flags); -		goto out; -	} - -	tsk = current; -	set_task_state(tsk, TASK_UNINTERRUPTIBLE); - -	/* set up my own style of waitqueue */ -	waiter.task = tsk; -	waiter.flags = RWSEM_WAITING_FOR_WRITE; -	get_task_struct(tsk); - -	list_add_tail(&waiter.list, &sem->wait_list); - -	/* we don't need to touch the semaphore struct anymore */ -	spin_unlock_irqrestore(&sem->wait_lock, flags); - -	/* wait to be given the lock */ -	for (;;) { -		if (!waiter.task) -			break; -		schedule(); -		set_task_state(tsk, TASK_UNINTERRUPTIBLE); -	} - -	tsk->state = TASK_RUNNING; - out: -	; -} - -void __sched __down_write(struct rw_semaphore *sem) -{ -	__down_write_nested(sem, 0); -} - -/* - * trylock for writing -- returns 1 if successful, 0 if contention - */ -int __down_write_trylock(struct rw_semaphore *sem) -{ -	unsigned long flags; -	int ret = 0; - -	spin_lock_irqsave(&sem->wait_lock, flags); - -	if (sem->activity == 0 && list_empty(&sem->wait_list)) { -		/* granted */ -		sem->activity = -1; -		ret = 1; -	} - -	spin_unlock_irqrestore(&sem->wait_lock, flags); - -	return ret; -} - -/* - * release a read lock on the semaphore - */ -void __up_read(struct rw_semaphore *sem) -{ -	unsigned long flags; - -	spin_lock_irqsave(&sem->wait_lock, flags); - -	if (--sem->activity == 0 && !list_empty(&sem->wait_list)) -		sem = __rwsem_wake_one_writer(sem); - -	spin_unlock_irqrestore(&sem->wait_lock, flags); -} - -/* - * release a write lock on the semaphore - */ -void __up_write(struct rw_semaphore *sem) -{ -	unsigned long flags; - -	spin_lock_irqsave(&sem->wait_lock, flags); - -	sem->activity = 0; -	if (!list_empty(&sem->wait_list)) -		sem = __rwsem_do_wake(sem, 1); - -	spin_unlock_irqrestore(&sem->wait_lock, flags); -} - -/* - * downgrade a write lock into a read lock - * - just wake up any readers at the front of the queue - */ -void __downgrade_write(struct rw_semaphore *sem) -{ -	unsigned long flags; - -	spin_lock_irqsave(&sem->wait_lock, flags); - -	sem->activity = 1; -	if (!list_empty(&sem->wait_list)) -		sem = __rwsem_do_wake(sem, 0); - -	spin_unlock_irqrestore(&sem->wait_lock, flags); -} -  | 
