crypt32: Make sure we show Unicode characters (Dutch translation).
[wine] / libs / port / interlocked.c
1 /*
2  * interlocked functions
3  *
4  * Copyright 1996 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23 #include <assert.h>
24
25 #ifdef __i386__
26
27 #ifdef __GNUC__
28
29 __ASM_GLOBAL_FUNC(interlocked_cmpxchg,
30                   "movl 12(%esp),%eax\n\t"
31                   "movl 8(%esp),%ecx\n\t"
32                   "movl 4(%esp),%edx\n\t"
33                   "lock; cmpxchgl %ecx,(%edx)\n\t"
34                   "ret")
35 __ASM_GLOBAL_FUNC(interlocked_cmpxchg_ptr,
36                   "movl 12(%esp),%eax\n\t"
37                   "movl 8(%esp),%ecx\n\t"
38                   "movl 4(%esp),%edx\n\t"
39                   "lock; cmpxchgl %ecx,(%edx)\n\t"
40                   "ret")
41  __ASM_GLOBAL_FUNC(interlocked_cmpxchg64,
42                    "push %ebx\n\t"
43                    __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
44                    __ASM_CFI(".cfi_rel_offset %ebx,0\n\t")
45                    "push %esi\n\t"
46                    __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
47                    __ASM_CFI(".cfi_rel_offset %esi,0\n\t")
48                    "movl 12(%esp),%esi\n\t"
49                    "movl 16(%esp),%ebx\n\t"
50                    "movl 20(%esp),%ecx\n\t"
51                    "movl 24(%esp),%eax\n\t"
52                    "movl 28(%esp),%edx\n\t"
53                    "lock; cmpxchg8b (%esi)\n\t"
54                    "pop %esi\n\t"
55                    __ASM_CFI(".cfi_same_value %esi\n\t")
56                    __ASM_CFI(".cfi_adjust_cfa_offset -4\n\t")
57                    "pop %ebx\n\t"
58                    __ASM_CFI(".cfi_same_value %ebx\n\t")
59                    __ASM_CFI(".cfi_adjust_cfa_offset -4\n\t")
60                    "ret")
61 __ASM_GLOBAL_FUNC(interlocked_xchg,
62                   "movl 8(%esp),%eax\n\t"
63                   "movl 4(%esp),%edx\n\t"
64                   "lock; xchgl %eax,(%edx)\n\t"
65                   "ret")
66 __ASM_GLOBAL_FUNC(interlocked_xchg_ptr,
67                   "movl 8(%esp),%eax\n\t"
68                   "movl 4(%esp),%edx\n\t"
69                   "lock; xchgl %eax,(%edx)\n\t"
70                   "ret")
71 __ASM_GLOBAL_FUNC(interlocked_xchg_add,
72                   "movl 8(%esp),%eax\n\t"
73                   "movl 4(%esp),%edx\n\t"
74                   "lock; xaddl %eax,(%edx)\n\t"
75                   "ret")
76
77 #elif defined(_MSC_VER)
78
79 __declspec(naked) int interlocked_cmpxchg( int *dest, int xchg, int compare )
80 {
81     __asm mov eax, 12[esp];
82     __asm mov ecx, 8[esp];
83     __asm mov edx, 4[esp];
84     __asm lock cmpxchg [edx], ecx;
85     __asm ret;
86 }
87
88 __declspec(naked) void *interlocked_cmpxchg_ptr( void **dest, void *xchg, void *compare )
89 {
90     __asm mov eax, 12[esp];
91     __asm mov ecx, 8[esp];
92     __asm mov edx, 4[esp];
93     __asm lock cmpxchg [edx], ecx;
94     __asm ret;
95 }
96
97 __declspec(naked) __int64 interlocked_cmpxchg64( __int64 *dest, __int64 xchg, __int64 compare)
98 {
99     __asm push ebx;
100     __asm push esi;
101     __asm mov esi, 12[esp];
102     __asm mov ebx, 16[esp];
103     __asm mov ecx, 20[esp];
104     __asm mov eax, 24[esp];
105     __asm mov edx, 28[esp];
106     __asm lock cmpxchg8b [esi];
107     __asm pop esi;
108     __asm pop ebx;
109     __asm ret;
110 }
111
112 __declspec(naked) int interlocked_xchg( int *dest, int val )
113 {
114     __asm mov eax, 8[esp];
115     __asm mov edx, 4[esp];
116     __asm lock xchg [edx], eax;
117     __asm ret;
118 }
119
120 __declspec(naked) void *interlocked_xchg_ptr( void **dest, void *val )
121 {
122     __asm mov eax, 8[esp];
123     __asm mov edx, 4[esp];
124     __asm lock xchg [edx], eax;
125     __asm ret;
126 }
127
128 __declspec(naked) int interlocked_xchg_add( int *dest, int incr )
129 {
130     __asm mov eax, 8[esp];
131     __asm mov edx, 4[esp];
132     __asm lock xadd [edx], eax;
133     __asm ret;
134 }
135
136 #else
137 # error You must implement the interlocked* functions for your compiler
138 #endif
139
140 #elif defined(__x86_64__)
141
142 #ifdef __GNUC__
143
144 __ASM_GLOBAL_FUNC(interlocked_cmpxchg,
145                   "mov %edx, %eax\n\t"
146                   "lock cmpxchgl %esi,(%rdi)\n\t"
147                   "ret")
148 __ASM_GLOBAL_FUNC(interlocked_cmpxchg_ptr,
149                   "mov %rdx, %rax\n\t"
150                   "lock cmpxchgq %rsi,(%rdi)\n\t"
151                   "ret")
152 __ASM_GLOBAL_FUNC(interlocked_cmpxchg64,
153                   "mov %rdx, %rax\n\t"
154                   "lock cmpxchgq %rsi,(%rdi)\n\t"
155                   "ret")
156 __ASM_GLOBAL_FUNC(interlocked_xchg,
157                   "mov %esi, %eax\n\t"
158                   "lock xchgl %eax, (%rdi)\n\t"
159                   "ret")
160 __ASM_GLOBAL_FUNC(interlocked_xchg_ptr,
161                   "mov %rsi, %rax\n\t"
162                   "lock xchgq %rax,(%rdi)\n\t"
163                   "ret")
164 __ASM_GLOBAL_FUNC(interlocked_xchg_add,
165                   "mov %esi, %eax\n\t"
166                   "lock xaddl %eax, (%rdi)\n\t"
167                   "ret")
168
169 #else
170 # error You must implement the interlocked* functions for your compiler
171 #endif
172
173 #elif defined(__powerpc__)
174 void* interlocked_cmpxchg_ptr( void **dest, void* xchg, void* compare)
175 {
176     void *ret = 0;
177     void *scratch;
178     __asm__ __volatile__(
179         "0:    lwarx %0,0,%2\n"
180         "      xor. %1,%4,%0\n"
181         "      bne 1f\n"
182         "      stwcx. %3,0,%2\n"
183         "      bne- 0b\n"
184         "      isync\n"
185         "1:    "
186         : "=&r"(ret), "=&r"(scratch)
187         : "r"(dest), "r"(xchg), "r"(compare)
188         : "cr0","memory");
189     return ret;
190 }
191
192 __int64 interlocked_cmpxchg64( __int64 *dest, __int64 xchg, __int64 compare)
193 {
194     /* FIXME: add code */
195     assert(0);
196 }
197
198 int interlocked_cmpxchg( int *dest, int xchg, int compare)
199 {
200     int ret = 0;
201     int scratch;
202     __asm__ __volatile__(
203         "0:    lwarx %0,0,%2\n"
204         "      xor. %1,%4,%0\n"
205         "      bne 1f\n"
206         "      stwcx. %3,0,%2\n"
207         "      bne- 0b\n"
208         "      isync\n"
209         "1:    "
210         : "=&r"(ret), "=&r"(scratch)
211         : "r"(dest), "r"(xchg), "r"(compare)
212         : "cr0","memory","r0");
213     return ret;
214 }
215
216 int interlocked_xchg_add( int *dest, int incr )
217 {
218     int ret = 0;
219     int zero = 0;
220     __asm__ __volatile__(
221         "0:    lwarx %0, %3, %1\n"
222         "      add %0, %2, %0\n"
223         "      stwcx. %0, %3, %1\n"
224         "      bne- 0b\n"
225         "      isync\n"
226         : "=&r" (ret)
227         : "r"(dest), "r"(incr), "r"(zero)
228         : "cr0", "memory", "r0"
229     );
230     return ret-incr;
231 }
232
233 int interlocked_xchg( int* dest, int val )
234 {
235     int ret = 0;
236     __asm__ __volatile__(
237         "0:    lwarx %0,0,%1\n"
238         "      stwcx. %2,0,%1\n"
239         "      bne- 0b\n"
240         "      isync\n"
241         : "=&r"(ret)
242         : "r"(dest), "r"(val)
243         : "cr0","memory","r0");
244     return ret;
245 }
246
247 void* interlocked_xchg_ptr( void** dest, void* val )
248 {
249     void *ret = NULL;
250     __asm__ __volatile__(
251         "0:    lwarx %0,0,%1\n"
252         "      stwcx. %2,0,%1\n"
253         "      bne- 0b\n"
254         "      isync\n"
255         : "=&r"(ret)
256         : "r"(dest), "r"(val)
257         : "cr0","memory","r0");
258     return ret;
259 }
260
261 #elif defined(__sparc__) && defined(__sun__)
262
263 /*
264  * As the earlier Sparc processors lack necessary atomic instructions,
265  * I'm simply falling back to the library-provided _lwp_mutex routines
266  * to ensure mutual exclusion in a way appropriate for the current
267  * architecture.
268  *
269  * FIXME:  If we have the compare-and-swap instruction (Sparc v9 and above)
270  *         we could use this to speed up the Interlocked operations ...
271  */
272 #include <synch.h>
273 static lwp_mutex_t interlocked_mutex = DEFAULTMUTEX;
274
275 int interlocked_cmpxchg( int *dest, int xchg, int compare )
276 {
277     _lwp_mutex_lock( &interlocked_mutex );
278     if (*dest == compare) *dest = xchg;
279     else compare = *dest;
280     _lwp_mutex_unlock( &interlocked_mutex );
281     return compare;
282 }
283
284 void *interlocked_cmpxchg_ptr( void **dest, void *xchg, void *compare )
285 {
286     _lwp_mutex_lock( &interlocked_mutex );
287     if (*dest == compare) *dest = xchg;
288     else compare = *dest;
289     _lwp_mutex_unlock( &interlocked_mutex );
290     return compare;
291 }
292
293 __int64 interlocked_cmpxchg64( __int64 *dest, __int64 xchg, __int64 compare )
294 {
295     _lwp_mutex_lock( &interlocked_mutex );
296     if (*dest == compare) *dest = xchg;
297     else compare = *dest;
298     _lwp_mutex_unlock( &interlocked_mutex );
299     return compare;
300 }
301
302 int interlocked_xchg( int *dest, int val )
303 {
304     int retv;
305     _lwp_mutex_lock( &interlocked_mutex );
306     retv = *dest;
307     *dest = val;
308     _lwp_mutex_unlock( &interlocked_mutex );
309     return retv;
310 }
311
312 void *interlocked_xchg_ptr( void **dest, void *val )
313 {
314     void *retv;
315     _lwp_mutex_lock( &interlocked_mutex );
316     retv = *dest;
317     *dest = val;
318     _lwp_mutex_unlock( &interlocked_mutex );
319     return retv;
320 }
321
322 int interlocked_xchg_add( int *dest, int incr )
323 {
324     int retv;
325     _lwp_mutex_lock( &interlocked_mutex );
326     retv = *dest;
327     *dest += incr;
328     _lwp_mutex_unlock( &interlocked_mutex );
329     return retv;
330 }
331
332 #elif defined(__ALPHA__) && defined(__GNUC__)
333
334 __ASM_GLOBAL_FUNC(interlocked_cmpxchg,
335                   "L0cmpxchg:\n\t"
336                   "ldl_l $0,0($16)\n\t"
337                   "cmpeq $0,$18,$1\n\t"
338                   "beq   $1,L1cmpxchg\n\t"
339                   "mov   $17,$0\n\t"
340                   "stl_c $0,0($16)\n\t"
341                   "beq   $0,L0cmpxchg\n\t"
342                   "mov   $18,$0\n"
343                   "L1cmpxchg:\n\t"
344                   "mb")
345
346 __ASM_GLOBAL_FUNC(interlocked_cmpxchg_ptr,
347                   "L0cmpxchg_ptr:\n\t"
348                   "ldq_l $0,0($16)\n\t"
349                   "cmpeq $0,$18,$1\n\t"
350                   "beq   $1,L1cmpxchg_ptr\n\t"
351                   "mov   $17,$0\n\t"
352                   "stq_c $0,0($16)\n\t"
353                   "beq   $0,L0cmpxchg_ptr\n\t"
354                   "mov   $18,$0\n"
355                   "L1cmpxchg_ptr:\n\t"
356                   "mb")
357
358 __int64 interlocked_cmpxchg64(__int64 *dest, __int64 xchg, __int64 compare)
359 {
360     /* FIXME: add code */
361     assert(0);
362 }
363
364 __ASM_GLOBAL_FUNC(interlocked_xchg,
365                   "L0xchg:\n\t"
366                   "ldl_l $0,0($16)\n\t"
367                   "mov   $17,$1\n\t"
368                   "stl_c $1,0($16)\n\t"
369                   "beq   $1,L0xchg\n\t"
370                   "mb")
371
372 __ASM_GLOBAL_FUNC(interlocked_xchg_ptr,
373                   "L0xchg_ptr:\n\t"
374                   "ldq_l $0,0($16)\n\t"
375                   "mov   $17,$1\n\t"
376                   "stq_c $1,0($16)\n\t"
377                   "beq   $1,L0xchg_ptr\n\t"
378                   "mb")
379
380 __ASM_GLOBAL_FUNC(interlocked_xchg_add,
381                   "L0xchg_add:\n\t"
382                   "ldl_l $0,0($16)\n\t"
383                   "addl  $0,$17,$1\n\t"
384                   "stl_c $1,0($16)\n\t"
385                   "beq   $1,L0xchg_add\n\t"
386                   "mb")
387
388 #else
389 # error You must implement the interlocked* functions for your CPU
390 #endif