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