Re: [PATCH RFC 0/2] rust: sync: create lock class using `#[track_caller]`

From: Gary Guo

Date: Sat Jul 04 2026 - 13:46:54 EST


On Sat Jul 4, 2026 at 6:10 PM BST, Peter Zijlstra wrote:
> On Sat, Jul 04, 2026 at 05:52:35PM +0100, Gary Guo wrote:
>> On Fri Jul 3, 2026 at 11:32 PM BST, Peter Zijlstra wrote:
>> > On Fri, Jul 03, 2026 at 03:24:29PM +0100, Gary Guo wrote:
>> >> [snip] On the lockdep side,
>> >> essentially the name will be "(rust)", while the actual name can be retrieved
>> >> from the lock class key.
>> >>
>> >> So for
>> >>
>> >> let foo = KBox::pin_init(Mutex::new(42));
>> >>
>> >> in, say, foo.c:123
>> >>
>> >> it will eventually call
>> >>
>> >> struct rust_location *loc = /* static generated by the Rust compiler */;
>> >> mutex_init_lockdep(foo, "(rust)", (struct lock_class_key *)loc)
>> >>
>> >> And when "(rust)" is encountered as lock class name, instead of printing the
>> >> string as is, lockdep will call
>> >>
>> >> lockdep_print_rust_name(loc)
>> >>
>> >> which will be doing essentially
>> >>
>> >> pr_cont("foo.c:123");
>> >
>> > That seems quite terrible. The C names are based on the expression used
>> > to initialize the class and are thus somewhat descriptive. But file:line
>> > combos are horrid identifiers for locks.
>> >
>> > Why would you want to do this?
>>
>> I do think this is not ideal, however the current code is already doing this.
>> This RFC series isn't changing the name at all, just represent this in a
>> different way.
>>
>> The reason that file:line is used for names is due to the fundamental difference
>> between initialization in C and Rust. In C you create something uninitialized
>> first, and then initialize it, and it'll be UB if the value is used before
>> initialization or (for some types) initialize a value twice. In Rust we use
>> pin_init to ensure that a value cannot be used uninitialized.
>>
>> The way the syntax is write out currently is something like
>>
>> pin_init!(MyStruct {
>> my_mutex <- new_mutex!(initial_data),
>> })
>>
>> [
>> which this series is turning it to
>>
>> pin_init!(MyStruct {
>> my_mutex <- Mutex::new(initial_data),
>> })
>> ]
>>
>> as you can see the `new_mutex!` or `Mutx::new` does not know where it is going
>
> To be frank, no I don't see. I have absolutely no frigging clue what any
> of that means :-(
>
>> to be initialized to, because we prevent people from being able to name a
>> yet-to-be-initialized place.
>>
>> It is possible to use the C approach (which early days of Rust-for-Linux does
>> use), but doing so require a lot of unsafe keywords because you are relying on
>> the programmer to not mess things up, instead of having the compiler check.
>>
>> So the best alternative that we can use for the name under this constraint is
>> the file:line combo. It is less descriptive, but at least it does tell you where
>> the lock class is used, so you can still trace it back. Given lockdep is a
>> debugging feature, I think the less descriptive name, albeit inconvenient, is
>> not a dealbreaker.
>
> People already struggle to make sense of lockdep reports, this isn't
> going to make it better :/
>
>> The trade off here is the convenience of creating a lock (safely) vs the
>> descriptiveness of the name, and I think the former is more important. It is
>> still possible to explicit give a name if it helps (Binder is actually doing
>> this already), but this currently cannot be implicitly created.
>
> Like I said, Rust is still line noise to me, and I really don't
> understand anything you've just tried to tell me.
>
> Now, I do speak (some) C++, and the new thing you mention got me
> thinking you're talking about a constructor. Are you trying to say that
> since the invocation of the constructor is somewhat implicit, there is
> no good way to stringize the structure member name and store it?

It's indeed somewhat similar to a C++ constructor (the actual mechanism is
different, but conceptually they're similar). You do get explicit invocation
(there's no implicit invocation of constructors like C++, you can see this as
similar to C++'s constructor with "explicit" keyword).

But the gist here is correct, there's no good way to stringify the structure
member name.

> That said, in C++ you can mandate a string be handed to the constructor;
> this would mean everybody would need to explicitly provide a descriptive
> name, surely Rust can do this same? Every !debug build could then
> instantly ignore that string, but at least it'd be there.

It's certainly possible to give explicit names (this is what patch 1/2's
"new_with_name" function is for). To mandate names being provided we just need
to remove the constructor function without the name. That said, I am not sure
that we want everyone to explicitly give names. Especially for types like
delayed_work where it needs two lock classes and names, it's somewhat
leaky abstraction if the constructor asks to user to provide a name for its
work completion and a name for its timer (as it's not possible to concat strings
without allocation without using macros).

Best,
Gary