Skip to content

Commit

Permalink
std::runtime: add functions for atomicity
Browse files Browse the repository at this point in the history
  • Loading branch information
mertcandav committed Sep 15, 2024
1 parent 7ec0f33 commit c076f4c
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 33 deletions.
52 changes: 52 additions & 0 deletions std/runtime/atomic.jule
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright 2024 The Jule Programming Language.
// Use of this source code is governed by a BSD 3-Clause
// license that can be found in the LICENSE file.

type atomicMemoryOrder: int

const atomicRelaxed = atomicMemoryOrder(0)
const atomicConsume = atomicMemoryOrder(1)
const atomicAcquire = atomicMemoryOrder(2)
const atomicRelease = atomicMemoryOrder(3)
const atomicAcqRel = atomicMemoryOrder(4)
const atomicSeqCst = atomicMemoryOrder(5)

#cdef
cpp unsafe fn __atomic_store(*unsafe, *unsafe, atomicMemoryOrder)

#cdef
cpp unsafe fn __atomic_load(*unsafe, *unsafe, atomicMemoryOrder)

#cdef
cpp unsafe fn __atomic_exchange[T](*unsafe, *unsafe, *unsafe, atomicMemoryOrder): T

#cdef
cpp unsafe fn __atomic_compare_exchange(*unsafe, *unsafe, *unsafe, int, atomicMemoryOrder, atomicMemoryOrder): bool

#cdef
cpp unsafe fn __atomic_fetch_add[T](*unsafe, T, atomicMemoryOrder): T

unsafe fn atomicSwap[T](mut p: *T, new: *T, mo: atomicMemoryOrder): (old: T) {
let mut tmp: T
cpp.__atomic_exchange[T](p, new, &tmp, mo)
ret tmp
}

unsafe fn atomicLoad[T](p: *T, mo: atomicMemoryOrder): T {
let mut tmp: T
cpp.__atomic_load(p, &tmp, mo)
ret tmp
}

unsafe fn atomicCompareSwap[T](mut p: *T, old: *T, new: *T, suc: atomicMemoryOrder, fail: atomicMemoryOrder): (swapped: bool) {
const Magic = 0x0
ret cpp.__atomic_compare_exchange(p, old, new, Magic, suc, fail)
}

unsafe fn atomicAdd[T](mut p: *T, delta: T, mo: atomicMemoryOrder): (old: T) {
ret cpp.__atomic_fetch_add[T](p, delta, mo)
}

unsafe fn atomicStore[T](mut p: *T, val: *T, mo: atomicMemoryOrder) {
cpp.__atomic_store(p, val, mo)
}
49 changes: 16 additions & 33 deletions std/sync/atomic/atomic.jule
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,7 @@
// Use of this source code is governed by a BSD 3-Clause
// license that can be found in the LICENSE file.

#cdef
cpp unsafe fn __jule_atomic_swap_explicit[T](
mut addr: *T, new: T, order: MemoryOrder): (old: T)

#cdef
cpp unsafe fn __jule_atomic_compare_swap_explicit[T](mut addr: *T, old: *T,
new: T, suc: MemoryOrder, fail: MemoryOrder): (swapped: bool)

#cdef
cpp unsafe fn __jule_atomic_add_explicit[T](
mut addr: *T, delta: T, order: MemoryOrder): (old: T)

#cdef
cpp unsafe fn __jule_atomic_load_explicit[T](addr: *T, order: MemoryOrder): T

#cdef
cpp unsafe fn __jule_atomic_store_explicit[T](
mut addr: *T, val: T, order: MemoryOrder)
use runtime for std::runtime

// Memory order for atomic operations.
// Specifies how memory accesses.
Expand All @@ -28,31 +11,31 @@ enum MemoryOrder {
// There no synchronization or ordering on read/write access.
// Only the operation is guaranteed to be atomic.
// Usually performs fastest atomicity performance.
Relaxed: 0,
Relaxed: runtime::atomicRelaxed,

// Combined with a load, if the loaded value was written
// by a store operation with a Release or stronger order,
// all subsequent operations are ordered after that store.
// Especially all subsequent uploads will see the data
// written before the repository.
Acquire: 2,
Acquire: runtime::atomicAcquire,

// When combined with a store, all previous operations are
// ordered with the Acquire or stronger order before any load
// of that value. In particular, all previous writes become
// visible to all threads that perform an Acquire or stronger
// load of this value.
Release: 3,
Release: runtime::atomicRelease,

// Acquire and Release combined.
// Aka acquire/release.
// For loads it uses Acquire, for stores it uses Release ordering.
AcqRel: 4,
AcqRel: runtime::atomicAcqRel,

// Default memory order for most things.
// Aka sequentially consistent.
// Operations are sequenced consistently.
SeqCst: 5,
SeqCst: runtime::atomicSeqCst,
}

