←back to thread

Futurelock: A subtle risk in async Rust

(rfd.shared.oxide.computer)
421 points bcantrill | 8 comments | | HN request time: 1.079s | source | bottom

This RFD describes our distillation of a really gnarly issue that we hit in the Oxide control plane.[0] Not unlike our discovery of the async cancellation issue[1][2][3], this is larger than the issue itself -- and worse, the program that hits futurelock is correct from the programmer's point of view. Fortunately, the surface area here is smaller than that of async cancellation and the conditions required to hit it can be relatively easily mitigated. Still, this is a pretty deep issue -- and something that took some very seasoned Rust hands quite a while to find.

[0] https://github.com/oxidecomputer/omicron/issues/9259

[1] https://rfd.shared.oxide.computer/rfd/397

[2] https://rfd.shared.oxide.computer/rfd/400

[3] https://www.youtube.com/watch?v=zrv5Cy1R7r4

1. forrestthewoods ◴[] No.45776951[source]
I feel like I’m pretty good at writing multithreaded code. I’ve done it a lot. As long as you use primitives like Rust Mutex that enforce correctness for data access (ie no accessing data without the lock) it’s pretty simple. Define a clean boundary API and you’re off to the races.

async code is so so so much more complex. It’s so hard to read and rationalize. I could not follow this post. I tried. But it’s just a full extra order of complexity.

Which is a shame because async code is supposed to make code simpler! But I’m increasingly unconfident that’s true.

replies(2): >>45777647 #>>45779215 #
2. amelius ◴[] No.45777647[source]
Async code is simpler because you're implicitly holding a lock on the CPU. That's also why you should stay away from it: it increases latency. Especially since Rust is about speed and responsiveness. In general, async programming in Rust makes little sense.
replies(1): >>45778182 #
3. forrestthewoods ◴[] No.45778182[source]
I love Rust. But I’m 100% convinced Rust chose the wrong tradeoffs with their async model. Just give me green threads and use malloc to grow the stack. It’s fine. That would have been better imho.
replies(2): >>45778838 #>>45780751 #
4. mjevans ◴[] No.45778838{3}[source]
Hell, even force threads to be allocated from a bucket of N threads defined at compile time. Surely that'd work for embedded / GPU space?
5. foota ◴[] No.45779215[source]
Async code isn't supposed to be simpler than sync code, it's supposed to be simpler than doing thing like continuation passing.
6. gf000 ◴[] No.45780751{3}[source]
You can't have a low-level language and green threads at the same time.
replies(2): >>45783318 #>>45783319 #
7. forrestthewoods ◴[] No.45783319{4}[source]
Why not?
8. forrestthewoods ◴[] No.45783318{4}[source]
Why not?