1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
|
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __PERF_MUTEX_H
#define __PERF_MUTEX_H
#include <pthread.h>
#include <stdbool.h>
/*
* A function-like feature checking macro that is a wrapper around
* `__has_attribute`, which is defined by GCC 5+ and Clang and evaluates to a
* nonzero constant integer if the attribute is supported or 0 if not.
*/
#ifdef __has_attribute
#define HAVE_ATTRIBUTE(x) __has_attribute(x)
#else
#define HAVE_ATTRIBUTE(x) 0
#endif
#if HAVE_ATTRIBUTE(guarded_by) && HAVE_ATTRIBUTE(pt_guarded_by) && \
HAVE_ATTRIBUTE(lockable) && HAVE_ATTRIBUTE(exclusive_lock_function) && \
HAVE_ATTRIBUTE(exclusive_trylock_function) && HAVE_ATTRIBUTE(exclusive_locks_required) && \
HAVE_ATTRIBUTE(no_thread_safety_analysis)
/* Documents if a shared field or global variable needs to be protected by a mutex. */
#define GUARDED_BY(x) __attribute__((guarded_by(x)))
/*
* Documents if the memory location pointed to by a pointer should be guarded by
* a mutex when dereferencing the pointer.
*/
#define PT_GUARDED_BY(x) __attribute__((pt_guarded_by(x)))
/* Documents if a type is a lockable type. */
#define LOCKABLE __attribute__((lockable))
/* Documents a function that expects a lock not to be held prior to entry. */
#define LOCKS_EXCLUDED(...) __attribute__((locks_excluded(__VA_ARGS__)))
/* Documents a function that returns a lock. */
#define LOCK_RETURNED(x) __attribute__((lock_returned(x)))
/* Documents functions that acquire a lock in the body of a function, and do not release it. */
#define EXCLUSIVE_LOCK_FUNCTION(...) __attribute__((exclusive_lock_function(__VA_ARGS__)))
/*
* Documents functions that acquire a shared (reader) lock in the body of a
* function, and do not release it.
*/
#define SHARED_LOCK_FUNCTION(...) __attribute__((shared_lock_function(__VA_ARGS__)))
/*
* Documents functions that expect a lock to be held on entry to the function,
* and release it in the body of the function.
*/
#define UNLOCK_FUNCTION(...) __attribute__((unlock_function(__VA_ARGS__)))
/* Documents functions that try to acquire a lock, and return success or failure. */
#define EXCLUSIVE_TRYLOCK_FUNCTION(...) \
__attribute__((exclusive_trylock_function(__VA_ARGS__)))
/* Documents a function that expects a mutex to be held prior to entry. */
#define EXCLUSIVE_LOCKS_REQUIRED(...) __attribute__((exclusive_locks_required(__VA_ARGS__)))
/* Documents a function that expects a shared (reader) lock to be held prior to entry. */
#define SHARED_LOCKS_REQUIRED(...) __attribute__((shared_locks_required(__VA_ARGS__)))
/* Turns off thread safety checking within the body of a particular function. */
#define NO_THREAD_SAFETY_ANALYSIS __attribute__((no_thread_safety_analysis))
#else
#define GUARDED_BY(x)
#define PT_GUARDED_BY(x)
#define LOCKABLE
#define LOCKS_EXCLUDED(...)
#define LOCK_RETURNED(x)
#define EXCLUSIVE_LOCK_FUNCTION(...)
#define SHARED_LOCK_FUNCTION(...)
#define UNLOCK_FUNCTION(...)
#define EXCLUSIVE_TRYLOCK_FUNCTION(...)
#define EXCLUSIVE_LOCKS_REQUIRED(...)
#define SHARED_LOCKS_REQUIRED(...)
#define NO_THREAD_SAFETY_ANALYSIS
#endif
/*
* A wrapper around the mutex implementation that allows perf to error check
* usage, etc.
*/
struct LOCKABLE mutex {
pthread_mutex_t lock;
};
/*
* Statically initialized mutex, for the file scope ones. Error checking
* in !NDEBUG builds, like mutex_init(); the glibc-only errorcheck
* initializer falls back to the default type elsewhere.
*/
#if !defined(NDEBUG) && defined(PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP)
#define __PERF_MUTEX_INITIALIZER PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
#else
#define __PERF_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
#endif
#define DEFINE_MUTEX(name) struct mutex name = { .lock = __PERF_MUTEX_INITIALIZER }
/*
* Runs fn() exactly once however many threads race to it, the rest wait
* for it to finish; per call site state, so multiple sites wanting the
* same once use a common helper, as in the kernel's DO_ONCE().
*/
#define DO_ONCE(fn, ...) \
({ \
static bool ___done; \
static DEFINE_MUTEX(___once_lock); \
bool ___ret = false; \
\
if (!__atomic_load_n(&___done, __ATOMIC_ACQUIRE)) { \
mutex_lock(&___once_lock); \
if (!___done) { \
fn(__VA_ARGS__); \
__atomic_store_n(&___done, true, \
__ATOMIC_RELEASE); \
___ret = true; \
} \
mutex_unlock(&___once_lock); \
} \
___ret; \
})
/* A wrapper around the condition variable implementation. */
struct cond {
pthread_cond_t cond;
};
/* Default initialize the mtx struct. */
void mutex_init(struct mutex *mtx);
/*
* Initialize the mtx struct and set the process-shared rather than default
* process-private attribute.
*/
void mutex_init_pshared(struct mutex *mtx);
/* Initializes a mutex that may be recursively held on the same thread. */
void mutex_init_recursive(struct mutex *mtx);
/*
* As mutex_init_pshared(), plus the robust attribute: a process dying while
* holding it doesn't leave it locked, but the takeover isn't reported and the
* data it protects may be mid update. Returns false when not available.
*/
bool mutex_init_pshared_robust(struct mutex *mtx);
void mutex_destroy(struct mutex *mtx);
void mutex_lock(struct mutex *mtx) EXCLUSIVE_LOCK_FUNCTION(*mtx);
void mutex_unlock(struct mutex *mtx) UNLOCK_FUNCTION(*mtx);
/* Tries to acquire the lock and returns true on success. */
bool mutex_trylock(struct mutex *mtx) EXCLUSIVE_TRYLOCK_FUNCTION(true, *mtx);
/* Default initialize the cond struct. */
void cond_init(struct cond *cnd);
/*
* Initialize the cond struct and specify the process-shared rather than default
* process-private attribute.
*/
void cond_init_pshared(struct cond *cnd);
void cond_destroy(struct cond *cnd);
void cond_wait(struct cond *cnd, struct mutex *mtx) EXCLUSIVE_LOCKS_REQUIRED(mtx);
void cond_signal(struct cond *cnd);
void cond_broadcast(struct cond *cnd);
#endif /* __PERF_MUTEX_H */
|