I have the following code, which runs fine on Mac and Windows, but panics on Ubuntu Linux. The panic is at the borrow_mut and the indication is that server is already immutably borrowed. That would seem to indicate that the if leaked the server borrow, which I wasn't expecting it to do. I then wrapped the 3 ifs within a { } and Ubuntu Linux no longer panics. Which I think proves that the if leaked the borrow. Am I wrong? is this expected? Or, is there something else going on with Rust and AtomicRefCell that I'm unaware of?
AtomicRefCell comes from atomic_refcell.
static server: AtomicRefCell<Server> = AtomicRefCell::new(Server {..});
...
if let ServerField::Executor(executor) = &server.borrow().executor {
executor.stop();
}
if let ServerField::Scheduler(scheduler) = &server.borrow().scheduler {
scheduler.stop()
}
if let ServerField::Monitor(monitor) = &server.borrow().monitor {
monitor.stop()
}
let mut s = server.borrow_mut();
...
Here's the code that works with all 3 platforms:
// ensure that server.borrows don't leak out.
{
if let ServerField::Executor(executor) = &server.borrow().executor {
executor.stop();
}
if let ServerField::Scheduler(scheduler) = &server.borrow().scheduler {
scheduler.stop()
}
if let ServerField::Monitor(monitor) = &server.borrow().monitor {
monitor.stop()
}
}
let mut s = server.borrow_mut();
...
Here is a complete impl to illustrate the problem. main.rs:
use atomic_refcell::AtomicRefCell;
#[allow(non_upper_case_globals)]
static server: AtomicRefCell<Server> = AtomicRefCell::new(Server {
value: ServerField::Uninitialized,
});
#[derive(Debug)]
pub struct Server {
value: ServerField,
}
#[derive(Debug)]
enum ServerField {
Uninitialized,
Value(usize),
}
fn start() {
server.borrow_mut().value = ServerField::Value(41);
}
fn stop() {
// enclose this in a scope to not panic
let borrow = &server.borrow();
println!("value is {:#?}", borrow.value);
drop(borrow);
// end scope
let mut s = server.borrow_mut();
s.value = ServerField::Uninitialized;
}
fn main() {
println!("Hello, world!");
start();
stop();
}
#[cfg(test)]
pub mod tests {
use super::*;
#[test]
fn test() {
start();
stop();
}
}
Add this to your Cargo.toml:
[dependencies]
atomic_refcell = "0.1"
In this example an if let is employed with a RHS of &server.borrow().value, which doesn't panic on Mac but may panic on Ubuntu Linux (I don't have a Linux box, and didn't upload to GitHub and create a workflow). However, this mirrors my code that I do have on GitHub with a workflow, where it showed that behavior.
use atomic_refcell::AtomicRefCell;
#[allow(non_upper_case_globals)]
static server: AtomicRefCell<Server> = AtomicRefCell::new(Server {
value: ServerField::Uninitialized,
});
#[derive(Debug)]
pub struct Server {
value: ServerField,
}
#[derive(Debug)]
enum ServerField {
Uninitialized,
Value(usize),
}
fn start() {
server.borrow_mut().value = ServerField::Value(41);
}
fn stop() {
if let ServerField::Value(val) = &server.borrow().value {
println!("value is {:#?}", val);
}
let mut s = server.borrow_mut();
s.value = ServerField::Uninitialized;
}
fn main() {
println!("Hello, world!");
start();
stop();
}
#[cfg(test)]
pub mod tests {
use super::*;
#[test]
fn test_start_stop() {
start();
stop();
}
}