Fix getauxval error at qemu
[platform/upstream/glib.git] / glib / gatomic.c
1 /*
2  * Copyright © 2011 Ryan Lortie
3  *
4  * SPDX-License-Identifier: LGPL-2.1-or-later
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
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 `meson 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 /**
102  * g_atomic_int_get:
103  * @atomic: a pointer to a #gint or #guint
104  *
105  * Gets the current value of @atomic.
106  *
107  * This call acts as a full compiler and hardware
108  * memory barrier (before the get).
109  *
110  * While @atomic has a `volatile` qualifier, this is a historical artifact and
111  * the pointer passed to it should not be `volatile`.
112  *
113  * Returns: the value of the integer
114  *
115  * Since: 2.4
116  **/
117 gint
118 (g_atomic_int_get) (const volatile gint *atomic)
119 {
120   return g_atomic_int_get (atomic);
121 }
122
123 /**
124  * g_atomic_int_set:
125  * @atomic: a pointer to a #gint or #guint
126  * @newval: a new value to store
127  *
128  * Sets the value of @atomic to @newval.
129  *
130  * This call acts as a full compiler and hardware
131  * memory barrier (after the set).
132  *
133  * While @atomic has a `volatile` qualifier, this is a historical artifact and
134  * the pointer passed to it should not be `volatile`.
135  *
136  * Since: 2.4
137  */
138 void
139 (g_atomic_int_set) (volatile gint *atomic,
140                     gint           newval)
141 {
142   g_atomic_int_set (atomic, newval);
143 }
144
145 /**
146  * g_atomic_int_inc:
147  * @atomic: a pointer to a #gint or #guint
148  *
149  * Increments the value of @atomic by 1.
150  *
151  * Think of this operation as an atomic version of `{ *atomic += 1; }`.
152  *
153  * This call acts as a full compiler and hardware memory barrier.
154  *
155  * While @atomic has a `volatile` qualifier, this is a historical artifact and
156  * the pointer passed to it should not be `volatile`.
157  *
158  * Since: 2.4
159  **/
160 void
161 (g_atomic_int_inc) (volatile gint *atomic)
162 {
163   g_atomic_int_inc (atomic);
164 }
165
166 /**
167  * g_atomic_int_dec_and_test:
168  * @atomic: a pointer to a #gint or #guint
169  *
170  * Decrements the value of @atomic by 1.
171  *
172  * Think of this operation as an atomic version of
173  * `{ *atomic -= 1; return (*atomic == 0); }`.
174  *
175  * This call acts as a full compiler and hardware memory barrier.
176  *
177  * While @atomic has a `volatile` qualifier, this is a historical artifact and
178  * the pointer passed to it should not be `volatile`.
179  *
180  * Returns: %TRUE if the resultant value is zero
181  *
182  * Since: 2.4
183  **/
184 gboolean
185 (g_atomic_int_dec_and_test) (volatile gint *atomic)
186 {
187   return g_atomic_int_dec_and_test (atomic);
188 }
189
190 /**
191  * g_atomic_int_compare_and_exchange:
192  * @atomic: a pointer to a #gint or #guint
193  * @oldval: the value to compare with
194  * @newval: the value to conditionally replace with
195  *
196  * Compares @atomic to @oldval and, if equal, sets it to @newval.
197  * If @atomic was not equal to @oldval then no change occurs.
198  *
199  * This compare and exchange is done atomically.
200  *
201  * Think of this operation as an atomic version of
202  * `{ if (*atomic == oldval) { *atomic = newval; return TRUE; } else return FALSE; }`.
203  *
204  * This call acts as a full compiler and hardware memory barrier.
205  *
206  * While @atomic has a `volatile` qualifier, this is a historical artifact and
207  * the pointer passed to it should not be `volatile`.
208  *
209  * Returns: %TRUE if the exchange took place
210  *
211  * Since: 2.4
212  **/
213 gboolean
214 (g_atomic_int_compare_and_exchange) (volatile gint *atomic,
215                                      gint           oldval,
216                                      gint           newval)
217 {
218   return g_atomic_int_compare_and_exchange (atomic, oldval, newval);
219 }
220
221 /**
222  * g_atomic_int_compare_and_exchange_full:
223  * @atomic: a pointer to a #gint or #guint
224  * @oldval: the value to compare with
225  * @newval: the value to conditionally replace with
226  * @preval: (out): the contents of @atomic before this operation
227  *
228  * Compares @atomic to @oldval and, if equal, sets it to @newval.
229  * If @atomic was not equal to @oldval then no change occurs.
230  * In any case the value of @atomic before this operation is stored in @preval.
231  *
232  * This compare and exchange is done atomically.
233  *
234  * Think of this operation as an atomic version of
235  * `{ *preval = *atomic; if (*atomic == oldval) { *atomic = newval; return TRUE; } else return FALSE; }`.
236  *
237  * This call acts as a full compiler and hardware memory barrier.
238  *
239  * See also g_atomic_int_compare_and_exchange()
240  *
241  * Returns: %TRUE if the exchange took place
242  *
243  * Since: 2.74
244  **/
245 gboolean
246 (g_atomic_int_compare_and_exchange_full) (gint *atomic,
247                                           gint  oldval,
248                                           gint  newval,
249                                           gint *preval)
250 {
251   return g_atomic_int_compare_and_exchange_full (atomic, oldval, newval, preval);
252 }
253
254 /**
255  * g_atomic_int_exchange:
256  * @atomic: a pointer to a #gint or #guint
257  * @newval: the value to replace with
258  *
259  * Sets the @atomic to @newval and returns the old value from @atomic.
260  *
261  * This exchange is done atomically.
262  *
263  * Think of this operation as an atomic version of
264  * `{ tmp = *atomic; *atomic = val; return tmp; }`.
265  *
266  * This call acts as a full compiler and hardware memory barrier.
267  *
268  * Returns: the value of @atomic before the exchange, signed
269  *
270  * Since: 2.74
271  **/
272 gint
273 (g_atomic_int_exchange) (gint *atomic,
274                          gint  newval)
275 {
276   return g_atomic_int_exchange (atomic, newval);
277 }
278
279 /**
280  * g_atomic_int_add:
281  * @atomic: a pointer to a #gint or #guint
282  * @val: the value to add
283  *
284  * Atomically adds @val to the value of @atomic.
285  *
286  * Think of this operation as an atomic version of
287  * `{ tmp = *atomic; *atomic += val; return tmp; }`.
288  *
289  * This call acts as a full compiler and hardware memory barrier.
290  *
291  * Before version 2.30, this function did not return a value
292  * (but g_atomic_int_exchange_and_add() did, and had the same meaning).
293  *
294  * While @atomic has a `volatile` qualifier, this is a historical artifact and
295  * the pointer passed to it should not be `volatile`.
296  *
297  * Returns: the value of @atomic before the add, signed
298  *
299  * Since: 2.4
300  **/
301 gint
302 (g_atomic_int_add) (volatile gint *atomic,
303                     gint           val)
304 {
305   return g_atomic_int_add (atomic, val);
306 }
307
308 /**
309  * g_atomic_int_and:
310  * @atomic: a pointer to a #gint or #guint
311  * @val: the value to 'and'
312  *
313  * Performs an atomic bitwise 'and' of the value of @atomic and @val,
314  * storing the result back in @atomic.
315  *
316  * This call acts as a full compiler and hardware memory barrier.
317  *
318  * Think of this operation as an atomic version of
319  * `{ tmp = *atomic; *atomic &= val; return tmp; }`.
320  *
321  * While @atomic has a `volatile` qualifier, this is a historical artifact and
322  * the pointer passed to it should not be `volatile`.
323  *
324  * Returns: the value of @atomic before the operation, unsigned
325  *
326  * Since: 2.30
327  **/
328 guint
329 (g_atomic_int_and) (volatile guint *atomic,
330                     guint           val)
331 {
332   return g_atomic_int_and (atomic, val);
333 }
334
335 /**
336  * g_atomic_int_or:
337  * @atomic: a pointer to a #gint or #guint
338  * @val: the value to 'or'
339  *
340  * Performs an atomic bitwise 'or' of the value of @atomic and @val,
341  * storing the result back in @atomic.
342  *
343  * Think of this operation as an atomic version of
344  * `{ tmp = *atomic; *atomic |= val; return tmp; }`.
345  *
346  * This call acts as a full compiler and hardware memory barrier.
347  *
348  * While @atomic has a `volatile` qualifier, this is a historical artifact and
349  * the pointer passed to it should not be `volatile`.
350  *
351  * Returns: the value of @atomic before the operation, unsigned
352  *
353  * Since: 2.30
354  **/
355 guint
356 (g_atomic_int_or) (volatile guint *atomic,
357                    guint           val)
358 {
359   return g_atomic_int_or (atomic, val);
360 }
361
362 /**
363  * g_atomic_int_xor:
364  * @atomic: a pointer to a #gint or #guint
365  * @val: the value to 'xor'
366  *
367  * Performs an atomic bitwise 'xor' of the value of @atomic and @val,
368  * storing the result back in @atomic.
369  *
370  * Think of this operation as an atomic version of
371  * `{ tmp = *atomic; *atomic ^= val; return tmp; }`.
372  *
373  * This call acts as a full compiler and hardware memory barrier.
374  *
375  * While @atomic has a `volatile` qualifier, this is a historical artifact and
376  * the pointer passed to it should not be `volatile`.
377  *
378  * Returns: the value of @atomic before the operation, unsigned
379  *
380  * Since: 2.30
381  **/
382 guint
383 (g_atomic_int_xor) (volatile guint *atomic,
384                     guint           val)
385 {
386   return g_atomic_int_xor (atomic, val);
387 }
388
389
390 /**
391  * g_atomic_pointer_get:
392  * @atomic: (not nullable): a pointer to a #gpointer-sized value
393  *
394  * Gets the current value of @atomic.
395  *
396  * This call acts as a full compiler and hardware
397  * memory barrier (before the get).
398  *
399  * While @atomic has a `volatile` qualifier, this is a historical artifact and
400  * the pointer passed to it should not be `volatile`.
401  *
402  * Returns: the value of the pointer
403  *
404  * Since: 2.4
405  **/
406 gpointer
407 (g_atomic_pointer_get) (const volatile void *atomic)
408 {
409   return g_atomic_pointer_get ((gpointer *) atomic);
410 }
411
412 /**
413  * g_atomic_pointer_set:
414  * @atomic: (not nullable): a pointer to a #gpointer-sized value
415  * @newval: a new value to store
416  *
417  * Sets the value of @atomic to @newval.
418  *
419  * This call acts as a full compiler and hardware
420  * memory barrier (after the set).
421  *
422  * While @atomic has a `volatile` qualifier, this is a historical artifact and
423  * the pointer passed to it should not be `volatile`.
424  *
425  * Since: 2.4
426  **/
427 void
428 (g_atomic_pointer_set) (volatile void *atomic,
429                         gpointer       newval)
430 {
431   g_atomic_pointer_set ((gpointer *) atomic, newval);
432 }
433
434 /**
435  * g_atomic_pointer_compare_and_exchange:
436  * @atomic: (not nullable): a pointer to a #gpointer-sized value
437  * @oldval: the value to compare with
438  * @newval: the value to conditionally replace with
439  *
440  * Compares @atomic to @oldval and, if equal, sets it to @newval.
441  * If @atomic was not equal to @oldval then no change occurs.
442  *
443  * This compare and exchange is done atomically.
444  *
445  * Think of this operation as an atomic version of
446  * `{ if (*atomic == oldval) { *atomic = newval; return TRUE; } else return FALSE; }`.
447  *
448  * This call acts as a full compiler and hardware memory barrier.
449  *
450  * While @atomic has a `volatile` qualifier, this is a historical artifact and
451  * the pointer passed to it should not be `volatile`.
452  *
453  * Returns: %TRUE if the exchange took place
454  *
455  * Since: 2.4
456  **/
457 gboolean
458 (g_atomic_pointer_compare_and_exchange) (volatile void *atomic,
459                                          gpointer       oldval,
460                                          gpointer       newval)
461 {
462   return g_atomic_pointer_compare_and_exchange ((gpointer *) atomic,
463                                                 oldval, newval);
464 }
465
466  /**
467  * g_atomic_pointer_compare_and_exchange_full:
468  * @atomic: (not nullable): a pointer to a #gpointer-sized value
469  * @oldval: the value to compare with
470  * @newval: the value to conditionally replace with
471  * @preval: (not nullable) (out): the contents of @atomic before this operation
472  *
473  * Compares @atomic to @oldval and, if equal, sets it to @newval.
474  * If @atomic was not equal to @oldval then no change occurs.
475  * In any case the value of @atomic before this operation is stored in @preval.
476  *
477  * This compare and exchange is done atomically.
478  *
479  * Think of this operation as an atomic version of
480  * `{ *preval = *atomic; if (*atomic == oldval) { *atomic = newval; return TRUE; } else return FALSE; }`.
481  *
482  * This call acts as a full compiler and hardware memory barrier.
483  *
484  * See also g_atomic_pointer_compare_and_exchange()
485  *
486  * Returns: %TRUE if the exchange took place
487  *
488  * Since: 2.74
489  **/
490 gboolean
491 (g_atomic_pointer_compare_and_exchange_full) (void     *atomic,
492                                               gpointer  oldval,
493                                               gpointer  newval,
494                                               void     *preval)
495 {
496   return g_atomic_pointer_compare_and_exchange_full ((gpointer *) atomic,
497                                                      oldval, newval,
498                                                      (gpointer *) preval);
499 }
500
501 /**
502  * g_atomic_pointer_exchange:
503  * @atomic: a pointer to a #gpointer-sized value
504  * @newval: the value to replace with
505  *
506  * Sets the @atomic to @newval and returns the old value from @atomic.
507  *
508  * This exchange is done atomically.
509  *
510  * Think of this operation as an atomic version of
511  * `{ tmp = *atomic; *atomic = val; return tmp; }`.
512  *
513  * This call acts as a full compiler and hardware memory barrier.
514  *
515  * Returns: the value of @atomic before the exchange
516  *
517  * Since: 2.74
518  **/
519 gpointer
520 (g_atomic_pointer_exchange) (void     *atomic,
521                              gpointer  newval)
522 {
523   return g_atomic_pointer_exchange ((gpointer *) atomic, newval);
524 }
525
526 /**
527  * g_atomic_pointer_add:
528  * @atomic: (not nullable): a pointer to a #gpointer-sized value
529  * @val: the value to add
530  *
531  * Atomically adds @val to the value of @atomic.
532  *
533  * Think of this operation as an atomic version of
534  * `{ tmp = *atomic; *atomic += val; return tmp; }`.
535  *
536  * This call acts as a full compiler and hardware memory barrier.
537  *
538  * While @atomic has a `volatile` qualifier, this is a historical artifact and
539  * the pointer passed to it should not be `volatile`.
540  *
541  * Returns: the value of @atomic before the add, signed
542  *
543  * Since: 2.30
544  **/
545 gssize
546 (g_atomic_pointer_add) (volatile void *atomic,
547                         gssize         val)
548 {
549   return g_atomic_pointer_add ((gpointer *) atomic, val);
550 }
551
552 /**
553  * g_atomic_pointer_and:
554  * @atomic: (not nullable): a pointer to a #gpointer-sized value
555  * @val: the value to 'and'
556  *
557  * Performs an atomic bitwise 'and' of the value of @atomic and @val,
558  * storing the result back in @atomic.
559  *
560  * Think of this operation as an atomic version of
561  * `{ tmp = *atomic; *atomic &= val; return tmp; }`.
562  *
563  * This call acts as a full compiler and hardware memory barrier.
564  *
565  * While @atomic has a `volatile` qualifier, this is a historical artifact and
566  * the pointer passed to it should not be `volatile`.
567  *
568  * Returns: the value of @atomic before the operation, unsigned
569  *
570  * Since: 2.30
571  **/
572 gsize
573 (g_atomic_pointer_and) (volatile void *atomic,
574                         gsize          val)
575 {
576   return g_atomic_pointer_and ((gpointer *) atomic, val);
577 }
578
579 /**
580  * g_atomic_pointer_or:
581  * @atomic: (not nullable): a pointer to a #gpointer-sized value
582  * @val: the value to 'or'
583  *
584  * Performs an atomic bitwise 'or' of the value of @atomic and @val,
585  * storing the result back in @atomic.
586  *
587  * Think of this operation as an atomic version of
588  * `{ tmp = *atomic; *atomic |= val; return tmp; }`.
589  *
590  * This call acts as a full compiler and hardware memory barrier.
591  *
592  * While @atomic has a `volatile` qualifier, this is a historical artifact and
593  * the pointer passed to it should not be `volatile`.
594  *
595  * Returns: the value of @atomic before the operation, unsigned
596  *
597  * Since: 2.30
598  **/
599 gsize
600 (g_atomic_pointer_or) (volatile void *atomic,
601                        gsize          val)
602 {
603   return g_atomic_pointer_or ((gpointer *) atomic, val);
604 }
605
606 /**
607  * g_atomic_pointer_xor:
608  * @atomic: (not nullable): a pointer to a #gpointer-sized value
609  * @val: the value to 'xor'
610  *
611  * Performs an atomic bitwise 'xor' of the value of @atomic and @val,
612  * storing the result back in @atomic.
613  *
614  * Think of this operation as an atomic version of
615  * `{ tmp = *atomic; *atomic ^= val; return tmp; }`.
616  *
617  * This call acts as a full compiler and hardware memory barrier.
618  *
619  * While @atomic has a `volatile` qualifier, this is a historical artifact and
620  * the pointer passed to it should not be `volatile`.
621  *
622  * Returns: the value of @atomic before the operation, unsigned
623  *
624  * Since: 2.30
625  **/
626 gsize
627 (g_atomic_pointer_xor) (volatile void *atomic,
628                         gsize          val)
629 {
630   return g_atomic_pointer_xor ((gpointer *) atomic, val);
631 }
632
633 #elif defined (G_PLATFORM_WIN32)
634
635 #include <windows.h>
636 #if !defined(_M_AMD64) && !defined (_M_IA64) && !defined(_M_X64) && !(defined _MSC_VER && _MSC_VER <= 1200)
637 #define InterlockedAnd _InterlockedAnd
638 #define InterlockedOr _InterlockedOr
639 #define InterlockedXor _InterlockedXor
640 #endif
641
642 #if !defined (_MSC_VER) || _MSC_VER <= 1200
643 #include "gmessages.h"
644 /* Inlined versions for older compiler */
645 static LONG
646 _gInterlockedAnd (volatile guint *atomic,
647                   guint           val)
648 {
649   LONG i, j;
650
651   j = *atomic;
652   do {
653     i = j;
654     j = InterlockedCompareExchange(atomic, i & val, i);
655   } while (i != j);
656
657   return j;
658 }
659 #define InterlockedAnd(a,b) _gInterlockedAnd(a,b)
660 static LONG
661 _gInterlockedOr (volatile guint *atomic,
662                  guint           val)
663 {
664   LONG i, j;
665
666   j = *atomic;
667   do {
668     i = j;
669     j = InterlockedCompareExchange(atomic, i | val, i);
670   } while (i != j);
671
672   return j;
673 }
674 #define InterlockedOr(a,b) _gInterlockedOr(a,b)
675 static LONG
676 _gInterlockedXor (volatile guint *atomic,
677                   guint           val)
678 {
679   LONG i, j;
680
681   j = *atomic;
682   do {
683     i = j;
684     j = InterlockedCompareExchange(atomic, i ^ val, i);
685   } while (i != j);
686
687   return j;
688 }
689 #define InterlockedXor(a,b) _gInterlockedXor(a,b)
690 #endif
691
692 /*
693  * http://msdn.microsoft.com/en-us/library/ms684122(v=vs.85).aspx
694  */
695 gint
696 (g_atomic_int_get) (const volatile gint *atomic)
697 {
698   MemoryBarrier ();
699   return *atomic;
700 }
701
702 void
703 (g_atomic_int_set) (volatile gint *atomic,
704                     gint           newval)
705 {
706   *atomic = newval;
707   MemoryBarrier ();
708 }
709
710 void
711 (g_atomic_int_inc) (volatile gint *atomic)
712 {
713   InterlockedIncrement (atomic);
714 }
715
716 gboolean
717 (g_atomic_int_dec_and_test) (volatile gint *atomic)
718 {
719   return InterlockedDecrement (atomic) == 0;
720 }
721
722 gboolean
723 (g_atomic_int_compare_and_exchange) (volatile gint *atomic,
724                                      gint           oldval,
725                                      gint           newval)
726 {
727   return InterlockedCompareExchange (atomic, newval, oldval) == oldval;
728 }
729
730 gboolean
731 (g_atomic_int_compare_and_exchange_full) (gint *atomic,
732                                           gint  oldval,
733                                           gint  newval,
734                                           gint *preval)
735 {
736   *preval = InterlockedCompareExchange (atomic, newval, oldval);
737   return *preval == oldval;
738 }
739
740 gint
741 (g_atomic_int_exchange) (gint *atomic,
742                          gint  newval)
743 {
744   return InterlockedExchange (atomic, newval);
745 }
746
747 gint
748 (g_atomic_int_add) (volatile gint *atomic,
749                     gint           val)
750 {
751   return InterlockedExchangeAdd (atomic, val);
752 }
753
754 guint
755 (g_atomic_int_and) (volatile guint *atomic,
756                     guint           val)
757 {
758   return InterlockedAnd (atomic, val);
759 }
760
761 guint
762 (g_atomic_int_or) (volatile guint *atomic,
763                    guint           val)
764 {
765   return InterlockedOr (atomic, val);
766 }
767
768 guint
769 (g_atomic_int_xor) (volatile guint *atomic,
770                     guint           val)
771 {
772   return InterlockedXor (atomic, val);
773 }
774
775
776 gpointer
777 (g_atomic_pointer_get) (const volatile void *atomic)
778 {
779   const gpointer *ptr = atomic;
780
781   MemoryBarrier ();
782   return *ptr;
783 }
784
785 void
786 (g_atomic_pointer_set) (volatile void *atomic,
787                         gpointer       newval)
788 {
789   gpointer *ptr = atomic;
790
791   *ptr = newval;
792   MemoryBarrier ();
793 }
794
795 gboolean
796 (g_atomic_pointer_compare_and_exchange) (volatile void *atomic,
797                                          gpointer       oldval,
798                                          gpointer       newval)
799 {
800   return InterlockedCompareExchangePointer (atomic, newval, oldval) == oldval;
801 }
802
803 gboolean
804 (g_atomic_pointer_compare_and_exchange_full) (void     *atomic,
805                                               gpointer  oldval,
806                                               gpointer  newval,
807                                               void     *preval)
808 {
809   gpointer *pre = preval;
810
811   *pre = InterlockedCompareExchangePointer (atomic, newval, oldval);
812
813   return *pre == oldval;
814 }
815
816 gpointer
817 (g_atomic_pointer_exchange) (void     *atomic,
818                              gpointer  newval)
819 {
820   return InterlockedExchangePointer (atomic, newval);
821 }
822
823 gssize
824 (g_atomic_pointer_add) (volatile void *atomic,
825                         gssize         val)
826 {
827 #if GLIB_SIZEOF_VOID_P == 8
828   return InterlockedExchangeAdd64 (atomic, val);
829 #else
830   return InterlockedExchangeAdd (atomic, val);
831 #endif
832 }
833
834 gsize
835 (g_atomic_pointer_and) (volatile void *atomic,
836                         gsize          val)
837 {
838 #if GLIB_SIZEOF_VOID_P == 8
839   return InterlockedAnd64 (atomic, val);
840 #else
841   return InterlockedAnd (atomic, val);
842 #endif
843 }
844
845 gsize
846 (g_atomic_pointer_or) (volatile void *atomic,
847                        gsize          val)
848 {
849 #if GLIB_SIZEOF_VOID_P == 8
850   return InterlockedOr64 (atomic, val);
851 #else
852   return InterlockedOr (atomic, val);
853 #endif
854 }
855
856 gsize
857 (g_atomic_pointer_xor) (volatile void *atomic,
858                         gsize          val)
859 {
860 #if GLIB_SIZEOF_VOID_P == 8
861   return InterlockedXor64 (atomic, val);
862 #else
863   return InterlockedXor (atomic, val);
864 #endif
865 }
866 #else
867
868 /* This error occurs when `meson configure` decided that we should be capable
869  * of lock-free atomics but we find at compile-time that we are not.
870  */
871 #error G_ATOMIC_LOCK_FREE defined, but incapable of lock-free atomics.
872
873 #endif /* defined (__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) */
874
875 #else /* G_ATOMIC_LOCK_FREE */
876
877 /* We are not permitted to call into any GLib functions from here, so we
878  * can not use GMutex.
879  *
880  * Fortunately, we already take care of the Windows case above, and all
881  * non-Windows platforms on which glib runs have pthreads.  Use those.
882  */
883 #include <pthread.h>
884
885 static pthread_mutex_t g_atomic_lock = PTHREAD_MUTEX_INITIALIZER;
886
887 gint
888 (g_atomic_int_get) (const volatile gint *atomic)
889 {
890   gint value;
891
892   pthread_mutex_lock (&g_atomic_lock);
893   value = *atomic;
894   pthread_mutex_unlock (&g_atomic_lock);
895
896   return value;
897 }
898
899 void
900 (g_atomic_int_set) (volatile gint *atomic,
901                     gint           value)
902 {
903   pthread_mutex_lock (&g_atomic_lock);
904   *atomic = value;
905   pthread_mutex_unlock (&g_atomic_lock);
906 }
907
908 void
909 (g_atomic_int_inc) (volatile gint *atomic)
910 {
911   pthread_mutex_lock (&g_atomic_lock);
912   (*atomic)++;
913   pthread_mutex_unlock (&g_atomic_lock);
914 }
915
916 gboolean
917 (g_atomic_int_dec_and_test) (volatile gint *atomic)
918 {
919   gboolean is_zero;
920
921   pthread_mutex_lock (&g_atomic_lock);
922   is_zero = --(*atomic) == 0;
923   pthread_mutex_unlock (&g_atomic_lock);
924
925   return is_zero;
926 }
927
928 gboolean
929 (g_atomic_int_compare_and_exchange) (volatile gint *atomic,
930                                      gint           oldval,
931                                      gint           newval)
932 {
933   gboolean success;
934
935   pthread_mutex_lock (&g_atomic_lock);
936
937   if ((success = (*atomic == oldval)))
938     *atomic = newval;
939
940   pthread_mutex_unlock (&g_atomic_lock);
941
942   return success;
943 }
944
945 gboolean
946 (g_atomic_int_compare_and_exchange_full) (gint *atomic,
947                                           gint  oldval,
948                                           gint  newval,
949                                           gint *preval)
950 {
951   gboolean success;
952
953   pthread_mutex_lock (&g_atomic_lock);
954
955   *preval = *atomic;
956
957   if ((success = (*atomic == oldval)))
958     *atomic = newval;
959
960   pthread_mutex_unlock (&g_atomic_lock);
961
962   return success;
963 }
964
965 gint
966 (g_atomic_int_exchange) (gint *atomic,
967                          gint  newval)
968 {
969   gint *ptr = atomic;
970   gint oldval;
971
972   pthread_mutex_lock (&g_atomic_lock);
973   oldval = *ptr;
974   *ptr = newval;
975   pthread_mutex_unlock (&g_atomic_lock);
976
977   return oldval;
978 }
979
980 gint
981 (g_atomic_int_add) (volatile gint *atomic,
982                     gint           val)
983 {
984   gint oldval;
985
986   pthread_mutex_lock (&g_atomic_lock);
987   oldval = *atomic;
988   *atomic = oldval + val;
989   pthread_mutex_unlock (&g_atomic_lock);
990
991   return oldval;
992 }
993
994 guint
995 (g_atomic_int_and) (volatile guint *atomic,
996                     guint           val)
997 {
998   guint oldval;
999
1000   pthread_mutex_lock (&g_atomic_lock);
1001   oldval = *atomic;
1002   *atomic = oldval & val;
1003   pthread_mutex_unlock (&g_atomic_lock);
1004
1005   return oldval;
1006 }
1007
1008 guint
1009 (g_atomic_int_or) (volatile guint *atomic,
1010                    guint           val)
1011 {
1012   guint oldval;
1013
1014   pthread_mutex_lock (&g_atomic_lock);
1015   oldval = *atomic;
1016   *atomic = oldval | val;
1017   pthread_mutex_unlock (&g_atomic_lock);
1018
1019   return oldval;
1020 }
1021
1022 guint
1023 (g_atomic_int_xor) (volatile guint *atomic,
1024                     guint           val)
1025 {
1026   guint oldval;
1027
1028   pthread_mutex_lock (&g_atomic_lock);
1029   oldval = *atomic;
1030   *atomic = oldval ^ val;
1031   pthread_mutex_unlock (&g_atomic_lock);
1032
1033   return oldval;
1034 }
1035
1036
1037 gpointer
1038 (g_atomic_pointer_get) (const volatile void *atomic)
1039 {
1040   const gpointer *ptr = atomic;
1041   gpointer value;
1042
1043   pthread_mutex_lock (&g_atomic_lock);
1044   value = *ptr;
1045   pthread_mutex_unlock (&g_atomic_lock);
1046
1047   return value;
1048 }
1049
1050 void
1051 (g_atomic_pointer_set) (volatile void *atomic,
1052                         gpointer       newval)
1053 {
1054   gpointer *ptr = atomic;
1055
1056   pthread_mutex_lock (&g_atomic_lock);
1057   *ptr = newval;
1058   pthread_mutex_unlock (&g_atomic_lock);
1059 }
1060
1061 gboolean
1062 (g_atomic_pointer_compare_and_exchange) (volatile void *atomic,
1063                                          gpointer       oldval,
1064                                          gpointer       newval)
1065 {
1066   gpointer *ptr = atomic;
1067   gboolean success;
1068
1069   pthread_mutex_lock (&g_atomic_lock);
1070
1071   if ((success = (*ptr == oldval)))
1072     *ptr = newval;
1073
1074   pthread_mutex_unlock (&g_atomic_lock);
1075
1076   return success;
1077 }
1078
1079 gboolean
1080 (g_atomic_pointer_compare_and_exchange_full) (void     *atomic,
1081                                               gpointer  oldval,
1082                                               gpointer  newval,
1083                                               void     *preval)
1084 {
1085   gpointer *ptr = atomic;
1086   gpointer *pre = preval;
1087   gboolean success;
1088
1089   pthread_mutex_lock (&g_atomic_lock);
1090
1091   *pre = *ptr;
1092   if ((success = (*ptr == oldval)))
1093     *ptr = newval;
1094
1095   pthread_mutex_unlock (&g_atomic_lock);
1096
1097   return success;
1098 }
1099
1100 gpointer
1101 (g_atomic_pointer_exchange) (void    *atomic,
1102                              gpointer newval)
1103 {
1104   gpointer *ptr = atomic;
1105   gpointer oldval;
1106
1107   pthread_mutex_lock (&g_atomic_lock);
1108   oldval = *ptr;
1109   *ptr = newval;
1110   pthread_mutex_unlock (&g_atomic_lock);
1111
1112   return oldval;
1113 }
1114
1115 gssize
1116 (g_atomic_pointer_add) (volatile void *atomic,
1117                         gssize         val)
1118 {
1119   gssize *ptr = atomic;
1120   gssize oldval;
1121
1122   pthread_mutex_lock (&g_atomic_lock);
1123   oldval = *ptr;
1124   *ptr = oldval + val;
1125   pthread_mutex_unlock (&g_atomic_lock);
1126
1127   return oldval;
1128 }
1129
1130 gsize
1131 (g_atomic_pointer_and) (volatile void *atomic,
1132                         gsize          val)
1133 {
1134   gsize *ptr = atomic;
1135   gsize oldval;
1136
1137   pthread_mutex_lock (&g_atomic_lock);
1138   oldval = *ptr;
1139   *ptr = oldval & val;
1140   pthread_mutex_unlock (&g_atomic_lock);
1141
1142   return oldval;
1143 }
1144
1145 gsize
1146 (g_atomic_pointer_or) (volatile void *atomic,
1147                        gsize          val)
1148 {
1149   gsize *ptr = atomic;
1150   gsize oldval;
1151
1152   pthread_mutex_lock (&g_atomic_lock);
1153   oldval = *ptr;
1154   *ptr = oldval | val;
1155   pthread_mutex_unlock (&g_atomic_lock);
1156
1157   return oldval;
1158 }
1159
1160 gsize
1161 (g_atomic_pointer_xor) (volatile void *atomic,
1162                         gsize          val)
1163 {
1164   gsize *ptr = atomic;
1165   gsize oldval;
1166
1167   pthread_mutex_lock (&g_atomic_lock);
1168   oldval = *ptr;
1169   *ptr = oldval ^ val;
1170   pthread_mutex_unlock (&g_atomic_lock);
1171
1172   return oldval;
1173 }
1174
1175 #endif
1176
1177 /**
1178  * g_atomic_int_exchange_and_add:
1179  * @atomic: a pointer to a #gint
1180  * @val: the value to add
1181  *
1182  * This function existed before g_atomic_int_add() returned the prior
1183  * value of the integer (which it now does).  It is retained only for
1184  * compatibility reasons.  Don't use this function in new code.
1185  *
1186  * Returns: the value of @atomic before the add, signed
1187  * Since: 2.4
1188  * Deprecated: 2.30: Use g_atomic_int_add() instead.
1189  **/
1190 gint
1191 g_atomic_int_exchange_and_add (volatile gint *atomic,
1192                                gint           val)
1193 {
1194   return (g_atomic_int_add) ((gint *) atomic, val);
1195 }