Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mark AtomicCell::is_lock_free() as const fn? #531

Closed
nyanpasu64 opened this issue Jun 16, 2020 · 2 comments · Fixed by #546
Closed

Mark AtomicCell::is_lock_free() as const fn? #531

nyanpasu64 opened this issue Jun 16, 2020 · 2 comments · Fixed by #546

Comments

@nyanpasu64
Copy link

nyanpasu64 commented Jun 16, 2020

It would be convenient if I could check if AtomicCells are lock-free at compile time. by marking AtomicCell<T>::is_lock_free() as a const fn.

For context, I'm working on an audio program in C++, due to C++ libraries including Qt. In audio programs, taking locks on the audio thread is regarded as unacceptable because it can block and cause the audio to stutter. As a result, I'd like to statically assert that a given atomic type written by the audio thread is lock-free. (I'm mostly looking at Rust for inspiration and comparison, to see whether parts of my code are nicer in C++ or Rust.)

pub fn is_lock_free() -> bool {
atomic_is_lock_free::<T>()
}

calls atomic_is_lock_free<T>:

/// Returns `true` if operations on `AtomicCell<T>` are lock-free.
fn atomic_is_lock_free<T>() -> bool {
atomic! { T, _a, true, false }
}

expands to the atomic! macro:

macro_rules! atomic {
// If values of type `$t` can be transmuted into values of the primitive atomic type `$atomic`,
// declares variable `$a` of type `$atomic` and executes `$atomic_op`, breaking out of the loop.
(@check, $t:ty, $atomic:ty, $a:ident, $atomic_op:expr) => {
if can_transmute::<$t, $atomic>() {
let $a: &$atomic;
break $atomic_op;
}
};
// If values of type `$t` can be transmuted into values of a primitive atomic type, declares
// variable `$a` of that type and executes `$atomic_op`. Otherwise, just executes
// `$fallback_op`.
($t:ty, $a:ident, $atomic_op:expr, $fallback_op:expr) => {
loop {
atomic!(@check, $t, AtomicUnit, $a, $atomic_op);
atomic!(@check, $t, atomic::AtomicUsize, $a, $atomic_op);
#[cfg(has_atomic_u8)]
atomic!(@check, $t, atomic::AtomicU8, $a, $atomic_op);
#[cfg(has_atomic_u16)]
atomic!(@check, $t, atomic::AtomicU16, $a, $atomic_op);
#[cfg(has_atomic_u32)]
atomic!(@check, $t, atomic::AtomicU32, $a, $atomic_op);
#[cfg(has_atomic_u64)]
atomic!(@check, $t, atomic::AtomicU64, $a, $atomic_op);
break $fallback_op;
}
};
}

Marking AtomicCell<T>::is_lock_free() as const doesn't seem to cause issues, but depends on atomic_is_lock_free. Trying to mark atomic_is_lock_free as const fails on rust-lang/rust#49146 "Allow if and match in constants", and rust-lang/rust#52000 "Allow loop in constant evaluation".

From a cursory examination, atomic! doesn't truly need a loop, but depends on if. Note that I don't fully understand atomic! nor all call sites.

Are there any plans to mark this as a const fn, to allow users to statically assert it's lock-free? I don't know if atomic! needs to be split into two macros or not, with duplication and possible future desynchronization.

@taiki-e
Copy link
Member

taiki-e commented Jun 23, 2020

Probably const_if_match and const_loop will be stable at the same time (rust-lang/rust#72437 (comment)), but either way, atomic! doesn't really need a loop, so I think it makes sense to conditionally mark is_lock_free as a const fn when const_if_match is stable.

@taiki-e
Copy link
Member

taiki-e commented Jul 6, 2020

Seems stabilization pr has been merged: rust-lang/rust#72437

@ghost ghost closed this as completed in #546 Aug 29, 2020
bors bot added a commit that referenced this issue Nov 17, 2020
600: Make AtomicCell::is_lock_free always const fn r=Vtec234 a=taiki-e

`if` expression can only be used in const fn since Rust 1.46, so const `is_lock_free` was require Rust 1.46 (context: #531, #546).
However, when we replace uses of `if` expression with `|` and `&` operators, it seems `is_lock_free` can be used as const fn even in Rust 1.36.

r? @jeehoonkang or @Vtec234 

Co-authored-by: Taiki Endo <te316e89@gmail.com>
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging a pull request may close this issue.

2 participants