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