While I was reading a Linux kernel implementation for RCU lock primitives, I ended up reaching the below code.
#define WRITE_ONCE(x, val) \
({ \
union { typeof(x) __val; char __c[1]; } __u = \
{ .__val = (__force typeof(x)) (val) }; \
__write_once_size(&(x), __u.__c, sizeof(x)); \
__u.__val; \
})
static __always_inline void __write_once_size(volatile void *p, void *res, int size)
{
switch (size) {
case 1: *(volatile __u8 *)p = *(__u8 *)res; break;
case 2: *(volatile __u16 *)p = *(__u16 *)res; break;
case 4: *(volatile __u32 *)p = *(__u32 *)res; break;
case 8: *(volatile __u64 *)p = *(__u64 *)res; break;
default:
barrier();
__builtin_memcpy((void *)p, (const void *)res, size);
barrier();
}
}
As far as I can tell, union ending with the char array having the size of the previous part of the union allows you to access memory assigned to the union in byte granularity.
For example,
#define UNION_PARTIAL \
int a; \
int b; \
char *c; \
union union_partial {
UNION_PARTIAL
};
union union_full {
UNION_PARTIAL
char bytes[sizeof(union union_partial)];
};
However, it seems that the union used in the WRITE_ONCE macro is not declared to provide fine granularity accesses to the union memory. The below code may be used instead, but I don't know why we need char __c[1].
#define WRITE_ONCE(x, val) \
({ \
union { typeof(x) __val; char __c[1]; } __u = \
{ .__val = (__force typeof(x)) (val) }; \
__write_once_size(&(x), &(__u.val), sizeof(x)); \
__u.__val; \
})
is it only because to reduce burden for a programmer to type & in front of the __u.val ?