-
Notifications
You must be signed in to change notification settings - Fork 237
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
Replace static mut
for CORE1_STACK
#864
Comments
Yeah we shouldn't use a reference here - a pointer is fine. But not a *const u8 because it might not be sufficiently aligned. For the global a UnsafeCell with a MaybeUninit makes sense because we don't need to init the stack to anything. |
The Stack struct itself ensures the address is sufficiently aligned, is that not enough? |
If the argument is a pointer to a u8, what forces them to use the Stack struct? |
Well if the spawn function takes a pointer it doesn't really matter if it's a So that would be an argument to find a different solution, where spawn gets passed some reference or struct that actually guarantees alignment. It's not like the current function signature is wrong. It's just that the most obvious way to get a reference with a static lifetime, using a |
We could make |
As I understand it, as soon as the function takes a pointer, it must be unsafe, as a pointer could be anything, and there's no feasible runtime check to ensure it's valid. (Alignment is not the only issue.) And once we make it unsafe, we are technically free to just assume it's properly aligned, given we document the function accordingly. Sure, panicking if we can detect an invalid pointer would be a nice safeguard. I would prefer a safe API where the type system guarantees a valid argument, like we currently have. |
So, something like: use std::sync::atomic::Ordering;
use std::sync::atomic::AtomicBool;
use std::mem::MaybeUninit;
use std::cell::UnsafeCell;
#[repr(C, align(65536))]
struct Stack<const N: usize> {
inner: UnsafeCell<MaybeUninit<[u8; N]>>,
taken: AtomicBool
}
unsafe impl<const N: usize> Sync for Stack<N> {}
impl<const N: usize> Stack<N> {
const fn new() -> Stack<N> {
Stack {
inner: UnsafeCell::new(unsafe { MaybeUninit::zeroed().assume_init() }),
taken: AtomicBool::new(false),
}
}
fn get(&self) -> *const u8 {
// I guess if you have CAS, you could do that
if self.taken.load(Ordering::Relaxed) {
panic!("Stack taken");
}
self.taken.store(true, Ordering::Relaxed);
(&raw const self.inner).cast()
}
}
fn spawn<const N: usize>(stack: &Stack<N>) {
println!("Buffer starts at {:p}", stack.get())
}
static STACK: Stack<8192> = Stack::new();
fn main() {
spawn(&STACK);
} |
Yes, for example.
Advantage:
Disadvantage:
BTW, passing a |
Also note that if this assessment is correct, we need to change the signature of |
I'm not sure I'm comfortable passing around an |
Yes, that's exactly what I meant with "Also note that if this assessment is correct, we need to change the signature of spawn anyway to make it sound." While it would be nice to not break the current API, I don't think this can't be sound. So we have to change it. Still thinking about the best alternative. But yes, it probably needs to be some struct that's passed by shared reference. |
How about such an interface?
So
With this approach, it's also possible to place the stack in RAM4 by defining appropriate linker symbols and calling Design considerations:
|
I love it. |
Both in our docs and in some examples, we suggest using a
static mut
for allocating memory for core1's stack:With rust 1.83, this will cause a warning (at least it does with current beta), and with edition 2024 the lint will become deny-by-default. (https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html)
Therefore, we should suggest something else. Maybe we should also change the signature of
multicore::Core::spawn
to take a pointer instead of a&'static mut
for the stack?The text was updated successfully, but these errors were encountered: