Initial project import
This commit is contained in:
commit
23f2d29e32
11957 files changed
+1754577
No files matched your search
@@ -0,0 +1,333 @@
|
||||
module stdatomic
|
||||
|
||||
// Implement the atomic operations. For now TCC does not support the atomic
|
||||
// versions on nix so it uses locks to simulate the same behavior.
|
||||
//
|
||||
// On windows tcc can simulate with other atomic operations.
|
||||
//
|
||||
// Note: this implementations should be regarded as alpha stage and be tested
|
||||
// much more.
|
||||
|
||||
// add_u64 adds provided delta as an atomic operation
|
||||
@[inline]
|
||||
pub fn add_u64(ptr &u64, delta int) u64 {
|
||||
C.atomic_fetch_add_u64(voidptr(ptr), delta)
|
||||
return *ptr
|
||||
}
|
||||
|
||||
// sub_u64 subtracts provided delta as an atomic operation
|
||||
@[inline]
|
||||
pub fn sub_u64(ptr &u64, delta int) u64 {
|
||||
C.atomic_fetch_sub_u64(voidptr(ptr), delta)
|
||||
return *ptr
|
||||
}
|
||||
|
||||
// add_i64 adds provided delta as an atomic operation
|
||||
@[inline]
|
||||
pub fn add_i64(ptr &i64, delta int) i64 {
|
||||
C.atomic_fetch_add_u64(voidptr(ptr), delta)
|
||||
return *ptr
|
||||
}
|
||||
|
||||
// add_i64 subtracts provided delta as an atomic operation
|
||||
@[inline]
|
||||
pub fn sub_i64(ptr &i64, delta int) i64 {
|
||||
C.atomic_fetch_sub_u64(voidptr(ptr), delta)
|
||||
return *ptr
|
||||
}
|
||||
|
||||
// atomic store/load operations have to be used when there might be another concurrent access
|
||||
// atomicall set a value
|
||||
@[inline]
|
||||
pub fn store_u64(ptr &u64, val u64) {
|
||||
C.atomic_store_u64(voidptr(ptr), val)
|
||||
}
|
||||
|
||||
// atomicall get a value
|
||||
@[inline]
|
||||
pub fn load_u64(ptr &u64) u64 {
|
||||
return C.atomic_load_u64(voidptr(ptr))
|
||||
}
|
||||
|
||||
// atomicall set a value
|
||||
@[inline]
|
||||
pub fn store_i64(ptr &i64, val i64) {
|
||||
C.atomic_store_u64(voidptr(ptr), val)
|
||||
}
|
||||
|
||||
// atomicall get a value
|
||||
@[inline]
|
||||
pub fn load_i64(ptr &i64) i64 {
|
||||
return i64(C.atomic_load_u64(voidptr(ptr)))
|
||||
}
|
||||
|
||||
@[heap]
|
||||
pub struct AtomicVal[T] {
|
||||
val T
|
||||
}
|
||||
|
||||
// new_atomic creates a new atomic value of `T` type
|
||||
@[inline]
|
||||
pub fn new_atomic[T](val T) &AtomicVal[T] {
|
||||
$if T is $int {
|
||||
return &AtomicVal[T]{
|
||||
val: val
|
||||
}
|
||||
} $else $if T is bool {
|
||||
return &AtomicVal[T]{
|
||||
val: val
|
||||
}
|
||||
} $else $if T is voidptr {
|
||||
return &AtomicVal[T]{
|
||||
val: val
|
||||
}
|
||||
} $else {
|
||||
$compile_error('atomic: only support number, bool, and voidptr types')
|
||||
}
|
||||
return unsafe { nil }
|
||||
}
|
||||
|
||||
// load returns current value of the atomic value
|
||||
@[inline]
|
||||
pub fn (mut a AtomicVal[T]) load() T {
|
||||
$if T is bool {
|
||||
return C.atomic_load_byte(voidptr(&a.val)) != 0
|
||||
} $else $if T is u8 || T is i8 {
|
||||
return T(C.atomic_load_byte(voidptr(&a.val)))
|
||||
} $else $if T is u16 || T is i16 {
|
||||
return T(C.atomic_load_u16(voidptr(&a.val)))
|
||||
} $else $if T is u32 || T is i32 {
|
||||
return T(C.atomic_load_u32(voidptr(&a.val)))
|
||||
} $else $if T is u64 || T is i64 {
|
||||
return T(C.atomic_load_u64(voidptr(&a.val)))
|
||||
} $else $if T is int {
|
||||
if sizeof(int) == 4 {
|
||||
return int(C.atomic_load_u32(voidptr(&a.val)))
|
||||
} else {
|
||||
return int(C.atomic_load_u64(voidptr(&a.val)))
|
||||
}
|
||||
} $else $if T is isize || T is usize {
|
||||
if sizeof(isize) == 4 {
|
||||
return T(C.atomic_load_u32(voidptr(&a.val)))
|
||||
} else {
|
||||
return T(C.atomic_load_u64(voidptr(&a.val)))
|
||||
}
|
||||
} $else $if T is voidptr {
|
||||
// TODO: this should be $if sizeof(T) == 4
|
||||
$if x32 {
|
||||
return T(C.atomic_load_u32(voidptr(&a.val)))
|
||||
} $else {
|
||||
return T(C.atomic_load_u64(voidptr(&a.val)))
|
||||
}
|
||||
}
|
||||
return a.val
|
||||
}
|
||||
|
||||
// store updates the atomic value with `val`
|
||||
@[inline]
|
||||
pub fn (mut a AtomicVal[T]) store(val T) {
|
||||
$if T is bool {
|
||||
C.atomic_store_byte(voidptr(&a.val), u8(val))
|
||||
} $else $if T is u8 || T is i8 {
|
||||
C.atomic_store_byte(voidptr(&a.val), u8(val))
|
||||
} $else $if T is u16 || T is i16 {
|
||||
C.atomic_store_u16(voidptr(&a.val), u16(val))
|
||||
} $else $if T is u32 || T is i32 {
|
||||
C.atomic_store_u32(voidptr(&a.val), u32(val))
|
||||
} $else $if T is u64 || T is i64 {
|
||||
C.atomic_store_u64(voidptr(&a.val), u64(val))
|
||||
} $else $if T is int {
|
||||
if sizeof(int) == 4 {
|
||||
C.atomic_store_u32(voidptr(&a.val), u32(val))
|
||||
} else {
|
||||
C.atomic_store_u64(voidptr(&a.val), u64(val))
|
||||
}
|
||||
} $else $if T is isize || T is usize {
|
||||
if sizeof(isize) == 4 {
|
||||
C.atomic_store_u32(voidptr(&a.val), u32(val))
|
||||
} else {
|
||||
C.atomic_store_u64(voidptr(&a.val), u64(val))
|
||||
}
|
||||
} $else $if T is voidptr {
|
||||
// TODO: this should be $if sizeof(T) == 4
|
||||
$if x32 {
|
||||
C.atomic_store_u32(voidptr(&a.val), u32(val))
|
||||
} $else {
|
||||
C.atomic_store_u64(voidptr(&a.val), u64(val))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add adds the atomic value with `delta` and returns the previous value
|
||||
@[inline]
|
||||
pub fn (mut a AtomicVal[T]) add(delta T) T {
|
||||
$if T is bool {
|
||||
panic('atomic: add() not supported for bool type')
|
||||
} $else $if T is voidptr {
|
||||
panic('atomic: add() not supported for voidptr type')
|
||||
} $else $if T is u8 || T is i8 {
|
||||
old := C.atomic_fetch_add_byte(voidptr(&a.val), u8(delta))
|
||||
return T(old)
|
||||
} $else $if T is u16 || T is i16 {
|
||||
old := C.atomic_fetch_add_u16(voidptr(&a.val), u16(delta))
|
||||
return T(old)
|
||||
} $else $if T is u32 || T is i32 {
|
||||
old := C.atomic_fetch_add_u32(voidptr(&a.val), u32(delta))
|
||||
return T(old)
|
||||
} $else $if T is u64 || T is i64 {
|
||||
old := C.atomic_fetch_add_u64(voidptr(&a.val), u64(delta))
|
||||
return T(old)
|
||||
} $else $if T is int {
|
||||
if sizeof(int) == 4 {
|
||||
old := C.atomic_fetch_add_u32(voidptr(&a.val), u32(delta))
|
||||
return T(old)
|
||||
} else {
|
||||
old := C.atomic_fetch_add_u64(voidptr(&a.val), u64(delta))
|
||||
return T(old)
|
||||
}
|
||||
} $else $if T is isize || T is usize {
|
||||
if sizeof(isize) == 4 {
|
||||
old := C.atomic_fetch_add_u32(voidptr(&a.val), u32(delta))
|
||||
return T(old)
|
||||
} else {
|
||||
old := C.atomic_fetch_add_u64(voidptr(&a.val), u64(delta))
|
||||
return T(old)
|
||||
}
|
||||
}
|
||||
panic('unreachable')
|
||||
}
|
||||
|
||||
// sub subtracts the atomic value with `delta` and returns the previous value
|
||||
@[inline]
|
||||
pub fn (mut a AtomicVal[T]) sub(delta T) T {
|
||||
$if T is bool {
|
||||
panic('atomic: sub() not supported for bool type')
|
||||
} $else $if T is voidptr {
|
||||
panic('atomic: sub() not supported for voidptr type')
|
||||
} $else $if T is u8 || T is i8 {
|
||||
old := C.atomic_fetch_sub_byte(voidptr(&a.val), u8(delta))
|
||||
return T(old)
|
||||
} $else $if T is u16 || T is i16 {
|
||||
old := C.atomic_fetch_sub_u16(voidptr(&a.val), u16(delta))
|
||||
return T(old)
|
||||
} $else $if T is u32 || T is i32 {
|
||||
old := C.atomic_fetch_sub_u32(voidptr(&a.val), u32(delta))
|
||||
return T(old)
|
||||
} $else $if T is u64 || T is i64 {
|
||||
old := C.atomic_fetch_sub_u64(voidptr(&a.val), u64(delta))
|
||||
return T(old)
|
||||
} $else $if T is int {
|
||||
if sizeof(int) == 4 {
|
||||
old := C.atomic_fetch_sub_u32(voidptr(&a.val), u32(delta))
|
||||
return T(old)
|
||||
} else {
|
||||
old := C.atomic_fetch_sub_u64(voidptr(&a.val), u64(delta))
|
||||
return T(old)
|
||||
}
|
||||
} $else $if T is isize || T is usize {
|
||||
if sizeof(isize) == 4 {
|
||||
old := C.atomic_fetch_sub_u32(voidptr(&a.val), u32(delta))
|
||||
return T(old)
|
||||
} else {
|
||||
old := C.atomic_fetch_sub_u64(voidptr(&a.val), u64(delta))
|
||||
return T(old)
|
||||
}
|
||||
}
|
||||
panic('unreachable')
|
||||
}
|
||||
|
||||
// swap sets the `new` value and returns the previous value
|
||||
@[inline]
|
||||
pub fn (mut a AtomicVal[T]) swap(new T) T {
|
||||
$if T is bool {
|
||||
old := C.atomic_exchange_byte(voidptr(&a.val), u8(new))
|
||||
return old != 0
|
||||
} $else $if T is u8 || T is i8 {
|
||||
old := C.atomic_exchange_byte(voidptr(&a.val), u8(new))
|
||||
return T(old)
|
||||
} $else $if T is u16 || T is i16 {
|
||||
old := C.atomic_exchange_u16(voidptr(&a.val), u16(new))
|
||||
return T(old)
|
||||
} $else $if T is u32 || T is i32 {
|
||||
old := C.atomic_exchange_u32(voidptr(&a.val), u32(new))
|
||||
return T(old)
|
||||
} $else $if T is u64 || T is i64 {
|
||||
old := C.atomic_exchange_u64(voidptr(&a.val), u64(new))
|
||||
return T(old)
|
||||
} $else $if T is int {
|
||||
if sizeof(int) == 4 {
|
||||
old := C.atomic_exchange_u32(voidptr(&a.val), u32(new))
|
||||
return T(old)
|
||||
} else {
|
||||
old := C.atomic_exchange_u64(voidptr(&a.val), u64(new))
|
||||
return T(old)
|
||||
}
|
||||
} $else $if T is isize || T is usize {
|
||||
if sizeof(isize) == 4 {
|
||||
old := C.atomic_exchange_u32(voidptr(&a.val), u32(new))
|
||||
return T(old)
|
||||
} else {
|
||||
old := C.atomic_exchange_u64(voidptr(&a.val), u64(new))
|
||||
return T(old)
|
||||
}
|
||||
} $else $if T is voidptr {
|
||||
// TODO: this should be $if sizeof(T) == 4
|
||||
$if x32 {
|
||||
old := C.atomic_exchange_u32(voidptr(&a.val), u32(new))
|
||||
return T(old)
|
||||
} $else {
|
||||
old := C.atomic_exchange_u64(voidptr(&a.val), u64(new))
|
||||
return T(old)
|
||||
}
|
||||
}
|
||||
panic('unreachable')
|
||||
}
|
||||
|
||||
// compare_and_swap executes the compare-and-swap(CAS) operation
|
||||
// if atomic value == `expected`, then it will be set to `new`, and return true
|
||||
// else return false, and the atomic value remains unchanged
|
||||
@[inline]
|
||||
pub fn (mut a AtomicVal[T]) compare_and_swap(expected T, new T) bool {
|
||||
$if T is bool {
|
||||
mut exp := u8(expected)
|
||||
return C.atomic_compare_exchange_strong_byte(voidptr(&a.val), &exp, u8(new))
|
||||
} $else $if T is u8 || T is i8 {
|
||||
mut exp := u8(expected)
|
||||
return C.atomic_compare_exchange_strong_byte(voidptr(&a.val), &exp, u8(new))
|
||||
} $else $if T is u16 || T is i16 {
|
||||
mut exp := u16(expected)
|
||||
return C.atomic_compare_exchange_strong_u16(voidptr(&a.val), &exp, u16(new))
|
||||
} $else $if T is u32 || T is i32 {
|
||||
mut exp := u32(expected)
|
||||
return C.atomic_compare_exchange_strong_u32(voidptr(&a.val), &exp, u32(new))
|
||||
} $else $if T is u64 || T is i64 {
|
||||
mut exp := u64(expected)
|
||||
return C.atomic_compare_exchange_strong_u64(voidptr(&a.val), &exp, u64(new))
|
||||
} $else $if T is int {
|
||||
if sizeof(int) == 4 {
|
||||
mut exp := u32(expected)
|
||||
return C.atomic_compare_exchange_strong_u32(voidptr(&a.val), &exp, u32(new))
|
||||
} else {
|
||||
mut exp := u64(expected)
|
||||
return C.atomic_compare_exchange_strong_u64(voidptr(&a.val), &exp, u64(new))
|
||||
}
|
||||
} $else $if T is isize || T is usize {
|
||||
if sizeof(isize) == 4 {
|
||||
mut exp := u32(expected)
|
||||
return C.atomic_compare_exchange_strong_u32(voidptr(&a.val), &exp, u32(new))
|
||||
} else {
|
||||
mut exp := u64(expected)
|
||||
return C.atomic_compare_exchange_strong_u64(voidptr(&a.val), &exp, u64(new))
|
||||
}
|
||||
} $else $if T is voidptr {
|
||||
// TODO: this should be $if sizeof(T) == 4
|
||||
$if x32 {
|
||||
mut exp := u32(expected)
|
||||
return C.atomic_compare_exchange_strong_u32(voidptr(&a.val), &exp, u32(new))
|
||||
} $else {
|
||||
mut exp := u64(expected)
|
||||
return C.atomic_compare_exchange_strong_u64(voidptr(&a.val), &exp, u64(new))
|
||||
}
|
||||
}
|
||||
panic('unreachable')
|
||||
}
|
||||
Reference in new issue
Block a user