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