This is just a bad driver model. There's no reason for a driver to have any complex data structures or structure lifetimes. Hardware is highly finite and static.
Conversation
The OS infrastructure using/interfacing with the drivers should be the component responsible for awareness of connections between hardware/drivers, user or kernel space consumers using the hardware, etc. and driver should have no access to these structures.
1
Rust discourages having shared ownership (Rc, Arc), but there end up being use cases for it. It just isn't the normal way to design / implement things. It's painful to use Rust if you don't design things around simple ownership models because it forces it to be verified as safe.
1
1
The code is very clean if you have unique ownership and use lots of lightweight references. If you have complex data structures, like linked data structures with cycles and mutability, you are forced into using Rc / RefCell or a similar approach which really discourages doing it.
1
So for example, if you have a nice recursive tree data structure, you can represent that with the nodes as Box<T>, which is a uniquely owned dynamic allocation. If you want to have cycles back from the children to the parent nodes, you need Rc<T> with Weak<T> for parent pointers.
1
So when you are actually using the parent pointer, you call upgrade(), which gives you an Option<Rc<T>> (since it might have been deallocated). You can do it, but you're encouraged to do things in a more simple way by the requirement for safety, like avoiding reference cycles.
2
Honestly that's very complicated and would discourage me from using those conventions unless it's a project requirement or if the outcome was clearly positive.
I'll think about it more carefully. There's a lot I think I only partially understand here. 1/
2
Well it's worth noting these are all library features and in a kernel you are only using libcore rather than libstd which builds on it. You'd want to smart pointers and collections returning Option from methods making them for handling out-of-memory without needing unwinding.
2
Just had a thought. What about depth of preemption ?
Kernel lock hierarchies have different levels of preemptability. The graphs that they form intersect and nodes below them have to guarantee safety for both locking parents. Typically file system drivers 1/
1
can get quite complicated here and the IO subsystems they call to work on their behalf 2/
1
Rust enforces memory safety including full type safety and preventing data races but doesn't prevent higher level race conditions, deadlocks, memory leaks via something like an Rc<T> cycle, etc. It definitely makes it easier to avoid a lot of these things, but they're possible.
There is a lot of safety that matters beyond just memory / type safety and preventing data races. It's good at providing a lot of it, but it doesn't consider it unsafe, so it can't claim to outright prevent it in safe code, even though it makes stuff like memory leaks way harder.


