/* Simple Plugin API */ /* SPDX-FileCopyrightText: Copyright © 2023 PipeWire authors */ /* SPDX-License-Identifier: MIT */ #ifndef SPA_UTILS_CLEANUP_H #define SPA_UTILS_CLEANUP_H #define spa_exchange(var, new_value) \ __extension__ ({ \ __typeof__(var) *_ptr_ = &(var); \ __typeof__(var) _old_value_ = *_ptr_; \ *_ptr_ = (new_value); \ _old_value_; \ }) /* ========================================================================== */ #if __GNUC__ >= 10 || defined(__clang__) #define spa_steal_ptr(ptr) ((__typeof__(*(ptr)) *) spa_exchange((ptr), NULL)) #else #define spa_steal_ptr(ptr) spa_exchange((ptr), NULL) #endif #define spa_clear_ptr(ptr, destructor) \ __extension__ ({ \ __typeof__(ptr) _old_value = spa_steal_ptr(ptr); \ if (_old_value) \ destructor(_old_value); \ (void) 0; \ }) /* ========================================================================== */ #include #include #define spa_steal_fd(fd) spa_exchange((fd), -1) #define spa_clear_fd(fd) \ __extension__ ({ \ int _old_value = spa_steal_fd(fd), _res = 0; \ if (_old_value >= 0) \ _res = close(_old_value); \ _res; \ }) /* ========================================================================== */ #if defined(__has_attribute) && __has_attribute(__cleanup__) #define spa_cleanup(func) __attribute__((__cleanup__(func))) #define SPA_DEFINE_AUTO_CLEANUP(name, type, ...) \ typedef __typeof__(type) _spa_auto_cleanup_type_ ## name; \ static inline void _spa_auto_cleanup_func_ ## name (__typeof__(type) *thing) \ { \ int _save_errno = errno; \ __VA_ARGS__ \ errno = _save_errno; \ } #define spa_auto(name) \ spa_cleanup(_spa_auto_cleanup_func_ ## name) \ _spa_auto_cleanup_type_ ## name #define SPA_DEFINE_AUTOPTR_CLEANUP(name, type, ...) \ typedef __typeof__(type) * _spa_autoptr_cleanup_type_ ## name; \ static inline void _spa_autoptr_cleanup_func_ ## name (__typeof__(type) **thing) \ { \ int _save_errno = errno; \ __VA_ARGS__ \ errno = _save_errno; \ } #define spa_autoptr(name) \ spa_cleanup(_spa_autoptr_cleanup_func_ ## name) \ _spa_autoptr_cleanup_type_ ## name /* ========================================================================== */ #include static inline void _spa_autofree_cleanup_func(void *p) { int save_errno = errno; free(*(void **) p); errno = save_errno; } #define spa_autofree spa_cleanup(_spa_autofree_cleanup_func) /* ========================================================================== */ static inline void _spa_autoclose_cleanup_func(int *fd) { int save_errno = errno; spa_clear_fd(*fd); errno = save_errno; } #define spa_autoclose spa_cleanup(_spa_autoclose_cleanup_func) /* ========================================================================== */ #include SPA_DEFINE_AUTOPTR_CLEANUP(FILE, FILE, { spa_clear_ptr(*thing, fclose); }) /* ========================================================================== */ #include SPA_DEFINE_AUTOPTR_CLEANUP(DIR, DIR, { spa_clear_ptr(*thing, closedir); }) #else #define SPA_DEFINE_AUTO_CLEANUP(name, type, ...) #define SPA_DEFINE_AUTOPTR_CLEANUP(name, type, ...) #endif #endif /* SPA_UTILS_CLEANUP_H */