]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/lib/libk/atomic.cpp
1f4681cee0e164b93a6b7851bb5455418f5a1b0c
[l4.git] / kernel / fiasco / src / lib / libk / atomic.cpp
1 INTERFACE:
2
3 #include "types.h"
4
5 extern "C" void cas_error_type_with_bad_size_used(void);
6
7 #define MACRO_CAS_ASSERT(rs,cs) \
8   if( (rs) != (cs) ) \
9     cas_error_type_with_bad_size_used()
10
11
12 template< typename A, typename B >
13 struct Pair
14 {
15   A first;
16   B second;
17
18   Pair() {}
19   Pair(A const &a, B const &b) : first(a), second(b) {}
20 };
21
22
23 //---------------------------------------------------------------------------
24 IMPLEMENTATION:
25
26 template< typename Type > inline
27 bool
28 cas(Type *ptr, Type oldval, Type newval)
29 {
30   MACRO_CAS_ASSERT(sizeof(Type),sizeof(Mword));
31   return cas_unsafe(reinterpret_cast<Mword*>(ptr),
32                     (Mword)oldval, (Mword)newval);
33 }
34
35 template< typename Type > inline
36 bool
37 cas2(Type *ptr, Type *oldval, Type *newval)
38 {
39   MACRO_CAS_ASSERT(sizeof(Type),(sizeof(Mword)*2));
40   return cas2_unsafe(reinterpret_cast<Mword*>(ptr),
41                      reinterpret_cast<Mword*>(oldval),
42                      reinterpret_cast<Mword*>(newval));
43 }
44
45 template <typename T> inline
46 T
47 atomic_change(T *ptr, T mask, T bits)
48 {
49   T old;
50   do
51     {
52       old = *ptr;
53     }
54   while (!cas(ptr, old, (old & mask) | bits));
55   return old;
56 }
57
58 //---------------------------------------------------------------------------
59 IMPLEMENTATION [ia32,ux]:
60
61 inline
62 void
63 atomic_mp_and(Mword *l, Mword value)
64 {
65   asm volatile ("lock; andl %1, %2" : "=m"(*l) : "ir"(value), "m"(*l));
66 }
67
68 inline
69 void
70 atomic_mp_or(Mword *l, Mword value)
71 {
72   asm volatile ("lock; orl %1, %2" : "=m"(*l) : "ir"(value), "m"(*l));
73 }
74
75
76 inline
77 void
78 atomic_mp_add(Mword *l, Mword value)
79 {
80   asm volatile ("lock; addl %1, %2" : "=m"(*l) : "ir"(value), "m"(*l));
81 }
82
83 inline
84 void
85 atomic_add(Mword *l, Mword value)
86 {
87   asm volatile ("addl %1, %2" : "=m"(*l) : "ir"(value), "m"(*l));
88 }
89
90 inline
91 void
92 atomic_and(Mword *l, Mword mask)
93 {
94   asm volatile ("andl %1, %2" : "=m"(*l) : "ir"(mask), "m"(*l));
95 }
96
97 inline
98 void
99 atomic_or(Mword *l, Mword bits)
100 {
101   asm volatile ("orl %1, %2" : "=m"(*l) : "ir"(bits), "m"(*l));
102 }
103
104 // ``unsafe'' stands for no safety according to the size of the given type.
105 // There are type safe versions of the cas operations in the architecture
106 // independent part of atomic that use the unsafe versions and make a type
107 // check.
108
109 inline
110 bool
111 cas_unsafe(Mword *ptr, Mword oldval, Mword newval)
112 {
113   Mword tmp;
114
115   asm volatile
116     ("cmpxchgl %1, %2"
117      : "=a" (tmp)
118      : "r" (newval), "m" (*ptr), "a" (oldval)
119      : "memory");
120
121   return tmp == oldval;
122 }
123
124
125 inline
126 bool
127 mp_cas_arch(Mword *m, Mword o, Mword n)
128 {
129   Mword tmp;
130
131   asm volatile
132     ("lock; cmpxchgl %1, %2"
133      : "=a" (tmp)
134      : "r" (n), "m" (*m), "a" (o)
135      : "memory");
136
137   return tmp == o;
138 }
139
140 inline
141 bool
142 cas2_unsafe(Mword *ptr, Mword *oldval, Mword *newval)
143 {
144   char ret;
145   asm volatile
146     ("cmpxchg8b %3 ; sete %%cl"
147      : "=c" (ret), 
148        "=a" (* oldval), 
149        "=d" (*(oldval+1))
150      : "m" (*ptr) , 
151        "a" (* oldval), "d" (*(oldval+1)), 
152        "b" (* newval), "c" (*(newval+1))
153      : "memory");
154
155   return ret;
156 }
157
158 inline
159 bool
160 mp_cas2_arch(char *m, Mword o1, Mword o2, Mword n1, Mword n2)
161 {
162   char ret;
163   asm volatile
164     ("lock; cmpxchg8b %3 ; sete %%cl"
165      : "=c" (ret), "=a" (o1), "=d" (o2)
166      : "m" (*m), "a" (o1), "d" (o2),
167        "b" (n1), "c" (n2)
168      : "memory");
169
170   return ret;
171 }
172 inline
173 bool
174 tas(Mword *l)
175 {
176   Mword tmp;
177   asm volatile ("xchg %0, %1" : "=r"(tmp) : "m"(*l), "0"(1) : "memory");
178   return tmp;
179 }
180
181 //---------------------------------------------------------------------------
182 IMPLEMENTATION[(ppc32 && !mp) || (arm && !armv6plus)]:
183
184 #include "processor.h"
185
186 inline NEEDS["processor.h"]
187 void
188 atomic_mp_and(Mword *l, Mword value)
189 {
190   Proc::Status s = Proc::cli_save();
191   *l &= value;
192   Proc::sti_restore(s);
193 }
194
195 inline NEEDS["processor.h"]
196 void
197 atomic_mp_or(Mword *l, Mword value)
198 {
199   Proc::Status s = Proc::cli_save();
200   *l |= value;
201   Proc::sti_restore(s);
202 }
203
204 inline NEEDS["processor.h"]
205 void
206 atomic_mp_add(Mword *l, Mword value)
207 {
208   Proc::Status s = Proc::cli_save();
209   *l += value;
210   Proc::sti_restore(s);
211 }
212
213 //---------------------------------------------------------------------------
214 IMPLEMENTATION[arm && armv6plus]:
215
216 inline
217 void
218 atomic_mp_add(Mword *l, Mword value)
219 {
220   Mword tmp, ret;
221
222   asm volatile (
223       "1:                                 \n"
224       "ldrex   %[v], [%[mem]]             \n"
225       "add     %[v], %[v], %[addval]      \n"
226       "strex   %[ret], %[v], [%[mem]]     \n"
227       "teq     %[ret], #0                 \n"
228       "bne     1b                         \n"
229       : [v] "=&r" (tmp), [ret] "=&r" (ret), "+m" (*l)
230       :  [mem] "r" (l), [addval] "r" (value)
231       : "cc");
232 }
233
234 inline
235 void
236 atomic_mp_and(Mword *l, Mword value)
237 {
238   Mword tmp, ret;
239
240   asm volatile (
241       "1:                                 \n"
242       "ldrex   %[v], [%[mem]]             \n"
243       "and     %[v], %[v], %[andval]     \n"
244       "strex   %[ret], %[v], [%[mem]]     \n"
245       "teq     %[ret], #0                 \n"
246       "bne     1b                         \n"
247       : [v] "=&r" (tmp), [ret] "=&r" (ret), "+m" (*l)
248       :  [mem] "r" (l), [andval] "r" (value)
249       : "cc");
250 }
251
252 inline
253 void
254 atomic_mp_or(Mword *l, Mword value)
255 {
256   Mword tmp, ret;
257
258   asm volatile (
259       "1:                                 \n"
260       "ldrex   %[v], [%[mem]]             \n"
261       "orr     %[v], %[v], %[orval]     \n"
262       "strex   %[ret], %[v], [%[mem]]     \n"
263       "teq     %[ret], #0                 \n"
264       "bne     1b                         \n"
265       : [v] "=&r" (tmp), [ret] "=&r" (ret), "+m" (*l)
266       :  [mem] "r" (l), [orval] "r" (value)
267       : "cc");
268 }
269
270
271 inline
272 bool
273 mp_cas_arch(Mword *m, Mword o, Mword n)
274 {
275   Mword tmp, res;
276
277   asm volatile
278     ("mov     %[res], #1           \n"
279      "1:                           \n"
280      "ldr     %[tmp], [%[m]]       \n"
281      "teq     %[tmp], %[o]         \n"
282      "bne     2f                   \n"
283      "ldrex   %[tmp], [%[m]]       \n"
284      "teq     %[tmp], %[o]         \n"
285      "strexeq %[res], %[n], [%[m]] \n"
286      "teq     %[res], #1           \n"
287      "beq     1b                   \n"
288      "2:                           \n"
289      : [tmp] "=&r" (tmp), [res] "=&r" (res), "+m" (*m)
290      : [n] "r" (n), [m] "r" (m), [o] "r" (o)
291      : "cc");
292
293   // res == 0 is ok
294   // res == 1 is failed
295
296   return !res;
297 }
298
299 inline
300 bool
301 mp_cas2_arch(char *m, Mword o1, Mword o2, Mword n1, Mword n2)
302 {
303   register Mword _n1 asm("r6") = n1;
304   register Mword _n2 asm("r7") = n2;
305   register Mword tmp1 asm("r8");
306   register Mword tmp2 asm("r9");
307   Mword res;
308
309   asm volatile
310     ("mov      %[res], #1             \n"
311      "1:                              \n"
312      "ldrd     %[tmp1], [%[m]]        \n"
313      "teq      %[tmp1], %[o1]         \n"
314      "teqeq    %[tmp2], %[o2]         \n"
315      "bne      2f                     \n"
316      "ldrexd   %[tmp1], [%[m]]        \n"
317      "mov      %[res], #1             \n"
318      "teq      %[tmp1], %[o1]         \n"
319      "teqeq    %[tmp2], %[o2]         \n"
320      "strexdeq %[res], %[n1], [%[m]]  \n"
321      "teq      %[res], #1             \n"
322      "beq      1b                     \n"
323      "2:                              \n"
324      : [tmp1] "=r" (tmp1), [tmp2] "=r" (tmp2),
325        [res] "=&r" (res), "+m" (*m), "+m" (*(m + 1))
326      : "0" (tmp1), "1" (tmp2),
327        [n1] "r" (_n1), "r" (_n2),
328        [m]  "r" (m),
329        [o1] "r" (o1), [o2] "r" (o2)
330      : "cc");
331
332   return !res;
333 }
334
335 //---------------------------------------------------------------------------
336 IMPLEMENTATION [mp]:
337
338 template< typename T > inline
339 bool
340 mp_cas(T *m, T o, T n)
341 {
342   MACRO_CAS_ASSERT(sizeof(T),sizeof(Mword));
343   return mp_cas_arch(reinterpret_cast<Mword*>(m),
344                      Mword(o),
345                      Mword(n));
346 }
347
348 template< typename T, typename T2 > inline
349 bool
350 mp_cas2(Pair<T,T2> *m, T o1, T2 o2, T n1, T2 n2)
351 {
352   MACRO_CAS_ASSERT(sizeof(T),sizeof(Mword));
353   MACRO_CAS_ASSERT(sizeof(T2),sizeof(Mword));
354   return mp_cas2_arch(reinterpret_cast<char *>(m),
355                       Mword(o1),
356                       Mword(o2),
357                       Mword(n1),
358                       Mword(n2));
359 }
360
361
362 //---------------------------------------------------------------------------
363 IMPLEMENTATION [!mp]:
364
365 template< typename T > inline
366 bool
367 mp_cas(T *m, T o, T n)
368 { return cas(m,o,n); }
369