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