@@ -273,6 +273,12 @@ static inline class_##_name##_t class_##_name##ext##_constructor(_init_args) \
273273 * an anonymous instance of the (guard) class, not recommended for
274274 * conditional locks.
275275 *
276+ * if_not_guard(name, args...) { <error handling> }:
277+ * convenience macro for conditional guards that calls the statement that
278+ * follows only if the lock was not acquired (typically an error return).
279+ *
280+ * Only for conditional locks.
281+ *
276282 * scoped_guard (name, args...) { }:
277283 * similar to CLASS(name, scope)(args), except the variable (with the
278284 * explicit name 'scope') is declard in a for-loop such that its scope is
@@ -285,14 +291,20 @@ static inline class_##_name##_t class_##_name##ext##_constructor(_init_args) \
285291 * similar to scoped_guard(), except it does fail when the lock
286292 * acquire fails.
287293 *
294+ * Only for conditional locks.
288295 */
289296
297+ #define __DEFINE_CLASS_IS_CONDITIONAL (_name , _is_cond ) \
298+ static __maybe_unused const bool class_##_name##_is_conditional = _is_cond
299+
290300#define DEFINE_GUARD (_name , _type , _lock , _unlock ) \
301+ __DEFINE_CLASS_IS_CONDITIONAL(_name, false); \
291302 DEFINE_CLASS(_name, _type, if (_T) { _unlock; }, ({ _lock; _T; }), _type _T); \
292303 static inline void * class_##_name##_lock_ptr(class_##_name##_t *_T) \
293- { return *_T; }
304+ { return (void *)(__force unsigned long) *_T; }
294305
295306#define DEFINE_GUARD_COND (_name , _ext , _condlock ) \
307+ __DEFINE_CLASS_IS_CONDITIONAL(_name##_ext, true); \
296308 EXTEND_CLASS(_name, _ext, \
297309 ({ void *_t = _T; if (_T && !(_condlock)) _t = NULL; _t; }), \
298310 class_##_name##_t _T) \
@@ -303,16 +315,48 @@ static inline class_##_name##_t class_##_name##ext##_constructor(_init_args) \
303315 CLASS(_name, __UNIQUE_ID(guard))
304316
305317#define __guard_ptr (_name ) class_##_name##_lock_ptr
318+ #define __is_cond_ptr (_name ) class_##_name##_is_conditional
306319
307- #define scoped_guard (_name , args ...) \
308- for (CLASS(_name, scope)(args), \
309- *done = NULL; __guard_ptr(_name)(&scope) && !done; done = (void *)1)
310-
311- #define scoped_cond_guard (_name , _fail , args ...) \
312- for (CLASS(_name, scope)(args), \
313- *done = NULL; !done; done = (void *)1) \
314- if (!__guard_ptr(_name)(&scope)) _fail; \
315- else
320+ /*
321+ * Helper macro for scoped_guard().
322+ *
323+ * Note that the "!__is_cond_ptr(_name)" part of the condition ensures that
324+ * compiler would be sure that for the unconditional locks the body of the
325+ * loop (caller-provided code glued to the else clause) could not be skipped.
326+ * It is needed because the other part - "__guard_ptr(_name)(&scope)" - is too
327+ * hard to deduce (even if could be proven true for unconditional locks).
328+ */
329+ #define __scoped_guard (_name , _label , args ...) \
330+ for (CLASS(_name, scope)(args); \
331+ __guard_ptr(_name)(&scope) || !__is_cond_ptr(_name); \
332+ ({ goto _label; })) \
333+ if (0) { \
334+ _label: \
335+ break; \
336+ } else
337+
338+ #define scoped_guard (_name , args ...) \
339+ __scoped_guard(_name, __UNIQUE_ID(label), args)
340+
341+ #define __scoped_cond_guard (_name , _fail , _label , args ...) \
342+ for (CLASS(_name, scope)(args); true; ({ goto _label; })) \
343+ if (!__guard_ptr(_name)(&scope)) { \
344+ BUILD_BUG_ON(!__is_cond_ptr(_name)); \
345+ _fail; \
346+ _label: \
347+ break; \
348+ } else
349+
350+ #define scoped_cond_guard (_name , _fail , args ...) \
351+ __scoped_cond_guard(_name, _fail, __UNIQUE_ID(label), args)
352+
353+ #define __if_not_guard (_name , _id , args ...) \
354+ BUILD_BUG_ON(!__is_cond_ptr(_name)); \
355+ CLASS(_name, _id)(args); \
356+ if (!__guard_ptr(_name)(&_id))
357+
358+ #define if_not_guard (_name , args ...) \
359+ __if_not_guard(_name, __UNIQUE_ID(guard), args)
316360
317361/*
318362 * Additional helper macros for generating lock guards with types, either for
@@ -347,7 +391,7 @@ static inline void class_##_name##_destructor(class_##_name##_t *_T) \
347391 \
348392static inline void *class_##_name##_lock_ptr(class_##_name##_t *_T) \
349393{ \
350- return _T->lock; \
394+ return (void *)(__force unsigned long) _T->lock; \
351395}
352396
353397
@@ -369,14 +413,17 @@ static inline class_##_name##_t class_##_name##_constructor(void) \
369413}
370414
371415#define DEFINE_LOCK_GUARD_1 (_name , _type , _lock , _unlock , ...) \
416+ __DEFINE_CLASS_IS_CONDITIONAL(_name, false); \
372417__DEFINE_UNLOCK_GUARD(_name, _type, _unlock, __VA_ARGS__) \
373418__DEFINE_LOCK_GUARD_1(_name, _type, _lock)
374419
375420#define DEFINE_LOCK_GUARD_0 (_name , _lock , _unlock , ...) \
421+ __DEFINE_CLASS_IS_CONDITIONAL(_name, false); \
376422__DEFINE_UNLOCK_GUARD(_name, void, _unlock, __VA_ARGS__) \
377423__DEFINE_LOCK_GUARD_0(_name, _lock)
378424
379425#define DEFINE_LOCK_GUARD_1_COND (_name , _ext , _condlock ) \
426+ __DEFINE_CLASS_IS_CONDITIONAL(_name##_ext, true); \
380427 EXTEND_CLASS(_name, _ext, \
381428 ({ class_##_name##_t _t = { .lock = l }, *_T = &_t;\
382429 if (_T->lock && !(_condlock)) _T->lock = NULL; \
0 commit comments