On Mon, Jun 12, 2023 at 10:12 AM Sean Christopherson <seanjc@xxxxxxxxxx> wrote: > > What if we require that all guarded sections have explicit scoping? E.g. drop > the current version of guard() and rename scoped_guard() => guard(). And then > figure out macro magic to guard an entire function? Hmm. I didn't love the excessive scoping, but most of the cases I was thinking about were for the freeing part, not the locking part. I agree that explicit scoping might be a good idea for locks as a rule, but that "entire function" case _is_ a special case, and I don't see how to do it sanely with a scoping guard. Unless you accept ugly syntax like int fn(..) { scoped_guard(rcu)() { ... }} which is just a violation of our usual scoping indentation rules. Of course, at that point, the "scoped" part doesn't actually buy us anything either, so you'd probably just be better off listing all the guarding locks, and make it be int fn(..) { guard(rcu)(); guard(mutex)(&mymutex); { ... }} or whatever. Ugly, ugly. End result: I think the non-explicitly scoped syntax is pretty much required for sane use. The scoped version just causes too much indentation (or forces us to have the above kind of special "we don't indent this" rules). > IIUC, function scopes like that will be possible once > -Wdeclaration-after-statement goes away. Well, "-Wdeclaration-after-statement" already went away early in Peter's series, because without that you can't sanely do the normal "__free()" cleanup thng. But no, it doesn't help the C syntax case. If you were to wrap a whole function with a macro, you need to do some rather ugly things. They are ugly things that we already do: see our whole "SYSCALL_DEFINEx()" set of macros, so it's not *impossible*, but it's not possible with normal C syntax (and the normal C preprocessor). Of course, one way to do the "whole function scope" is to just do it in the caller, and not using the cleanup attribute at all. IOW, we could have things like #define WRAP(a,b,c) \ ({ __typeof__(b) __ret; a; __ret = (b); c; __ret; }) and then you can do things like #define guard_fn_mutex(mutex, fn) \ WRAP(mutex_lock(mutex), fn, mutex_unlock(mutex)) or #define rcu_read_action(x) WRAP(rcu_read_lock(), x, rcu_read_unlock()) and now you can easily guard the call-site (or any simple expression that doesn't include any non-local control flow). Nothing new and fancy required. But when you don't want to do the wrapping in the caller, you do want to have a non-scoping guard at the top of the function, I suspect. Linus