gatomic: Use g(u)intptr where appropriate

This is required for CHERI systems such as Arm Morello, where gsize is
not large enough to hold a pointer. For all other architectures this
should not result in any functional changes since gsize is already the
same size (and I believe for most architectures even the same type)
as guintptr.

This is fully ABI compatible with all currently supported architectures
and should also be fully API compatible except for some rather unlikely
examples such as someone happening to use something like
`decltype(g_atomic_pointer_add(&a, 0))` in a C++ context where it
changes name mangling of some function.

Helps: https://gitlab.gnome.org/GNOME/glib/-/issues/2842
This commit is contained in:
Alex Richardson 2022-12-14 23:55:17 +00:00
parent 877c575cd9
commit c762d51134
3 changed files with 109 additions and 93 deletions

View File

@ -34,7 +34,7 @@
* *
* The macros that have 'int' in the name will operate on pointers to * The macros that have 'int' in the name will operate on pointers to
* #gint and #guint. The macros with 'pointer' in the name will operate * #gint and #guint. The macros with 'pointer' in the name will operate
* on pointers to any pointer-sized value, including #gsize. There is * on pointers to any pointer-sized value, including #guintptr. There is
* no support for 64bit operations on platforms with 32bit pointers * no support for 64bit operations on platforms with 32bit pointers
* because it is not generally possible to perform these operations * because it is not generally possible to perform these operations
* atomically. * atomically.
@ -538,11 +538,15 @@ gpointer
* While @atomic has a `volatile` qualifier, this is a historical artifact and * While @atomic has a `volatile` qualifier, this is a historical artifact and
* the pointer passed to it should not be `volatile`. * the pointer passed to it should not be `volatile`.
* *
* In GLib 2.80, the return type was changed from #gssize to #gintptr to add
* support for platforms with 128-bit pointers. This should not affect existing
* code.
*
* Returns: the value of @atomic before the add, signed * Returns: the value of @atomic before the add, signed
* *
* Since: 2.30 * Since: 2.30
**/ **/
gssize gintptr
(g_atomic_pointer_add) (volatile void *atomic, (g_atomic_pointer_add) (volatile void *atomic,
gssize val) gssize val)
{ {
@ -565,11 +569,15 @@ gssize
* While @atomic has a `volatile` qualifier, this is a historical artifact and * While @atomic has a `volatile` qualifier, this is a historical artifact and
* the pointer passed to it should not be `volatile`. * the pointer passed to it should not be `volatile`.
* *
* In GLib 2.80, the return type was changed from #gsize to #guintptr to add
* support for platforms with 128-bit pointers. This should not affect existing
* code.
*
* Returns: the value of @atomic before the operation, unsigned * Returns: the value of @atomic before the operation, unsigned
* *
* Since: 2.30 * Since: 2.30
**/ **/
gsize guintptr
(g_atomic_pointer_and) (volatile void *atomic, (g_atomic_pointer_and) (volatile void *atomic,
gsize val) gsize val)
{ {
@ -592,11 +600,15 @@ gsize
* While @atomic has a `volatile` qualifier, this is a historical artifact and * While @atomic has a `volatile` qualifier, this is a historical artifact and
* the pointer passed to it should not be `volatile`. * the pointer passed to it should not be `volatile`.
* *
* In GLib 2.80, the return type was changed from #gsize to #guintptr to add
* support for platforms with 128-bit pointers. This should not affect existing
* code.
*
* Returns: the value of @atomic before the operation, unsigned * Returns: the value of @atomic before the operation, unsigned
* *
* Since: 2.30 * Since: 2.30
**/ **/
gsize guintptr
(g_atomic_pointer_or) (volatile void *atomic, (g_atomic_pointer_or) (volatile void *atomic,
gsize val) gsize val)
{ {
@ -619,11 +631,15 @@ gsize
* While @atomic has a `volatile` qualifier, this is a historical artifact and * While @atomic has a `volatile` qualifier, this is a historical artifact and
* the pointer passed to it should not be `volatile`. * the pointer passed to it should not be `volatile`.
* *
* In GLib 2.80, the return type was changed from #gsize to #guintptr to add
* support for platforms with 128-bit pointers. This should not affect existing
* code.
*
* Returns: the value of @atomic before the operation, unsigned * Returns: the value of @atomic before the operation, unsigned
* *
* Since: 2.30 * Since: 2.30
**/ **/
gsize guintptr
(g_atomic_pointer_xor) (volatile void *atomic, (g_atomic_pointer_xor) (volatile void *atomic,
gsize val) gsize val)
{ {
@ -820,7 +836,7 @@ gpointer
return InterlockedExchangePointer (atomic, newval); return InterlockedExchangePointer (atomic, newval);
} }
gssize gintptr
(g_atomic_pointer_add) (volatile void *atomic, (g_atomic_pointer_add) (volatile void *atomic,
gssize val) gssize val)
{ {
@ -831,7 +847,7 @@ gssize
#endif #endif
} }
gsize guintptr
(g_atomic_pointer_and) (volatile void *atomic, (g_atomic_pointer_and) (volatile void *atomic,
gsize val) gsize val)
{ {
@ -842,7 +858,7 @@ gsize
#endif #endif
} }
gsize guintptr
(g_atomic_pointer_or) (volatile void *atomic, (g_atomic_pointer_or) (volatile void *atomic,
gsize val) gsize val)
{ {
@ -853,7 +869,7 @@ gsize
#endif #endif
} }
gsize guintptr
(g_atomic_pointer_xor) (volatile void *atomic, (g_atomic_pointer_xor) (volatile void *atomic,
gsize val) gsize val)
{ {
@ -1112,12 +1128,12 @@ gpointer
return oldval; return oldval;
} }
gssize gintptr
(g_atomic_pointer_add) (volatile void *atomic, (g_atomic_pointer_add) (volatile void *atomic,
gssize val) gssize val)
{ {
gssize *ptr = atomic; gintptr *ptr = atomic;
gssize oldval; gintptr oldval;
pthread_mutex_lock (&g_atomic_lock); pthread_mutex_lock (&g_atomic_lock);
oldval = *ptr; oldval = *ptr;
@ -1127,12 +1143,12 @@ gssize
return oldval; return oldval;
} }
gsize guintptr
(g_atomic_pointer_and) (volatile void *atomic, (g_atomic_pointer_and) (volatile void *atomic,
gsize val) gsize val)
{ {
gsize *ptr = atomic; guintptr *ptr = atomic;
gsize oldval; guintptr oldval;
pthread_mutex_lock (&g_atomic_lock); pthread_mutex_lock (&g_atomic_lock);
oldval = *ptr; oldval = *ptr;
@ -1142,12 +1158,12 @@ gsize
return oldval; return oldval;
} }
gsize guintptr
(g_atomic_pointer_or) (volatile void *atomic, (g_atomic_pointer_or) (volatile void *atomic,
gsize val) gsize val)
{ {
gsize *ptr = atomic; guintptr *ptr = atomic;
gsize oldval; guintptr oldval;
pthread_mutex_lock (&g_atomic_lock); pthread_mutex_lock (&g_atomic_lock);
oldval = *ptr; oldval = *ptr;
@ -1157,12 +1173,12 @@ gsize
return oldval; return oldval;
} }
gsize guintptr
(g_atomic_pointer_xor) (volatile void *atomic, (g_atomic_pointer_xor) (volatile void *atomic,
gsize val) gsize val)
{ {
gsize *ptr = atomic; guintptr *ptr = atomic;
gsize oldval; guintptr oldval;
pthread_mutex_lock (&g_atomic_lock); pthread_mutex_lock (&g_atomic_lock);
oldval = *ptr; oldval = *ptr;

View File

@ -83,16 +83,16 @@ GLIB_AVAILABLE_IN_2_74
gpointer g_atomic_pointer_exchange (void *atomic, gpointer g_atomic_pointer_exchange (void *atomic,
gpointer newval); gpointer newval);
GLIB_AVAILABLE_IN_ALL GLIB_AVAILABLE_IN_ALL
gssize g_atomic_pointer_add (volatile void *atomic, gintptr g_atomic_pointer_add (volatile void *atomic,
gssize val); gssize val);
GLIB_AVAILABLE_IN_2_30 GLIB_AVAILABLE_IN_2_30
gsize g_atomic_pointer_and (volatile void *atomic, guintptr g_atomic_pointer_and (volatile void *atomic,
gsize val); gsize val);
GLIB_AVAILABLE_IN_2_30 GLIB_AVAILABLE_IN_2_30
gsize g_atomic_pointer_or (volatile void *atomic, guintptr g_atomic_pointer_or (volatile void *atomic,
gsize val); gsize val);
GLIB_AVAILABLE_IN_ALL GLIB_AVAILABLE_IN_ALL
gsize g_atomic_pointer_xor (volatile void *atomic, guintptr g_atomic_pointer_xor (volatile void *atomic,
gsize val); gsize val);
GLIB_DEPRECATED_IN_2_30_FOR(g_atomic_int_add) GLIB_DEPRECATED_IN_2_30_FOR(g_atomic_int_add)
@ -280,34 +280,34 @@ G_END_DECLS
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \ G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
(void) (0 ? (gpointer) *(atomic) : NULL); \ (void) (0 ? (gpointer) *(atomic) : NULL); \
(void) (0 ? (val) ^ (val) : 1); \ (void) (0 ? (val) ^ (val) : 1); \
(gssize) __atomic_fetch_add ((atomic), (val), __ATOMIC_SEQ_CST); \ (gintptr) __atomic_fetch_add ((atomic), (val), __ATOMIC_SEQ_CST); \
})) }))
#define g_atomic_pointer_and(atomic, val) \ #define g_atomic_pointer_and(atomic, val) \
(G_GNUC_EXTENSION ({ \ (G_GNUC_EXTENSION ({ \
gsize *gapa_atomic = (gsize *) (atomic); \ guintptr *gapa_atomic = (guintptr *) (atomic); \
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \ G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gsize)); \ G_STATIC_ASSERT (sizeof *(atomic) == sizeof (guintptr)); \
(void) (0 ? (gpointer) *(atomic) : NULL); \ (void) (0 ? (gpointer) *(atomic) : NULL); \
(void) (0 ? (val) ^ (val) : 1); \ (void) (0 ? (val) ^ (val) : 1); \
(gsize) __atomic_fetch_and (gapa_atomic, (val), __ATOMIC_SEQ_CST); \ (guintptr) __atomic_fetch_and (gapa_atomic, (val), __ATOMIC_SEQ_CST); \
})) }))
#define g_atomic_pointer_or(atomic, val) \ #define g_atomic_pointer_or(atomic, val) \
(G_GNUC_EXTENSION ({ \ (G_GNUC_EXTENSION ({ \
gsize *gapo_atomic = (gsize *) (atomic); \ guintptr *gapo_atomic = (guintptr *) (atomic); \
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \ G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gsize)); \ G_STATIC_ASSERT (sizeof *(atomic) == sizeof (guintptr)); \
(void) (0 ? (gpointer) *(atomic) : NULL); \ (void) (0 ? (gpointer) *(atomic) : NULL); \
(void) (0 ? (val) ^ (val) : 1); \ (void) (0 ? (val) ^ (val) : 1); \
(gsize) __atomic_fetch_or (gapo_atomic, (val), __ATOMIC_SEQ_CST); \ (guintptr) __atomic_fetch_or (gapo_atomic, (val), __ATOMIC_SEQ_CST); \
})) }))
#define g_atomic_pointer_xor(atomic, val) \ #define g_atomic_pointer_xor(atomic, val) \
(G_GNUC_EXTENSION ({ \ (G_GNUC_EXTENSION ({ \
gsize *gapx_atomic = (gsize *) (atomic); \ guintptr *gapx_atomic = (guintptr *) (atomic); \
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \ G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gsize)); \ G_STATIC_ASSERT (sizeof *(atomic) == sizeof (guintptr)); \
(void) (0 ? (gpointer) *(atomic) : NULL); \ (void) (0 ? (gpointer) *(atomic) : NULL); \
(void) (0 ? (val) ^ (val) : 1); \ (void) (0 ? (val) ^ (val) : 1); \
(gsize) __atomic_fetch_xor (gapx_atomic, (val), __ATOMIC_SEQ_CST); \ (guintptr) __atomic_fetch_xor (gapx_atomic, (val), __ATOMIC_SEQ_CST); \
})) }))
#else /* defined(__ATOMIC_SEQ_CST) */ #else /* defined(__ATOMIC_SEQ_CST) */
@ -374,7 +374,7 @@ G_END_DECLS
(void) (0 ? (gpointer) *(atomic) : NULL); \ (void) (0 ? (gpointer) *(atomic) : NULL); \
__sync_synchronize (); \ __sync_synchronize (); \
__asm__ __volatile__ ("" : : : "memory"); \ __asm__ __volatile__ ("" : : : "memory"); \
*(atomic) = (glib_typeof (*(atomic))) (gsize) (newval); \ *(atomic) = (glib_typeof (*(atomic))) (guintptr) (newval); \
})) }))
#else /* if !(defined(glib_typeof) */ #else /* if !(defined(glib_typeof) */
#define g_atomic_pointer_set(atomic, newval) \ #define g_atomic_pointer_set(atomic, newval) \
@ -383,7 +383,7 @@ G_END_DECLS
(void) (0 ? (gpointer) *(atomic) : NULL); \ (void) (0 ? (gpointer) *(atomic) : NULL); \
__sync_synchronize (); \ __sync_synchronize (); \
__asm__ __volatile__ ("" : : : "memory"); \ __asm__ __volatile__ ("" : : : "memory"); \
*(atomic) = (gpointer) (gsize) (newval); \ *(atomic) = (gpointer) (guintptr) (newval); \
})) }))
#endif /* if defined(glib_typeof) */ #endif /* if defined(glib_typeof) */
@ -498,28 +498,28 @@ G_END_DECLS
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \ G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
(void) (0 ? (gpointer) *(atomic) : NULL); \ (void) (0 ? (gpointer) *(atomic) : NULL); \
(void) (0 ? (val) ^ (val) : 1); \ (void) (0 ? (val) ^ (val) : 1); \
(gssize) __sync_fetch_and_add ((atomic), (val)); \ (gintptr) __sync_fetch_and_add ((atomic), (val)); \
})) }))
#define g_atomic_pointer_and(atomic, val) \ #define g_atomic_pointer_and(atomic, val) \
(G_GNUC_EXTENSION ({ \ (G_GNUC_EXTENSION ({ \
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \ G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
(void) (0 ? (gpointer) *(atomic) : NULL); \ (void) (0 ? (gpointer) *(atomic) : NULL); \
(void) (0 ? (val) ^ (val) : 1); \ (void) (0 ? (val) ^ (val) : 1); \
(gsize) __sync_fetch_and_and ((atomic), (val)); \ (guintptr) __sync_fetch_and_and ((atomic), (val)); \
})) }))
#define g_atomic_pointer_or(atomic, val) \ #define g_atomic_pointer_or(atomic, val) \
(G_GNUC_EXTENSION ({ \ (G_GNUC_EXTENSION ({ \
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \ G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
(void) (0 ? (gpointer) *(atomic) : NULL); \ (void) (0 ? (gpointer) *(atomic) : NULL); \
(void) (0 ? (val) ^ (val) : 1); \ (void) (0 ? (val) ^ (val) : 1); \
(gsize) __sync_fetch_and_or ((atomic), (val)); \ (guintptr) __sync_fetch_and_or ((atomic), (val)); \
})) }))
#define g_atomic_pointer_xor(atomic, val) \ #define g_atomic_pointer_xor(atomic, val) \
(G_GNUC_EXTENSION ({ \ (G_GNUC_EXTENSION ({ \
G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \ G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
(void) (0 ? (gpointer) *(atomic) : NULL); \ (void) (0 ? (gpointer) *(atomic) : NULL); \
(void) (0 ? (val) ^ (val) : 1); \ (void) (0 ? (val) ^ (val) : 1); \
(gsize) __sync_fetch_and_xor ((atomic), (val)); \ (guintptr) __sync_fetch_and_xor ((atomic), (val)); \
})) }))
#endif /* !defined(__ATOMIC_SEQ_CST) */ #endif /* !defined(__ATOMIC_SEQ_CST) */

