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
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.