Unbreak getTcpTable() on Linux-based systems and make it work on BSD
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #ifdef __i386__
25
26 #ifdef __GNUC__
27
28 __ASM_GLOBAL_FUNC(interlocked_cmpxchg,
29                   "movl 12(%esp),%eax\n\t"
30                   "movl 8(%esp),%ecx\n\t"
31                   "movl 4(%esp),%edx\n\t"
32                   "lock; cmpxchgl %ecx,(%edx)\n\t"
33                   "ret");
34 __ASM_GLOBAL_FUNC(interlocked_cmpxchg_ptr,
35                   "movl 12(%esp),%eax\n\t"
36                   "movl 8(%esp),%ecx\n\t"
37                   "movl 4(%esp),%edx\n\t"
38                   "lock; cmpxchgl %ecx,(%edx)\n\t"
39                   "ret");
40 __ASM_GLOBAL_FUNC(interlocked_xchg,
41                   "movl 8(%esp),%eax\n\t"
42                   "movl 4(%esp),%edx\n\t"
43                   "lock; xchgl %eax,(%edx)\n\t"
44                   "ret");
45 __ASM_GLOBAL_FUNC(interlocked_xchg_ptr,
46                   "movl 8(%esp),%eax\n\t"
47                   "movl 4(%esp),%edx\n\t"
48                   "lock; xchgl %eax,(%edx)\n\t"
49                   "ret");
50 __ASM_GLOBAL_FUNC(interlocked_xchg_add,
51                   "movl 8(%esp),%eax\n\t"
52                   "movl 4(%esp),%edx\n\t"
53                   "lock; xaddl %eax,(%edx)\n\t"
54                   "ret");
55
56 #elif defined(_MSC_VER)
57
58 __declspec(naked) long interlocked_cmpxchg( long *dest, long xchg, long compare )
59 {
60     __asm mov eax, 12[esp];
61     __asm mov ecx, 8[esp];
62     __asm mov edx, 4[esp];
63     __asm lock cmpxchg [edx], ecx;
64     __asm ret;
65 }
66
67 __declspec(naked) void *interlocked_cmpxchg_ptr( void **dest, void *xchg, void *compare )
68 {
69     __asm mov eax, 12[esp];
70     __asm mov ecx, 8[esp];
71     __asm mov edx, 4[esp];
72     __asm lock cmpxchg [edx], ecx;
73     __asm ret;
74 }
75
76 __declspec(naked) long interlocked_xchg( long *dest, long val )
77 {
78     __asm mov eax, 8[esp];
79     __asm mov edx, 4[esp];
80     __asm lock xchg [edx], eax;
81     __asm ret;
82 }
83
84 __declspec(naked) void *interlocked_xchg_ptr( void **dest, void *val )
85 {
86     __asm mov eax, 8[esp];
87     __asm mov edx, 4[esp];
88     __asm lock xchg [edx], eax;
89     __asm ret;
90 }
91
92 __declspec(naked) long interlocked_xchg_add( long *dest, long incr )
93 {
94     __asm mov eax, 8[esp];
95     __asm mov edx, 4[esp];
96     __asm lock xadd [edx], eax;
97     __asm ret;
98 }
99
100 #else
101 # error You must implement the interlocked* functions for your compiler
102 #endif
103
104 #elif defined(__powerpc__)
105 void* interlocked_cmpxchg_ptr( void **dest, void* xchg, void* compare)
106 {
107     long ret = 0;
108     long scratch;
109     __asm__ __volatile__(
110         "0:    lwarx %0,0,%2\n"
111         "      xor. %1,%4,%0\n"
112         "      bne 1f\n"
113         "      stwcx. %3,0,%2\n"
114         "      bne- 0b\n"
115         "1:    "
116         : "=&r"(ret), "=&r"(scratch)
117         : "r"(dest), "r"(xchg), "r"(compare)
118         : "cr0","memory");
119     return (void*)ret;
120 }
121
122 long interlocked_cmpxchg( long *dest, long xchg, long compare)
123 {
124     long ret = 0;
125     long scratch;
126     __asm__ __volatile__(
127         "0:    lwarx %0,0,%2\n"
128         "      xor. %1,%4,%0\n"
129         "      bne 1f\n"
130         "      stwcx. %3,0,%2\n"
131         "      bne- 0b\n"
132         "1:    "
133         : "=&r"(ret), "=&r"(scratch)
134         : "r"(dest), "r"(xchg), "r"(compare)
135         : "cr0","memory","r0");
136     return ret;
137 }
138
139 long interlocked_xchg_add( long *dest, long incr )
140 {
141     long ret = 0;
142     long zero = 0;
143     __asm__ __volatile__(
144         "0:    lwarx %0, %3, %1\n"
145         "      add %0, %2, %0\n"
146         "      stwcx. %0, %3, %1\n"
147         "      bne- 0b\n"
148         : "=&r" (ret)
149         : "r"(dest), "r"(incr), "r"(zero)
150         : "cr0", "memory", "r0"
151     );
152     return ret-incr;
153 }
154
155 long interlocked_xchg( long* dest, long val )
156 {
157     long ret = 0;
158     __asm__ __volatile__(
159         "0:    lwarx %0,0,%1\n"
160         "      stwcx. %2,0,%1\n"
161         "      bne- 0b\n"
162         : "=&r"(ret)
163         : "r"(dest), "r"(val)
164         : "cr0","memory","r0");
165     return ret;
166 }
167
168 void* interlocked_xchg_ptr( void** dest, void* val )
169 {
170     void *ret = NULL;
171     __asm__ __volatile__(
172         "0:    lwarx %0,0,%1\n"
173         "      stwcx. %2,0,%1\n"
174         "      bne- 0b \n"
175         : "=&r"(ret)
176         : "r"(dest), "r"(val)
177         : "cr0","memory","r0");
178     return ret;
179 }
180
181 #elif defined(__sparc__) && defined(__sun__)
182
183 /*
184  * As the earlier Sparc processors lack necessary atomic instructions,
185  * I'm simply falling back to the library-provided _lwp_mutex routines
186  * to ensure mutual exclusion in a way appropriate for the current
187  * architecture.
188  *
189  * FIXME:  If we have the compare-and-swap instruction (Sparc v9 and above)
190  *         we could use this to speed up the Interlocked operations ...
191  */
192 #include <synch.h>
193 static lwp_mutex_t interlocked_mutex = DEFAULTMUTEX;
194
195 long interlocked_cmpxchg( long *dest, long xchg, long compare )
196 {
197     _lwp_mutex_lock( &interlocked_mutex );
198     if (*dest == compare) *dest = xchg;
199     else compare = *dest;
200     _lwp_mutex_unlock( &interlocked_mutex );
201     return compare;
202 }
203
204 void *interlocked_cmpxchg_ptr( void **dest, void *xchg, void *compare )
205 {
206     _lwp_mutex_lock( &interlocked_mutex );
207     if (*dest == compare) *dest = xchg;
208     else compare = *dest;
209     _lwp_mutex_unlock( &interlocked_mutex );
210     return compare;
211 }
212
213 long interlocked_xchg( long *dest, long val )
214 {
215     long retv;
216     _lwp_mutex_lock( &interlocked_mutex );
217     retv = *dest;
218     *dest = val;
219     _lwp_mutex_unlock( &interlocked_mutex );
220     return retv;
221 }
222
223 void *interlocked_xchg_ptr( void **dest, void *val )
224 {
225     long retv;
226     _lwp_mutex_lock( &interlocked_mutex );
227     retv = *dest;
228     *dest = val;
229     _lwp_mutex_unlock( &interlocked_mutex );
230     return retv;
231 }
232
233 long interlocked_xchg_add( long *dest, long incr )
234 {
235     long retv;
236     _lwp_mutex_lock( &interlocked_mutex );
237     retv = *dest;
238     *dest += incr;
239     _lwp_mutex_unlock( &interlocked_mutex );
240     return retv;
241 }
242 #else
243 # error You must implement the interlocked* functions for your CPU
244 #endif