PageRenderTime 20ms CodeModel.GetById 12ms app.highlight 6ms RepoModel.GetById 1ms app.codeStats 0ms

/arch/parisc/kernel/semaphore.c

https://bitbucket.org/evzijst/gittest
C | 102 lines | 64 code | 16 blank | 22 comment | 16 complexity | f505be20c1dfc9099ebeb9d93f9e6d94 MD5 | raw file
  1/*
  2 * Semaphore implementation Copyright (c) 2001 Matthew Wilcox, Hewlett-Packard
  3 */
  4
  5#include <linux/sched.h>
  6#include <linux/spinlock.h>
  7#include <linux/errno.h>
  8#include <linux/init.h>
  9
 10/*
 11 * Semaphores are complex as we wish to avoid using two variables.
 12 * `count' has multiple roles, depending on its value.  If it is positive
 13 * or zero, there are no waiters.  The functions here will never be
 14 * called; see <asm/semaphore.h>
 15 *
 16 * When count is -1 it indicates there is at least one task waiting
 17 * for the semaphore.
 18 *
 19 * When count is less than that, there are '- count - 1' wakeups
 20 * pending.  ie if it has value -3, there are 2 wakeups pending.
 21 *
 22 * Note that these functions are only called when there is contention
 23 * on the lock, and as such all this is the "non-critical" part of the
 24 * whole semaphore business. The critical part is the inline stuff in
 25 * <asm/semaphore.h> where we want to avoid any extra jumps and calls.
 26 */
 27void __up(struct semaphore *sem)
 28{
 29	sem->count--;
 30	wake_up(&sem->wait);
 31}
 32
 33#define wakers(count) (-1 - count)
 34
 35#define DOWN_HEAD							\
 36	int ret = 0;							\
 37	DECLARE_WAITQUEUE(wait, current);				\
 38									\
 39	/* Note that someone is waiting */				\
 40	if (sem->count == 0)						\
 41		sem->count = -1;					\
 42									\
 43	/* protected by the sentry still -- use unlocked version */	\
 44	wait.flags = WQ_FLAG_EXCLUSIVE;					\
 45	__add_wait_queue_tail(&sem->wait, &wait);			\
 46 lost_race:								\
 47	spin_unlock_irq(&sem->sentry);					\
 48
 49#define DOWN_TAIL							\
 50	spin_lock_irq(&sem->sentry);					\
 51	if (wakers(sem->count) == 0 && ret == 0)			\
 52		goto lost_race;	/* Someone stole our wakeup */		\
 53	__remove_wait_queue(&sem->wait, &wait);				\
 54	current->state = TASK_RUNNING;					\
 55	if (!waitqueue_active(&sem->wait) && (sem->count < 0))		\
 56		sem->count = wakers(sem->count);
 57
 58#define UPDATE_COUNT							\
 59	sem->count += (sem->count < 0) ? 1 : - 1;
 60	
 61
 62void __sched __down(struct semaphore * sem)
 63{
 64	DOWN_HEAD
 65
 66	for(;;) {
 67		set_task_state(current, TASK_UNINTERRUPTIBLE);
 68		/* we can _read_ this without the sentry */
 69		if (sem->count != -1)
 70			break;
 71 		schedule();
 72 	}
 73
 74	DOWN_TAIL
 75	UPDATE_COUNT
 76}
 77
 78int __sched __down_interruptible(struct semaphore * sem)
 79{
 80	DOWN_HEAD
 81
 82	for(;;) {
 83		set_task_state(current, TASK_INTERRUPTIBLE);
 84		/* we can _read_ this without the sentry */
 85		if (sem->count != -1)
 86			break;
 87
 88		if (signal_pending(current)) {
 89			ret = -EINTR;
 90			break;
 91		}
 92		schedule();
 93	}
 94
 95	DOWN_TAIL
 96
 97	if (!ret) {
 98		UPDATE_COUNT
 99	}
100
101	return ret;
102}