struct atomicNumber[T] {
Expand All @@ -62,27 +45,27 @@ struct atomicNumber[T] {
impl atomicNumber {
// Atomically stores new value and returns the previous value.
fn Swap(mut self, new: T, order: MemoryOrder): (old: T) {
ret unsafe { cpp.__jule_atomic_swap_explicit[T](&self.n, new, order) }
ret unsafe { runtime::atomicSwap[T](&self.n, &new, order) }
}

// Executes the compare-and-swap operation.
fn CompareSwap(mut self, old: T, new: T, order: MemoryOrder): (swapped: bool) {
ret unsafe { cpp.__jule_atomic_compare_swap_explicit[T](&self.n, &old, new, order, order) }
ret unsafe { runtime::atomicCompareSwap[T](&self.n, &old, &new, order, order) }
}

// Atomically adds delta to value and returns the previous value.
fn Add(mut self, delta: T, order: MemoryOrder): (old: T) {
ret unsafe { cpp.__jule_atomic_add_explicit[T](&self.n, delta, order) }
ret unsafe { runtime::atomicAdd[T](&self.n, delta, order) }
}

// Atomically reads and returns value.
fn Load(self, order: MemoryOrder): T {
ret unsafe { cpp.__jule_atomic_load_explicit[T](&self.n, order) }
ret unsafe { runtime::atomicLoad[T](&self.n, order) }
}

// Atomically assigns to value.
fn Store(mut self, val: T, order: MemoryOrder) {
unsafe { cpp.__jule_atomic_store_explicit[T](&self.n, val, order) }
unsafe { runtime::atomicStore[T](&self.n, &val, order) }
}
}

Expand Down Expand Up @@ -129,29 +112,29 @@ type AtomicUintptr: atomicNumber[uintptr]
// Atomically stores new into addr and returns the previous addr value.
// Only integer types are supported.
fn Swap[T: int | uint | i8 | i16 | i32 | i64 | u8 | u16 | u32 | u64 | uintptr](mut &addr: T, new: T, order: MemoryOrder): (old: T) {
ret unsafe { cpp.__jule_atomic_swap_explicit[T](&addr, new, order) }
ret unsafe { runtime::atomicSwap[T](&addr, &new, order) }
}

// Executes the compare-and-swap operation for value.
// Only integer types are supported.
fn CompareSwap[T: int | uint | i8 | i16 | i32 | i64 | u8 | u16 | u32 | u64 | uintptr](mut &addr: T, old: T, new: T, order: MemoryOrder): (swapped: bool) {
ret unsafe { cpp.__jule_atomic_compare_swap_explicit[T](&addr, &old, new, order, order) }
ret unsafe { runtime::atomicCompareSwap[T](&addr, &old, &new, order, order) }
}

// Atomically adds delta to addr and returns the previous addr value.
// Only integer types are supported.
fn Add[T: int | uint | i8 | i16 | i32 | i64 | u8 | u16 | u32 | u64 | uintptr](mut &addr: T, delta: T, order: MemoryOrder): (old: T) {
ret unsafe { cpp.__jule_atomic_add_explicit[T](&addr, delta, order) }
ret unsafe { runtime::atomicAdd[T](&addr, delta, order) }
}

// Atomically loads addr.
// Only integer types are supported.
fn Load[T: int | uint | i8 | i16 | i32 | i64 | u8 | u16 | u32 | u64 | uintptr](&addr: T, order: MemoryOrder): T {
ret unsafe { cpp.__jule_atomic_load_explicit[T](&addr, order) }
ret unsafe { runtime::atomicLoad[T](&addr, order) }
}

// Atomically stores val into addr.
// Only integer types are supported.
fn Store[T: int | uint | i8 | i16 | i32 | i64 | u8 | u16 | u32 | u64 | uintptr](mut &addr: T, val: T, order: MemoryOrder) {
unsafe { cpp.__jule_atomic_store_explicit[T](&addr, val, order) }
unsafe { runtime::atomicStore[T](&addr, &val, order) }
}

0 comments on commit c076f4c

Please sign in to comment.