View File

@ -31,7 +31,7 @@ test_types (void)
const char *str = "Hello"; const char *str = "Hello";
const char *old_str; const char *old_str;
int *ip, *ip2; int *ip, *ip2;
gsize gs, gs2; guintptr gu, gu2;
gboolean res; gboolean res;
csp = &s; csp = &s;
@ -158,36 +158,36 @@ test_types (void)
res = g_atomic_pointer_compare_and_exchange_full (&ip, NULL, &s, &ip2); res = g_atomic_pointer_compare_and_exchange_full (&ip, NULL, &s, &ip2);
g_assert_true (res); g_assert_true (res);
g_assert_true (ip == &s); g_assert_true (ip == &s);
g_assert_cmpuint ((gsize) ip2, ==, 0); g_assert_cmpuint ((guintptr) ip2, ==, 0);
res = g_atomic_pointer_compare_and_exchange_full (&ip, NULL, NULL, &ip2); res = g_atomic_pointer_compare_and_exchange_full (&ip, NULL, NULL, &ip2);
g_assert_false (res); g_assert_false (res);
g_assert_true (ip == &s); g_assert_true (ip == &s);
g_assert_true (ip2 == &s); g_assert_true (ip2 == &s);
g_atomic_pointer_set (&gs, 0); g_atomic_pointer_set (&gu, 0);
vp2 = (gpointer) g_atomic_pointer_get (&gs); vp2 = (gpointer) g_atomic_pointer_get (&gu);
gs2 = (gsize) vp2; gu2 = (guintptr) vp2;
g_assert_cmpuint (gs2, ==, 0); g_assert_cmpuint (gu2, ==, 0);
res = g_atomic_pointer_compare_and_exchange (&gs, NULL, (gsize) NULL); res = g_atomic_pointer_compare_and_exchange (&gu, NULL, (guintptr) NULL);
g_assert_true (res); g_assert_true (res);
g_assert_cmpuint (gs, ==, 0); g_assert_cmpuint (gu, ==, 0);
res = g_atomic_pointer_compare_and_exchange_full (&gs, (gsize) NULL, (gsize) NULL, &gs2); res = g_atomic_pointer_compare_and_exchange_full (&gu, (guintptr) NULL, (guintptr) NULL, &gu2);
g_assert_true (res); g_assert_true (res);
g_assert_cmpuint (gs, ==, 0); g_assert_cmpuint (gu, ==, 0);
g_assert_cmpuint (gs2, ==, 0); g_assert_cmpuint (gu2, ==, 0);
gs2 = (gsize) g_atomic_pointer_add (&gs, 5); gu2 = (guintptr) g_atomic_pointer_add (&gu, 5);
g_assert_cmpuint (gs2, ==, 0); g_assert_cmpuint (gu2, ==, 0);
g_assert_cmpuint (gs, ==, 5); g_assert_cmpuint (gu, ==, 5);
gs2 = g_atomic_pointer_and (&gs, 6); gu2 = g_atomic_pointer_and (&gu, 6);
g_assert_cmpuint (gs2, ==, 5); g_assert_cmpuint (gu2, ==, 5);
g_assert_cmpuint (gs, ==, 4); g_assert_cmpuint (gu, ==, 4);
gs2 = g_atomic_pointer_or (&gs, 8); gu2 = g_atomic_pointer_or (&gu, 8);
g_assert_cmpuint (gs2, ==, 4); g_assert_cmpuint (gu2, ==, 4);
g_assert_cmpuint (gs, ==, 12); g_assert_cmpuint (gu, ==, 12);
gs2 = g_atomic_pointer_xor (&gs, 4); gu2 = g_atomic_pointer_xor (&gu, 4);
g_assert_cmpuint (gs2, ==, 12); g_assert_cmpuint (gu2, ==, 12);
g_assert_cmpuint (gs, ==, 8); g_assert_cmpuint (gu, ==, 8);
vp_str2 = g_atomic_pointer_exchange (&vp_str, str); vp_str2 = g_atomic_pointer_exchange (&vp_str, str);
g_assert_cmpstr (vp_str, ==, str); g_assert_cmpstr (vp_str, ==, str);
g_assert_null (vp_str2); g_assert_null (vp_str2);
@ -340,41 +340,41 @@ G_GNUC_END_IGNORE_DEPRECATIONS
res = g_atomic_pointer_compare_and_exchange_full (&ip, NULL, (gpointer) 1, &cp); res = g_atomic_pointer_compare_and_exchange_full (&ip, NULL, (gpointer) 1, &cp);
g_assert_true (res); g_assert_true (res);
g_assert_cmpint ((gsize) ip, ==, 1); g_assert_cmpint ((guintptr) ip, ==, 1);
g_assert_cmpuint ((gsize) cp, ==, 0); g_assert_cmpuint ((guintptr) cp, ==, 0);
res = g_atomic_pointer_compare_and_exchange_full (&ip, NULL, NULL, &cp); res = g_atomic_pointer_compare_and_exchange_full (&ip, NULL, NULL, &cp);
g_assert_false (res); g_assert_false (res);
g_assert_cmpuint ((gsize) ip, ==, 1); g_assert_cmpuint ((guintptr) ip, ==, 1);
g_assert_cmpuint ((gsize) cp, ==, 1); g_assert_cmpuint ((guintptr) cp, ==, 1);
g_atomic_pointer_set (&gs, 0); g_atomic_pointer_set (&gu, 0);
vp = g_atomic_pointer_get (&gs); vp = g_atomic_pointer_get (&gu);
gs2 = (gsize) vp; gu2 = (guintptr) vp;
g_assert_cmpuint (gs2, ==, 0); g_assert_cmpuint (gu2, ==, 0);
res = g_atomic_pointer_compare_and_exchange (&gs, NULL, NULL); res = g_atomic_pointer_compare_and_exchange (&gu, NULL, NULL);
g_assert_true (res); g_assert_true (res);
g_assert_cmpuint (gs, ==, 0); g_assert_cmpuint (gu, ==, 0);
res = g_atomic_pointer_compare_and_exchange_full (&gs, NULL, NULL, &cp); res = g_atomic_pointer_compare_and_exchange_full (&gu, NULL, NULL, &cp);
g_assert_true (res); g_assert_true (res);
g_assert_cmpuint (gs, ==, 0); g_assert_cmpuint (gu, ==, 0);
g_assert_cmpuint ((gsize) cp, ==, 0); g_assert_cmpuint ((guintptr) cp, ==, 0);
gs2 = (gsize) g_atomic_pointer_add (&gs, 5); gu2 = (guintptr) g_atomic_pointer_add (&gu, 5);
g_assert_cmpuint (gs2, ==, 0); g_assert_cmpuint (gu2, ==, 0);
g_assert_cmpuint (gs, ==, 5); g_assert_cmpuint (gu, ==, 5);
gs2 = g_atomic_pointer_and (&gs, 6); gu2 = g_atomic_pointer_and (&gu, 6);
g_assert_cmpuint (gs2, ==, 5); g_assert_cmpuint (gu2, ==, 5);
g_assert_cmpuint (gs, ==, 4); g_assert_cmpuint (gu, ==, 4);
gs2 = g_atomic_pointer_or (&gs, 8); gu2 = g_atomic_pointer_or (&gu, 8);
g_assert_cmpuint (gs2, ==, 4); g_assert_cmpuint (gu2, ==, 4);
g_assert_cmpuint (gs, ==, 12); g_assert_cmpuint (gu, ==, 12);
gs2 = g_atomic_pointer_xor (&gs, 4); gu2 = g_atomic_pointer_xor (&gu, 4);
g_assert_cmpuint (gs2, ==, 12); g_assert_cmpuint (gu2, ==, 12);
g_assert_cmpuint (gs, ==, 8); g_assert_cmpuint (gu, ==, 8);
vp2 = g_atomic_pointer_exchange (&gs, NULL); vp2 = g_atomic_pointer_exchange (&gu, NULL);
gs2 = (gsize) vp2; gu2 = (guintptr) vp2;
g_assert_cmpuint (gs2, ==, 8); g_assert_cmpuint (gu2, ==, 8);
g_assert_null ((gpointer) gs); g_assert_null ((gpointer) gu);
g_assert_cmpint (g_atomic_int_get (csp), ==, s); g_assert_cmpint (g_atomic_int_get (csp), ==, s);
g_assert_true (g_atomic_pointer_get (cspp) == csp); g_assert_true (g_atomic_pointer_get (cspp) == csp);