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