~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/include/asm-mips/semaphore-helper.h

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /* $Id: semaphore-helper.h,v 1.6 1999/10/20 21:10:58 ralf Exp $
  2  *
  3  * SMP- and interrupt-safe semaphores helper functions.
  4  *
  5  * (C) Copyright 1996 Linus Torvalds
  6  * (C) Copyright 1999 Andrea Arcangeli
  7  * (C) Copyright 1999 Ralf Baechle
  8  * (C) Copyright 1999 Silicon Graphics, Inc.
  9  */
 10 #ifndef _ASM_SEMAPHORE_HELPER_H
 11 #define _ASM_SEMAPHORE_HELPER_H
 12 
 13 #include <linux/config.h>
 14 
 15 /*
 16  * These two _must_ execute atomically wrt each other.
 17  */
 18 static inline void wake_one_more(struct semaphore * sem)
 19 {
 20         atomic_inc(&sem->waking);
 21 }
 22 
 23 #if !defined(CONFIG_CPU_HAS_LLSC)
 24 
 25 /*
 26  * It doesn't make sense, IMHO, to endlessly turn interrupts off and on again.
 27  * Do it once and that's it. ll/sc *has* it's advantages. HK
 28  */
 29 #define read(a) ((a)->counter)
 30 #define inc(a) (((a)->counter)++)
 31 #define dec(a) (((a)->counter)--)
 32 
 33 static inline int waking_non_zero(struct semaphore *sem)
 34 {
 35         unsigned long flags;
 36         int ret = 0;
 37 
 38         save_and_cli(flags);
 39         if (read(&sem->waking) > 0) {
 40                 dec(&sem->waking);
 41                 ret = 1;
 42         }
 43         restore_flags(flags);
 44         return ret;
 45 }
 46 
 47 static inline int waking_non_zero_interruptible(struct semaphore *sem,
 48                                                 struct task_struct *tsk)
 49 {
 50         int ret = 0;
 51         unsigned long flags;
 52 
 53         save_and_cli(flags);
 54         if (read(&sem->waking) > 0) {
 55                 dec(&sem->waking);
 56                 ret = 1;
 57         } else if (signal_pending(tsk)) {
 58                 inc(&sem->count);
 59                 ret = -EINTR;
 60         }
 61         restore_flags(flags);
 62         return ret;
 63 }
 64 
 65 static inline int waking_non_zero_trylock(struct semaphore *sem)
 66 {
 67         int ret = 1;
 68         unsigned long flags;
 69 
 70         save_and_cli(flags);
 71         if (read(&sem->waking) <= 0)
 72                 inc(&sem->count);
 73         else {
 74                 dec(&sem->waking);
 75                 ret = 0;
 76         }
 77         restore_flags(flags);
 78         return ret;
 79 }
 80 
 81 #else /* CONFIG_CPU_HAS_LLSC */
 82 
 83 static inline int
 84 waking_non_zero(struct semaphore *sem)
 85 {
 86         int ret, tmp;
 87 
 88         __asm__ __volatile__(
 89         "1:\tll\t%1, %2\n\t"
 90         "blez\t%1, 2f\n\t"
 91         "subu\t%0, %1, 1\n\t"
 92         "sc\t%0, %2\n\t"
 93         "beqz\t%0, 1b\n\t"
 94         "2:"
 95         : "=r"(ret), "=r"(tmp), "=m"(__atomic_fool_gcc(&sem->waking))
 96         : ""(0));
 97 
 98         return ret;
 99 }
100 
101 /*
102  * waking_non_zero_interruptible:
103  *      1       got the lock
104  *      0       go to sleep
105  *      -EINTR  interrupted
106  *
107  * We must undo the sem->count down_interruptible decrement
108  * simultaneously and atomicly with the sem->waking adjustment,
109  * otherwise we can race with wake_one_more.
110  *
111  * This is accomplished by doing a 64-bit ll/sc on the 2 32-bit words.
112  *
113  * This is crazy.  Normally it stricly forbidden to use 64-bit operations
114  * in the 32-bit MIPS kernel.  In this case it's however ok because if an
115  * interrupt has destroyed the upper half of registers sc will fail.
116  * Note also that this will not work for MIPS32 CPUS!
117  *
118  * Pseudocode:
119  *
120  * If(sem->waking > 0) {
121  *      Decrement(sem->waking)
122  *      Return(SUCCESS)
123  * } else If(segnal_pending(tsk)) {
124  *      Increment(sem->count)
125  *      Return(-EINTR)
126  * } else {
127  *      Return(SLEEP)
128  * }
129  */
130 
131 static inline int
132 waking_non_zero_interruptible(struct semaphore *sem, struct task_struct *tsk)
133 {
134         long ret, tmp;
135 
136         __asm__ __volatile__("
137         .set    push
138         .set    mips3
139         .set    noat
140 0:      lld     %1, %2
141         li      %0, 0
142         sll     $1, %1, 0
143         blez    $1, 1f
144         daddiu  %1, %1, -1
145         li      %0, 1
146         b       2f
147 1:
148         beqz    %3, 2f
149         li      %0, %4
150         dli     $1, 0x0000000100000000
151         daddu   %1, %1, $1
152 2:
153         scd     %1, %2
154         beqz    %1, 0b
155 
156         .set    pop"
157         : "=&r"(ret), "=&r"(tmp), "=m"(*sem)
158         : "r"(signal_pending(tsk)), "i"(-EINTR));
159 
160         return ret;
161 }
162 
163 /*
164  * waking_non_zero_trylock is unused.  we do everything in 
165  * down_trylock and let non-ll/sc hosts bounce around.
166  */
167 
168 static inline int
169 waking_non_zero_trylock(struct semaphore *sem)
170 {
171 #if WAITQUEUE_DEBUG
172         CHECK_MAGIC(sem->__magic);
173 #endif
174 
175         return 0;
176 }
177 
178 #endif /* CONFIG_CPU_HAS_LLSC */
179 
180 #endif /* _ASM_SEMAPHORE_HELPER_H */
181 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.