PipeWire  1.6.4
cleanup.h
1 /* Simple Plugin API */
2 /* SPDX-FileCopyrightText: Copyright © 2023 PipeWire authors */
3 /* SPDX-License-Identifier: MIT */
4 
5 #ifndef SPA_UTILS_CLEANUP_H
6 #define SPA_UTILS_CLEANUP_H
7 
8 #define spa_exchange(var, new_value) \
9 __extension__ ({ \
10  __typeof__(var) *_ptr_ = &(var); \
11  __typeof__(var) _old_value_ = *_ptr_; \
12  *_ptr_ = (new_value); \
13  _old_value_; \
14 })
15 
16 /* ========================================================================== */
17 
18 #if __GNUC__ >= 10 || defined(__clang__)
19 #define spa_steal_ptr(ptr) ((__typeof__(*(ptr)) *) spa_exchange((ptr), NULL))
20 #else
21 #define spa_steal_ptr(ptr) spa_exchange((ptr), NULL)
22 #endif
23 
24 #define spa_clear_ptr(ptr, destructor) \
25 __extension__ ({ \
26  __typeof__(ptr) _old_value = spa_steal_ptr(ptr); \
27  if (_old_value) \
28  destructor(_old_value); \
29  (void) 0; \
30 })
31 
32 /* ========================================================================== */
33 
34 #include <errno.h>
35 #include <unistd.h>
36 
37 #define spa_steal_fd(fd) spa_exchange((fd), -1)
38 
39 #define spa_clear_fd(fd) \
40 __extension__ ({ \
41  int _old_value = spa_steal_fd(fd), _res = 0; \
42  if (_old_value >= 0) \
43  _res = close(_old_value); \
44  _res; \
45 })
46 
47 /* ========================================================================== */
48 
49 #ifdef __has_attribute
50 #if __has_attribute(__cleanup__)
51 #define spa_cleanup(func) __attribute__((__cleanup__(func)))
52 #endif
53 #endif
54 
55 #ifdef spa_cleanup
56 
57 #define SPA_DEFINE_AUTO_CLEANUP(name, type, ...) \
58 typedef __typeof__(type) _spa_auto_cleanup_type_ ## name; \
59 static inline void _spa_auto_cleanup_func_ ## name (__typeof__(type) *thing) \
60 { \
61  int _save_errno = errno; \
62  __VA_ARGS__ \
63  errno = _save_errno; \
64 }
65 
66 #define spa_auto(name) \
67  spa_cleanup(_spa_auto_cleanup_func_ ## name) \
68  _spa_auto_cleanup_type_ ## name
69 
70 #define SPA_DEFINE_AUTOPTR_CLEANUP(name, type, ...) \
71 typedef __typeof__(type) * _spa_autoptr_cleanup_type_ ## name; \
72 static inline void _spa_autoptr_cleanup_func_ ## name (__typeof__(type) **thing) \
73 { \
74  int _save_errno = errno; \
75  __VA_ARGS__ \
76  errno = _save_errno; \
77 }
78 
79 #define spa_autoptr(name) \
80  spa_cleanup(_spa_autoptr_cleanup_func_ ## name) \
81  _spa_autoptr_cleanup_type_ ## name
82 
83 /* ========================================================================== */
84 
85 #include <stdlib.h>
86 
87 static inline void _spa_autofree_cleanup_func(void *p)
88 {
89  int save_errno = errno;
90  free(*(void **) p);
91  errno = save_errno;
92 }
93 #define spa_autofree spa_cleanup(_spa_autofree_cleanup_func)
94 
95 /* ========================================================================== */
96 
97 static inline void _spa_autoclose_cleanup_func(int *fd)
98 {
99  int save_errno = errno;
100  spa_clear_fd(*fd);
101  errno = save_errno;
102 }
103 #define spa_autoclose spa_cleanup(_spa_autoclose_cleanup_func)
104 
105 /* ========================================================================== */
106 
107 #include <stdio.h>
108 
109 SPA_DEFINE_AUTOPTR_CLEANUP(FILE, FILE, {
110  spa_clear_ptr(*thing, fclose);
111 })
112 
113 /* ========================================================================== */
114 
115 #include <dirent.h>
116 
117 SPA_DEFINE_AUTOPTR_CLEANUP(DIR, DIR, {
118  spa_clear_ptr(*thing, closedir);
119 })
120 
121 #else
122 
123 #define SPA_DEFINE_AUTO_CLEANUP(name, type, ...)
124 #define SPA_DEFINE_AUTOPTR_CLEANUP(name, type, ...)
125 
126 #endif
127 
128 #endif /* SPA_UTILS_CLEANUP_H */