jch
jch

Reputation: 5651

C11 stdatomic and calloc

I've got a structure that contains an atomic field:

#include <stdatomic.h>

struct s {
    ...
    atomic_int a;
};

This structure is allocated with calloc:

struct s *p = calloc(1, sizeof(struct s));

Is it portable to expect p->a to be initialised to 0? There are enough barriers in the code so that weakly consistent initialisation is fine, but is the initial value guaranteed to be 0?

Upvotes: 10

Views: 751

Answers (3)

Jens Gustedt
Jens Gustedt

Reputation: 78923

No, this is not portable in general. calloc only guarantees a byte-wise 0 value of the underlying object. For types that (may) have a state this is not equivalent to an initialization. You definitively have to use atomic_init to put your object into a valid state.

The reason for this are platforms that hold a "lock" in addition to the base object because they don't implement the corresponding assembler instruction. So to be portable you really need to use ATOMIC_VAR_INIT or atomic_init for all atomic objects that are not statically allocated.

That said, I don't know of any existing platform that would need such cruft for atomic_int. If your platform has ATOMIC_INT_LOCK_FREE set to 2 and sizeof(atomic_int)==sizeof(int), you can be relatively sure that your strategy works. You could test that in a _Static_assert.

Upvotes: 3

chux
chux

Reputation: 153517

struct s *p = calloc(1, sizeof(struct s));
struct s *q = p;
// some other thread
foo(*q);

The initialization to zero is accounted for before p or any of its assginees can access the memory. It is 0.

Also see deferred zero-ing.

Upvotes: -1

Xaqq
Xaqq

Reputation: 4386

My guess is that this is not portable/safe.

It's very likely that calloc() end up doing a simple memset() on the memory area. This simple memset() would not issue the required memory barriers to ensure that other threads reading the structure would see the p->a as 0.

Upvotes: 0

Related Questions