On Tue, 20 Sep 2022 10:55:27 -0500 "Eric W. Biederman" <ebiederm@xxxxxxxxxxxx> wrote: > Linus Torvalds <torvalds@xxxxxxxxxxxxxxxxxxxx> writes: > > > On Mon, Sep 19, 2022 at 4:58 PM Linus Torvalds > > <torvalds@xxxxxxxxxxxxxxxxxxxx> wrote: > >> > >> This is not some kind of "a few special things". > >> > >> This is things like absolutely _anything_ that allocates memory, or > >> takes a lock, or does a number of other things. > > > > Examples of "number of other things" ends up being things like > > "accessing user memory", which depending on what you are doing may > > be very common too. > > > > And btw, it's not only about the (multiple kinds of) atomic regions. > > > > We have other context rules in the kernel too, like "does floating > > point or vector unit calculations". Which you can actually do, but > > only in a kernel_fpu_begin/kernel_fpu_end region. > > > > Now, the floating point thing is rare enough that it's probably fine > > to just say "no floating point at all in Rust code". It tends to be > > very special code, so you'd write it in C or inline assembly, > > because you're doing special things like using the vector unit for > > crypto hashes using special CPU instructions. > > I just want to point out that there are ways of representing things > like the context you are running in during compile time. I won't > argue they are necessarily practical, but there are ways and by > exploring those ways some practical solutions may result. > > Instead of saying: > spin_lock(&lock); > do_something(); > spin_unlock(&lock); > > It is possible to say: > with_spin_lock(&lock, do_something()); > > This can be taken a step farther and with_spin_lock can pass a > ``token'' say a structure with no members that disappears at compile > time that let's the code know it has the spinlock held. > > In C I would do: > struct have_spin_lock_x { > // nothing > }; > > do_something(struct have_spin_lock_x context_guarantee) > { > ...; > } > > I think most of the special contexts in the kernel can be represented > in a similar manner. A special parameter that can be passed and will > compile out. > > I don't recall seeing anything like that tried in the kernel so I > don't know if it makes sense or if it would get too wordy to live, > but it is possible. If passing a free context parameter is not too > wordy it would catch silly errors, and would hopefully leave more > mental space for developers to pay attention to the other details of > the problems they are solving. > > *Shrug* I don't know if rust allows for free parameters like that and > if it does I don't know if it would be cheap enough to live. I believe this was mentioned by Wedson in one of his previous emails. This pattern is quite common in Rust code. It looks like this: #[derive(Clone, Copy)] pub struct Token<'a>(PhantomData<&'a ()>); pub fn with_token<T>(f: impl for<'a> FnOnce(Token<'a>) -> T) -> T { f(Token(PhantomData)) } Any function that requires something can just take token by value, e.g. with `token: Token<'_>`. Since Token is a zero-sized type (ZST), this parameter will be omitted during code generation, so it won't affect the ABI and this has no runtime cost. Example on godbolt: https://godbolt.org/z/9n954cG4d, showing that the token is actually all optimised out. It should be noted however, atomic context is not something that a token can represent. You can only use tokens to restrict what you *can* do, but not what you *can't* do. There is no negative reasoning with tokens, you can't create a function that can only be called when you don't have token. You can use tokens to represent non-atomic contexts, but that'll be really painful because this requires carrying a token in almost all functions. This kind of API also works well for FPU contexts. Best, Gary