1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2024-2026 The FreeBSD Foundation 5 * 6 * This software was developed by Björn Zeeb under sponsorship from 7 * the FreeBSD Foundation. 8 */ 9 10 #ifndef _LINUXKPI_LINUX_CLEANUP_H 11 #define _LINUXKPI_LINUX_CLEANUP_H 12 13 #include <linux/err.h> 14 15 #define CLEANUP_NAME(_n, _s) __CONCAT(__CONCAT(cleanup_, _n), _s) 16 17 #define __cleanup(_f) __attribute__((__cleanup__(_f))) 18 19 #define DECLARE(_n, _x) \ 20 CLEANUP_NAME(_n, _t) _x __cleanup(CLEANUP_NAME(_n, _destroy)) = \ 21 CLEANUP_NAME(_n, _create) 22 23 /* 24 * Note: "_T" are special as they are exposed into common code for 25 * statements. Extra care should be taken when changing the code. 26 */ 27 #define DEFINE_GUARD(_n, _dt, _lock, _unlock) \ 28 \ 29 typedef _dt CLEANUP_NAME(_n, _t); \ 30 \ 31 static inline _dt \ 32 CLEANUP_NAME(_n, _create)( _dt _T) \ 33 { \ 34 _dt c; \ 35 \ 36 c = ({ _lock; _T; }); \ 37 return (c); \ 38 } \ 39 \ 40 static inline void \ 41 CLEANUP_NAME(_n, _destroy)(_dt *t) \ 42 { \ 43 _dt _T; \ 44 \ 45 _T = *t; \ 46 if (_T) { _unlock; }; \ 47 } 48 49 /* We need to keep these calls unique. */ 50 #define _guard(_n, _x) \ 51 DECLARE(_n, _x) 52 #define guard(_n) \ 53 _guard(_n, guard_ ## _n ## _ ## __COUNTER__) 54 55 #define DEFINE_FREE(_n, _t, _f) \ 56 static inline void \ 57 __free_ ## _n(void *p) \ 58 { \ 59 _t _T; \ 60 \ 61 _T = *(_t *)p; \ 62 _f; \ 63 } 64 65 #define __free(_n) __cleanup(__free_##_n) 66 67 /* 68 * Our initial version go broken up. Some simplifications like using 69 * "bool" for the lock had to be changed to a more general type. 70 * _T is still special and, like other bits, may not always be used, 71 * so tag with __unused (or better the LinuxKPI __maybe_unused). 72 */ 73 #define _DEFINE_LOCK_GUARD_0(_n, _lock) \ 74 static inline CLEANUP_NAME(_n, _t) \ 75 CLEANUP_NAME(_n, _create)(void) \ 76 { \ 77 CLEANUP_NAME(_n, _t) _tmp; \ 78 CLEANUP_NAME(_n, _t) *_T __maybe_unused; \ 79 \ 80 _tmp.lock = (void *)1; \ 81 _T = &_tmp; \ 82 _lock; \ 83 return (_tmp); \ 84 } 85 86 #define _DEFINE_LOCK_GUARD_1(_n, _type, _lock) \ 87 static inline CLEANUP_NAME(_n, _t) \ 88 CLEANUP_NAME(_n, _create)(_type *l) \ 89 { \ 90 CLEANUP_NAME(_n, _t) _tmp; \ 91 CLEANUP_NAME(_n, _t) *_T __maybe_unused; \ 92 \ 93 _tmp.lock = l; \ 94 _T = &_tmp; \ 95 _lock; \ 96 return (_tmp); \ 97 } 98 99 #define _GUARD_IS_ERR(_v) \ 100 ({ \ 101 uintptr_t x = (uintptr_t)(void *)(_v); \ 102 IS_ERR_VALUE(x); \ 103 }) 104 105 #define __is_cond_ptr(_n) \ 106 CLEANUP_NAME(_n, _is_cond) 107 #define __guard_ptr(_n) \ 108 CLEANUP_NAME(_n, _ptr) 109 110 #define _DEFINE_CLEANUP_IS_CONDITIONAL(_n, _b) \ 111 static const bool CLEANUP_NAME(_n, _is_cond) __maybe_unused = _b 112 113 #define _DEFINE_GUARD_LOCK_PTR(_n, _lp) \ 114 static inline void * \ 115 CLEANUP_NAME(_n, _lock_ptr)(CLEANUP_NAME(_n, _t) *_T) \ 116 { \ 117 void *_p; \ 118 \ 119 _p = (void *)(uintptr_t)*(_lp); \ 120 if (IS_ERR(_p)) \ 121 _p = NULL; \ 122 return (_p); \ 123 } 124 125 #define _DEFINE_UNLOCK_GUARD(_n, _type, _unlock, ...) \ 126 typedef struct { \ 127 _type *lock; \ 128 __VA_ARGS__; \ 129 } CLEANUP_NAME(_n, _t); \ 130 \ 131 static inline void \ 132 CLEANUP_NAME(_n, _destroy)(CLEANUP_NAME(_n, _t) *_T) \ 133 { \ 134 if (!_GUARD_IS_ERR(_T->lock)) { \ 135 _unlock; \ 136 } \ 137 } \ 138 \ 139 _DEFINE_GUARD_LOCK_PTR(_n, &_T->lock) 140 141 #define DEFINE_LOCK_GUARD_0(_n, _lock, _unlock, ...) \ 142 _DEFINE_CLEANUP_IS_CONDITIONAL(_n, false); \ 143 _DEFINE_UNLOCK_GUARD(_n, void, _unlock, __VA_ARGS__) \ 144 _DEFINE_LOCK_GUARD_0(_n, _lock) 145 146 /* This allows the type to be set. */ 147 #define DEFINE_LOCK_GUARD_1(_n, _t, _lock, _unlock, ...) \ 148 _DEFINE_CLEANUP_IS_CONDITIONAL(_n, false); \ 149 _DEFINE_UNLOCK_GUARD(_n, _t, _unlock, __VA_ARGS__) \ 150 _DEFINE_LOCK_GUARD_1(_n, _t, _lock) 151 152 #define _scoped_guard(_n, _l, ...) \ 153 for (DECLARE(_n, _scoped)(__VA_ARGS__); \ 154 1 /*__guard_ptr(_n)(&_scoped) || !__is_cond_ptr(_n) */; \ 155 ({ goto _l; })) \ 156 if (0) { \ 157 _l: \ 158 break; \ 159 } else 160 161 #define scoped_guard(_n, ...) \ 162 _scoped_guard(_n, ___label_ ## __COUNTER__, ##__VA_ARGS__) 163 164 #endif /* _LINUXKPI_LINUX_CLEANUP_H */ 165