IlBowsta
IlBowsta

Reputation: 1

Incompatible pointer types passing with atomic function calls

I am trying to implement a global version clock that is accessed by multiple threads, so it should be atomic as far as I know to ensure thread safety. To modify and read the values I implemented the methods below, however I get the warning "Incompatible pointer types passing 'typeof ((void) 0 , *__atomic_load_ptr) *' (aka 'unsigned long *') to parameter of type '_Atomic(unsigned long) *'" on the atomic_load_explicit and atomic_compare_exchange_strong_explicit function calls.

More specifically, the warning says:

Incompatible pointer types passing 'typeof ((void) 0 , *__atomic_exchange_ptr) *' (aka 'int *') to parameter of type '_Atomic(int) *'

Declared in: stdatomic. h
Definition:
#define atomic_init(PTR, VAL)                           \
  atomic_store_explicit (PTR, VAL, __ATOMIC_RELAXED)
Replacement:
({
    __auto_type __atomic_store_ptr = (&(lock->lock_state));
    __typeof__((void) 0, *__atomic_store_ptr) __atomic_store_tmp = (0);
    __atomic_store(__atomic_store_ptr, &__atomic_store_tmp, (0));
})

I can clear the warning by not using _Atomic, but I am not convinced it would be thread safe, what would be the solution?

Written in C11, gcc version 13.2.0, Ubuntu 24.04 LTS

Thanks!

#include <stdatomic.h>

_Atomic unsigned long global_version_clock = 0;

uint64_t get_current_version() {
    return atomic_load_explicit(&global_version_clock, memory_order_acquire);
}

uint64_t increment_version() {
    uint64_t old_version, new_version;
    do {
        old_version = atomic_load_explicit(&global_version_clock, memory_order_relaxed);
        new_version = old_version + 1;
    } while (!atomic_compare_exchange_strong_explicit(&global_version_clock, &old_version, new_version,
                                                      memory_order_release, memory_order_relaxed));
    return new_version;
}

Edit:

I am now using this struct in the header file:

#include <stdatomic.h>
#include <stdint-gcc.h>
#include <stdbool.h>

#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#ifndef __USE_XOPEN2K
#define __USE_XOPEN2K
#endif


typedef struct version_clock_t{
    _Atomic uint64_t version;
}version_clock_t;

bool init_version_clock(version_clock_t* global_version_clock);

uint64_t get_current_version(version_clock_t* global_version_clock);

uint64_t increment_version(version_clock_t* global_version_clock);

And in the C file I implement the declared functions, which still gives the warnings "Incompatible pointer types passing 'typeof ((void) 0 , *__atomic_store_ptr) *' (aka 'unsigned long *') to parameter of type '_Atomic(uint64_t) *'" and "Incompatible pointer types passing 'typeof ((void) 0 , *__atomic_load_ptr) *' (aka 'unsigned long *') to parameter of type '_Atomic(uint64_t) *'" respectively:

#include "version-clock.h"

bool init_version_clock(version_clock_t* global_version_clock) {
    atomic_init(&(global_version_clock->version), 0); // Warning here
    return true;
}

uint64_t get_current_version(version_clock_t* global_version_clock) {
    return atomic_load(&(global_version_clock->version));  // Warning here
}

uint64_t increment_version(version_clock_t* global_version_clock) {
    return atomic_fetch_add(&(global_version_clock->version), 1) + 1;
}

Upvotes: 0

Views: 85

Answers (1)

0___________
0___________

Reputation: 67835

The type of global_version_clock is declared as _Atomic unsigned long, while the function increment_version() uses uint64_t for old_version and new_version. The atomic_compare_exchange_strong_explicit function will issue a type compatibility warning if the types are not the same.

Solution use the same types uint64_t or unsigned long.

_Atomic uint64_t global_version_clock = 0;

uint64_t get_current_version() {
    return atomic_load_explicit(&global_version_clock, memory_order_acquire);
}

uint64_t increment_version() {
    uint64_t old_version, new_version;
    do {
        old_version = atomic_load_explicit(&global_version_clock, memory_order_relaxed);
        new_version = old_version + 1;
    } while (!atomic_compare_exchange_strong_explicit(&global_version_clock, &old_version, new_version,
                                                      memory_order_release, memory_order_relaxed));
    return new_version;
}

Remember that unsigned long does not have to be 64 bits long!

Upvotes: 1

Related Questions