1 /*
2  *
3  *  C++ Portable Types Library (PTypes)
4  *  Version 2.1.1  Released 27-Jun-2007
5  *
6  *  Copyright (C) 2001-2007 Hovik Melikyan
7  *
8  *  http://www.melikyan.com/ptypes/
9  *
10  */
11 
12 #ifdef WIN32
13 #  include <windows.h>
14 #endif
15 
16 #include "ptypes.h"
17 #include "pasync.h"     // for pmemlock*
18 
19 
20 PTYPES_BEGIN
21 
22 
23 #ifdef PTYPES_ST
24 // single-threaded version
25 
26 
pexchange(int * target,int value)27 int __PFASTCALL pexchange(int* target, int value)
28 {
29     int r = *target;
30     *target = value;
31     return r;
32 }
33 
34 
pexchange(void ** target,void * value)35 void* __PFASTCALL pexchange(void** target, void* value)
36 {
37     void* r = *target;
38     *target = value;
39     return r;
40 }
41 
42 
pincrement(int * target)43 int __PFASTCALL pincrement(int* target)
44 {
45     return ++(*target);
46 }
47 
48 
pdecrement(int * target)49 int __PFASTCALL pdecrement(int* target)
50 {
51     return --(*target);
52 }
53 
54 
55 #else
56 // multi-threaded version
57 
58 #if defined(__GNUC__) && (defined(__i386__) || defined(__I386__))
59 #  define GCC_i386
60 #elif defined(__GNUC__) && defined(__ppc__)
61 #  define GCC_PPC
62 #elif defined(_MSC_VER) && defined(_M_IX86)
63 #  define MSC_i386
64 #elif defined(__BORLANDC__) && defined(_M_IX86)
65 #  define BCC_i386
66 #elif defined(__GNUC__) && defined(__sparc__) && !defined(__arch64__)
67 #  define GCC_sparc
68 #endif
69 
70 
71 #if defined(MSC_i386) || defined(BCC_i386)
72 
73 //
74 // atomic operations for Microsoft C or Borland C on Windows
75 //
76 
77 #if defined(_MSC_VER)
78 #  pragma warning (disable: 4035)
79 #elif defined(__BORLANDC__)
80 #  pragma warn -rvl
81 #endif
82 
83 
84 // !!! NOTE
85 // the following functions implement atomic exchange/inc/dec on
86 // windows. they are dangerous in that they rely on the calling
87 // conventions of MSVC and BCC. the first one passes the first
88 // two arguments in ECX and EDX, and the second one - in EAX and
89 // EDX.
90 
91 int __PFASTCALL pincrement(int*)
92 {
93     __asm
94     {
95 #ifdef BCC_i386
96         mov         ecx,eax
97 #endif
98         mov         eax,1;
99         lock xadd   [ecx],eax;
100         inc         eax
101     }
102 }
103 
104 
105 int __PFASTCALL pdecrement(int*)
106 {
107     __asm
108     {
109 #ifdef BCC_i386
110         mov         ecx,eax
111 #endif
112         mov         eax,-1;
113         lock xadd   [ecx],eax;
114         dec         eax
115     }
116 }
117 
118 
119 int __PFASTCALL pexchange(int*, int)
120 {
121     __asm
122     {
123 #ifdef BCC_i386
124         xchg        eax,edx;
125         lock xchg   eax,[edx];
126 #else
127         mov         eax,edx;
128         lock xchg   eax,[ecx];
129 #endif
130     }
131 }
132 
133 
134 void* __PFASTCALL pexchange(void**, void*)
135 {
136     __asm
137     {
138 #ifdef BCC_i386
139         xchg        eax,edx;
140         lock xchg   eax,[edx];
141 #else
142         mov         eax,edx;
143         lock xchg   eax,[ecx];
144 #endif
145     }
146 }
147 
148 
149 #elif defined(GCC_i386)
150 
151 //
152 // GNU C compiler on any i386 platform (actually 486+ for xadd)
153 //
154 
155 int pexchange(int* target, int value)
156 {
157     __asm__ __volatile ("lock ; xchgl (%1),%0" : "+r" (value) : "r" (target));
158     return value;
159 }
160 
161 
162 void* pexchange(void** target, void* value)
163 {
164     __asm__ __volatile ("lock ; xchgl (%1),%0" : "+r" (value) : "r" (target));
165     return value;
166 }
167 
168 
169 int pincrement(int* target)
170 {
171     int temp = 1;
172     __asm__ __volatile ("lock ; xaddl %0,(%1)" : "+r" (temp) : "r" (target));
173     return temp + 1;
174 }
175 
176 
177 int pdecrement(int* target)
178 {
179     int temp = -1;
180     __asm__ __volatile ("lock ; xaddl %0,(%1)" : "+r" (temp) : "r" (target));
181     return temp - 1;
182 }
183 
184 
185 #elif defined(GCC_PPC)
186 
187 //
188 // GNU C compiler on any PPC platform
189 //
190 
191 int pexchange(int* target, int value)
192 {
193     int temp;
194     __asm__ __volatile (
195 "1: lwarx  %0,0,%1\n\
196 	stwcx. %2,0,%1\n\
197 	bne-   1b\n\
198 	isync"
199 	: "=&r" (temp)
200 	: "r" (target), "r" (value)
201 	: "cc", "memory"
202 	);
203     return temp;
204 }
205 
206 
207 void* pexchange(void** target, void* value)
208 {
209     void* temp;
210     __asm__ __volatile (
211 "1: lwarx  %0,0,%1\n\
212 	stwcx. %2,0,%1\n\
213 	bne-   1b\n\
214 	isync"
215 	: "=&r" (temp)
216 	: "r" (target), "r" (value)
217 	: "cc", "memory"
218 	);
219     return temp;
220 }
221 
222 
223 int pincrement(int* target)
224 {
225     int temp;
226     __asm__ __volatile (
227 "1: lwarx  %0,0,%1\n\
228 	addic  %0,%0,1\n\
229 	stwcx. %0,0,%1\n\
230 	bne-   1b\n\
231 	isync"
232 	: "=&r" (temp)
233 	: "r" (target)
234 	: "cc", "memory"
235 	);
236     return temp;
237 }
238 
239 
240 int pdecrement(int* target)
241 {
242     int temp;
243     __asm__ __volatile (
244 "1: lwarx  %0,0,%1\n\
245 	addic  %0,%0,-1\n\
246 	stwcx. %0,0,%1\n\
247 	bne-   1b\n\
248 	isync"
249 	: "=&r" (temp)
250 	: "r" (target)
251 	: "cc", "memory"
252 	);
253     return temp;
254 }
255 
256 
257 #elif defined GCC_sparc
258 
259 //
260 // GNU C compiler on SPARC in 32-bit mode (pointers are 32-bit)
261 //
262 
263 // assembly routines defined in patomic.sparc.s
264 // we currently don't use CAS in the library, but let it be there
265 extern "C" {
266     int __patomic_add(volatile int* __mem, int __val);
267     int __patomic_swap(volatile int* __mem, int __val);
268     int __patomic_cas(volatile int* __mem, int __expected, int __newval);
269 }
270 
271 #define __patomic_swap_p(mem,val) \
272     (void*)(__patomic_swap((int*)(mem), (int)(val)))
273 
274 
275 int pexchange(int* target, int value)
276 {
277     return __patomic_swap(target, value);
278 }
279 
280 
281 void* pexchange(void** target, void* value)
282 {
283     return __patomic_swap_p(target, value);
284 }
285 
286 
287 int pincrement(int* target)
288 {
289     return __patomic_add(target, 1);
290 }
291 
292 
293 int pdecrement(int* target)
294 {
295     return __patomic_add(target, -1);
296 }
297 
298 
299 
300 
301 #else
302 
303 //
304 // other platforms: mutex locking
305 //
306 
307 int pexchange(int* target, int value)
308 {
309     pmemlock* m = pgetmemlock(target);
310     pmementer(m);
311     int r = *target;
312     *target = value;
313     pmemleave(m);
314     return r;
315 }
316 
317 
318 void* pexchange(void** target, void* value)
319 {
320     pmemlock* m = pgetmemlock(target);
321     pmementer(m);
322     void* r = *target;
323     *target = value;
324     pmemleave(m);
325     return r;
326 }
327 
328 
329 int pincrement(int* target)
330 {
331     pmemlock* m = pgetmemlock(target);
332     pmementer(m);
333     int r = ++(*target);
334     pmemleave(m);
335     return r;
336 }
337 
338 
339 int pdecrement(int* target)
340 {
341     pmemlock* m = pgetmemlock(target);
342     pmementer(m);
343     int r = --(*target);
344     pmemleave(m);
345     return r;
346 }
347 
348 #endif
349 
350 
351 #endif
352 
353 
354 PTYPES_END
355