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: (type gconstpointer): 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.
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 : 36 : (g_atomic_int_get) (const volatile gint *atomic)
76 : : {
77 : 36 : return g_atomic_int_get (atomic);
78 : : }
79 : :
80 : : /**
81 : : * g_atomic_int_set:
82 : : * @atomic: (type gpointer): 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.
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 : 24 : (g_atomic_int_set) (volatile gint *atomic,
97 : : gint newval)
98 : : {
99 : 24 : g_atomic_int_set (atomic, newval);
100 : 24 : }
101 : :
102 : : /**
103 : : * g_atomic_int_inc:
104 : : * @atomic: (type gpointer): 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 : 24 : (g_atomic_int_inc) (volatile gint *atomic)
119 : : {
120 : 24 : g_atomic_int_inc (atomic);
121 : 24 : }
122 : :
123 : : /**
124 : : * g_atomic_int_dec_and_test:
125 : : * @atomic: (type gpointer): 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 : 24 : (g_atomic_int_dec_and_test) (volatile gint *atomic)
143 : : {
144 : 24 : return g_atomic_int_dec_and_test (atomic);
145 : : }
146 : :
147 : : /**
148 : : * g_atomic_int_compare_and_exchange:
149 : : * @atomic: (type gpointer): 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 : 24 : (g_atomic_int_compare_and_exchange) (volatile gint *atomic,
172 : : gint oldval,
173 : : gint newval)
174 : : {
175 : 24 : return g_atomic_int_compare_and_exchange (atomic, oldval, newval);
176 : : }
177 : :
178 : : /**
179 : : * g_atomic_int_compare_and_exchange_full:
180 : : * @atomic: (type gpointer): 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 : 24 : (g_atomic_int_compare_and_exchange_full) (gint *atomic,
204 : : gint oldval,
205 : : gint newval,
206 : : gint *preval)
207 : : {
208 : 24 : return g_atomic_int_compare_and_exchange_full (atomic, oldval, newval, preval);
209 : : }
210 : :
211 : : /**
212 : : * g_atomic_int_exchange:
213 : : * @atomic: (type gpointer): 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 : 24 : (g_atomic_int_exchange) (gint *atomic,
231 : : gint newval)
232 : : {
233 : 24 : return g_atomic_int_exchange (atomic, newval);
234 : : }
235 : :
236 : : /**
237 : : * g_atomic_int_add:
238 : : * @atomic: (type gpointer): 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 : 1199933 : (g_atomic_int_add) (volatile gint *atomic,
260 : : gint val)
261 : : {
262 : 1199933 : return g_atomic_int_add (atomic, val);
263 : : }
264 : :
265 : : /**
266 : : * g_atomic_int_and:
267 : : * @atomic: (type gpointer): 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 : 24 : (g_atomic_int_and) (volatile guint *atomic,
287 : : guint val)
288 : : {
289 : 24 : return g_atomic_int_and (atomic, val);
290 : : }
291 : :
292 : : /**
293 : : * g_atomic_int_or:
294 : : * @atomic: (type gpointer): 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 : 24 : (g_atomic_int_or) (volatile guint *atomic,
314 : : guint val)
315 : : {
316 : 24 : return g_atomic_int_or (atomic, val);
317 : : }
318 : :
319 : : /**
320 : : * g_atomic_int_xor:
321 : : * @atomic: (type gpointer): 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 : 24 : (g_atomic_int_xor) (volatile guint *atomic,
341 : : guint val)
342 : : {
343 : 24 : 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.
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 : 48 : (g_atomic_pointer_get) (const volatile void *atomic)
365 : : {
366 : 48 : 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.
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 : 72 : (g_atomic_pointer_set) (volatile void *atomic,
386 : : gpointer newval)
387 : : {
388 : 72 : g_atomic_pointer_set ((gpointer *) atomic, newval);
389 : 72 : }
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 : 72 : (g_atomic_pointer_compare_and_exchange) (volatile void *atomic,
416 : : gpointer oldval,
417 : : gpointer newval)
418 : : {
419 : 108 : return g_atomic_pointer_compare_and_exchange ((gpointer *) atomic,
420 : 72 : 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 : 96 : (g_atomic_pointer_compare_and_exchange_full) (void *atomic,
449 : : gpointer oldval,
450 : : gpointer newval,
451 : : void *preval)
452 : : {
453 : 144 : return g_atomic_pointer_compare_and_exchange_full ((gpointer *) atomic,
454 : 96 : oldval, newval,
455 : 96 : (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 : 48 : (g_atomic_pointer_exchange) (void *atomic,
478 : : gpointer newval)
479 : : {
480 : 48 : 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 : 12 : (g_atomic_pointer_add) (volatile void *atomic,
508 : : gssize val)
509 : : {
510 : 12 : 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 : 12 : (g_atomic_pointer_and) (volatile void *atomic,
539 : : gsize val)
540 : : {
541 : 12 : 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 : 12 : (g_atomic_pointer_or) (volatile void *atomic,
570 : : gsize val)
571 : : {
572 : 12 : 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 : 12 : (g_atomic_pointer_xor) (volatile void *atomic,
601 : : gsize val)
602 : : {
603 : 12 : return g_atomic_pointer_xor ((gpointer *) atomic, val);
604 : : }
605 : :
606 : : #elif defined (G_PLATFORM_WIN32)
607 : :
608 : : #include <windows.h>
609 : :
610 : : #if defined (_M_IX86) && defined (_MSC_VER) && _MSC_VER <= 1800 /* VS2013 */
611 : : /* Older Windows SDKs did not provide definitions of InterlockedAnd,
612 : : * InterlockedOr, and InterlockedXor on x86. This is also stated on
613 : : * MSDN: "for the x86 architecture, use the compiler intrinsic directly".
614 : : *
615 : : * https://bugzilla.gnome.org/show_bug.cgi?id=652000
616 : : */
617 : : #include <intrin.h>
618 : : #endif
619 : :
620 : : #if defined (_MSC_VER) && \
621 : : ((!defined (_M_IX86) && !defined (_M_AMD64)) || _MSC_VER >= 1920) /* VS2019 */
622 : : /* VS2017 and earlier do not provide __iso_volatile intrinsics
623 : : * on Intel targets.
624 : : */
625 : : # define HAVE_ISO_VOLATILE_INTRINSICS
626 : : #endif
627 : :
628 : : /*
629 : : * http://msdn.microsoft.com/en-us/library/ms684122(v=vs.85).aspx
630 : : */
631 : :
632 : : #if defined(HAVE_ISO_VOLATILE_INTRINSICS)
633 : :
634 : : G_STATIC_ASSERT (sizeof (int) == sizeof (__int32));
635 : :
636 : : gint
637 : : (g_atomic_int_get) (const volatile gint *atomic)
638 : : {
639 : : int result = __iso_volatile_load32 (atomic);
640 : : _ReadWriteBarrier ();
641 : : MemoryBarrier ();
642 : :
643 : : return result;
644 : : }
645 : :
646 : : #else /* ! defined(HAVE_ISO_VOLATILE_INTRINSICS) */
647 : :
648 : : gint
649 : : (g_atomic_int_get) (const volatile gint *atomic)
650 : : {
651 : : int result = *atomic;
652 : : _ReadWriteBarrier ();
653 : : MemoryBarrier ();
654 : :
655 : : return result;
656 : : }
657 : :
658 : : #endif /* ! defined(HAVE_ISO_VOLATILE_INTRINSICS) */
659 : :
660 : : void
661 : : (g_atomic_int_set) (volatile gint *atomic,
662 : : gint newval)
663 : : {
664 : : (void) InterlockedExchange (atomic, newval);
665 : : }
666 : :
667 : : void
668 : : (g_atomic_int_inc) (volatile gint *atomic)
669 : : {
670 : : InterlockedIncrement (atomic);
671 : : }
672 : :
673 : : gboolean
674 : : (g_atomic_int_dec_and_test) (volatile gint *atomic)
675 : : {
676 : : return InterlockedDecrement (atomic) == 0;
677 : : }
678 : :
679 : : gboolean
680 : : (g_atomic_int_compare_and_exchange) (volatile gint *atomic,
681 : : gint oldval,
682 : : gint newval)
683 : : {
684 : : return InterlockedCompareExchange (atomic, newval, oldval) == oldval;
685 : : }
686 : :
687 : : gboolean
688 : : (g_atomic_int_compare_and_exchange_full) (gint *atomic,
689 : : gint oldval,
690 : : gint newval,
691 : : gint *preval)
692 : : {
693 : : *preval = InterlockedCompareExchange (atomic, newval, oldval);
694 : : return *preval == oldval;
695 : : }
696 : :
697 : : gint
698 : : (g_atomic_int_exchange) (gint *atomic,
699 : : gint newval)
700 : : {
701 : : return InterlockedExchange (atomic, newval);
702 : : }
703 : :
704 : : gint
705 : : (g_atomic_int_add) (volatile gint *atomic,
706 : : gint val)
707 : : {
708 : : return InterlockedExchangeAdd (atomic, val);
709 : : }
710 : :
711 : : guint
712 : : (g_atomic_int_and) (volatile guint *atomic,
713 : : guint val)
714 : : {
715 : : #if defined (_M_IX86) && defined (_MSC_VER) && _MSC_VER <= 1800 /* VS2013 */
716 : : return _InterlockedAnd (atomic, val);
717 : : #else
718 : : return InterlockedAnd (atomic, val);
719 : : #endif
720 : : }
721 : :
722 : : guint
723 : : (g_atomic_int_or) (volatile guint *atomic,
724 : : guint val)
725 : : {
726 : : #if defined (_M_IX86) && defined (_MSC_VER) && _MSC_VER <= 1800 /* VS2013 */
727 : : return _InterlockedOr (atomic, val);
728 : : #else
729 : : return InterlockedOr (atomic, val);
730 : : #endif
731 : : }
732 : :
733 : : guint
734 : : (g_atomic_int_xor) (volatile guint *atomic,
735 : : guint val)
736 : : {
737 : : #if defined (_M_IX86) && defined (_MSC_VER) && _MSC_VER <= 1800 /* VS2013 */
738 : : return _InterlockedXor (atomic, val);
739 : : #else
740 : : return InterlockedXor (atomic, val);
741 : : #endif
742 : : }
743 : :
744 : : #if defined(HAVE_ISO_VOLATILE_INTRINSICS)
745 : :
746 : : gpointer
747 : : (g_atomic_pointer_get) (const volatile void *atomic)
748 : : {
749 : : #if GLIB_SIZEOF_VOID_P == 8
750 : : const __int64 volatile *p = (const __int64 volatile *) atomic;
751 : : #else
752 : : const __int32 volatile *p = (const __int32 volatile *) atomic;
753 : : #endif
754 : :
755 : : #if GLIB_SIZEOF_VOID_P == 8
756 : : gpointer result = (gpointer) __iso_volatile_load64 (p);
757 : : #else
758 : : gpointer result = (gpointer) __iso_volatile_load32 (p);
759 : : #endif
760 : : _ReadWriteBarrier ();
761 : : MemoryBarrier ();
762 : :
763 : : return result;
764 : : }
765 : :
766 : : #else /* ! defined(HAVE_ISO_VOLATILE_INTRINSICS) */
767 : :
768 : : gpointer
769 : : (g_atomic_pointer_get) (const volatile void *atomic)
770 : : {
771 : : const void * volatile *p = (const void * volatile *) atomic;
772 : :
773 : : gpointer result = *p;
774 : : _ReadWriteBarrier ();
775 : : MemoryBarrier ();
776 : :
777 : : return result;
778 : : }
779 : :
780 : : #endif /* ! defined(HAVE_ISO_VOLATILE_INTRINSICS) */
781 : :
782 : : void
783 : : (g_atomic_pointer_set) (volatile void *atomic,
784 : : gpointer newval)
785 : : {
786 : : void * volatile *p = (void * volatile *) atomic;
787 : : (void) InterlockedExchangePointer (p, newval);
788 : : }
789 : :
790 : : gboolean
791 : : (g_atomic_pointer_compare_and_exchange) (volatile void *atomic,
792 : : gpointer oldval,
793 : : gpointer newval)
794 : : {
795 : : return InterlockedCompareExchangePointer (atomic, newval, oldval) == oldval;
796 : : }
797 : :
798 : : gboolean
799 : : (g_atomic_pointer_compare_and_exchange_full) (void *atomic,
800 : : gpointer oldval,
801 : : gpointer newval,
802 : : void *preval)
803 : : {
804 : : gpointer *pre = preval;
805 : :
806 : : *pre = InterlockedCompareExchangePointer (atomic, newval, oldval);
807 : :
808 : : return *pre == oldval;
809 : : }
810 : :
811 : : gpointer
812 : : (g_atomic_pointer_exchange) (void *atomic,
813 : : gpointer newval)
814 : : {
815 : : return InterlockedExchangePointer (atomic, newval);
816 : : }
817 : :
818 : : gintptr
819 : : (g_atomic_pointer_add) (volatile void *atomic,
820 : : gssize val)
821 : : {
822 : : #if GLIB_SIZEOF_VOID_P == 8
823 : : return InterlockedExchangeAdd64 (atomic, val);
824 : : #else
825 : : return InterlockedExchangeAdd (atomic, val);
826 : : #endif
827 : : }
828 : :
829 : : guintptr
830 : : (g_atomic_pointer_and) (volatile void *atomic,
831 : : gsize val)
832 : : {
833 : : #if GLIB_SIZEOF_VOID_P == 8
834 : : return InterlockedAnd64 (atomic, val);
835 : : #elif defined (_M_IX86) && defined (_MSC_VER) && _MSC_VER <= 1800 /* VS2013 */
836 : : return _InterlockedAnd (atomic, val);
837 : : #else
838 : : return InterlockedAnd (atomic, val);
839 : : #endif
840 : : }
841 : :
842 : : guintptr
843 : : (g_atomic_pointer_or) (volatile void *atomic,
844 : : gsize val)
845 : : {
846 : : #if GLIB_SIZEOF_VOID_P == 8
847 : : return InterlockedOr64 (atomic, val);
848 : : #elif defined (_M_IX86) && defined (_MSC_VER) && _MSC_VER <= 1800 /* VS2013 */
849 : : return _InterlockedOr (atomic, val);
850 : : #else
851 : : return InterlockedOr (atomic, val);
852 : : #endif
853 : : }
854 : :
855 : : guintptr
856 : : (g_atomic_pointer_xor) (volatile void *atomic,
857 : : gsize val)
858 : : {
859 : : #if GLIB_SIZEOF_VOID_P == 8
860 : : return InterlockedXor64 (atomic, val);
861 : : #elif defined (_M_IX86) && defined (_MSC_VER) && _MSC_VER <= 1800 /* VS2013 */
862 : : return _InterlockedXor (atomic, val);
863 : : #else
864 : : return InterlockedXor (atomic, val);
865 : : #endif
866 : : }
867 : : #else
868 : :
869 : : /* This error occurs when `meson configure` decided that we should be capable
870 : : * of lock-free atomics but we find at compile-time that we are not.
871 : : */
872 : : #error G_ATOMIC_LOCK_FREE defined, but incapable of lock-free atomics.
873 : :
874 : : #endif /* defined (__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) */
875 : :
876 : : #else /* G_ATOMIC_LOCK_FREE */
877 : :
878 : : /* We are not permitted to call into any GLib functions from here, so we
879 : : * can not use GMutex.
880 : : *
881 : : * Fortunately, we already take care of the Windows case above, and all
882 : : * non-Windows platforms on which glib runs have pthreads. Use those.
883 : : */
884 : : #include <pthread.h>
885 : :
886 : : static pthread_mutex_t g_atomic_lock = PTHREAD_MUTEX_INITIALIZER;
887 : :
888 : : gint
889 : : (g_atomic_int_get) (const volatile gint *atomic)
890 : : {
891 : : gint value;
892 : :
893 : : pthread_mutex_lock (&g_atomic_lock);
894 : : value = *atomic;
895 : : pthread_mutex_unlock (&g_atomic_lock);
896 : :
897 : : return value;
898 : : }
899 : :
900 : : void
901 : : (g_atomic_int_set) (volatile gint *atomic,
902 : : gint value)
903 : : {
904 : : pthread_mutex_lock (&g_atomic_lock);
905 : : *atomic = value;
906 : : pthread_mutex_unlock (&g_atomic_lock);
907 : : }
908 : :
909 : : void
910 : : (g_atomic_int_inc) (volatile gint *atomic)
911 : : {
912 : : pthread_mutex_lock (&g_atomic_lock);
913 : : (*atomic)++;
914 : : pthread_mutex_unlock (&g_atomic_lock);
915 : : }
916 : :
917 : : gboolean
918 : : (g_atomic_int_dec_and_test) (volatile gint *atomic)
919 : : {
920 : : gboolean is_zero;
921 : :
922 : : pthread_mutex_lock (&g_atomic_lock);
923 : : is_zero = --(*atomic) == 0;
924 : : pthread_mutex_unlock (&g_atomic_lock);
925 : :
926 : : return is_zero;
927 : : }
928 : :
929 : : gboolean
930 : : (g_atomic_int_compare_and_exchange) (volatile gint *atomic,
931 : : gint oldval,
932 : : gint newval)
933 : : {
934 : : gboolean success;
935 : :
936 : : pthread_mutex_lock (&g_atomic_lock);
937 : :
938 : : if ((success = (*atomic == oldval)))
939 : : *atomic = newval;
940 : :
941 : : pthread_mutex_unlock (&g_atomic_lock);
942 : :
943 : : return success;
944 : : }
945 : :
946 : : gboolean
947 : : (g_atomic_int_compare_and_exchange_full) (gint *atomic,
948 : : gint oldval,
949 : : gint newval,
950 : : gint *preval)
951 : : {
952 : : gboolean success;
953 : :
954 : : pthread_mutex_lock (&g_atomic_lock);
955 : :
956 : : *preval = *atomic;
957 : :
958 : : if ((success = (*atomic == oldval)))
959 : : *atomic = newval;
960 : :
961 : : pthread_mutex_unlock (&g_atomic_lock);
962 : :
963 : : return success;
964 : : }
965 : :
966 : : gint
967 : : (g_atomic_int_exchange) (gint *atomic,
968 : : gint newval)
969 : : {
970 : : gint *ptr = atomic;
971 : : gint oldval;
972 : :
973 : : pthread_mutex_lock (&g_atomic_lock);
974 : : oldval = *ptr;
975 : : *ptr = newval;
976 : : pthread_mutex_unlock (&g_atomic_lock);
977 : :
978 : : return oldval;
979 : : }
980 : :
981 : : gint
982 : : (g_atomic_int_add) (volatile gint *atomic,
983 : : gint val)
984 : : {
985 : : gint 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_and) (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 : : guint
1010 : : (g_atomic_int_or) (volatile guint *atomic,
1011 : : guint val)
1012 : : {
1013 : : guint oldval;
1014 : :
1015 : : pthread_mutex_lock (&g_atomic_lock);
1016 : : oldval = *atomic;
1017 : : *atomic = oldval | val;
1018 : : pthread_mutex_unlock (&g_atomic_lock);
1019 : :
1020 : : return oldval;
1021 : : }
1022 : :
1023 : : guint
1024 : : (g_atomic_int_xor) (volatile guint *atomic,
1025 : : guint val)
1026 : : {
1027 : : guint oldval;
1028 : :
1029 : : pthread_mutex_lock (&g_atomic_lock);
1030 : : oldval = *atomic;
1031 : : *atomic = oldval ^ val;
1032 : : pthread_mutex_unlock (&g_atomic_lock);
1033 : :
1034 : : return oldval;
1035 : : }
1036 : :
1037 : :
1038 : : gpointer
1039 : : (g_atomic_pointer_get) (const volatile void *atomic)
1040 : : {
1041 : : const gpointer *ptr = atomic;
1042 : : gpointer value;
1043 : :
1044 : : pthread_mutex_lock (&g_atomic_lock);
1045 : : value = *ptr;
1046 : : pthread_mutex_unlock (&g_atomic_lock);
1047 : :
1048 : : return value;
1049 : : }
1050 : :
1051 : : void
1052 : : (g_atomic_pointer_set) (volatile void *atomic,
1053 : : gpointer newval)
1054 : : {
1055 : : gpointer *ptr = atomic;
1056 : :
1057 : : pthread_mutex_lock (&g_atomic_lock);
1058 : : *ptr = newval;
1059 : : pthread_mutex_unlock (&g_atomic_lock);
1060 : : }
1061 : :
1062 : : gboolean
1063 : : (g_atomic_pointer_compare_and_exchange) (volatile void *atomic,
1064 : : gpointer oldval,
1065 : : gpointer newval)
1066 : : {
1067 : : gpointer *ptr = atomic;
1068 : : gboolean success;
1069 : :
1070 : : pthread_mutex_lock (&g_atomic_lock);
1071 : :
1072 : : if ((success = (*ptr == oldval)))
1073 : : *ptr = newval;
1074 : :
1075 : : pthread_mutex_unlock (&g_atomic_lock);
1076 : :
1077 : : return success;
1078 : : }
1079 : :
1080 : : gboolean
1081 : : (g_atomic_pointer_compare_and_exchange_full) (void *atomic,
1082 : : gpointer oldval,
1083 : : gpointer newval,
1084 : : void *preval)
1085 : : {
1086 : : gpointer *ptr = atomic;
1087 : : gpointer *pre = preval;
1088 : : gboolean success;
1089 : :
1090 : : pthread_mutex_lock (&g_atomic_lock);
1091 : :
1092 : : *pre = *ptr;
1093 : : if ((success = (*ptr == oldval)))
1094 : : *ptr = newval;
1095 : :
1096 : : pthread_mutex_unlock (&g_atomic_lock);
1097 : :
1098 : : return success;
1099 : : }
1100 : :
1101 : : gpointer
1102 : : (g_atomic_pointer_exchange) (void *atomic,
1103 : : gpointer newval)
1104 : : {
1105 : : gpointer *ptr = atomic;
1106 : : gpointer oldval;
1107 : :
1108 : : pthread_mutex_lock (&g_atomic_lock);
1109 : : oldval = *ptr;
1110 : : *ptr = newval;
1111 : : pthread_mutex_unlock (&g_atomic_lock);
1112 : :
1113 : : return oldval;
1114 : : }
1115 : :
1116 : : gintptr
1117 : : (g_atomic_pointer_add) (volatile void *atomic,
1118 : : gssize val)
1119 : : {
1120 : : gintptr *ptr = atomic;
1121 : : gintptr oldval;
1122 : :
1123 : : pthread_mutex_lock (&g_atomic_lock);
1124 : : oldval = *ptr;
1125 : : *ptr = oldval + val;
1126 : : pthread_mutex_unlock (&g_atomic_lock);
1127 : :
1128 : : return oldval;
1129 : : }
1130 : :
1131 : : guintptr
1132 : : (g_atomic_pointer_and) (volatile void *atomic,
1133 : : gsize val)
1134 : : {
1135 : : guintptr *ptr = atomic;
1136 : : guintptr oldval;
1137 : :
1138 : : pthread_mutex_lock (&g_atomic_lock);
1139 : : oldval = *ptr;
1140 : : *ptr = oldval & val;
1141 : : pthread_mutex_unlock (&g_atomic_lock);
1142 : :
1143 : : return oldval;
1144 : : }
1145 : :
1146 : : guintptr
1147 : : (g_atomic_pointer_or) (volatile void *atomic,
1148 : : gsize val)
1149 : : {
1150 : : guintptr *ptr = atomic;
1151 : : guintptr oldval;
1152 : :
1153 : : pthread_mutex_lock (&g_atomic_lock);
1154 : : oldval = *ptr;
1155 : : *ptr = oldval | val;
1156 : : pthread_mutex_unlock (&g_atomic_lock);
1157 : :
1158 : : return oldval;
1159 : : }
1160 : :
1161 : : guintptr
1162 : : (g_atomic_pointer_xor) (volatile void *atomic,
1163 : : gsize val)
1164 : : {
1165 : : guintptr *ptr = atomic;
1166 : : guintptr oldval;
1167 : :
1168 : : pthread_mutex_lock (&g_atomic_lock);
1169 : : oldval = *ptr;
1170 : : *ptr = oldval ^ val;
1171 : : pthread_mutex_unlock (&g_atomic_lock);
1172 : :
1173 : : return oldval;
1174 : : }
1175 : :
1176 : : #endif
1177 : :
1178 : : /**
1179 : : * g_atomic_int_exchange_and_add:
1180 : : * @atomic: (type gpointer): a pointer to a #gint
1181 : : * @val: the value to add
1182 : : *
1183 : : * This function existed before g_atomic_int_add() returned the prior
1184 : : * value of the integer (which it now does). It is retained only for
1185 : : * compatibility reasons. Don't use this function in new code.
1186 : : *
1187 : : * Returns: the value of @atomic before the add, signed
1188 : : * Since: 2.4
1189 : : * Deprecated: 2.30: Use g_atomic_int_add() instead.
1190 : : **/
1191 : : gint
1192 : 12 : g_atomic_int_exchange_and_add (volatile gint *atomic,
1193 : : gint val)
1194 : : {
1195 : 12 : return (g_atomic_int_add) ((gint *) atomic, val);
1196 : : }
|