On Tue, Jun 6, 2023 at 11:08 AM Peter Zijlstra <peterz@xxxxxxxxxxxxx> wrote:> > Would it all be less offensive if I did: s/guard/cleanup/ on the whole > thing? It's more than "guard" for me. What is "ptr"? Why? We already know of at least one case where it's not a pointer at all, ie 'struct fd'. So I *really* hate the naming. Absolutely none of it makes sense to me. One part is a nonsensical name apparently based on a special-case operation, and the other part is a nonsensical type from just one random - if common - implementation issue. What you want to do is to have a way to define and name a "constructor/desctructor" pair for an arbitrary type - *not* necessarily a pointer - and then optionally a way to say "Oh, don't do the destructor, because I'm actually going to use it long-term". I said "cleanup", but that's not right either, since we always have to have that initializer too. Maybe just bite the bullet, and call the damn thing a "class", and have some syntax like DEFINE_CLASS(name, type, exit, init, initarg...); to create the infrastructure for some named 'class'. So you'd have DEFINE_CLASS(mutex, struct mutex *, mutex_unlock(*_P), ({mutex_lock(mutex); mutex;}), struct mutex *mutex) to define the mutex "class", and do DEFINE_CLASS(fd, struct fd, fdput(*_P), fdget(f), int f) for the 'struct fd' thing. The above basically would just create the wrapper functions (and typedefs) for the constructor and destructor. So the 'DEFINE_CLASS(mutex ..)' thing would basically just expand to typedef struct mutex *class_mutex_type; static inline void class_mutex_destructor(class_mutex_type *_C) { mutex_unlock(*_C); } static inline class_mutex_type class_mutex_constructor(struct mutex *mutex) { return ({mutex_lock(mutex); mutex;}); } Then to _instantiate_ one of those, you'd do INSTANTIATE_CLASS(name, var) which would expand to class_name_type var __attribute__((__cleanup__(class_name_destructor))) = class_name_constructor and the magic of that syntax is that you'd actually use that "INSTANTIATE_CLASS()" with the argument to the init function afterwards, so you'd actually do INSTANTIATE_CLASS(mutex, n)(&sched_domains_mutex); to create a variable 'n' of class 'mutex', where the class_mutex_constructor gets the pointer to 'sched_domain_mutex' as the argument. And at THAT point, you can do this: #define mutex_guard(m) \ INSTANTIATE_CLASS(mutex, __UNIQUE_ID(mutex))(m) and now you can do mutex_guard(&sched_domains_mutex); to basically start a guarded section where you hold 'sched_domains_mutex'. And in that *very* least situation, 'guard' makes sense in the name. But no earlier. And there is absolutely no 'ptr' anywhere here. The above should work also for the 'struct fd' case, so you can do INSTANTIATE(fd, f)(fd); to create a 'struct fd' named 'f' that is initialized with 'fdget(fd)', and will DTRT when going out of scope. Modulo any stupid errors I did. And ok, I didn't write out the exact macro magic to *get* those expansions above (I just tried to write out the approximate end result), but it should be mostly fairly straightforward. So it would be the usual token pasting tricks to get the 'class type', the 'class destructor' and the 'class constructor' functions. Finally, note that the "initarg" part is a macro vararg thing. The initargs can be empty (for things like RCU), but it could also possibly be multiple arguments (like a "size and gfp_flags" for an allocation?). I'm sure there's something horribly wrong in the above, but my point is that I'd really like this to make naming and conceptual sense. And if somebody goes "The above is basically exactly what the original C++ compiler did back when it was really just a pre-processor for C", then you'd be 100% right. The above is basically (a part of) what Bjarne did, except he did it as a separate pass. And to answer the next question: why not just give up and do C++ - it's because of all the *other* things Bjarne did. Linus