|
1 /* GLIB - Library of useful routines for C programming |
|
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald |
|
3 * |
|
4 * g_atomic_*: atomic operations. |
|
5 * Copyright (C) 2003 Sebastian Wilhelmi |
|
6 * Portions copyright (c) 2006 Nokia Corporation. All rights reserved. |
|
7 * |
|
8 * This library is free software; you can redistribute it and/or |
|
9 * modify it under the terms of the GNU Lesser General Public |
|
10 * License as published by the Free Software Foundation; either |
|
11 * version 2 of the License, or (at your option) any later version. |
|
12 * |
|
13 * This library is distributed in the hope that it will be useful, |
|
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
16 * Lesser General Public License for more details. |
|
17 * |
|
18 * You should have received a copy of the GNU Lesser General Public |
|
19 * License along with this library; if not, write to the |
|
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
|
21 * Boston, MA 02111-1307, USA. |
|
22 */ |
|
23 |
|
24 #include "config.h" |
|
25 |
|
26 #include "glib.h" |
|
27 #include "gthreadinit.h" |
|
28 #include "galias.h" |
|
29 |
|
30 #ifdef __SYMBIAN32__ |
|
31 #include <glib_wsd.h> |
|
32 #endif /* __SYMBIAN32__ */ |
|
33 |
|
34 #if EMULATOR |
|
35 #define g_thread_functions_for_glib_use (*_g_thread_functions_for_glib_use()) |
|
36 #define g_thread_use_default_impl (*_g_thread_use_default_impl()) |
|
37 #endif /* EMULATOR */ |
|
38 |
|
39 |
|
40 #if defined (__GNUC__) |
|
41 # if defined (G_ATOMIC_I486) |
|
42 /* Adapted from CVS version 1.10 of glibc's sysdeps/i386/i486/bits/atomic.h |
|
43 */ |
|
44 EXPORT_C gint |
|
45 g_atomic_int_exchange_and_add (volatile gint *atomic, |
|
46 gint val) |
|
47 { |
|
48 gint result; |
|
49 |
|
50 __asm__ __volatile__ ("lock; xaddl %0,%1" |
|
51 : "=r" (result), "=m" (*atomic) |
|
52 : "0" (val), "m" (*atomic)); |
|
53 return result; |
|
54 } |
|
55 |
|
56 EXPORT_C void |
|
57 g_atomic_int_add (volatile gint *atomic, |
|
58 gint val) |
|
59 { |
|
60 __asm__ __volatile__ ("lock; addl %1,%0" |
|
61 : "=m" (*atomic) |
|
62 : "ir" (val), "m" (*atomic)); |
|
63 } |
|
64 |
|
65 EXPORT_C gboolean |
|
66 g_atomic_int_compare_and_exchange (volatile gint *atomic, |
|
67 gint oldval, |
|
68 gint newval) |
|
69 { |
|
70 gint result; |
|
71 |
|
72 __asm__ __volatile__ ("lock; cmpxchgl %2, %1" |
|
73 : "=a" (result), "=m" (*atomic) |
|
74 : "r" (newval), "m" (*atomic), "0" (oldval)); |
|
75 |
|
76 return result == oldval; |
|
77 } |
|
78 |
|
79 /* The same code as above, as on i386 gpointer is 32 bit as well. |
|
80 * Duplicating the code here seems more natural than casting the |
|
81 * arguments and calling the former function */ |
|
82 |
|
83 EXPORT_C gboolean |
|
84 g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic, |
|
85 gpointer oldval, |
|
86 gpointer newval) |
|
87 { |
|
88 gpointer result; |
|
89 |
|
90 __asm__ __volatile__ ("lock; cmpxchgl %2, %1" |
|
91 : "=a" (result), "=m" (*atomic) |
|
92 : "r" (newval), "m" (*atomic), "0" (oldval)); |
|
93 |
|
94 return result == oldval; |
|
95 } |
|
96 |
|
97 # elif defined (G_ATOMIC_SPARCV9) |
|
98 /* Adapted from CVS version 1.3 of glibc's sysdeps/sparc/sparc64/bits/atomic.h |
|
99 */ |
|
100 # define ATOMIC_INT_CMP_XCHG(atomic, oldval, newval) \ |
|
101 ({ \ |
|
102 gint __result; \ |
|
103 __asm__ __volatile__ ("cas [%4], %2, %0" \ |
|
104 : "=r" (__result), "=m" (*(atomic)) \ |
|
105 : "r" (oldval), "m" (*(atomic)), "r" (atomic),\ |
|
106 "0" (newval)); \ |
|
107 __result == oldval; \ |
|
108 }) |
|
109 |
|
110 # if GLIB_SIZEOF_VOID_P == 4 /* 32-bit system */ |
|
111 EXPORT_C gboolean |
|
112 g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic, |
|
113 gpointer oldval, |
|
114 gpointer newval) |
|
115 { |
|
116 gpointer result; |
|
117 __asm__ __volatile__ ("cas [%4], %2, %0" |
|
118 : "=r" (result), "=m" (*atomic) |
|
119 : "r" (oldval), "m" (*atomic), "r" (atomic), |
|
120 "0" (newval)); |
|
121 return result == oldval; |
|
122 } |
|
123 # elif GLIB_SIZEOF_VOID_P == 8 /* 64-bit system */ |
|
124 EXPORT_C gboolean |
|
125 g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic, |
|
126 gpointer oldval, |
|
127 gpointer newval) |
|
128 { |
|
129 gpointer result; |
|
130 gpointer *a = atomic; |
|
131 __asm__ __volatile__ ("casx [%4], %2, %0" |
|
132 : "=r" (result), "=m" (*a) |
|
133 : "r" (oldval), "m" (*a), "r" (a), |
|
134 "0" (newval)); |
|
135 return result == oldval; |
|
136 } |
|
137 # else /* What's that */ |
|
138 # error "Your system has an unsupported pointer size" |
|
139 # endif /* GLIB_SIZEOF_VOID_P */ |
|
140 # define G_ATOMIC_MEMORY_BARRIER \ |
|
141 __asm__ __volatile__ ("membar #LoadLoad | #LoadStore" \ |
|
142 " | #StoreLoad | #StoreStore" : : : "memory") |
|
143 |
|
144 # elif defined (G_ATOMIC_ALPHA) |
|
145 /* Adapted from CVS version 1.3 of glibc's sysdeps/alpha/bits/atomic.h |
|
146 */ |
|
147 # define ATOMIC_INT_CMP_XCHG(atomic, oldval, newval) \ |
|
148 ({ \ |
|
149 gint __result; \ |
|
150 gint __prev; \ |
|
151 __asm__ __volatile__ ( \ |
|
152 " mb\n" \ |
|
153 "1: ldl_l %0,%2\n" \ |
|
154 " cmpeq %0,%3,%1\n" \ |
|
155 " beq %1,2f\n" \ |
|
156 " mov %4,%1\n" \ |
|
157 " stl_c %1,%2\n" \ |
|
158 " beq %1,1b\n" \ |
|
159 " mb\n" \ |
|
160 "2:" \ |
|
161 : "=&r" (__prev), \ |
|
162 "=&r" (__result) \ |
|
163 : "m" (*(atomic)), \ |
|
164 "Ir" (oldval), \ |
|
165 "Ir" (newval) \ |
|
166 : "memory"); \ |
|
167 __result != 0; \ |
|
168 }) |
|
169 # if GLIB_SIZEOF_VOID_P == 4 /* 32-bit system */ |
|
170 EXPORT_C gboolean |
|
171 g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic, |
|
172 gpointer oldval, |
|
173 gpointer newval) |
|
174 { |
|
175 gint result; |
|
176 gpointer prev; |
|
177 __asm__ __volatile__ ( |
|
178 " mb\n" |
|
179 "1: ldl_l %0,%2\n" |
|
180 " cmpeq %0,%3,%1\n" |
|
181 " beq %1,2f\n" |
|
182 " mov %4,%1\n" |
|
183 " stl_c %1,%2\n" |
|
184 " beq %1,1b\n" |
|
185 " mb\n" |
|
186 "2:" |
|
187 : "=&r" (prev), |
|
188 "=&r" (result) |
|
189 : "m" (*atomic), |
|
190 "Ir" (oldval), |
|
191 "Ir" (newval) |
|
192 : "memory"); |
|
193 return result != 0; |
|
194 } |
|
195 # elif GLIB_SIZEOF_VOID_P == 8 /* 64-bit system */ |
|
196 EXPORT_C gboolean |
|
197 g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic, |
|
198 gpointer oldval, |
|
199 gpointer newval) |
|
200 { |
|
201 gint result; |
|
202 gpointer prev; |
|
203 __asm__ __volatile__ ( |
|
204 " mb\n" |
|
205 "1: ldq_l %0,%2\n" |
|
206 " cmpeq %0,%3,%1\n" |
|
207 " beq %1,2f\n" |
|
208 " mov %4,%1\n" |
|
209 " stq_c %1,%2\n" |
|
210 " beq %1,1b\n" |
|
211 " mb\n" |
|
212 "2:" |
|
213 : "=&r" (prev), |
|
214 "=&r" (result) |
|
215 : "m" (*atomic), |
|
216 "Ir" (oldval), |
|
217 "Ir" (newval) |
|
218 : "memory"); |
|
219 return result != 0; |
|
220 } |
|
221 # else /* What's that */ |
|
222 # error "Your system has an unsupported pointer size" |
|
223 # endif /* GLIB_SIZEOF_VOID_P */ |
|
224 # define G_ATOMIC_MEMORY_BARRIER __asm__ ("mb" : : : "memory") |
|
225 # elif defined (G_ATOMIC_X86_64) |
|
226 /* Adapted from CVS version 1.9 of glibc's sysdeps/x86_64/bits/atomic.h |
|
227 */ |
|
228 EXPORT_C gint |
|
229 g_atomic_int_exchange_and_add (volatile gint *atomic, |
|
230 gint val) |
|
231 { |
|
232 gint result; |
|
233 |
|
234 __asm__ __volatile__ ("lock; xaddl %0,%1" |
|
235 : "=r" (result), "=m" (*atomic) |
|
236 : "0" (val), "m" (*atomic)); |
|
237 return result; |
|
238 } |
|
239 |
|
240 EXPORT_C void |
|
241 g_atomic_int_add (volatile gint *atomic, |
|
242 gint val) |
|
243 { |
|
244 __asm__ __volatile__ ("lock; addl %1,%0" |
|
245 : "=m" (*atomic) |
|
246 : "ir" (val), "m" (*atomic)); |
|
247 } |
|
248 |
|
249 EXPORT_C gboolean |
|
250 g_atomic_int_compare_and_exchange (volatile gint *atomic, |
|
251 gint oldval, |
|
252 gint newval) |
|
253 { |
|
254 gint result; |
|
255 |
|
256 __asm__ __volatile__ ("lock; cmpxchgl %2, %1" |
|
257 : "=a" (result), "=m" (*atomic) |
|
258 : "r" (newval), "m" (*atomic), "0" (oldval)); |
|
259 |
|
260 return result == oldval; |
|
261 } |
|
262 |
|
263 EXPORT_C gboolean |
|
264 g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic, |
|
265 gpointer oldval, |
|
266 gpointer newval) |
|
267 { |
|
268 gpointer result; |
|
269 |
|
270 __asm__ __volatile__ ("lock; cmpxchgq %q2, %1" |
|
271 : "=a" (result), "=m" (*atomic) |
|
272 : "r" (newval), "m" (*atomic), "0" (oldval)); |
|
273 |
|
274 return result == oldval; |
|
275 } |
|
276 |
|
277 # elif defined (G_ATOMIC_POWERPC) |
|
278 /* Adapted from CVS version 1.16 of glibc's sysdeps/powerpc/bits/atomic.h |
|
279 * and CVS version 1.4 of glibc's sysdeps/powerpc/powerpc32/bits/atomic.h |
|
280 * and CVS version 1.7 of glibc's sysdeps/powerpc/powerpc64/bits/atomic.h |
|
281 */ |
|
282 # ifdef __OPTIMIZE__ |
|
283 /* Non-optimizing compile bails on the following two asm statements |
|
284 * for reasons unknown to the author */ |
|
285 EXPORT_C gint |
|
286 g_atomic_int_exchange_and_add (volatile gint *atomic, |
|
287 gint val) |
|
288 { |
|
289 gint result, temp; |
|
290 __asm__ __volatile__ ("1: lwarx %0,0,%3\n" |
|
291 " add %1,%0,%4\n" |
|
292 " stwcx. %1,0,%3\n" |
|
293 " bne- 1b" |
|
294 : "=&b" (result), "=&r" (temp), "=m" (*atomic) |
|
295 : "b" (atomic), "r" (val), "m" (*atomic) |
|
296 : "cr0", "memory"); |
|
297 return result; |
|
298 } |
|
299 |
|
300 /* The same as above, to save a function call repeated here */ |
|
301 EXPORT_C void |
|
302 g_atomic_int_add (volatile gint *atomic, |
|
303 gint val) |
|
304 { |
|
305 gint result, temp; |
|
306 __asm__ __volatile__ ("1: lwarx %0,0,%3\n" |
|
307 " add %1,%0,%4\n" |
|
308 " stwcx. %1,0,%3\n" |
|
309 " bne- 1b" |
|
310 : "=&b" (result), "=&r" (temp), "=m" (*atomic) |
|
311 : "b" (atomic), "r" (val), "m" (*atomic) |
|
312 : "cr0", "memory"); |
|
313 } |
|
314 # else /* !__OPTIMIZE__ */ |
|
315 EXPORT_C gint |
|
316 g_atomic_int_exchange_and_add (volatile gint *atomic, |
|
317 gint val) |
|
318 { |
|
319 gint result; |
|
320 do |
|
321 result = *atomic; |
|
322 while (!g_atomic_int_compare_and_exchange (atomic, result, result + val)); |
|
323 |
|
324 return result; |
|
325 } |
|
326 |
|
327 EXPORT_C void |
|
328 g_atomic_int_add (volatile gint *atomic, |
|
329 gint val) |
|
330 { |
|
331 gint result; |
|
332 do |
|
333 result = *atomic; |
|
334 while (!g_atomic_int_compare_and_exchange (atomic, result, result + val)); |
|
335 } |
|
336 # endif /* !__OPTIMIZE__ */ |
|
337 |
|
338 # if GLIB_SIZEOF_VOID_P == 4 /* 32-bit system */ |
|
339 EXPORT_C gboolean |
|
340 g_atomic_int_compare_and_exchange (volatile gint *atomic, |
|
341 gint oldval, |
|
342 gint newval) |
|
343 { |
|
344 gint result; |
|
345 __asm__ __volatile__ ("sync\n" |
|
346 "1: lwarx %0,0,%1\n" |
|
347 " subf. %0,%2,%0\n" |
|
348 " bne 2f\n" |
|
349 " stwcx. %3,0,%1\n" |
|
350 " bne- 1b\n" |
|
351 "2: isync" |
|
352 : "=&r" (result) |
|
353 : "b" (atomic), "r" (oldval), "r" (newval) |
|
354 : "cr0", "memory"); |
|
355 return result == 0; |
|
356 } |
|
357 |
|
358 EXPORT_C gboolean |
|
359 g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic, |
|
360 gpointer oldval, |
|
361 gpointer newval) |
|
362 { |
|
363 gpointer result; |
|
364 __asm__ __volatile__ ("sync\n" |
|
365 "1: lwarx %0,0,%1\n" |
|
366 " subf. %0,%2,%0\n" |
|
367 " bne 2f\n" |
|
368 " stwcx. %3,0,%1\n" |
|
369 " bne- 1b\n" |
|
370 "2: isync" |
|
371 : "=&r" (result) |
|
372 : "b" (atomic), "r" (oldval), "r" (newval) |
|
373 : "cr0", "memory"); |
|
374 return result == 0; |
|
375 } |
|
376 # elif GLIB_SIZEOF_VOID_P == 8 /* 64-bit system */ |
|
377 EXPORT_C gboolean |
|
378 g_atomic_int_compare_and_exchange (volatile gint *atomic, |
|
379 gint oldval, |
|
380 gint newval) |
|
381 { |
|
382 gpointer result; |
|
383 __asm__ __volatile__ ("sync\n" |
|
384 "1: lwarx %0,0,%1\n" |
|
385 " extsw %0,%0\n" |
|
386 " subf. %0,%2,%0\n" |
|
387 " bne 2f\n" |
|
388 " stwcx. %3,0,%1\n" |
|
389 " bne- 1b\n" |
|
390 "2: isync" |
|
391 : "=&r" (result) |
|
392 : "b" (atomic), "r" (oldval), "r" (newval) |
|
393 : "cr0", "memory"); |
|
394 return result == 0; |
|
395 } |
|
396 |
|
397 EXPORT_C gboolean |
|
398 g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic, |
|
399 gpointer oldval, |
|
400 gpointer newval) |
|
401 { |
|
402 gpointer result; |
|
403 __asm__ __volatile__ ("sync\n" |
|
404 "1: ldarx %0,0,%1\n" |
|
405 " subf. %0,%2,%0\n" |
|
406 " bne 2f\n" |
|
407 " stdcx. %3,0,%1\n" |
|
408 " bne- 1b\n" |
|
409 "2: isync" |
|
410 : "=&r" (result) |
|
411 : "b" (atomic), "r" (oldval), "r" (newval) |
|
412 : "cr0", "memory"); |
|
413 return result == 0; |
|
414 } |
|
415 # else /* What's that */ |
|
416 # error "Your system has an unsupported pointer size" |
|
417 # endif /* GLIB_SIZEOF_VOID_P */ |
|
418 |
|
419 # define G_ATOMIC_MEMORY_BARRIER __asm__ ("sync" : : : "memory") |
|
420 |
|
421 # elif defined (G_ATOMIC_IA64) |
|
422 /* Adapted from CVS version 1.8 of glibc's sysdeps/ia64/bits/atomic.h |
|
423 */ |
|
424 EXPORT_C gint |
|
425 g_atomic_int_exchange_and_add (volatile gint *atomic, |
|
426 gint val) |
|
427 { |
|
428 return __sync_fetch_and_add (atomic, val); |
|
429 } |
|
430 |
|
431 EXPORT_C void |
|
432 g_atomic_int_add (volatile gint *atomic, |
|
433 gint val) |
|
434 { |
|
435 __sync_fetch_and_add (atomic, val); |
|
436 } |
|
437 |
|
438 EXPORT_C gboolean |
|
439 g_atomic_int_compare_and_exchange (volatile gint *atomic, |
|
440 gint oldval, |
|
441 gint newval) |
|
442 { |
|
443 return __sync_bool_compare_and_swap (atomic, oldval, newval); |
|
444 } |
|
445 |
|
446 EXPORT_C gboolean |
|
447 g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic, |
|
448 gpointer oldval, |
|
449 gpointer newval) |
|
450 { |
|
451 return __sync_bool_compare_and_swap ((long *)atomic, |
|
452 (long)oldval, (long)newval); |
|
453 } |
|
454 |
|
455 # define G_ATOMIC_MEMORY_BARRIER __sync_synchronize () |
|
456 # elif defined (G_ATOMIC_S390) |
|
457 /* Adapted from glibc's sysdeps/s390/bits/atomic.h |
|
458 */ |
|
459 # define ATOMIC_INT_CMP_XCHG(atomic, oldval, newval) \ |
|
460 ({ \ |
|
461 gint __result = oldval; \ |
|
462 __asm__ __volatile__ ("cs %0, %2, %1" \ |
|
463 : "+d" (__result), "=Q" (*(atomic)) \ |
|
464 : "d" (newval), "m" (*(atomic)) : "cc" ); \ |
|
465 __result == oldval; \ |
|
466 }) |
|
467 |
|
468 # if GLIB_SIZEOF_VOID_P == 4 /* 32-bit system */ |
|
469 EXPORT_C gboolean |
|
470 g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic, |
|
471 gpointer oldval, |
|
472 gpointer newval) |
|
473 { |
|
474 gpointer result = oldval; |
|
475 __asm__ __volatile__ ("cs %0, %2, %1" |
|
476 : "+d" (result), "=Q" (*(atomic)) |
|
477 : "d" (newval), "m" (*(atomic)) : "cc" ); |
|
478 return result == oldval; |
|
479 } |
|
480 # elif GLIB_SIZEOF_VOID_P == 8 /* 64-bit system */ |
|
481 EXPORT_C gboolean |
|
482 g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic, |
|
483 gpointer oldval, |
|
484 gpointer newval) |
|
485 { |
|
486 gpointer result = oldval; |
|
487 gpointer *a = atomic; |
|
488 __asm__ __volatile__ ("csg %0, %2, %1" |
|
489 : "+d" (result), "=Q" (*a) |
|
490 : "d" ((long)(newval)), "m" (*a) : "cc" ); |
|
491 return result == oldval; |
|
492 } |
|
493 # else /* What's that */ |
|
494 # error "Your system has an unsupported pointer size" |
|
495 # endif /* GLIB_SIZEOF_VOID_P */ |
|
496 # else /* !G_ATOMIC_IA64 */ |
|
497 # define DEFINE_WITH_MUTEXES |
|
498 # endif /* G_ATOMIC_IA64 */ |
|
499 #else /* !__GNUC__ */ |
|
500 # ifdef G_PLATFORM_WIN32 |
|
501 # define DEFINE_WITH_WIN32_INTERLOCKED |
|
502 # else |
|
503 # define DEFINE_WITH_MUTEXES |
|
504 # endif |
|
505 #endif /* __GNUC__ */ |
|
506 |
|
507 #ifdef DEFINE_WITH_WIN32_INTERLOCKED |
|
508 # include <windows.h> |
|
509 /* Following indicates that InterlockedCompareExchangePointer is |
|
510 * declared in winbase.h (included by windows.h) and needs to be |
|
511 * commented out if not true. It is defined iff WINVER > 0x0400, |
|
512 * which is usually correct but can be wrong if WINVER is set before |
|
513 * windows.h is included. |
|
514 */ |
|
515 # if WINVER > 0x0400 |
|
516 # define HAVE_INTERLOCKED_COMPARE_EXCHANGE_POINTER |
|
517 # endif |
|
518 |
|
519 EXPORT_C gint32 |
|
520 g_atomic_int_exchange_and_add (volatile gint32 *atomic, |
|
521 gint32 val) |
|
522 { |
|
523 return InterlockedExchangeAdd (atomic, val); |
|
524 } |
|
525 |
|
526 EXPORT_C void |
|
527 g_atomic_int_add (volatile gint32 *atomic, |
|
528 gint32 val) |
|
529 { |
|
530 InterlockedExchangeAdd (atomic, val); |
|
531 } |
|
532 |
|
533 EXPORT_C gboolean |
|
534 g_atomic_int_compare_and_exchange (volatile gint32 *atomic, |
|
535 gint32 oldval, |
|
536 gint32 newval) |
|
537 { |
|
538 #ifndef HAVE_INTERLOCKED_COMPARE_EXCHANGE_POINTER |
|
539 return (guint32) InterlockedCompareExchange ((PVOID*)atomic, |
|
540 (PVOID)newval, |
|
541 (PVOID)oldval) == oldval; |
|
542 #else |
|
543 return InterlockedCompareExchange (atomic, |
|
544 newval, |
|
545 oldval) == oldval; |
|
546 #endif |
|
547 } |
|
548 |
|
549 EXPORT_C gboolean |
|
550 g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic, |
|
551 gpointer oldval, |
|
552 gpointer newval) |
|
553 { |
|
554 # ifdef HAVE_INTERLOCKED_COMPARE_EXCHANGE_POINTER |
|
555 return InterlockedCompareExchangePointer (atomic, newval, oldval) == oldval; |
|
556 # else |
|
557 # if GLIB_SIZEOF_VOID_P != 4 /* no 32-bit system */ |
|
558 # error "InterlockedCompareExchangePointer needed" |
|
559 # else |
|
560 return InterlockedCompareExchange (atomic, newval, oldval) == oldval; |
|
561 # endif |
|
562 # endif |
|
563 } |
|
564 #endif /* DEFINE_WITH_WIN32_INTERLOCKED */ |
|
565 |
|
566 #ifdef DEFINE_WITH_MUTEXES |
|
567 /* We have to use the slow, but safe locking method */ |
|
568 |
|
569 #if EMULATOR |
|
570 |
|
571 PLS(g_atomic_mutex , gatomic,GMutex *) |
|
572 #define g_atomic_mutex (*FUNCTION_NAME(g_atomic_mutex,gatomic)()) |
|
573 |
|
574 #else |
|
575 |
|
576 static GMutex *g_atomic_mutex; |
|
577 |
|
578 #endif /* EMULATOR */ |
|
579 |
|
580 EXPORT_C gint |
|
581 g_atomic_int_exchange_and_add (volatile gint *atomic, |
|
582 gint val) |
|
583 { |
|
584 gint result; |
|
585 |
|
586 g_mutex_lock (g_atomic_mutex); |
|
587 result = *atomic; |
|
588 *atomic += val; |
|
589 g_mutex_unlock (g_atomic_mutex); |
|
590 |
|
591 return result; |
|
592 } |
|
593 |
|
594 |
|
595 EXPORT_C void |
|
596 g_atomic_int_add (volatile gint *atomic, |
|
597 gint val) |
|
598 { |
|
599 g_mutex_lock (g_atomic_mutex); |
|
600 *atomic += val; |
|
601 g_mutex_unlock (g_atomic_mutex); |
|
602 } |
|
603 |
|
604 EXPORT_C gboolean |
|
605 g_atomic_int_compare_and_exchange (volatile gint *atomic, |
|
606 gint oldval, |
|
607 gint newval) |
|
608 { |
|
609 gboolean result; |
|
610 |
|
611 g_mutex_lock (g_atomic_mutex); |
|
612 if (*atomic == oldval) |
|
613 { |
|
614 result = TRUE; |
|
615 *atomic = newval; |
|
616 } |
|
617 else |
|
618 result = FALSE; |
|
619 g_mutex_unlock (g_atomic_mutex); |
|
620 |
|
621 return result; |
|
622 } |
|
623 |
|
624 EXPORT_C gboolean |
|
625 g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic, |
|
626 gpointer oldval, |
|
627 gpointer newval) |
|
628 { |
|
629 gboolean result; |
|
630 |
|
631 g_mutex_lock (g_atomic_mutex); |
|
632 if (*atomic == oldval) |
|
633 { |
|
634 result = TRUE; |
|
635 *atomic = newval; |
|
636 } |
|
637 else |
|
638 result = FALSE; |
|
639 g_mutex_unlock (g_atomic_mutex); |
|
640 |
|
641 return result; |
|
642 } |
|
643 |
|
644 #ifdef G_ATOMIC_OP_MEMORY_BARRIER_NEEDED |
|
645 EXPORT_C gint |
|
646 g_atomic_int_get (volatile gint *atomic) |
|
647 { |
|
648 gint result; |
|
649 |
|
650 g_mutex_lock (g_atomic_mutex); |
|
651 result = *atomic; |
|
652 g_mutex_unlock (g_atomic_mutex); |
|
653 |
|
654 return result; |
|
655 } |
|
656 |
|
657 EXPORT_C void |
|
658 g_atomic_int_set (volatile gint *atomic, |
|
659 gint newval) |
|
660 { |
|
661 g_mutex_lock (g_atomic_mutex); |
|
662 *atomic = newval; |
|
663 g_mutex_unlock (g_atomic_mutex); |
|
664 } |
|
665 |
|
666 EXPORT_C gpointer |
|
667 g_atomic_pointer_get (volatile gpointer *atomic) |
|
668 { |
|
669 gpointer result; |
|
670 |
|
671 g_mutex_lock (g_atomic_mutex); |
|
672 result = *atomic; |
|
673 g_mutex_unlock (g_atomic_mutex); |
|
674 |
|
675 return result; |
|
676 } |
|
677 |
|
678 EXPORT_C void |
|
679 g_atomic_pointer_set (volatile gpointer *atomic, |
|
680 gpointer newval) |
|
681 { |
|
682 g_mutex_lock (g_atomic_mutex); |
|
683 *atomic = newval; |
|
684 g_mutex_unlock (g_atomic_mutex); |
|
685 } |
|
686 #endif /* G_ATOMIC_OP_MEMORY_BARRIER_NEEDED */ |
|
687 #elif defined (G_ATOMIC_OP_MEMORY_BARRIER_NEEDED) |
|
688 EXPORT_C gint |
|
689 g_atomic_int_get (volatile gint *atomic) |
|
690 { |
|
691 G_ATOMIC_MEMORY_BARRIER; |
|
692 return *atomic; |
|
693 } |
|
694 |
|
695 EXPORT_C void |
|
696 g_atomic_int_set (volatile gint *atomic, |
|
697 gint newval) |
|
698 { |
|
699 *atomic = newval; |
|
700 G_ATOMIC_MEMORY_BARRIER; |
|
701 } |
|
702 |
|
703 EXPORT_C gpointer |
|
704 g_atomic_pointer_get (volatile gpointer *atomic) |
|
705 { |
|
706 G_ATOMIC_MEMORY_BARRIER; |
|
707 return *atomic; |
|
708 } |
|
709 |
|
710 EXPORT_C gpointer |
|
711 g_atomic_pointer_set (volatile gpointer *atomic, |
|
712 gpointer newval) |
|
713 { |
|
714 *atomic = newval; |
|
715 G_ATOMIC_MEMORY_BARRIER; |
|
716 } |
|
717 #endif /* DEFINE_WITH_MUTEXES || G_ATOMIC_OP_MEMORY_BARRIER_NEEDED */ |
|
718 |
|
719 #ifdef ATOMIC_INT_CMP_XCHG |
|
720 EXPORT_C gboolean |
|
721 g_atomic_int_compare_and_exchange (volatile gint *atomic, |
|
722 gint oldval, |
|
723 gint newval) |
|
724 { |
|
725 return ATOMIC_INT_CMP_XCHG (atomic, oldval, newval); |
|
726 } |
|
727 |
|
728 EXPORT_C gint |
|
729 g_atomic_int_exchange_and_add (volatile gint *atomic, |
|
730 gint val) |
|
731 { |
|
732 gint result; |
|
733 do |
|
734 result = *atomic; |
|
735 while (!ATOMIC_INT_CMP_XCHG (atomic, result, result + val)); |
|
736 |
|
737 return result; |
|
738 } |
|
739 |
|
740 EXPORT_C void |
|
741 g_atomic_int_add (volatile gint *atomic, |
|
742 gint val) |
|
743 { |
|
744 gint result; |
|
745 do |
|
746 result = *atomic; |
|
747 while (!ATOMIC_INT_CMP_XCHG (atomic, result, result + val)); |
|
748 } |
|
749 #endif /* ATOMIC_INT_CMP_XCHG */ |
|
750 |
|
751 void |
|
752 _g_atomic_thread_init (void) |
|
753 { |
|
754 #ifdef DEFINE_WITH_MUTEXES |
|
755 g_atomic_mutex = g_mutex_new (); |
|
756 #endif /* DEFINE_WITH_MUTEXES */ |
|
757 } |
|
758 |
|
759 #ifndef G_ATOMIC_OP_MEMORY_BARRIER_NEEDED |
|
760 EXPORT_C gint |
|
761 (g_atomic_int_get) (volatile gint *atomic) |
|
762 { |
|
763 return g_atomic_int_get (atomic); |
|
764 } |
|
765 |
|
766 EXPORT_C void |
|
767 (g_atomic_int_set) (volatile gint *atomic, |
|
768 gint newval) |
|
769 { |
|
770 g_atomic_int_set (atomic, newval); |
|
771 } |
|
772 |
|
773 EXPORT_C gpointer |
|
774 (g_atomic_pointer_get) (volatile gpointer *atomic) |
|
775 { |
|
776 return g_atomic_pointer_get (atomic); |
|
777 } |
|
778 |
|
779 EXPORT_C void |
|
780 (g_atomic_pointer_set) (volatile gpointer *atomic, |
|
781 gpointer newval) |
|
782 { |
|
783 g_atomic_pointer_set (atomic, newval); |
|
784 } |
|
785 #endif /* G_ATOMIC_OP_MEMORY_BARRIER_NEEDED */ |
|
786 |
|
787 #define __G_ATOMIC_C__ |
|
788 #include "galiasdef.c" |