]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/lib/libk/atomic.cpp
Inital import
[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_add (Mword *l, Mword value)
64 {
65   asm volatile ("lock; addl %1, %2" : "=m"(*l) : "ir"(value), "m"(*l));
66 }
67
68 inline
69 void
70 atomic_add (Mword *l, Mword value)
71 {
72   asm volatile ("addl %1, %2" : "=m"(*l) : "ir"(value), "m"(*l));
73 }
74
75 inline
76 void
77 atomic_and (Mword *l, Mword mask)
78 {
79   asm volatile ("andl %1, %2" : "=m"(*l) : "ir"(mask), "m"(*l));
80 }
81
82 inline
83 void
84 atomic_or (Mword *l, Mword bits)
85 {
86   asm volatile ("orl %1, %2" : "=m"(*l) : "ir"(bits), "m"(*l));
87 }
88
89 // ``unsafe'' stands for no safety according to the size of the given type.
90 // There are type safe versions of the cas operations in the architecture
91 // independent part of atomic that use the unsafe versions and make a type
92 // check.
93
94 inline
95 bool
96 cas_unsafe (Mword *ptr, Mword oldval, Mword newval)
97 {
98   Mword tmp;
99
100   asm volatile
101     ("cmpxchgl %1, %2"
102      : "=a" (tmp)
103      : "r" (newval), "m" (*ptr), "a" (oldval)
104      : "memory");
105
106   return tmp == oldval;
107 }
108
109
110 inline
111 bool
112 mp_cas_arch(Mword *m, Mword o, Mword n)
113 {
114   Mword tmp;
115
116   asm volatile
117     ("lock; cmpxchgl %1, %2"
118      : "=a" (tmp)
119      : "r" (n), "m" (*m), "a" (o)
120      : "memory");
121
122   return tmp == o;
123 }
124
125 inline
126 bool
127 cas2_unsafe (Mword *ptr, Mword *oldval, Mword *newval)
128 {
129   char ret;
130   asm volatile
131     ("cmpxchg8b %3 ; sete %%cl"
132      : "=c" (ret), 
133        "=a" (* oldval), 
134        "=d" (*(oldval+1))
135      : "m" (*ptr) , 
136        "a" (* oldval), "d" (*(oldval+1)), 
137        "b" (* newval), "c" (*(newval+1))
138      : "memory");
139
140   return ret;
141 }
142
143 inline
144 bool
145 mp_cas2_arch (char *m, Mword o1, Mword o2, Mword n1, Mword n2)
146 {
147   char ret;
148   asm volatile
149     ("lock; cmpxchg8b %3 ; sete %%cl"
150      : "=c" (ret), "=a" (o1), "=d" (o2)
151      : "m" (*m), "a" (o1), "d" (o2),
152        "b" (n1), "c" (n2)
153      : "memory");
154
155   return ret;
156 }
157 inline
158 bool
159 tas (Mword *l)
160 {
161   Mword tmp;
162   asm volatile ("xchg %0, %1" : "=r"(tmp) : "m"(*l), "0"(1) : "memory");
163   return tmp;
164 }
165
166 //---------------------------------------------------------------------------
167 IMPLEMENTATION[(ppc32 && !mp) || (arm && !armv6plus)]:
168
169 #include "processor.h"
170
171 inline NEEDS["processor.h"]
172 void
173 atomic_mp_add (Mword *l, Mword value)
174 {
175   Proc::Status s = Proc::cli_save();
176   *l += value;
177   Proc::sti_restore(s);
178 }
179
180
181 //---------------------------------------------------------------------------
182 IMPLEMENTATION[arm && armv6plus]:
183
184 inline
185 void
186 atomic_mp_add (Mword *l, Mword value)
187 {
188   Mword tmp, ret;
189
190   asm volatile (
191       "1:                                 \n"
192       "ldrex   %[v], [%[mem]]             \n"
193       "add     %[v], %[v], %[addval]      \n"
194       "strex   %[ret], %[v], [%[mem]]     \n"
195       "teq     %[ret], #0                 \n"
196       "bne     1b                         \n"
197       : [v] "=&r" (tmp), [ret] "=&r" (ret), "+m" (*l)
198       :  [mem] "r" (l), [addval] "r" (value)
199       : "cc");
200 }
201
202
203 inline
204 bool
205 mp_cas_arch(Mword *m, Mword o, Mword n)
206 {
207   Mword tmp, res;
208
209   asm volatile
210     ("ldrex   %[tmp], [%[m]]       \n"
211      "mov     %[res], #1           \n"
212      "teq     %[tmp], %[o]         \n"
213      "strexeq %[res], %[n], [%[m]] \n"
214      : [tmp] "=&r" (tmp), [res] "=&r" (res), "+m" (*m)
215      : [n] "r" (n), [m] "r" (m), [o] "r" (o)
216      : "cc");
217
218   // res == 0 is ok
219   // res == 1 is failed
220
221   return !res;
222 }
223
224 inline
225 bool
226 mp_cas2_arch (char *m, Mword o1, Mword o2, Mword n1, Mword n2)
227 {
228   register Mword _n1 asm("r6") = n1;
229   register Mword _n2 asm("r7") = n2;
230   register Mword tmp1 asm("r8");
231   register Mword tmp2 asm("r9");
232   Mword res;
233
234   asm volatile
235     ("ldrexd   %[tmp1], [%[m]]        \n"
236      "mov      %[res], #1             \n"
237      "teq      %[tmp1], %[o1]         \n"
238      "teqeq    %[tmp2], %[o2]         \n"
239      "strexdeq %[res], %[n1], [%[m]]  \n"
240      : [tmp1] "=r" (tmp1), [tmp2] "=r" (tmp2),
241        [res] "=&r" (res), "+m" (*m), "+m" (*(m + 1))
242      : "0" (tmp1), "1" (tmp2),
243        [n1] "r" (_n1), "r" (_n2),
244        [m]  "r" (m),
245        [o1] "r" (o1), [o2] "r" (o2)
246      : "cc");
247
248   return !res;
249 }
250
251 //---------------------------------------------------------------------------
252 IMPLEMENTATION [mp]:
253
254 template< typename T > inline
255 bool
256 mp_cas (T *m, T o, T n)
257 {
258   MACRO_CAS_ASSERT(sizeof(T),sizeof(Mword));
259   return mp_cas_arch(reinterpret_cast<Mword*>(m),
260                      Mword(o),
261                      Mword(n));
262 }
263
264 template< typename T, typename T2 > inline
265 bool
266 mp_cas2 (Pair<T,T2> *m, T o1, T2 o2, T n1, T2 n2)
267 {
268   MACRO_CAS_ASSERT(sizeof(T),sizeof(Mword));
269   MACRO_CAS_ASSERT(sizeof(T2),sizeof(Mword));
270   return mp_cas2_arch(reinterpret_cast<char *>(m),
271                       Mword(o1),
272                       Mword(o2),
273                       Mword(n1),
274                       Mword(n2));
275 }
276
277
278 //---------------------------------------------------------------------------
279 IMPLEMENTATION [!mp]:
280
281 template< typename T > inline
282 bool
283 mp_cas (T *m, T o, T n)
284 { return cas(m,o,n); }
285