#ifndef _LINUXKPI_LINUX_CLEANUP_H
#define _LINUXKPI_LINUX_CLEANUP_H
#include <linux/err.h>
#define CLEANUP_NAME(_n, _s) __CONCAT(__CONCAT(cleanup_, _n), _s)
#define __cleanup(_f) __attribute__((__cleanup__(_f)))
#define DECLARE(_n, _x) \
CLEANUP_NAME(_n, _t) _x __cleanup(CLEANUP_NAME(_n, _destroy)) = \
CLEANUP_NAME(_n, _create)
#define DEFINE_GUARD(_n, _dt, _lock, _unlock) \
\
typedef _dt CLEANUP_NAME(_n, _t); \
\
static inline _dt \
CLEANUP_NAME(_n, _create)( _dt _T) \
{ \
_dt c; \
\
c = ({ _lock; _T; }); \
return (c); \
} \
\
static inline void \
CLEANUP_NAME(_n, _destroy)(_dt *t) \
{ \
_dt _T; \
\
_T = *t; \
if (_T) { _unlock; }; \
}
#define _guard(_n, _x) \
DECLARE(_n, _x)
#define guard(_n) \
_guard(_n, guard_ ## _n ## _ ## __COUNTER__)
#define DEFINE_FREE(_n, _t, _f) \
static inline void \
__free_ ## _n(void *p) \
{ \
_t _T; \
\
_T = *(_t *)p; \
_f; \
}
#define __free(_n) __cleanup(__free_##_n)
#define _DEFINE_LOCK_GUARD_0(_n, _lock) \
static inline CLEANUP_NAME(_n, _t) \
CLEANUP_NAME(_n, _create)(void) \
{ \
CLEANUP_NAME(_n, _t) _tmp; \
CLEANUP_NAME(_n, _t) *_T __maybe_unused; \
\
_tmp.lock = (void *)1; \
_T = &_tmp; \
_lock; \
return (_tmp); \
}
#define _DEFINE_LOCK_GUARD_1(_n, _type, _lock) \
static inline CLEANUP_NAME(_n, _t) \
CLEANUP_NAME(_n, _create)(_type *l) \
{ \
CLEANUP_NAME(_n, _t) _tmp; \
CLEANUP_NAME(_n, _t) *_T __maybe_unused; \
\
_tmp.lock = l; \
_T = &_tmp; \
_lock; \
return (_tmp); \
}
#define _GUARD_IS_ERR(_v) \
({ \
uintptr_t x = (uintptr_t)(void *)(_v); \
IS_ERR_VALUE(x); \
})
#define __is_cond_ptr(_n) \
CLEANUP_NAME(_n, _is_cond)
#define __guard_ptr(_n) \
CLEANUP_NAME(_n, _ptr)
#define _DEFINE_CLEANUP_IS_CONDITIONAL(_n, _b) \
static const bool CLEANUP_NAME(_n, _is_cond) __maybe_unused = _b
#define _DEFINE_GUARD_LOCK_PTR(_n, _lp) \
static inline void * \
CLEANUP_NAME(_n, _lock_ptr)(CLEANUP_NAME(_n, _t) *_T) \
{ \
void *_p; \
\
_p = (void *)(uintptr_t)*(_lp); \
if (IS_ERR(_p)) \
_p = NULL; \
return (_p); \
}
#define _DEFINE_UNLOCK_GUARD(_n, _type, _unlock, ...) \
typedef struct { \
_type *lock; \
__VA_ARGS__; \
} CLEANUP_NAME(_n, _t); \
\
static inline void \
CLEANUP_NAME(_n, _destroy)(CLEANUP_NAME(_n, _t) *_T) \
{ \
if (!_GUARD_IS_ERR(_T->lock)) { \
_unlock; \
} \
} \
\
_DEFINE_GUARD_LOCK_PTR(_n, &_T->lock)
#define DEFINE_LOCK_GUARD_0(_n, _lock, _unlock, ...) \
_DEFINE_CLEANUP_IS_CONDITIONAL(_n, false); \
_DEFINE_UNLOCK_GUARD(_n, void, _unlock, __VA_ARGS__) \
_DEFINE_LOCK_GUARD_0(_n, _lock)
#define DEFINE_LOCK_GUARD_1(_n, _t, _lock, _unlock, ...) \
_DEFINE_CLEANUP_IS_CONDITIONAL(_n, false); \
_DEFINE_UNLOCK_GUARD(_n, _t, _unlock, __VA_ARGS__) \
_DEFINE_LOCK_GUARD_1(_n, _t, _lock)
#define _scoped_guard(_n, _l, ...) \
for (DECLARE(_n, _scoped)(__VA_ARGS__); \
1 ; \
({ goto _l; })) \
if (0) { \
_l: \
break; \
} else
#define scoped_guard(_n, ...) \
_scoped_guard(_n, ___label_ ## __COUNTER__, ##__VA_ARGS__)
#endif