123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224 |
- /*
- * Alpha semaphore implementation.
- *
- * (C) Copyright 1996 Linus Torvalds
- * (C) Copyright 1999, 2000 Richard Henderson
- */
- #include <linux/errno.h>
- #include <linux/sched.h>
- #include <linux/init.h>
- /*
- * This is basically the PPC semaphore scheme ported to use
- * the Alpha ll/sc sequences, so see the PPC code for
- * credits.
- */
- /*
- * Atomically update sem->count.
- * This does the equivalent of the following:
- *
- * old_count = sem->count;
- * tmp = MAX(old_count, 0) + incr;
- * sem->count = tmp;
- * return old_count;
- */
- static inline int __sem_update_count(struct semaphore *sem, int incr)
- {
- long old_count, tmp = 0;
- __asm__ __volatile__(
- "1: ldl_l %0,%2\n"
- " cmovgt %0,%0,%1\n"
- " addl %1,%3,%1\n"
- " stl_c %1,%2\n"
- " beq %1,2f\n"
- " mb\n"
- ".subsection 2\n"
- "2: br 1b\n"
- ".previous"
- : "=&r" (old_count), "=&r" (tmp), "=m" (sem->count)
- : "Ir" (incr), "1" (tmp), "m" (sem->count));
- return old_count;
- }
- /*
- * Perform the "down" function. Return zero for semaphore acquired,
- * return negative for signalled out of the function.
- *
- * If called from down, the return is ignored and the wait loop is
- * not interruptible. This means that a task waiting on a semaphore
- * using "down()" cannot be killed until someone does an "up()" on
- * the semaphore.
- *
- * If called from down_interruptible, the return value gets checked
- * upon return. If the return value is negative then the task continues
- * with the negative value in the return register (it can be tested by
- * the caller).
- *
- * Either form may be used in conjunction with "up()".
- */
- void __sched
- __down_failed(struct semaphore *sem)
- {
- struct task_struct *tsk = current;
- DECLARE_WAITQUEUE(wait, tsk);
- #ifdef CONFIG_DEBUG_SEMAPHORE
- printk("%s(%d): down failed(%p)\n",
- tsk->comm, tsk->pid, sem);
- #endif
- tsk->state = TASK_UNINTERRUPTIBLE;
- wmb();
- add_wait_queue_exclusive(&sem->wait, &wait);
- /*
- * Try to get the semaphore. If the count is > 0, then we've
- * got the semaphore; we decrement count and exit the loop.
- * If the count is 0 or negative, we set it to -1, indicating
- * that we are asleep, and then sleep.
- */
- while (__sem_update_count(sem, -1) <= 0) {
- schedule();
- set_task_state(tsk, TASK_UNINTERRUPTIBLE);
- }
- remove_wait_queue(&sem->wait, &wait);
- tsk->state = TASK_RUNNING;
- /*
- * If there are any more sleepers, wake one of them up so
- * that it can either get the semaphore, or set count to -1
- * indicating that there are still processes sleeping.
- */
- wake_up(&sem->wait);
- #ifdef CONFIG_DEBUG_SEMAPHORE
- printk("%s(%d): down acquired(%p)\n",
- tsk->comm, tsk->pid, sem);
- #endif
- }
- int __sched
- __down_failed_interruptible(struct semaphore *sem)
- {
- struct task_struct *tsk = current;
- DECLARE_WAITQUEUE(wait, tsk);
- long ret = 0;
- #ifdef CONFIG_DEBUG_SEMAPHORE
- printk("%s(%d): down failed(%p)\n",
- tsk->comm, tsk->pid, sem);
- #endif
- tsk->state = TASK_INTERRUPTIBLE;
- wmb();
- add_wait_queue_exclusive(&sem->wait, &wait);
- while (__sem_update_count(sem, -1) <= 0) {
- if (signal_pending(current)) {
- /*
- * A signal is pending - give up trying.
- * Set sem->count to 0 if it is negative,
- * since we are no longer sleeping.
- */
- __sem_update_count(sem, 0);
- ret = -EINTR;
- break;
- }
- schedule();
- set_task_state(tsk, TASK_INTERRUPTIBLE);
- }
- remove_wait_queue(&sem->wait, &wait);
- tsk->state = TASK_RUNNING;
- wake_up(&sem->wait);
- #ifdef CONFIG_DEBUG_SEMAPHORE
- printk("%s(%d): down %s(%p)\n",
- current->comm, current->pid,
- (ret < 0 ? "interrupted" : "acquired"), sem);
- #endif
- return ret;
- }
- void
- __up_wakeup(struct semaphore *sem)
- {
- /*
- * Note that we incremented count in up() before we came here,
- * but that was ineffective since the result was <= 0, and
- * any negative value of count is equivalent to 0.
- * This ends up setting count to 1, unless count is now > 0
- * (i.e. because some other cpu has called up() in the meantime),
- * in which case we just increment count.
- */
- __sem_update_count(sem, 1);
- wake_up(&sem->wait);
- }
- void __sched
- down(struct semaphore *sem)
- {
- #ifdef WAITQUEUE_DEBUG
- CHECK_MAGIC(sem->__magic);
- #endif
- #ifdef CONFIG_DEBUG_SEMAPHORE
- printk("%s(%d): down(%p) <count=%d> from %p\n",
- current->comm, current->pid, sem,
- atomic_read(&sem->count), __builtin_return_address(0));
- #endif
- __down(sem);
- }
- int __sched
- down_interruptible(struct semaphore *sem)
- {
- #ifdef WAITQUEUE_DEBUG
- CHECK_MAGIC(sem->__magic);
- #endif
- #ifdef CONFIG_DEBUG_SEMAPHORE
- printk("%s(%d): down(%p) <count=%d> from %p\n",
- current->comm, current->pid, sem,
- atomic_read(&sem->count), __builtin_return_address(0));
- #endif
- return __down_interruptible(sem);
- }
- int
- down_trylock(struct semaphore *sem)
- {
- int ret;
- #ifdef WAITQUEUE_DEBUG
- CHECK_MAGIC(sem->__magic);
- #endif
- ret = __down_trylock(sem);
- #ifdef CONFIG_DEBUG_SEMAPHORE
- printk("%s(%d): down_trylock %s from %p\n",
- current->comm, current->pid,
- ret ? "failed" : "acquired",
- __builtin_return_address(0));
- #endif
- return ret;
- }
- void
- up(struct semaphore *sem)
- {
- #ifdef WAITQUEUE_DEBUG
- CHECK_MAGIC(sem->__magic);
- #endif
- #ifdef CONFIG_DEBUG_SEMAPHORE
- printk("%s(%d): up(%p) <count=%d> from %p\n",
- current->comm, current->pid, sem,
- atomic_read(&sem->count), __builtin_return_address(0));
- #endif
- __up(sem);
- }
|