Check whether assembler supports numerical local labels.
[platform/upstream/glib.git] / glib / gatomic.c
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  * Copyright (C) 2007 Nokia Corporation
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 #if defined (G_ATOMIC_ARM)
25 #include <sched.h>
26 #endif
27
28 #include "config.h"
29
30 #include "glib.h"
31 #include "gthreadprivate.h"
32 #include "galias.h"
33
34 #if defined (__GNUC__)
35 # if defined (G_ATOMIC_I486)
36 /* Adapted from CVS version 1.10 of glibc's sysdeps/i386/i486/bits/atomic.h 
37  */
38 gint
39 g_atomic_int_exchange_and_add (volatile gint *atomic, 
40                                gint           val)
41 {
42   gint result;
43
44   __asm__ __volatile__ ("lock; xaddl %0,%1"
45                         : "=r" (result), "=m" (*atomic) 
46                         : "0" (val), "m" (*atomic));
47   return result;
48 }
49  
50 void
51 g_atomic_int_add (volatile gint *atomic, 
52                   gint           val)
53 {
54   __asm__ __volatile__ ("lock; addl %1,%0"
55                         : "=m" (*atomic) 
56                         : "ir" (val), "m" (*atomic));
57 }
58
59 gboolean
60 g_atomic_int_compare_and_exchange (volatile gint *atomic, 
61                                    gint           oldval, 
62                                    gint           newval)
63 {
64   gint result;
65  
66   __asm__ __volatile__ ("lock; cmpxchgl %2, %1"
67                         : "=a" (result), "=m" (*atomic)
68                         : "r" (newval), "m" (*atomic), "0" (oldval)); 
69
70   return result == oldval;
71 }
72
73 /* The same code as above, as on i386 gpointer is 32 bit as well.
74  * Duplicating the code here seems more natural than casting the
75  * arguments and calling the former function */
76
77 gboolean
78 g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic, 
79                                        gpointer           oldval, 
80                                        gpointer           newval)
81 {
82   gpointer result;
83  
84   __asm__ __volatile__ ("lock; cmpxchgl %2, %1"
85                         : "=a" (result), "=m" (*atomic)
86                         : "r" (newval), "m" (*atomic), "0" (oldval)); 
87
88   return result == oldval;
89 }
90
91 # elif defined (G_ATOMIC_SPARCV9)
92 /* Adapted from CVS version 1.3 of glibc's sysdeps/sparc/sparc64/bits/atomic.h
93  */
94 #  define ATOMIC_INT_CMP_XCHG(atomic, oldval, newval)                   \
95   ({                                                                    \
96      gint __result;                                                     \
97      __asm__ __volatile__ ("cas [%4], %2, %0"                           \
98                            : "=r" (__result), "=m" (*(atomic))          \
99                            : "r" (oldval), "m" (*(atomic)), "r" (atomic),\
100                            "0" (newval));                               \
101      __result == oldval;                                                \
102   })
103
104 #  if GLIB_SIZEOF_VOID_P == 4 /* 32-bit system */
105 gboolean
106 g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic, 
107                                        gpointer           oldval, 
108                                        gpointer           newval)
109 {
110   gpointer result;
111   __asm__ __volatile__ ("cas [%4], %2, %0"
112                         : "=r" (result), "=m" (*atomic)
113                         : "r" (oldval), "m" (*atomic), "r" (atomic),
114                         "0" (newval));
115   return result == oldval;
116 }
117 #  elif GLIB_SIZEOF_VOID_P == 8 /* 64-bit system */
118 gboolean
119 g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic, 
120                                        gpointer           oldval, 
121                                        gpointer           newval)
122 {
123   gpointer result;
124   gpointer *a = atomic;
125   __asm__ __volatile__ ("casx [%4], %2, %0"
126                         : "=r" (result), "=m" (*a)
127                         : "r" (oldval), "m" (*a), "r" (a),
128                         "0" (newval));
129   return result == oldval;
130 }
131 #  else /* What's that */
132 #    error "Your system has an unsupported pointer size"
133 #  endif /* GLIB_SIZEOF_VOID_P */
134 #  define G_ATOMIC_MEMORY_BARRIER                                       \
135   __asm__ __volatile__ ("membar #LoadLoad | #LoadStore"                 \
136                         " | #StoreLoad | #StoreStore" : : : "memory")
137
138 # elif defined (G_ATOMIC_ALPHA)
139 /* Adapted from CVS version 1.3 of glibc's sysdeps/alpha/bits/atomic.h
140  */
141 #  define ATOMIC_INT_CMP_XCHG(atomic, oldval, newval)                   \
142   ({                                                                    \
143      gint __result;                                                     \
144      gint __prev;                                                       \
145      __asm__ __volatile__ (                                             \
146         "       mb\n"                                                   \
147         "1:     ldl_l   %0,%2\n"                                        \
148         "       cmpeq   %0,%3,%1\n"                                     \
149         "       beq     %1,2f\n"                                        \
150         "       mov     %4,%1\n"                                        \
151         "       stl_c   %1,%2\n"                                        \
152         "       beq     %1,1b\n"                                        \
153         "       mb\n"                                                   \
154         "2:"                                                            \
155         : "=&r" (__prev),                                               \
156           "=&r" (__result)                                              \
157         : "m" (*(atomic)),                                              \
158           "Ir" (oldval),                                                \
159           "Ir" (newval)                                                 \
160         : "memory");                                                    \
161      __result != 0;                                                     \
162   })
163 #  if GLIB_SIZEOF_VOID_P == 4 /* 32-bit system */
164 gboolean
165 g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic, 
166                                        gpointer           oldval, 
167                                        gpointer           newval)
168 {
169   gint result;
170   gpointer prev;
171   __asm__ __volatile__ (
172         "       mb\n"
173         "1:     ldl_l   %0,%2\n"
174         "       cmpeq   %0,%3,%1\n"
175         "       beq     %1,2f\n"
176         "       mov     %4,%1\n"
177         "       stl_c   %1,%2\n"
178         "       beq     %1,1b\n"
179         "       mb\n"
180         "2:"
181         : "=&r" (prev), 
182           "=&r" (result)
183         : "m" (*atomic),
184           "Ir" (oldval),
185           "Ir" (newval)
186         : "memory");
187   return result != 0;
188 }
189 #  elif GLIB_SIZEOF_VOID_P == 8 /* 64-bit system */
190 gboolean
191 g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic, 
192                                        gpointer           oldval, 
193                                        gpointer           newval)
194 {
195   gint result;
196   gpointer prev;
197   __asm__ __volatile__ (
198         "       mb\n"
199         "1:     ldq_l   %0,%2\n"
200         "       cmpeq   %0,%3,%1\n"
201         "       beq     %1,2f\n"
202         "       mov     %4,%1\n"
203         "       stq_c   %1,%2\n"
204         "       beq     %1,1b\n"
205         "       mb\n"
206         "2:"
207         : "=&r" (prev), 
208           "=&r" (result)
209         : "m" (*atomic),
210           "Ir" (oldval),
211           "Ir" (newval)
212         : "memory");
213   return result != 0;
214 }
215 #  else /* What's that */
216 #   error "Your system has an unsupported pointer size"
217 #  endif /* GLIB_SIZEOF_VOID_P */
218 #  define G_ATOMIC_MEMORY_BARRIER  __asm__ ("mb" : : : "memory")
219 # elif defined (G_ATOMIC_X86_64)
220 /* Adapted from CVS version 1.9 of glibc's sysdeps/x86_64/bits/atomic.h 
221  */
222 gint
223 g_atomic_int_exchange_and_add (volatile gint *atomic,
224                                gint           val)
225 {
226   gint result;
227
228   __asm__ __volatile__ ("lock; xaddl %0,%1"
229                         : "=r" (result), "=m" (*atomic) 
230                         : "0" (val), "m" (*atomic));
231   return result;
232 }
233  
234 void
235 g_atomic_int_add (volatile gint *atomic, 
236                   gint           val)
237 {
238   __asm__ __volatile__ ("lock; addl %1,%0"
239                         : "=m" (*atomic) 
240                         : "ir" (val), "m" (*atomic));
241 }
242
243 gboolean
244 g_atomic_int_compare_and_exchange (volatile gint *atomic, 
245                                    gint           oldval, 
246                                    gint           newval)
247 {
248   gint result;
249  
250   __asm__ __volatile__ ("lock; cmpxchgl %2, %1"
251                         : "=a" (result), "=m" (*atomic)
252                         : "r" (newval), "m" (*atomic), "0" (oldval)); 
253
254   return result == oldval;
255 }
256
257 gboolean
258 g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic, 
259                                        gpointer           oldval, 
260                                        gpointer           newval)
261 {
262   gpointer result;
263  
264   __asm__ __volatile__ ("lock; cmpxchgq %q2, %1"
265                         : "=a" (result), "=m" (*atomic)
266                         : "r" (newval), "m" (*atomic), "0" (oldval)); 
267
268   return result == oldval;
269 }
270
271 # elif defined (G_ATOMIC_POWERPC)
272 /* Adapted from CVS version 1.16 of glibc's sysdeps/powerpc/bits/atomic.h 
273  * and CVS version 1.4 of glibc's sysdeps/powerpc/powerpc32/bits/atomic.h 
274  * and CVS version 1.7 of glibc's sysdeps/powerpc/powerpc64/bits/atomic.h 
275  */
276 #   ifdef __OPTIMIZE__
277 /* Non-optimizing compile bails on the following two asm statements
278  * for reasons unknown to the author */
279 gint
280 g_atomic_int_exchange_and_add (volatile gint *atomic, 
281                                gint           val)
282 {
283   gint result, temp;
284 #if ASM_NUMERIC_LABELS
285   __asm__ __volatile__ ("1:       lwarx   %0,0,%3\n"
286                         "         add     %1,%0,%4\n"
287                         "         stwcx.  %1,0,%3\n"
288                         "         bne-    1b"
289                         : "=&b" (result), "=&r" (temp), "=m" (*atomic)
290                         : "b" (atomic), "r" (val), "m" (*atomic)
291                         : "cr0", "memory");
292 #else
293   __asm__ __volatile__ (".Lieaa%=:       lwarx   %0,0,%3\n"
294                         "         add     %1,%0,%4\n"
295                         "         stwcx.  %1,0,%3\n"
296                         "         bne-    .Lieaa%="
297                         : "=&b" (result), "=&r" (temp), "=m" (*atomic)
298                         : "b" (atomic), "r" (val), "m" (*atomic)
299                         : "cr0", "memory");
300 #endif
301   return result;
302 }
303  
304 /* The same as above, to save a function call repeated here */
305 void
306 g_atomic_int_add (volatile gint *atomic, 
307                   gint           val)
308 {
309   gint result, temp;  
310 #if ASM_NUMERIC_LABELS
311   __asm__ __volatile__ ("1:       lwarx   %0,0,%3\n"
312                         "         add     %1,%0,%4\n"
313                         "         stwcx.  %1,0,%3\n"
314                         "         bne-    1b"
315                         : "=&b" (result), "=&r" (temp), "=m" (*atomic)
316                         : "b" (atomic), "r" (val), "m" (*atomic)
317                         : "cr0", "memory");
318 #else
319   __asm__ __volatile__ (".Lia%=:       lwarx   %0,0,%3\n"
320                         "         add     %1,%0,%4\n"
321                         "         stwcx.  %1,0,%3\n"
322                         "         bne-    .Lia%="
323                         : "=&b" (result), "=&r" (temp), "=m" (*atomic)
324                         : "b" (atomic), "r" (val), "m" (*atomic)
325                         : "cr0", "memory");
326 #endif
327 }
328 #   else /* !__OPTIMIZE__ */
329 gint
330 g_atomic_int_exchange_and_add (volatile gint *atomic, 
331                                gint           val)
332 {
333   gint result;
334   do
335     result = *atomic;
336   while (!g_atomic_int_compare_and_exchange (atomic, result, result + val));
337
338   return result;
339 }
340  
341 void
342 g_atomic_int_add (volatile gint *atomic,
343                   gint           val)
344 {
345   gint result;
346   do
347     result = *atomic;
348   while (!g_atomic_int_compare_and_exchange (atomic, result, result + val));
349 }
350 #   endif /* !__OPTIMIZE__ */
351
352 #   if GLIB_SIZEOF_VOID_P == 4 /* 32-bit system */
353 gboolean
354 g_atomic_int_compare_and_exchange (volatile gint *atomic, 
355                                    gint           oldval, 
356                                    gint           newval)
357 {
358   gint result;
359 #if ASM_NUMERIC_LABELS
360   __asm__ __volatile__ ("sync\n"
361                         "1: lwarx   %0,0,%1\n"
362                         "   subf.   %0,%2,%0\n"
363                         "   bne     2f\n"
364                         "   stwcx.  %3,0,%1\n"
365                         "   bne-    1b\n"
366                         "2: isync"
367                         : "=&r" (result)
368                         : "b" (atomic), "r" (oldval), "r" (newval)
369                         : "cr0", "memory"); 
370 #else
371   __asm__ __volatile__ ("sync\n"
372                         ".L1icae%=: lwarx   %0,0,%1\n"
373                         "   subf.   %0,%2,%0\n"
374                         "   bne     .L2icae%=\n"
375                         "   stwcx.  %3,0,%1\n"
376                         "   bne-    .L1icae%=\n"
377                         ".L2icae%=: isync"
378                         : "=&r" (result)
379                         : "b" (atomic), "r" (oldval), "r" (newval)
380                         : "cr0", "memory"); 
381 #endif
382   return result == 0;
383 }
384
385 gboolean
386 g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic, 
387                                        gpointer           oldval, 
388                                        gpointer           newval)
389 {
390   gpointer result;
391 #if ASM_NUMERIC_LABELS
392   __asm__ __volatile__ ("sync\n"
393                         "1: lwarx   %0,0,%1\n"
394                         "   subf.   %0,%2,%0\n"
395                         "   bne     2f\n"
396                         "   stwcx.  %3,0,%1\n"
397                         "   bne-    1b\n"
398                         "2: isync"
399                         : "=&r" (result)
400                         : "b" (atomic), "r" (oldval), "r" (newval)
401                         : "cr0", "memory"); 
402 #else
403   __asm__ __volatile__ ("sync\n"
404                         ".L1pcae%=: lwarx   %0,0,%1\n"
405                         "   subf.   %0,%2,%0\n"
406                         "   bne     .L2pcae%=\n"
407                         "   stwcx.  %3,0,%1\n"
408                         "   bne-    .L1pcae%=\n"
409                         ".L2pcae%=: isync"
410                         : "=&r" (result)
411                         : "b" (atomic), "r" (oldval), "r" (newval)
412                         : "cr0", "memory"); 
413 #endif
414   return result == 0;
415 }
416 #   elif GLIB_SIZEOF_VOID_P == 8 /* 64-bit system */
417 gboolean
418 g_atomic_int_compare_and_exchange (volatile gint *atomic,
419                                    gint           oldval, 
420                                    gint           newval)
421 {
422   gpointer result;
423 #if ASM_NUMERIC_LABELS
424   __asm__ __volatile__ ("sync\n"
425                         "1: lwarx   %0,0,%1\n"
426                         "   extsw   %0,%0\n"
427                         "   subf.   %0,%2,%0\n"
428                         "   bne     2f\n"
429                         "   stwcx.  %3,0,%1\n"
430                         "   bne-    1b\n"
431                         "2: isync"
432                         : "=&r" (result)
433                         : "b" (atomic), "r" (oldval), "r" (newval)
434                         : "cr0", "memory"); 
435 #else
436   __asm__ __volatile__ ("sync\n"
437                         ".L1icae%=: lwarx   %0,0,%1\n"
438                         "   extsw   %0,%0\n"
439                         "   subf.   %0,%2,%0\n"
440                         "   bne     .L2icae%=\n"
441                         "   stwcx.  %3,0,%1\n"
442                         "   bne-    .L1icae%=\n"
443                         ".L2icae%=: isync"
444                         : "=&r" (result)
445                         : "b" (atomic), "r" (oldval), "r" (newval)
446                         : "cr0", "memory"); 
447 #endif
448   return result == 0;
449 }
450
451 gboolean
452 g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic, 
453                                        gpointer           oldval, 
454                                        gpointer           newval)
455 {
456   gpointer result;
457 #if ASM_NUMERIC_LABELS
458   __asm__ __volatile__ ("sync\n"
459                         "1: ldarx   %0,0,%1\n"
460                         "   subf.   %0,%2,%0\n"
461                         "   bne     2f\n"
462                         "   stdcx.  %3,0,%1\n"
463                         "   bne-    1b\n"
464                         "2: isync"
465                         : "=&r" (result)
466                         : "b" (atomic), "r" (oldval), "r" (newval)
467                         : "cr0", "memory"); 
468 #else
469   __asm__ __volatile__ ("sync\n"
470                         ".L1pcae%=: ldarx   %0,0,%1\n"
471                         "   subf.   %0,%2,%0\n"
472                         "   bne     .L2pcae%=\n"
473                         "   stdcx.  %3,0,%1\n"
474                         "   bne-    .L1pcae%=\n"
475                         ".L2pcae%=: isync"
476                         : "=&r" (result)
477                         : "b" (atomic), "r" (oldval), "r" (newval)
478                         : "cr0", "memory"); 
479 #endif
480   return result == 0;
481 }
482 #  else /* What's that */
483 #   error "Your system has an unsupported pointer size"
484 #  endif /* GLIB_SIZEOF_VOID_P */
485
486 #  define G_ATOMIC_MEMORY_BARRIER __asm__ ("sync" : : : "memory")
487
488 # elif defined (G_ATOMIC_IA64)
489 /* Adapted from CVS version 1.8 of glibc's sysdeps/ia64/bits/atomic.h
490  */
491 gint
492 g_atomic_int_exchange_and_add (volatile gint *atomic,
493                                gint           val)
494 {
495   return __sync_fetch_and_add (atomic, val);
496 }
497  
498 void
499 g_atomic_int_add (volatile gint *atomic, 
500                   gint val)
501 {
502   __sync_fetch_and_add (atomic, val);
503 }
504
505 gboolean
506 g_atomic_int_compare_and_exchange (volatile gint *atomic,
507                                    gint           oldval, 
508                                    gint           newval)
509 {
510   return __sync_bool_compare_and_swap (atomic, oldval, newval);
511 }
512
513 gboolean
514 g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic,
515                                        gpointer           oldval, 
516                                        gpointer           newval)
517 {
518   return __sync_bool_compare_and_swap ((long *)atomic, 
519                                        (long)oldval, (long)newval);
520 }
521
522 #  define G_ATOMIC_MEMORY_BARRIER __sync_synchronize ()
523 # elif defined (G_ATOMIC_S390)
524 /* Adapted from glibc's sysdeps/s390/bits/atomic.h
525  */
526 #  define ATOMIC_INT_CMP_XCHG(atomic, oldval, newval)                   \
527   ({                                                                    \
528      gint __result = oldval;                                    \
529      __asm__ __volatile__ ("cs %0, %2, %1"                              \
530                            : "+d" (__result), "=Q" (*(atomic))          \
531                            : "d" (newval), "m" (*(atomic)) : "cc" );    \
532      __result == oldval;                                                \
533   })
534
535 #  if GLIB_SIZEOF_VOID_P == 4 /* 32-bit system */
536 gboolean
537 g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic,
538                                        gpointer           oldval,
539                                        gpointer           newval)
540 {
541   gpointer result = oldval;
542   __asm__ __volatile__ ("cs %0, %2, %1"
543                         : "+d" (result), "=Q" (*(atomic))
544                         : "d" (newval), "m" (*(atomic)) : "cc" );
545   return result == oldval;
546 }
547 #  elif GLIB_SIZEOF_VOID_P == 8 /* 64-bit system */
548 gboolean
549 g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic,
550                                        gpointer           oldval,
551                                        gpointer           newval)
552 {
553   gpointer result = oldval;
554   gpointer *a = atomic;
555   __asm__ __volatile__ ("csg %0, %2, %1"
556                         : "+d" (result), "=Q" (*a)
557                         : "d" ((long)(newval)), "m" (*a) : "cc" );
558   return result == oldval;
559 }
560 #  else /* What's that */
561 #    error "Your system has an unsupported pointer size"
562 #  endif /* GLIB_SIZEOF_VOID_P */
563 # elif defined (G_ATOMIC_ARM)
564 static volatile int atomic_spin = 0;
565
566 static int atomic_spin_trylock (void)
567 {
568   int result;
569
570   asm volatile (
571     "swp %0, %1, [%2]\n"
572     : "=&r,&r" (result)
573     : "r,0" (1), "r,r" (&atomic_spin)
574     : "memory");
575   if (result == 0)
576     return 0;
577   else
578     return -1;
579 }
580
581 static void atomic_spin_lock (void)
582 {
583   while (atomic_spin_trylock())
584     sched_yield();
585 }
586
587 static void atomic_spin_unlock (void)
588 {
589   atomic_spin = 0;
590 }
591
592 gint
593 g_atomic_int_exchange_and_add (volatile gint *atomic, 
594                                gint           val)
595 {
596   gint result;
597  
598   atomic_spin_lock();  
599   result = *atomic;
600   *atomic += val;
601   atomic_spin_unlock();
602
603   return result;
604 }
605
606 void
607 g_atomic_int_add (volatile gint *atomic,
608                   gint           val)
609 {
610   atomic_spin_lock();
611   *atomic += val;
612   atomic_spin_unlock();
613 }
614
615 gboolean
616 g_atomic_int_compare_and_exchange (volatile gint *atomic, 
617                                    gint           oldval, 
618                                    gint           newval)
619 {
620   gboolean result;
621
622   atomic_spin_lock();
623   if (*atomic == oldval)
624     {
625       result = TRUE;
626       *atomic = newval;
627     }
628   else
629     result = FALSE;
630   atomic_spin_unlock();
631
632   return result;
633 }
634
635 gboolean
636 g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic, 
637                                        gpointer           oldval, 
638                                        gpointer           newval)
639 {
640   gboolean result;
641  
642   atomic_spin_lock();
643   if (*atomic == oldval)
644     {
645       result = TRUE;
646       *atomic = newval;
647     }
648   else
649     result = FALSE;
650   atomic_spin_unlock();
651
652   return result;
653 }
654 # else /* !G_ATOMIC_ARM */
655 #  define DEFINE_WITH_MUTEXES
656 # endif /* G_ATOMIC_IA64 */
657 #else /* !__GNUC__ */
658 # ifdef G_PLATFORM_WIN32
659 #  define DEFINE_WITH_WIN32_INTERLOCKED
660 # else
661 #  define DEFINE_WITH_MUTEXES
662 # endif
663 #endif /* __GNUC__ */
664
665 #ifdef DEFINE_WITH_WIN32_INTERLOCKED
666 # include <windows.h>
667 /* Following indicates that InterlockedCompareExchangePointer is
668  * declared in winbase.h (included by windows.h) and needs to be
669  * commented out if not true. It is defined iff WINVER > 0x0400,
670  * which is usually correct but can be wrong if WINVER is set before
671  * windows.h is included.
672  */
673 # if WINVER > 0x0400
674 #  define HAVE_INTERLOCKED_COMPARE_EXCHANGE_POINTER
675 # endif
676
677 gint32
678 g_atomic_int_exchange_and_add (volatile gint32 *atomic,
679                                gint32           val)
680 {
681   return InterlockedExchangeAdd (atomic, val);
682 }
683
684 void     
685 g_atomic_int_add (volatile gint32 *atomic, 
686                   gint32           val)
687 {
688   InterlockedExchangeAdd (atomic, val);
689 }
690
691 gboolean 
692 g_atomic_int_compare_and_exchange (volatile gint32 *atomic,
693                                    gint32           oldval,
694                                    gint32           newval)
695 {
696 #ifndef HAVE_INTERLOCKED_COMPARE_EXCHANGE_POINTER
697   return (guint32) InterlockedCompareExchange ((PVOID*)atomic, 
698                                                (PVOID)newval, 
699                                                (PVOID)oldval) == oldval;
700 #else
701   return InterlockedCompareExchange (atomic, 
702                                      newval, 
703                                      oldval) == oldval;
704 #endif
705 }
706
707 gboolean 
708 g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic,
709                                        gpointer           oldval,
710                                        gpointer           newval)
711 {
712 # ifdef HAVE_INTERLOCKED_COMPARE_EXCHANGE_POINTER
713   return InterlockedCompareExchangePointer (atomic, newval, oldval) == oldval;
714 # else
715 #  if GLIB_SIZEOF_VOID_P != 4 /* no 32-bit system */
716 #   error "InterlockedCompareExchangePointer needed"
717 #  else
718    return InterlockedCompareExchange (atomic, newval, oldval) == oldval;
719 #  endif
720 # endif
721 }
722 #endif /* DEFINE_WITH_WIN32_INTERLOCKED */
723
724 #ifdef DEFINE_WITH_MUTEXES
725 /* We have to use the slow, but safe locking method */
726 static GMutex *g_atomic_mutex; 
727
728 gint
729 g_atomic_int_exchange_and_add (volatile gint *atomic, 
730                                gint           val)
731 {
732   gint result;
733     
734   g_mutex_lock (g_atomic_mutex);
735   result = *atomic;
736   *atomic += val;
737   g_mutex_unlock (g_atomic_mutex);
738
739   return result;
740 }
741
742
743 void
744 g_atomic_int_add (volatile gint *atomic,
745                   gint           val)
746 {
747   g_mutex_lock (g_atomic_mutex);
748   *atomic += val;
749   g_mutex_unlock (g_atomic_mutex);
750 }
751
752 gboolean
753 g_atomic_int_compare_and_exchange (volatile gint *atomic, 
754                                    gint           oldval, 
755                                    gint           newval)
756 {
757   gboolean result;
758     
759   g_mutex_lock (g_atomic_mutex);
760   if (*atomic == oldval)
761     {
762       result = TRUE;
763       *atomic = newval;
764     }
765   else
766     result = FALSE;
767   g_mutex_unlock (g_atomic_mutex);
768
769   return result;
770 }
771
772 gboolean
773 g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic, 
774                                        gpointer           oldval, 
775                                        gpointer           newval)
776 {
777   gboolean result;
778     
779   g_mutex_lock (g_atomic_mutex);
780   if (*atomic == oldval)
781     {
782       result = TRUE;
783       *atomic = newval;
784     }
785   else
786     result = FALSE;
787   g_mutex_unlock (g_atomic_mutex);
788
789   return result;
790 }
791
792 #ifdef G_ATOMIC_OP_MEMORY_BARRIER_NEEDED
793 gint
794 g_atomic_int_get (volatile gint *atomic)
795 {
796   gint result;
797
798   g_mutex_lock (g_atomic_mutex);
799   result = *atomic;
800   g_mutex_unlock (g_atomic_mutex);
801
802   return result;
803 }
804
805 void
806 g_atomic_int_set (volatile gint *atomic,
807                   gint           newval)
808 {
809   g_mutex_lock (g_atomic_mutex);
810   *atomic = newval;
811   g_mutex_unlock (g_atomic_mutex);
812 }
813
814 gpointer
815 g_atomic_pointer_get (volatile gpointer *atomic)
816 {
817   gpointer result;
818
819   g_mutex_lock (g_atomic_mutex);
820   result = *atomic;
821   g_mutex_unlock (g_atomic_mutex);
822
823   return result;
824 }
825
826 void
827 g_atomic_pointer_set (volatile gpointer *atomic,
828                       gpointer           newval)
829 {
830   g_mutex_lock (g_atomic_mutex);
831   *atomic = newval;
832   g_mutex_unlock (g_atomic_mutex);
833 }
834 #endif /* G_ATOMIC_OP_MEMORY_BARRIER_NEEDED */   
835 #elif defined (G_ATOMIC_OP_MEMORY_BARRIER_NEEDED)
836 gint
837 g_atomic_int_get (volatile gint *atomic)
838 {
839   G_ATOMIC_MEMORY_BARRIER;
840   return *atomic;
841 }
842
843 void
844 g_atomic_int_set (volatile gint *atomic,
845                   gint           newval)
846 {
847   *atomic = newval;
848   G_ATOMIC_MEMORY_BARRIER; 
849 }
850
851 gpointer
852 g_atomic_pointer_get (volatile gpointer *atomic)
853 {
854   G_ATOMIC_MEMORY_BARRIER;
855   return *atomic;
856 }   
857
858 void
859 g_atomic_pointer_set (volatile gpointer *atomic,
860                       gpointer           newval)
861 {
862   *atomic = newval;
863   G_ATOMIC_MEMORY_BARRIER; 
864 }
865 #endif /* DEFINE_WITH_MUTEXES || G_ATOMIC_OP_MEMORY_BARRIER_NEEDED */
866
867 #ifdef ATOMIC_INT_CMP_XCHG
868 gboolean
869 g_atomic_int_compare_and_exchange (volatile gint *atomic,
870                                    gint           oldval,
871                                    gint           newval)
872 {
873   return ATOMIC_INT_CMP_XCHG (atomic, oldval, newval);
874 }
875
876 gint
877 g_atomic_int_exchange_and_add (volatile gint *atomic,
878                                gint           val)
879 {
880   gint result;
881   do
882     result = *atomic;
883   while (!ATOMIC_INT_CMP_XCHG (atomic, result, result + val));
884
885   return result;
886 }
887  
888 void
889 g_atomic_int_add (volatile gint *atomic,
890                   gint           val)
891 {
892   gint result;
893   do
894     result = *atomic;
895   while (!ATOMIC_INT_CMP_XCHG (atomic, result, result + val));
896 }
897 #endif /* ATOMIC_INT_CMP_XCHG */
898
899 void 
900 _g_atomic_thread_init (void)
901 {
902 #ifdef DEFINE_WITH_MUTEXES
903   g_atomic_mutex = g_mutex_new ();
904 #endif /* DEFINE_WITH_MUTEXES */
905 }
906
907 #ifndef G_ATOMIC_OP_MEMORY_BARRIER_NEEDED
908 gint
909 (g_atomic_int_get) (volatile gint *atomic)
910 {
911   return g_atomic_int_get (atomic);
912 }
913
914 void
915 (g_atomic_int_set) (volatile gint *atomic,
916                     gint           newval)
917 {
918   g_atomic_int_set (atomic, newval);
919 }
920
921 gpointer
922 (g_atomic_pointer_get) (volatile gpointer *atomic)
923 {
924   return g_atomic_pointer_get (atomic);
925 }
926
927 void
928 (g_atomic_pointer_set) (volatile gpointer *atomic,
929                         gpointer           newval)
930 {
931   g_atomic_pointer_set (atomic, newval);
932 }
933 #endif /* G_ATOMIC_OP_MEMORY_BARRIER_NEEDED */
934
935 #define __G_ATOMIC_C__
936 #include "galiasdef.c"