tinycc/tests/tests2/124_atomic_counter.c
grischka 64552b3faa
Some checks failed
build and test / test-x86_64-linux (push) Has been cancelled
build and test / test-x86_64-osx (push) Has been cancelled
build and test / test-aarch64-osx (push) Has been cancelled
build and test / test-x86_64-win32 (push) Has been cancelled
build and test / test-i386-win32 (push) Has been cancelled
build and test / test-arm64-win32 (push) Has been cancelled
build and test / test-armv7-linux (push) Has been cancelled
build and test / test-aarch64-linux (push) Has been cancelled
build and test / test-riscv64-linux (push) Has been cancelled
build and test / test-i386-linux (push) Has been cancelled
tccelf: rework linker_sym (_end/end) logic
- tcc_add_linker_symbols():
    don't add for dlls
- bind_exe_dynsym():
    update _end symbol when done
    allow data definition in the .so override a bss symbol
    in the exe. For example
       exe: int x;
       .so: int x = 123;
- set_elf_sym():
    cannot compare section numbers with symbols from dlls
  tcc_load_obj():
    return -1 from symbol conflict errors

tests/tests2/148_linker_symbols:
- use only one file
- make it print useful output rather than just "2 errors."
  In general, the tests2 setup with .expect files is meant
  to compare text output.  For example:
      printf("val = %d\n", val);

  .expect file can be generated or refreshed using
       make tests2.nnn+
   or in order to force generation with tcc itself
       make tests2.nnn+ GEN-CC='$(GEN-TCC)'

tccgen.c:
- __attribute__((section(...))) : set section type/flags
    according to first usage
- fix bcheck bounds for -fcommon
2026-08-05 17:41:23 +02:00

133 lines
3.6 KiB
C

#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include "threads.h"
#include <stdatomic.h>
#define NR_THREADS 16
#define NR_STEPS 10000
#define BUG_ON(COND) \
do { \
if (!!(COND)) \
abort(); \
} while (0)
typedef struct {
atomic_flag flag;
atomic_uchar uc;
atomic_ushort us;
atomic_uint ui;
atomic_size_t ul;
} counter_type;
static
void *adder_simple(void *arg)
{
size_t step;
counter_type *counter = arg;
for (step = 0; step < NR_STEPS; ++step) {
atomic_fetch_add_explicit(&counter->uc, 1, memory_order_relaxed);
atomic_fetch_add_explicit(&counter->us, 1, memory_order_relaxed);
atomic_fetch_add_explicit(&counter->ui, 1, memory_order_relaxed);
atomic_fetch_add_explicit(&counter->ul, 1, memory_order_relaxed);
}
return NULL;
}
static
void *adder_cmpxchg(void *arg)
{
size_t step;
counter_type *counter = arg;
for (step = 0; step < NR_STEPS; ++step) {
unsigned char xchgc;
unsigned short xchgs;
unsigned int xchgi;
size_t xchgl;
unsigned char cmpc = atomic_load_explicit(&counter->uc, memory_order_relaxed);
unsigned short cmps = atomic_load_explicit(&counter->us, memory_order_relaxed);
unsigned int cmpi = atomic_load_explicit(&counter->ui, memory_order_relaxed);
size_t cmpl = atomic_load_explicit(&counter->ul, memory_order_relaxed);
do {
xchgc = (cmpc + 1);
} while (!atomic_compare_exchange_strong_explicit(&counter->uc,
&cmpc, xchgc, memory_order_relaxed, memory_order_relaxed));
do {
xchgs = (cmps + 1);
} while (!atomic_compare_exchange_strong_explicit(&counter->us,
&cmps, xchgs, memory_order_relaxed, memory_order_relaxed));
do {
xchgi = (cmpi + 1);
} while (!atomic_compare_exchange_strong_explicit(&counter->ui,
&cmpi, xchgi, memory_order_relaxed, memory_order_relaxed));
do {
xchgl = (cmpl + 1);
} while (!atomic_compare_exchange_strong_explicit(&counter->ul,
&cmpl, xchgl, memory_order_relaxed, memory_order_relaxed));
}
return NULL;
}
static
void *adder_test_and_set(void *arg)
{
size_t step;
counter_type *counter = arg;
for (step = 0; step < NR_STEPS; ++step) {
while (atomic_flag_test_and_set(&counter->flag));
++counter->uc;
++counter->us;
++counter->ui;
++counter->ul;
atomic_flag_clear(&counter->flag);
}
return NULL;
}
static
void atomic_counter_test(void *(*adder)(void *arg))
{
size_t index;
counter_type counter;
pthread_t thread[NR_THREADS];
atomic_flag_clear(&counter.flag);
atomic_init(&counter.uc, 0);
atomic_init(&counter.us, 0);
atomic_init(&counter.ui, 0);
atomic_init(&counter.ul, 0);
for (index = 0; index < NR_THREADS; ++index)
BUG_ON(pthread_create(&thread[index], NULL, adder, (void *)&counter));
for (index = 0; index < NR_THREADS; ++index)
BUG_ON(pthread_join(thread[index], NULL));
if (atomic_load(&counter.uc) == ((NR_THREADS * NR_STEPS) & 0xffu)
&& atomic_load(&counter.us) == ((NR_THREADS * NR_STEPS) & 0xffffu)
&& atomic_load(&counter.ui) == (NR_THREADS * NR_STEPS)
&& atomic_load(&counter.ul) == (NR_THREADS * NR_STEPS)
)
printf("SUCCESS\n");
else
printf("FAILURE\n");
}
int main(void)
{
atomic_counter_test(adder_simple);
atomic_counter_test(adder_cmpxchg);
atomic_counter_test(adder_test_and_set);
return 0;
}