Path: blob/main/sys/compat/linuxkpi/common/include/linux/cleanup.h
103095 views
/*-1* SPDX-License-Identifier: BSD-2-Clause2*3* Copyright (c) 2024-2026 The FreeBSD Foundation4*5* This software was developed by Björn Zeeb under sponsorship from6* the FreeBSD Foundation.7*/89#ifndef _LINUXKPI_LINUX_CLEANUP_H10#define _LINUXKPI_LINUX_CLEANUP_H1112#include <linux/err.h>1314#define CLEANUP_NAME(_n, _s) __CONCAT(__CONCAT(cleanup_, _n), _s)1516#define __cleanup(_f) __attribute__((__cleanup__(_f)))1718#define DECLARE(_n, _x) \19CLEANUP_NAME(_n, _t) _x __cleanup(CLEANUP_NAME(_n, _destroy)) = \20CLEANUP_NAME(_n, _create)2122/*23* Note: "_T" are special as they are exposed into common code for24* statements. Extra care should be taken when changing the code.25*/26#define DEFINE_GUARD(_n, _dt, _lock, _unlock) \27\28typedef _dt CLEANUP_NAME(_n, _t); \29\30static inline _dt \31CLEANUP_NAME(_n, _create)( _dt _T) \32{ \33_dt c; \34\35c = ({ _lock; _T; }); \36return (c); \37} \38\39static inline void \40CLEANUP_NAME(_n, _destroy)(_dt *t) \41{ \42_dt _T; \43\44_T = *t; \45if (_T) { _unlock; }; \46}4748/* We need to keep these calls unique. */49#define _guard(_n, _x) \50DECLARE(_n, _x)51#define guard(_n) \52_guard(_n, guard_ ## _n ## _ ## __COUNTER__)5354#define DEFINE_FREE(_n, _t, _f) \55static inline void \56__free_ ## _n(void *p) \57{ \58_t _T; \59\60_T = *(_t *)p; \61_f; \62}6364#define __free(_n) __cleanup(__free_##_n)6566/*67* Our initial version go broken up. Some simplifications like using68* "bool" for the lock had to be changed to a more general type.69* _T is still special and, like other bits, may not always be used,70* so tag with __unused (or better the LinuxKPI __maybe_unused).71*/72#define _DEFINE_LOCK_GUARD_0(_n, _lock) \73static inline CLEANUP_NAME(_n, _t) \74CLEANUP_NAME(_n, _create)(void) \75{ \76CLEANUP_NAME(_n, _t) _tmp; \77CLEANUP_NAME(_n, _t) *_T __maybe_unused; \78\79_tmp.lock = (void *)1; \80_T = &_tmp; \81_lock; \82return (_tmp); \83}8485#define _DEFINE_LOCK_GUARD_1(_n, _type, _lock) \86static inline CLEANUP_NAME(_n, _t) \87CLEANUP_NAME(_n, _create)(_type *l) \88{ \89CLEANUP_NAME(_n, _t) _tmp; \90CLEANUP_NAME(_n, _t) *_T __maybe_unused; \91\92_tmp.lock = l; \93_T = &_tmp; \94_lock; \95return (_tmp); \96}9798#define _GUARD_IS_ERR(_v) \99({ \100uintptr_t x = (uintptr_t)(void *)(_v); \101IS_ERR_VALUE(x); \102})103104#define __is_cond_ptr(_n) \105CLEANUP_NAME(_n, _is_cond)106#define __guard_ptr(_n) \107CLEANUP_NAME(_n, _ptr)108109#define _DEFINE_CLEANUP_IS_CONDITIONAL(_n, _b) \110static const bool CLEANUP_NAME(_n, _is_cond) __maybe_unused = _b111112#define _DEFINE_GUARD_LOCK_PTR(_n, _lp) \113static inline void * \114CLEANUP_NAME(_n, _lock_ptr)(CLEANUP_NAME(_n, _t) *_T) \115{ \116void *_p; \117\118_p = (void *)(uintptr_t)*(_lp); \119if (IS_ERR(_p)) \120_p = NULL; \121return (_p); \122}123124#define _DEFINE_UNLOCK_GUARD(_n, _type, _unlock, ...) \125typedef struct { \126_type *lock; \127__VA_ARGS__; \128} CLEANUP_NAME(_n, _t); \129\130static inline void \131CLEANUP_NAME(_n, _destroy)(CLEANUP_NAME(_n, _t) *_T) \132{ \133if (!_GUARD_IS_ERR(_T->lock)) { \134_unlock; \135} \136} \137\138_DEFINE_GUARD_LOCK_PTR(_n, &_T->lock)139140#define DEFINE_LOCK_GUARD_0(_n, _lock, _unlock, ...) \141_DEFINE_CLEANUP_IS_CONDITIONAL(_n, false); \142_DEFINE_UNLOCK_GUARD(_n, void, _unlock, __VA_ARGS__) \143_DEFINE_LOCK_GUARD_0(_n, _lock)144145/* This allows the type to be set. */146#define DEFINE_LOCK_GUARD_1(_n, _t, _lock, _unlock, ...) \147_DEFINE_CLEANUP_IS_CONDITIONAL(_n, false); \148_DEFINE_UNLOCK_GUARD(_n, _t, _unlock, __VA_ARGS__) \149_DEFINE_LOCK_GUARD_1(_n, _t, _lock)150151#define _scoped_guard(_n, _l, ...) \152for (DECLARE(_n, _scoped)(__VA_ARGS__); \1531 /*__guard_ptr(_n)(&_scoped) || !__is_cond_ptr(_n) */; \154({ goto _l; })) \155if (0) { \156_l: \157break; \158} else159160#define scoped_guard(_n, ...) \161_scoped_guard(_n, ___label_ ## __COUNTER__, ##__VA_ARGS__)162163#endif /* _LINUXKPI_LINUX_CLEANUP_H */164165166