Oh, I don't think recovery from poison is why poisoning is good. The reason poisoning is good is that at the moment you've acquired a lock on a mutex, you should be able to assume that the invariants guarded by the mutex are upheld (and panic if not).
Mutex doesn't promise to uphold any more invariants than `&mut T` does. If the state can be corrupted by a panic while holding `&mut T`, I don't think there's any good reason to expect that obtaining it through `MutexGuard` should make any difference.
Panic propagation is typically handled much better at thread `join()` boundaries.
A panic in single-threaded, non-parallel code will either terminate the program or be recovered cleanly, so the potential for side effects to be silently observed in a way that breaks invariants is unique to Mutex<>. This is the reason for mutex poisoning,
I fail to see that there is any material difference. Whether you catch-unwind within a single thread or in a separate thread such that the panic can be resumed on join makes zero difference.
Heck, you can have Drop impls observing the state while unwinding.
A true panic-safe data structure requires serious thought, and mutex poisoning does nothing here - it is neither necessary nor sufficient.
This is a false dichotomy. Not every technique needs to work in all cases in order to be useful.
This seems analogous to arguing that because seat belts don't save the lives of all people involved in car crashes, and they're kind of annoying, then they shouldn't be factory-standard.
This is a case of a feature that is actively harmful for the things it tries to prevent, because it increases the risk in practice of panics "spreading" throughout a system, even after the programmer thought she had finished handling it, and because it gives a false impression what kind of guarantee you actually have.
I understand what you mean, but you're saying has not been true for me in practice. Mutexes absolutely are used to uphold invariants in a way that &mut T is much less often.
There's something to be said here about what I've sometimes called the cancellation blast radius. The issues with cancellation happen when the data corruption/invariant violation is externally visible (if the corrupt data is torn down, who cares.) Mutexes make data corruption externally visible very often.
In projects I've worked on, this just hasn't been the case. Mutexes, especially in Rust, can grant you a `&mut T` when what you have is `&Mutex<T>`, and that's it - failing to uphold invariants in the API surface of `T` is a bug whether or not it lives inside a mutex.
Lots of data structures need to care about panic-safety. Inserting a node in a tree must leave the tree in a valid state if allocating memory for the new node fails, for example. All of that is completely orthogonal to whether or not the data structure is also observable from multiple threads behind a mutex, and I would argue especially in the case of mutex, whose purpose it is to make an object usable from multiple threads as-if they had ownership.
Acknowledging that panic safety is a real issue with data structures that mutex poisoning does not solve, I don't think we're going to agree on anything else here, unfortunately. We probably have entirely different experiences writing software -- mutex poisoning is very valuable in higher-level code.