mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Architecture generic Atomics (C11 + extras) (#958)
* Initial implementation for c11 atomics * Fix cmpxchg usage * Support for floating point atomics * Added atomic min and max * Updated copyright notice * Removed Floats from and or xor. Added mul, div, bitshift * Changed get_atomic_compatible_type to lower_to_atomic_compatible_type * Require non-null pointers * Fix spacing * Added Atomic type * Added macro to reduce code * Small reorder and cleanup * Added cmpxchg constrains * Apply all the restrictions for atomic loads/stores and cmpxchg
This commit is contained in:
committed by
GitHub
parent
efb492eace
commit
7aca8a02cb
245
test/unit/stdlib/atomic.c3
Normal file
245
test/unit/stdlib/atomic.c3
Normal file
@@ -0,0 +1,245 @@
|
||||
import std::thread;
|
||||
import std::io;
|
||||
import std::atomic;
|
||||
|
||||
uint a;
|
||||
float fa;
|
||||
|
||||
fn void! add() @test
|
||||
{
|
||||
Thread[100] ts;
|
||||
a = 0;
|
||||
foreach (&t : ts)
|
||||
{
|
||||
t.create(fn int(void* arg) {
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_add(&a, 5);
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_add(&a, 5);
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_add(&a, 5);
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_add(&a, 5);
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_add(&a, 5);
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_add(&a, 5);
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_add(&a, 5);
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_add(&a, 5);
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_add(&a, 5);
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_add(&a, 5);
|
||||
return 0;
|
||||
}, null)!;
|
||||
}
|
||||
foreach (&t : ts)
|
||||
{
|
||||
assert(t.join()! == 0);
|
||||
}
|
||||
assert(a == ts.len * 10 * 5, "Threads returned %d, expected %d", a, ts.len * 10 * 5);
|
||||
}
|
||||
|
||||
fn void! sub() @test
|
||||
{
|
||||
Thread[100] ts;
|
||||
a = ts.len * 10 * 5;
|
||||
foreach (&t : ts)
|
||||
{
|
||||
t.create(fn int(void* arg) {
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_sub(&a, 5);
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_sub(&a, 5);
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_sub(&a, 5);
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_sub(&a, 5);
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_sub(&a, 5);
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_sub(&a, 5);
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_sub(&a, 5);
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_sub(&a, 5);
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_sub(&a, 5);
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_sub(&a, 5);
|
||||
return 0;
|
||||
}, null)!;
|
||||
}
|
||||
foreach (&t : ts)
|
||||
{
|
||||
assert(t.join()! == 0);
|
||||
}
|
||||
assert(a == 0, "Threads returned %d, expected %d", a, 0);
|
||||
}
|
||||
|
||||
fn void! div() @test
|
||||
{
|
||||
Thread[8] ts;
|
||||
a = 8 * 8 * 8 * 8 * 8 * 8 * 8 * 8 * 8;
|
||||
foreach (&t : ts)
|
||||
{
|
||||
t.create(fn int(void* arg) {
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_div(&a, 8);
|
||||
return 0;
|
||||
}, null)!;
|
||||
}
|
||||
foreach (&t : ts)
|
||||
{
|
||||
assert(t.join()! == 0);
|
||||
}
|
||||
assert(a == 8, "Threads returned %d, expected %d", a, 8);
|
||||
}
|
||||
|
||||
fn void! max() @test
|
||||
{
|
||||
Thread[100] ts;
|
||||
a = 0;
|
||||
foreach (&t : ts)
|
||||
{
|
||||
t.create(fn int(void* arg) {
|
||||
uint la = 0;
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_max(&a, la);
|
||||
la++;
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_max(&a, la);
|
||||
la++;
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_max(&a, la);
|
||||
la++;
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_max(&a, la);
|
||||
la++;
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_max(&a, la);
|
||||
la++;
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_max(&a, la);
|
||||
la++;
|
||||
return 0;
|
||||
}, null)!;
|
||||
}
|
||||
foreach (&t : ts)
|
||||
{
|
||||
assert(t.join()! == 0);
|
||||
}
|
||||
assert(a == 5, "Threads returned %d, expected %d", a, 5);
|
||||
}
|
||||
|
||||
fn void! min() @test
|
||||
{
|
||||
Thread[100] ts;
|
||||
a = 10;
|
||||
foreach (&t : ts)
|
||||
{
|
||||
t.create(fn int(void* arg) {
|
||||
uint la = 5;
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_min(&a, la);
|
||||
la--;
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_min(&a, la);
|
||||
la--;
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_min(&a, la);
|
||||
la--;
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_min(&a, la);
|
||||
la--;
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_min(&a, la);
|
||||
la--;
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_min(&a, la);
|
||||
la--;
|
||||
return 0;
|
||||
}, null)!;
|
||||
}
|
||||
foreach (&t : ts)
|
||||
{
|
||||
assert(t.join()! == 0);
|
||||
}
|
||||
assert(a == 0, "Threads returned %d, expected %d", a, 0);
|
||||
}
|
||||
|
||||
fn void! fadd() @test
|
||||
{
|
||||
Thread[100] ts;
|
||||
fa = 0;
|
||||
foreach (&t : ts)
|
||||
{
|
||||
t.create(fn int(void* arg) {
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_add(&fa, 0.5f);
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_add(&fa, 0.5f);
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_add(&fa, 0.5f);
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_add(&fa, 0.5f);
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_add(&fa, 0.5f);
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_add(&fa, 0.5f);
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_add(&fa, 0.5f);
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_add(&fa, 0.5f);
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_add(&fa, 0.5f);
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_add(&fa, 0.5f);
|
||||
return 0;
|
||||
}, null)!;
|
||||
}
|
||||
foreach (&t : ts)
|
||||
{
|
||||
assert(t.join()! == 0);
|
||||
}
|
||||
assert(fa == ts.len * 10 * 0.5, "Threads returned %f, expected %f", fa, ts.len * 10 * 0.5);
|
||||
}
|
||||
|
||||
fn void! fsub() @test
|
||||
{
|
||||
Thread[100] ts;
|
||||
fa = ts.len * 10 * 0.5;
|
||||
foreach (&t : ts)
|
||||
{
|
||||
t.create(fn int(void* arg) {
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_sub(&fa, 0.5f);
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_sub(&fa, 0.5f);
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_sub(&fa, 0.5f);
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_sub(&fa, 0.5f);
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_sub(&fa, 0.5f);
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_sub(&fa, 0.5f);
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_sub(&fa, 0.5f);
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_sub(&fa, 0.5f);
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_sub(&fa, 0.5f);
|
||||
thread::sleep_ms(5);
|
||||
atomic::fetch_sub(&fa, 0.5f);
|
||||
return 0;
|
||||
}, null)!;
|
||||
}
|
||||
foreach (&t : ts)
|
||||
{
|
||||
assert(t.join()! == 0);
|
||||
}
|
||||
assert(fa == 0, "Threads returned %f, expected %f", fa, 0);
|
||||
}
|
||||
154
test/unit/stdlib/atomic_types.c3
Normal file
154
test/unit/stdlib/atomic_types.c3
Normal file
@@ -0,0 +1,154 @@
|
||||
import std::thread;
|
||||
import std::io;
|
||||
import std::atomic::types;
|
||||
|
||||
Atomic(<uint>) a;
|
||||
Atomic(<float>) fa;
|
||||
|
||||
fn void! add() @test
|
||||
{
|
||||
Thread[100] ts;
|
||||
a.store(0);
|
||||
foreach (&t : ts)
|
||||
{
|
||||
t.create(fn int(void* arg) {
|
||||
thread::sleep_ms(5);
|
||||
a.add(5);
|
||||
thread::sleep_ms(5);
|
||||
a.add(5);
|
||||
thread::sleep_ms(5);
|
||||
a.add(5);
|
||||
thread::sleep_ms(5);
|
||||
a.add(5);
|
||||
thread::sleep_ms(5);
|
||||
a.add(5);
|
||||
thread::sleep_ms(5);
|
||||
a.add(5);
|
||||
thread::sleep_ms(5);
|
||||
a.add(5);
|
||||
thread::sleep_ms(5);
|
||||
a.add(5);
|
||||
thread::sleep_ms(5);
|
||||
a.add(5);
|
||||
thread::sleep_ms(5);
|
||||
a.add(5);
|
||||
return 0;
|
||||
}, null)!;
|
||||
}
|
||||
foreach (&t : ts)
|
||||
{
|
||||
assert(t.join()! == 0);
|
||||
}
|
||||
assert(a.load() == ts.len * 10 * 5, "Threads returned %d, expected %d", a.load(), ts.len * 10 * 5);
|
||||
}
|
||||
|
||||
fn void! sub() @test
|
||||
{
|
||||
Thread[100] ts;
|
||||
a.store(ts.len * 10 * 5);
|
||||
foreach (&t : ts)
|
||||
{
|
||||
t.create(fn int(void* arg) {
|
||||
thread::sleep_ms(5);
|
||||
a.sub(5);
|
||||
thread::sleep_ms(5);
|
||||
a.sub(5);
|
||||
thread::sleep_ms(5);
|
||||
a.sub(5);
|
||||
thread::sleep_ms(5);
|
||||
a.sub(5);
|
||||
thread::sleep_ms(5);
|
||||
a.sub(5);
|
||||
thread::sleep_ms(5);
|
||||
a.sub(5);
|
||||
thread::sleep_ms(5);
|
||||
a.sub(5);
|
||||
thread::sleep_ms(5);
|
||||
a.sub(5);
|
||||
thread::sleep_ms(5);
|
||||
a.sub(5);
|
||||
thread::sleep_ms(5);
|
||||
a.sub(5);
|
||||
return 0;
|
||||
}, null)!;
|
||||
}
|
||||
foreach (&t : ts)
|
||||
{
|
||||
assert(t.join()! == 0);
|
||||
}
|
||||
assert(a.load() == 0, "Threads returned %d, expected %d", a.load(), 0);
|
||||
}
|
||||
|
||||
fn void! fadd() @test
|
||||
{
|
||||
Thread[100] ts;
|
||||
fa.store(0);
|
||||
foreach (&t : ts)
|
||||
{
|
||||
t.create(fn int(void* arg) {
|
||||
thread::sleep_ms(5);
|
||||
fa.add(0.5);
|
||||
thread::sleep_ms(5);
|
||||
fa.add(0.5);
|
||||
thread::sleep_ms(5);
|
||||
fa.add(0.5);
|
||||
thread::sleep_ms(5);
|
||||
fa.add(0.5);
|
||||
thread::sleep_ms(5);
|
||||
fa.add(0.5);
|
||||
thread::sleep_ms(5);
|
||||
fa.add(0.5);
|
||||
thread::sleep_ms(5);
|
||||
fa.add(0.5);
|
||||
thread::sleep_ms(5);
|
||||
fa.add(0.5);
|
||||
thread::sleep_ms(5);
|
||||
fa.add(0.5);
|
||||
thread::sleep_ms(5);
|
||||
fa.add(0.5);
|
||||
return 0;
|
||||
}, null)!;
|
||||
}
|
||||
foreach (&t : ts)
|
||||
{
|
||||
assert(t.join()! == 0);
|
||||
}
|
||||
assert(fa.load() == ts.len * 10 * 0.5, "Threads returned %f, expected %f", fa.load(), ts.len * 10 * 0.5);
|
||||
}
|
||||
|
||||
fn void! fsub() @test
|
||||
{
|
||||
Thread[100] ts;
|
||||
fa.store(ts.len * 10 * 0.5);
|
||||
foreach (&t : ts)
|
||||
{
|
||||
t.create(fn int(void* arg) {
|
||||
thread::sleep_ms(5);
|
||||
fa.sub(0.5);
|
||||
thread::sleep_ms(5);
|
||||
fa.sub(0.5);
|
||||
thread::sleep_ms(5);
|
||||
fa.sub(0.5);
|
||||
thread::sleep_ms(5);
|
||||
fa.sub(0.5);
|
||||
thread::sleep_ms(5);
|
||||
fa.sub(0.5);
|
||||
thread::sleep_ms(5);
|
||||
fa.sub(0.5);
|
||||
thread::sleep_ms(5);
|
||||
fa.sub(0.5);
|
||||
thread::sleep_ms(5);
|
||||
fa.sub(0.5);
|
||||
thread::sleep_ms(5);
|
||||
fa.sub(0.5);
|
||||
thread::sleep_ms(5);
|
||||
fa.sub(0.5);
|
||||
return 0;
|
||||
}, null)!;
|
||||
}
|
||||
foreach (&t : ts)
|
||||
{
|
||||
assert(t.join()! == 0);
|
||||
}
|
||||
assert(fa.load() == 0, "Threads returned %f, expected %f", fa.load(), 0);
|
||||
}
|
||||
Reference in New Issue
Block a user