[win32] Add fallback implementations for gatomic.c on mingw32
[platform/upstream/glib.git] / glib / gatomic.c
1 /*
2  * Copyright © 2011 Ryan Lortie
3  *
4  * This library is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * licence, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
17  * USA.
18  *
19  * Author: Ryan Lortie <desrt@desrt.ca>
20  */
21
22 #include "config.h"
23
24 #include "gatomic.h"
25
26 /**
27  * SECTION:atomic_operations
28  * @title: Atomic Operations
29  * @short_description: basic atomic integer and pointer operations
30  * @see_also: #GMutex
31  *
32  * The following is a collection of compiler macros to provide atomic
33  * access to integer and pointer-sized values.
34  *
35  * The macros that have 'int' in the name will operate on pointers to
36  * #gint and #guint.  The macros with 'pointer' in the name will operate
37  * on pointers to any pointer-sized value, including #gsize.  There is
38  * no support for 64bit operations on platforms with 32bit pointers
39  * because it is not generally possible to perform these operations
40  * atomically.
41  *
42  * The get, set and exchange operations for integers and pointers
43  * nominally operate on #gint and #gpointer, respectively.  Of the
44  * arithmetic operations, the 'add' operation operates on (and returns)
45  * signed integer values (#gint and #gssize) and the 'and', 'or', and
46  * 'xor' operations operate on (and return) unsigned integer values
47  * (#guint and #gsize).
48  *
49  * All of the operations act as a full compiler and (where appropriate)
50  * hardware memory barrier.  Acquire and release or producer and
51  * consumer barrier semantics are not available through this API.
52  *
53  * It is very important that all accesses to a particular integer or
54  * pointer be performed using only this API and that different sizes of
55  * operation are not mixed or used on overlapping memory regions.  Never
56  * read or assign directly from or to a value -- always use this API.
57  *
58  * For simple reference counting purposes you should use
59  * g_atomic_int_inc() and g_atomic_int_dec_and_test().  Other uses that
60  * fall outside of simple reference counting patterns are prone to
61  * subtle bugs and occasionally undefined behaviour.  It is also worth
62  * noting that since all of these operations require global
63  * synchronisation of the entire machine, they can be quite slow.  In
64  * the case of performing multiple atomic operations it can often be
65  * faster to simply acquire a mutex lock around the critical area,
66  * perform the operations normally and then release the lock.
67  **/
68
69 /**
70  * G_ATOMIC_LOCK_FREE:
71  *
72  * This macro is defined if the atomic operations of GLib are
73  * implemented using real hardware atomic operations.  This means that
74  * the GLib atomic API can be used between processes and safely mixed
75  * with other (hardware) atomic APIs.
76  *
77  * If this macro is not defined, the atomic operations may be
78  * emulated using a mutex.  In that case, the GLib atomic operations are
79  * only atomic relative to themselves and within a single process.
80  **/
81
82 /* NOTE CAREFULLY:
83  *
84  * This file is the lowest-level part of GLib.
85  *
86  * Other lowlevel parts of GLib (threads, slice allocator, g_malloc,
87  * messages, etc) call into these functions and macros to get work done.
88  *
89  * As such, these functions can not call back into any part of GLib
90  * without risking recursion.
91  */
92
93 #ifdef G_ATOMIC_LOCK_FREE
94
95 /* if G_ATOMIC_LOCK_FREE was defined by ./configure then we MUST
96  * implement the atomic operations in a lock-free manner.
97  */
98
99 #if defined (__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)
100 /**
101  * g_atomic_int_get:
102  * @atomic: a pointer to a #gint or #guint
103  *
104  * Gets the current value of @atomic.
105  *
106  * This call acts as a full compiler and hardware
107  * memory barrier (before the get).
108  *
109  * Returns: the value of the integer
110  *
111  * Since: 2.4
112  **/
113 gint
114 (g_atomic_int_get) (const volatile gint *atomic)
115 {
116   return g_atomic_int_get (atomic);
117 }
118
119 /**
120  * g_atomic_int_set:
121  * @atomic: a pointer to a #gint or #guint
122  * @newval: a new value to store
123  *
124  * Sets the value of @atomic to @newval.
125  *
126  * This call acts as a full compiler and hardware
127  * memory barrier (after the set).
128  *
129  * Since: 2.4
130  */
131 void
132 (g_atomic_int_set) (volatile gint *atomic,
133                     gint           newval)
134 {
135   g_atomic_int_set (atomic, newval);
136 }
137
138 /**
139  * g_atomic_int_inc:
140  * @atomic: a pointer to a #gint or #guint
141  *
142  * Increments the value of @atomic by 1.
143  *
144  * Think of this operation as an atomic version of
145  * <literal>{ *@atomic += 1; }</literal>
146  *
147  * This call acts as a full compiler and hardware memory barrier.
148  *
149  * Since: 2.4
150  **/
151 void
152 (g_atomic_int_inc) (volatile gint *atomic)
153 {
154   g_atomic_int_inc (atomic);
155 }
156
157 /**
158  * g_atomic_int_dec_and_test:
159  * @atomic: a pointer to a #gint or #guint
160  *
161  * Decrements the value of @atomic by 1.
162  *
163  * Think of this operation as an atomic version of
164  * <literal>{ *@atomic -= 1; return (*@atomic == 0); }</literal>
165  *
166  * This call acts as a full compiler and hardware memory barrier.
167  *
168  * Returns: %TRUE if the resultant value is zero
169  *
170  * Since: 2.4
171  **/
172 gboolean
173 (g_atomic_int_dec_and_test) (volatile gint *atomic)
174 {
175   return g_atomic_int_dec_and_test (atomic);
176 }
177
178 /**
179  * g_atomic_int_compare_and_exchange:
180  * @atomic: a pointer to a #gint or #guint
181  * @oldval: the value to compare with
182  * @newval: the value to conditionally replace with
183  *
184  * Compares @atomic to @oldval and, if equal, sets it to @newval.
185  * If @atomic was not equal to @oldval then no change occurs.
186  *
187  * This compare and exchange is done atomically.
188  *
189  * Think of this operation as an atomic version of
190  * <literal>{ if (*@atomic == @oldval) { *@atomic = @newval; return TRUE; } else return FALSE; }</literal>
191  *
192  * This call acts as a full compiler and hardware memory barrier.
193  *
194  * Returns: %TRUE if the exchange took place
195  *
196  * Since: 2.4
197  **/
198 gboolean
199 (g_atomic_int_compare_and_exchange) (volatile gint *atomic,
200                                      gint           oldval,
201                                      gint           newval)
202 {
203   return g_atomic_int_compare_and_exchange (atomic, oldval, newval);
204 }
205
206 /**
207  * g_atomic_int_add:
208  * @atomic: a pointer to a #gint or #guint
209  * @val: the value to add
210  *
211  * Atomically adds @val to the value of @atomic.
212  *
213  * Think of this operation as an atomic version of
214  * <literal>{ tmp = *atomic; *@atomic += @val; return tmp; }</literal>
215  *
216  * This call acts as a full compiler and hardware memory barrier.
217  *
218  * Before version 2.30, this function did not return a value
219  * (but g_atomic_int_exchange_and_add() did, and had the same meaning).
220  *
221  * Returns: the value of @atomic before the add, signed
222  *
223  * Since: 2.4
224  **/
225 gint
226 (g_atomic_int_add) (volatile gint *atomic,
227                     gint           val)
228 {
229   return g_atomic_int_add (atomic, val);
230 }
231
232 /**
233  * g_atomic_int_and:
234  * @atomic: a pointer to a #gint or #guint
235  * @val: the value to 'and'
236  *
237  * Performs an atomic bitwise 'and' of the value of @atomic and @val,
238  * storing the result back in @atomic.
239  *
240  * This call acts as a full compiler and hardware memory barrier.
241  *
242  * Think of this operation as an atomic version of
243  * <literal>{ tmp = *atomic; *@atomic &= @val; return tmp; }</literal>
244  *
245  * Returns: the value of @atomic before the operation, unsigned
246  *
247  * Since: 2.30
248  **/
249 guint
250 (g_atomic_int_and) (volatile guint *atomic,
251                     guint           val)
252 {
253   return g_atomic_int_and (atomic, val);
254 }
255
256 /**
257  * g_atomic_int_or:
258  * @atomic: a pointer to a #gint or #guint
259  * @val: the value to 'or'
260  *
261  * Performs an atomic bitwise 'or' of the value of @atomic and @val,
262  * storing the result back in @atomic.
263  *
264  * Think of this operation as an atomic version of
265  * <literal>{ tmp = *atomic; *@atomic |= @val; return tmp; }</literal>
266  *
267  * This call acts as a full compiler and hardware memory barrier.
268  *
269  * Returns: the value of @atomic before the operation, unsigned
270  *
271  * Since: 2.30
272  **/
273 guint
274 (g_atomic_int_or) (volatile guint *atomic,
275                    guint           val)
276 {
277   return g_atomic_int_or (atomic, val);
278 }
279
280 /**
281  * g_atomic_int_xor:
282  * @atomic: a pointer to a #gint or #guint
283  * @val: the value to 'xor'
284  *
285  * Performs an atomic bitwise 'xor' of the value of @atomic and @val,
286  * storing the result back in @atomic.
287  *
288  * Think of this operation as an atomic version of
289  * <literal>{ tmp = *atomic; *@atomic ^= @val; return tmp; }</literal>
290  *
291  * This call acts as a full compiler and hardware memory barrier.
292  *
293  * Returns: the value of @atomic before the operation, unsigned
294  *
295  * Since: 2.30
296  **/
297 guint
298 (g_atomic_int_xor) (volatile guint *atomic,
299                     guint           val)
300 {
301   return g_atomic_int_xor (atomic, val);
302 }
303
304
305 /**
306  * g_atomic_pointer_get:
307  * @atomic: a pointer to a #gpointer-sized value
308  *
309  * Gets the current value of @atomic.
310  *
311  * This call acts as a full compiler and hardware
312  * memory barrier (before the get).
313  *
314  * Returns: the value of the pointer
315  *
316  * Since: 2.4
317  **/
318 gpointer
319 (g_atomic_pointer_get) (const volatile void *atomic)
320 {
321   return g_atomic_pointer_get ((const volatile gpointer *) atomic);
322 }
323
324 /**
325  * g_atomic_pointer_set:
326  * @atomic: a pointer to a #gpointer-sized value
327  * @newval: a new value to store
328  *
329  * Sets the value of @atomic to @newval.
330  *
331  * This call acts as a full compiler and hardware
332  * memory barrier (after the set).
333  *
334  * Since: 2.4
335  **/
336 void
337 (g_atomic_pointer_set) (volatile void *atomic,
338                         gpointer       newval)
339 {
340   g_atomic_pointer_set ((volatile gpointer *) atomic, newval);
341 }
342
343 /**
344  * g_atomic_pointer_compare_and_exchange:
345  * @atomic: a pointer to a #gpointer-sized value
346  * @oldval: the value to compare with
347  * @newval: the value to conditionally replace with
348  *
349  * Compares @atomic to @oldval and, if equal, sets it to @newval.
350  * If @atomic was not equal to @oldval then no change occurs.
351  *
352  * This compare and exchange is done atomically.
353  *
354  * Think of this operation as an atomic version of
355  * <literal>{ if (*@atomic == @oldval) { *@atomic = @newval; return TRUE; } else return FALSE; }</literal>
356  *
357  * This call acts as a full compiler and hardware memory barrier.
358  *
359  * Returns: %TRUE if the exchange took place
360  *
361  * Since: 2.4
362  **/
363 gboolean
364 (g_atomic_pointer_compare_and_exchange) (volatile void *atomic,
365                                          gpointer       oldval,
366                                          gpointer       newval)
367 {
368   return g_atomic_pointer_compare_and_exchange ((volatile gpointer *) atomic,
369                                                 oldval, newval);
370 }
371
372 /**
373  * g_atomic_pointer_add:
374  * @atomic: a pointer to a #gpointer-sized value
375  * @val: the value to add
376  *
377  * Atomically adds @val to the value of @atomic.
378  *
379  * Think of this operation as an atomic version of
380  * <literal>{ tmp = *atomic; *@atomic += @val; return tmp; }</literal>
381  *
382  * This call acts as a full compiler and hardware memory barrier.
383  *
384  * Returns: the value of @atomic before the add, signed
385  *
386  * Since: 2.30
387  **/
388 gssize
389 (g_atomic_pointer_add) (volatile void *atomic,
390                         gssize         val)
391 {
392   return g_atomic_pointer_add ((volatile gpointer *) atomic, val);
393 }
394
395 /**
396  * g_atomic_pointer_and:
397  * @atomic: a pointer to a #gpointer-sized value
398  * @val: the value to 'and'
399  *
400  * Performs an atomic bitwise 'and' of the value of @atomic and @val,
401  * storing the result back in @atomic.
402  *
403  * Think of this operation as an atomic version of
404  * <literal>{ tmp = *atomic; *@atomic &= @val; return tmp; }</literal>
405  *
406  * This call acts as a full compiler and hardware memory barrier.
407  *
408  * Returns: the value of @atomic before the operation, unsigned
409  *
410  * Since: 2.30
411  **/
412 gsize
413 (g_atomic_pointer_and) (volatile void *atomic,
414                         gsize          val)
415 {
416   return g_atomic_pointer_and ((volatile gpointer *) atomic, val);
417 }
418
419 /**
420  * g_atomic_pointer_or:
421  * @atomic: a pointer to a #gpointer-sized value
422  * @val: the value to 'or'
423  *
424  * Performs an atomic bitwise 'or' of the value of @atomic and @val,
425  * storing the result back in @atomic.
426  *
427  * Think of this operation as an atomic version of
428  * <literal>{ tmp = *atomic; *@atomic |= @val; return tmp; }</literal>
429  *
430  * This call acts as a full compiler and hardware memory barrier.
431  *
432  * Returns: the value of @atomic before the operation, unsigned
433  *
434  * Since: 2.30
435  **/
436 gsize
437 (g_atomic_pointer_or) (volatile void *atomic,
438                        gsize          val)
439 {
440   return g_atomic_pointer_or ((volatile gpointer *) atomic, val);
441 }
442
443 /**
444  * g_atomic_pointer_xor:
445  * @atomic: a pointer to a #gpointer-sized value
446  * @val: the value to 'xor'
447  *
448  * Performs an atomic bitwise 'xor' of the value of @atomic and @val,
449  * storing the result back in @atomic.
450  *
451  * Think of this operation as an atomic version of
452  * <literal>{ tmp = *atomic; *@atomic ^= @val; return tmp; }</literal>
453  *
454  * This call acts as a full compiler and hardware memory barrier.
455  *
456  * Returns: the value of @atomic before the operation, unsigned
457  *
458  * Since: 2.30
459  **/
460 gsize
461 (g_atomic_pointer_xor) (volatile void *atomic,
462                         gsize          val)
463 {
464   return g_atomic_pointer_xor ((volatile gpointer *) atomic, val);
465 }
466
467 #elif defined (G_PLATFORM_WIN32)
468
469 #include <windows.h>
470 #if !defined(_M_AMD64) && !defined (_M_IA64) && !defined(_M_X64) && !(defined _MSC_VER && _MSC_VER <= 1200)
471 #define InterlockedAnd _InterlockedAnd
472 #define InterlockedOr _InterlockedOr
473 #define InterlockedXor _InterlockedXor
474 #endif
475
476 #if !defined (_MSC_VER) || _MSC_VER <= 1200
477 #include "gmessages.h"
478 /* Inlined versions for older compiler */
479 static LONG
480 _gInterlockedAnd (volatile guint *atomic,
481                   guint           val)
482 {
483   LONG i, j;
484
485   j = *atomic;
486   do {
487     i = j;
488     j = InterlockedCompareExchange(atomic, i & val, i);
489   } while (i != j);
490
491   return j;
492 }
493 #define InterlockedAnd(a,b) _gInterlockedAnd(a,b)
494 static LONG
495 _gInterlockedOr (volatile guint *atomic,
496                  guint           val)
497 {
498   LONG i, j;
499
500   j = *atomic;
501   do {
502     i = j;
503     j = InterlockedCompareExchange(atomic, i | val, i);
504   } while (i != j);
505
506   return j;
507 }
508 #define InterlockedOr(a,b) _gInterlockedOr(a,b)
509 static LONG
510 _gInterlockedXor (volatile guint *atomic,
511                   guint           val)
512 {
513   LONG i, j;
514
515   j = *atomic;
516   do {
517     i = j;
518     j = InterlockedCompareExchange(atomic, i ^ val, i);
519   } while (i != j);
520
521   return j;
522 }
523 #define InterlockedXor(a,b) _gInterlockedXor(a,b)
524 #endif
525
526 /* mingw32 does not have MemoryBarrier.
527  * MemoryBarrier may be defined as a macro or a function.
528  * Just make a failsafe version for ourselves. */
529 #ifdef MemoryBarrier
530 #define _GMemoryBarrier MemoryBarrier
531 #else
532 static inline void _GMemoryBarrier (void) {
533   long dummy = 0;
534   InterlockedExchange (&dummy, 1);
535 }
536 #endif
537
538 /*
539  * http://msdn.microsoft.com/en-us/library/ms684122(v=vs.85).aspx
540  */
541 gint
542 (g_atomic_int_get) (const volatile gint *atomic)
543 {
544   _GMemoryBarrier ();
545   return *atomic;
546 }
547
548 void
549 (g_atomic_int_set) (volatile gint *atomic,
550                     gint           newval)
551 {
552   *atomic = newval;
553   _GMemoryBarrier ();
554 }
555
556 void
557 (g_atomic_int_inc) (volatile gint *atomic)
558 {
559   InterlockedIncrement (atomic);
560 }
561
562 gboolean
563 (g_atomic_int_dec_and_test) (volatile gint *atomic)
564 {
565   return InterlockedDecrement (atomic) == 0;
566 }
567
568 gboolean
569 (g_atomic_int_compare_and_exchange) (volatile gint *atomic,
570                                      gint           oldval,
571                                      gint           newval)
572 {
573   return InterlockedCompareExchange (atomic, newval, oldval) == oldval;
574 }
575
576 gint
577 (g_atomic_int_add) (volatile gint *atomic,
578                     gint           val)
579 {
580   return InterlockedExchangeAdd (atomic, val);
581 }
582
583 guint
584 (g_atomic_int_and) (volatile guint *atomic,
585                     guint           val)
586 {
587   return InterlockedAnd (atomic, val);
588 }
589
590 guint
591 (g_atomic_int_or) (volatile guint *atomic,
592                    guint           val)
593 {
594   return InterlockedOr (atomic, val);
595 }
596
597 guint
598 (g_atomic_int_xor) (volatile guint *atomic,
599                     guint           val)
600 {
601   return InterlockedXor (atomic, val);
602 }
603
604
605 gpointer
606 (g_atomic_pointer_get) (const volatile void *atomic)
607 {
608   const volatile gpointer *ptr = atomic;
609
610   _GMemoryBarrier ();
611   return *ptr;
612 }
613
614 void
615 (g_atomic_pointer_set) (volatile void *atomic,
616                         gpointer       newval)
617 {
618   volatile gpointer *ptr = atomic;
619
620   *ptr = newval;
621   _GMemoryBarrier ();
622 }
623
624 gboolean
625 (g_atomic_pointer_compare_and_exchange) (volatile void *atomic,
626                                          gpointer       oldval,
627                                          gpointer       newval)
628 {
629   return InterlockedCompareExchangePointer (atomic, newval, oldval) == oldval;
630 }
631
632 gssize
633 (g_atomic_pointer_add) (volatile void *atomic,
634                         gssize         val)
635 {
636 #if GLIB_SIZEOF_VOID_P == 8
637   return InterlockedExchangeAdd64 (atomic, val);
638 #else
639   return InterlockedExchangeAdd (atomic, val);
640 #endif
641 }
642
643 gsize
644 (g_atomic_pointer_and) (volatile void *atomic,
645                         gsize          val)
646 {
647 #if GLIB_SIZEOF_VOID_P == 8
648   return InterlockedAnd64 (atomic, val);
649 #else
650   return InterlockedAnd (atomic, val);
651 #endif
652 }
653
654 gsize
655 (g_atomic_pointer_or) (volatile void *atomic,
656                        gsize          val)
657 {
658 #if GLIB_SIZEOF_VOID_P == 8
659   return InterlockedOr64 (atomic, val);
660 #else
661   return InterlockedOr (atomic, val);
662 #endif
663 }
664
665 gsize
666 (g_atomic_pointer_xor) (volatile void *atomic,
667                         gsize          val)
668 {
669 #if GLIB_SIZEOF_VOID_P == 8
670   return InterlockedXor64 (atomic, val);
671 #else
672   return InterlockedXor (atomic, val);
673 #endif
674 }
675 #else
676
677 /* This error occurs when ./configure decided that we should be capable
678  * of lock-free atomics but we find at compile-time that we are not.
679  */
680 #error G_ATOMIC_LOCK_FREE defined, but incapable of lock-free atomics.
681
682 #endif /* defined (__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) */
683
684 #else /* G_ATOMIC_LOCK_FREE */
685
686 /* We are not permitted to call into any GLib functions from here, so we
687  * can not use GMutex.
688  *
689  * Fortunately, we already take care of the Windows case above, and all
690  * non-Windows platforms on which glib runs have pthreads.  Use those.
691  */
692 #include <pthread.h>
693
694 static pthread_mutex_t g_atomic_lock = PTHREAD_MUTEX_INITIALIZER;
695
696 gint
697 (g_atomic_int_get) (volatile gint *atomic)
698 {
699   gint value;
700
701   pthread_mutex_lock (&g_atomic_lock);
702   value = *atomic;
703   pthread_mutex_unlock (&g_atomic_lock);
704
705   return value;
706 }
707
708 void
709 (g_atomic_int_set) (volatile gint *atomic,
710                     gint           value)
711 {
712   pthread_mutex_lock (&g_atomic_lock);
713   *atomic = value;
714   pthread_mutex_unlock (&g_atomic_lock);
715 }
716
717 void
718 (g_atomic_int_inc) (volatile gint *atomic)
719 {
720   pthread_mutex_lock (&g_atomic_lock);
721   (*atomic)++;
722   pthread_mutex_unlock (&g_atomic_lock);
723 }
724
725 gboolean
726 (g_atomic_int_dec_and_test) (volatile gint *atomic)
727 {
728   gboolean is_zero;
729
730   pthread_mutex_lock (&g_atomic_lock);
731   is_zero = --(*atomic) == 0;
732   pthread_mutex_unlock (&g_atomic_lock);
733
734   return is_zero;
735 }
736
737 gboolean
738 (g_atomic_int_compare_and_exchange) (volatile gint *atomic,
739                                      gint           oldval,
740                                      gint           newval)
741 {
742   gboolean success;
743
744   pthread_mutex_lock (&g_atomic_lock);
745
746   if ((success = (*atomic == oldval)))
747     *atomic = newval;
748
749   pthread_mutex_unlock (&g_atomic_lock);
750
751   return success;
752 }
753
754 gint
755 (g_atomic_int_add) (volatile gint *atomic,
756                     gint           val)
757 {
758   gint oldval;
759
760   pthread_mutex_lock (&g_atomic_lock);
761   oldval = *atomic;
762   *atomic = oldval + val;
763   pthread_mutex_unlock (&g_atomic_lock);
764
765   return oldval;
766 }
767
768 guint
769 (g_atomic_int_and) (volatile guint *atomic,
770                     guint           val)
771 {
772   guint oldval;
773
774   pthread_mutex_lock (&g_atomic_lock);
775   oldval = *atomic;
776   *atomic = oldval & val;
777   pthread_mutex_unlock (&g_atomic_lock);
778
779   return oldval;
780 }
781
782 guint
783 (g_atomic_int_or) (volatile guint *atomic,
784                    guint           val)
785 {
786   guint oldval;
787
788   pthread_mutex_lock (&g_atomic_lock);
789   oldval = *atomic;
790   *atomic = oldval | val;
791   pthread_mutex_unlock (&g_atomic_lock);
792
793   return oldval;
794 }
795
796 guint
797 (g_atomic_int_xor) (volatile guint *atomic,
798                     guint           val)
799 {
800   guint oldval;
801
802   pthread_mutex_lock (&g_atomic_lock);
803   oldval = *atomic;
804   *atomic = oldval ^ val;
805   pthread_mutex_unlock (&g_atomic_lock);
806
807   return oldval;
808 }
809
810
811 gpointer
812 (g_atomic_pointer_get) (volatile void *atomic)
813 {
814   volatile gpointer *ptr = atomic;
815   gpointer value;
816
817   pthread_mutex_lock (&g_atomic_lock);
818   value = *ptr;
819   pthread_mutex_unlock (&g_atomic_lock);
820
821   return value;
822 }
823
824 void
825 (g_atomic_pointer_set) (volatile void *atomic,
826                         gpointer       newval)
827 {
828   volatile gpointer *ptr = atomic;
829
830   pthread_mutex_lock (&g_atomic_lock);
831   *ptr = newval;
832   pthread_mutex_unlock (&g_atomic_lock);
833 }
834
835 gboolean
836 (g_atomic_pointer_compare_and_exchange) (volatile void *atomic,
837                                          gpointer       oldval,
838                                          gpointer       newval)
839 {
840   volatile gpointer *ptr = atomic;
841   gboolean success;
842
843   pthread_mutex_lock (&g_atomic_lock);
844
845   if ((success = (*ptr == oldval)))
846     *ptr = newval;
847
848   pthread_mutex_unlock (&g_atomic_lock);
849
850   return success;
851 }
852
853 gssize
854 (g_atomic_pointer_add) (volatile void *atomic,
855                         gssize         val)
856 {
857   volatile gssize *ptr = atomic;
858   gssize oldval;
859
860   pthread_mutex_lock (&g_atomic_lock);
861   oldval = *ptr;
862   *ptr = oldval + val;
863   pthread_mutex_unlock (&g_atomic_lock);
864
865   return oldval;
866 }
867
868 gsize
869 (g_atomic_pointer_and) (volatile void *atomic,
870                         gsize          val)
871 {
872   volatile gsize *ptr = atomic;
873   gsize oldval;
874
875   pthread_mutex_lock (&g_atomic_lock);
876   oldval = *ptr;
877   *ptr = oldval & val;
878   pthread_mutex_unlock (&g_atomic_lock);
879
880   return oldval;
881 }
882
883 gsize
884 (g_atomic_pointer_or) (volatile void *atomic,
885                        gsize          val)
886 {
887   volatile gsize *ptr = atomic;
888   gsize oldval;
889
890   pthread_mutex_lock (&g_atomic_lock);
891   oldval = *ptr;
892   *ptr = oldval | val;
893   pthread_mutex_unlock (&g_atomic_lock);
894
895   return oldval;
896 }
897
898 gsize
899 (g_atomic_pointer_xor) (volatile void *atomic,
900                         gsize          val)
901 {
902   volatile gsize *ptr = atomic;
903   gsize oldval;
904
905   pthread_mutex_lock (&g_atomic_lock);
906   oldval = *ptr;
907   *ptr = oldval ^ val;
908   pthread_mutex_unlock (&g_atomic_lock);
909
910   return oldval;
911 }
912
913 #endif
914
915 /**
916  * g_atomic_int_exchange_and_add:
917  * @atomic: a pointer to a #gint
918  * @val: the value to add
919  *
920  * This function existed before g_atomic_int_add() returned the prior
921  * value of the integer (which it now does).  It is retained only for
922  * compatibility reasons.  Don't use this function in new code.
923  *
924  * Returns: the value of @atomic before the add, signed
925  * Since: 2.4
926  * Deprecated: 2.30: Use g_atomic_int_add() instead.
927  **/
928 gint
929 g_atomic_int_exchange_and_add (volatile gint *atomic,
930                                gint           val)
931 {
932   return (g_atomic_int_add) (atomic, val);
933 }