Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/compat/linuxkpi/common/include/linux/cleanup.h
103095 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2024-2026 The FreeBSD Foundation
5
*
6
* This software was developed by Björn Zeeb under sponsorship from
7
* the FreeBSD Foundation.
8
*/
9
10
#ifndef _LINUXKPI_LINUX_CLEANUP_H
11
#define _LINUXKPI_LINUX_CLEANUP_H
12
13
#include <linux/err.h>
14
15
#define CLEANUP_NAME(_n, _s) __CONCAT(__CONCAT(cleanup_, _n), _s)
16
17
#define __cleanup(_f) __attribute__((__cleanup__(_f)))
18
19
#define DECLARE(_n, _x) \
20
CLEANUP_NAME(_n, _t) _x __cleanup(CLEANUP_NAME(_n, _destroy)) = \
21
CLEANUP_NAME(_n, _create)
22
23
/*
24
* Note: "_T" are special as they are exposed into common code for
25
* statements. Extra care should be taken when changing the code.
26
*/
27
#define DEFINE_GUARD(_n, _dt, _lock, _unlock) \
28
\
29
typedef _dt CLEANUP_NAME(_n, _t); \
30
\
31
static inline _dt \
32
CLEANUP_NAME(_n, _create)( _dt _T) \
33
{ \
34
_dt c; \
35
\
36
c = ({ _lock; _T; }); \
37
return (c); \
38
} \
39
\
40
static inline void \
41
CLEANUP_NAME(_n, _destroy)(_dt *t) \
42
{ \
43
_dt _T; \
44
\
45
_T = *t; \
46
if (_T) { _unlock; }; \
47
}
48
49
/* We need to keep these calls unique. */
50
#define _guard(_n, _x) \
51
DECLARE(_n, _x)
52
#define guard(_n) \
53
_guard(_n, guard_ ## _n ## _ ## __COUNTER__)
54
55
#define DEFINE_FREE(_n, _t, _f) \
56
static inline void \
57
__free_ ## _n(void *p) \
58
{ \
59
_t _T; \
60
\
61
_T = *(_t *)p; \
62
_f; \
63
}
64
65
#define __free(_n) __cleanup(__free_##_n)
66
67
/*
68
* Our initial version go broken up. Some simplifications like using
69
* "bool" for the lock had to be changed to a more general type.
70
* _T is still special and, like other bits, may not always be used,
71
* so tag with __unused (or better the LinuxKPI __maybe_unused).
72
*/
73
#define _DEFINE_LOCK_GUARD_0(_n, _lock) \
74
static inline CLEANUP_NAME(_n, _t) \
75
CLEANUP_NAME(_n, _create)(void) \
76
{ \
77
CLEANUP_NAME(_n, _t) _tmp; \
78
CLEANUP_NAME(_n, _t) *_T __maybe_unused; \
79
\
80
_tmp.lock = (void *)1; \
81
_T = &_tmp; \
82
_lock; \
83
return (_tmp); \
84
}
85
86
#define _DEFINE_LOCK_GUARD_1(_n, _type, _lock) \
87
static inline CLEANUP_NAME(_n, _t) \
88
CLEANUP_NAME(_n, _create)(_type *l) \
89
{ \
90
CLEANUP_NAME(_n, _t) _tmp; \
91
CLEANUP_NAME(_n, _t) *_T __maybe_unused; \
92
\
93
_tmp.lock = l; \
94
_T = &_tmp; \
95
_lock; \
96
return (_tmp); \
97
}
98
99
#define _GUARD_IS_ERR(_v) \
100
({ \
101
uintptr_t x = (uintptr_t)(void *)(_v); \
102
IS_ERR_VALUE(x); \
103
})
104
105
#define __is_cond_ptr(_n) \
106
CLEANUP_NAME(_n, _is_cond)
107
#define __guard_ptr(_n) \
108
CLEANUP_NAME(_n, _ptr)
109
110
#define _DEFINE_CLEANUP_IS_CONDITIONAL(_n, _b) \
111
static const bool CLEANUP_NAME(_n, _is_cond) __maybe_unused = _b
112
113
#define _DEFINE_GUARD_LOCK_PTR(_n, _lp) \
114
static inline void * \
115
CLEANUP_NAME(_n, _lock_ptr)(CLEANUP_NAME(_n, _t) *_T) \
116
{ \
117
void *_p; \
118
\
119
_p = (void *)(uintptr_t)*(_lp); \
120
if (IS_ERR(_p)) \
121
_p = NULL; \
122
return (_p); \
123
}
124
125
#define _DEFINE_UNLOCK_GUARD(_n, _type, _unlock, ...) \
126
typedef struct { \
127
_type *lock; \
128
__VA_ARGS__; \
129
} CLEANUP_NAME(_n, _t); \
130
\
131
static inline void \
132
CLEANUP_NAME(_n, _destroy)(CLEANUP_NAME(_n, _t) *_T) \
133
{ \
134
if (!_GUARD_IS_ERR(_T->lock)) { \
135
_unlock; \
136
} \
137
} \
138
\
139
_DEFINE_GUARD_LOCK_PTR(_n, &_T->lock)
140
141
#define DEFINE_LOCK_GUARD_0(_n, _lock, _unlock, ...) \
142
_DEFINE_CLEANUP_IS_CONDITIONAL(_n, false); \
143
_DEFINE_UNLOCK_GUARD(_n, void, _unlock, __VA_ARGS__) \
144
_DEFINE_LOCK_GUARD_0(_n, _lock)
145
146
/* This allows the type to be set. */
147
#define DEFINE_LOCK_GUARD_1(_n, _t, _lock, _unlock, ...) \
148
_DEFINE_CLEANUP_IS_CONDITIONAL(_n, false); \
149
_DEFINE_UNLOCK_GUARD(_n, _t, _unlock, __VA_ARGS__) \
150
_DEFINE_LOCK_GUARD_1(_n, _t, _lock)
151
152
#define _scoped_guard(_n, _l, ...) \
153
for (DECLARE(_n, _scoped)(__VA_ARGS__); \
154
1 /*__guard_ptr(_n)(&_scoped) || !__is_cond_ptr(_n) */; \
155
({ goto _l; })) \
156
if (0) { \
157
_l: \
158
break; \
159
} else
160
161
#define scoped_guard(_n, ...) \
162
_scoped_guard(_n, ___label_ ## __COUNTER__, ##__VA_ARGS__)
163
164
#endif /* _LINUXKPI_LINUX_CLEANUP_H */
165
166