Mutex<T> is ever so slightly more painful to use than RefCell<T> for the single-threaded case, because if a thread panics it poisons the mutexes as it unwinds (to avoid inconsistent state). So instead of borrow() you do get().unwrap() which propagates the failure across threads.
Conversation
If you don't have unwinding, which Rust doesn't require, you don't need that, so in a kernel Mutex wouldn't actually be any more verbose than the single-threaded version of shared ownership mutability (RefCell). There's also Cell, if you only need mutation and not mutable refs.
1
There's a good example here:
doc.rust-lang.org/std/sync/struc
Basically in an environment without unwinding, you don't need it to return Option<T> since it will always succeed. Linux kernel's concept of an 'oops' is what Rust calls panic. Rust without unwinding is like panic_on_oops=1.
1
So what returning Option<T> there does propagate the failure if a thread actually panics while holding the mutex lock, since it might have left whatever it's protecting in an inconsistent state. If you just abort on panic, you don't need that part of the API design.
1
In general, you're encouraged to communicate across threads via channels, but there's still a lot of use for atomic reference counting / shared data (especially for performance), and it's an interesting example of how safety is provided via these types and the Send/Sync traits.
1
If you're trying to check higher level correctness with further static analysis, it's much more feasible for code verified as being free of memory safety, type confusion, data races, etc. It has to be much more structured to pass compiler type checks and is a foundation for more.
1
You can also use the type system to provide safety beyond memory safety, the language just doesn't mandate / enforce opting into it. For example, an approach like github.com/iliekturtles/u for verifying units in physics code if it's a useful way of catching bugs in your domain.
1
What about a mutex with a compound safety requirement ?
It’s a common structure in kernel to have a spin-lock with the additional requirement that it also be interrupt-safe. Basically two locks in one mutex type structure. These do not have a blocking semantic btw
1
You can definitely implement that, and the high-level Mutex type implementation could even be reused with a different underlying lock type which just looks like github.com/rust-lang/rust. Rust as a language doesn't know about threads or locks other than Send/Sync as traits.
1
This is the high-level type building it into a safe abstraction:
github.com/rust-lang/rust
It's what you end up doing in a kernel. A small % of the code uses unsafe blocks to build safe abstractions used by the majority of the code. The vast majority of the code can be safe.
1
For example, a microkernel needs a very thin layer of unsafe code implementing the mechanism for communication because the tasks. Most of the communication layer can be implemented in safe code, and it doesn't impose unsafety everywhere else. You can keep the TCB very small.
Communication within the same address space is similar. You build safe abstractions for each communication primitive that you want to use, and those are what the rest of the code uses. You can also assemble a lot of the concurrency building blocks out of safe lower level APIs.

