pipewire/spa/include/spa/utils/cleanup.h
Barnabás Pőcze d3368ee0d5 spa: utils: cleanup: fix __has_attribute() usage
Unknown preprocessor symbols are replaced with 0 in preprocessor
conditionals, so if `__has_attribute()` is not supported, then
the condition will be the following:

  if 0 && 0(__cleanup__)

which is syntactically incorrect.

So split the condition and only check `__has_attribute()` if
it exists.

Fixes: 65d949558b ("spa: utils: add scope based resource cleanup")
Fixes #4962
2025-11-02 19:10:25 +01:00

128 lines
3.1 KiB
C

/* 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 <errno.h>
#include <unistd.h>
#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; \
})
/* ========================================================================== */
#ifdef __has_attribute
#if __has_attribute(__cleanup__)
#define spa_cleanup(func) __attribute__((__cleanup__(func)))
#endif
#endif
#ifdef spa_cleanup
#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 <stdlib.h>
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 <stdio.h>
SPA_DEFINE_AUTOPTR_CLEANUP(FILE, FILE, {
spa_clear_ptr(*thing, fclose);
})
/* ========================================================================== */
#include <dirent.h>
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 */