xref: /qemu/include/qemu/thread.h (revision 96215036f47403438c7c7869b7cd419bd7a11f82)
1 #ifndef QEMU_THREAD_H
2 #define QEMU_THREAD_H
3 
4 #include "qemu/processor.h"
5 #include "qemu/atomic.h"
6 #include "qemu/futex.h"
7 
8 typedef struct QemuCond QemuCond;
9 typedef struct QemuSemaphore QemuSemaphore;
10 typedef struct QemuLockCnt QemuLockCnt;
11 typedef struct QemuThread QemuThread;
12 
13 /*
14  * QemuEvent
15  * =========
16  *
17  * QemuEvent is an implementation of Win32 manual-reset event object.
18  * For details, refer to:
19  * https://learn.microsoft.com/en-us/windows/win32/sync/using-event-objects
20  *
21  * QemuEvent is more lightweight than QemuSemaphore when HAVE_FUTEX is defined.
22  */
23 typedef struct QemuEvent {
24 #ifndef HAVE_FUTEX
25     pthread_mutex_t lock;
26     pthread_cond_t cond;
27 #endif
28     unsigned value;
29     bool initialized;
30 } QemuEvent;
31 
32 #ifdef _WIN32
33 #include "qemu/thread-win32.h"
34 #else
35 #include "qemu/thread-posix.h"
36 #endif
37 
38 /* include QSP header once QemuMutex, QemuCond etc. are defined */
39 #include "qemu/qsp.h"
40 
41 #define QEMU_THREAD_JOINABLE 0
42 #define QEMU_THREAD_DETACHED 1
43 
44 void qemu_mutex_init(QemuMutex *mutex);
45 void qemu_mutex_destroy(QemuMutex *mutex);
46 int TSA_NO_TSA qemu_mutex_trylock_impl(QemuMutex *mutex, const char *file,
47                                        const int line);
48 void TSA_NO_TSA qemu_mutex_lock_impl(QemuMutex *mutex, const char *file,
49                                      const int line);
50 void TSA_NO_TSA qemu_mutex_unlock_impl(QemuMutex *mutex, const char *file,
51                                        const int line);
52 
53 void qemu_rec_mutex_init(QemuRecMutex *mutex);
54 void qemu_rec_mutex_destroy(QemuRecMutex *mutex);
55 void qemu_rec_mutex_lock_impl(QemuRecMutex *mutex, const char *file, int line);
56 int qemu_rec_mutex_trylock_impl(QemuRecMutex *mutex, const char *file, int line);
57 void qemu_rec_mutex_unlock_impl(QemuRecMutex *mutex, const char *file, int line);
58 
59 typedef void (*QemuMutexLockFunc)(QemuMutex *m, const char *f, int l);
60 typedef int (*QemuMutexTrylockFunc)(QemuMutex *m, const char *f, int l);
61 typedef void (*QemuRecMutexLockFunc)(QemuRecMutex *m, const char *f, int l);
62 typedef int (*QemuRecMutexTrylockFunc)(QemuRecMutex *m, const char *f, int l);
63 typedef void (*QemuCondWaitFunc)(QemuCond *c, QemuMutex *m, const char *f,
64                                  int l);
65 typedef bool (*QemuCondTimedWaitFunc)(QemuCond *c, QemuMutex *m, int ms,
66                                       const char *f, int l);
67 
68 extern QemuMutexLockFunc bql_mutex_lock_func;
69 extern QemuMutexLockFunc qemu_mutex_lock_func;
70 extern QemuMutexTrylockFunc qemu_mutex_trylock_func;
71 extern QemuRecMutexLockFunc qemu_rec_mutex_lock_func;
72 extern QemuRecMutexTrylockFunc qemu_rec_mutex_trylock_func;
73 extern QemuCondWaitFunc qemu_cond_wait_func;
74 extern QemuCondTimedWaitFunc qemu_cond_timedwait_func;
75 
76 /* convenience macros to bypass the profiler */
77 #define qemu_mutex_lock__raw(m)                         \
78         qemu_mutex_lock_impl(m, __FILE__, __LINE__)
79 #define qemu_mutex_trylock__raw(m)                      \
80         qemu_mutex_trylock_impl(m, __FILE__, __LINE__)
81 
82 #ifdef __COVERITY__
83 /*
84  * Coverity is severely confused by the indirect function calls,
85  * hide them.
86  */
87 #define qemu_mutex_lock(m)                                              \
88             qemu_mutex_lock_impl(m, __FILE__, __LINE__)
89 #define qemu_mutex_trylock(m)                                           \
90             qemu_mutex_trylock_impl(m, __FILE__, __LINE__)
91 #define qemu_rec_mutex_lock(m)                                          \
92             qemu_rec_mutex_lock_impl(m, __FILE__, __LINE__)
93 #define qemu_rec_mutex_trylock(m)                                       \
94             qemu_rec_mutex_trylock_impl(m, __FILE__, __LINE__)
95 #define qemu_cond_wait(c, m)                                            \
96             qemu_cond_wait_impl(c, m, __FILE__, __LINE__)
97 #define qemu_cond_timedwait(c, m, ms)                                   \
98             qemu_cond_timedwait_impl(c, m, ms, __FILE__, __LINE__)
99 #else
100 #define qemu_mutex_lock(m) ({                                           \
101             QemuMutexLockFunc _f = qatomic_read(&qemu_mutex_lock_func); \
102             _f(m, __FILE__, __LINE__);                                  \
103         })
104 
105 #define qemu_mutex_trylock(m) ({                                              \
106             QemuMutexTrylockFunc _f = qatomic_read(&qemu_mutex_trylock_func); \
107             _f(m, __FILE__, __LINE__);                                        \
108         })
109 
110 #define qemu_rec_mutex_lock(m) ({                                             \
111             QemuRecMutexLockFunc _f = qatomic_read(&qemu_rec_mutex_lock_func);\
112             _f(m, __FILE__, __LINE__);                                        \
113         })
114 
115 #define qemu_rec_mutex_trylock(m) ({                            \
116             QemuRecMutexTrylockFunc _f;                         \
117             _f = qatomic_read(&qemu_rec_mutex_trylock_func);    \
118             _f(m, __FILE__, __LINE__);                          \
119         })
120 
121 #define qemu_cond_wait(c, m) ({                                         \
122             QemuCondWaitFunc _f = qatomic_read(&qemu_cond_wait_func);   \
123             _f(c, m, __FILE__, __LINE__);                               \
124         })
125 
126 #define qemu_cond_timedwait(c, m, ms) ({                                       \
127             QemuCondTimedWaitFunc _f = qatomic_read(&qemu_cond_timedwait_func);\
128             _f(c, m, ms, __FILE__, __LINE__);                                  \
129         })
130 #endif
131 
132 #define qemu_mutex_unlock(mutex) \
133         qemu_mutex_unlock_impl(mutex, __FILE__, __LINE__)
134 
135 #define qemu_rec_mutex_unlock(mutex) \
136         qemu_rec_mutex_unlock_impl(mutex, __FILE__, __LINE__)
137 
138 static inline void (qemu_mutex_lock)(QemuMutex *mutex)
139 {
140     qemu_mutex_lock(mutex);
141 }
142 
143 static inline int (qemu_mutex_trylock)(QemuMutex *mutex)
144 {
145     return qemu_mutex_trylock(mutex);
146 }
147 
148 static inline void (qemu_mutex_unlock)(QemuMutex *mutex)
149 {
150     qemu_mutex_unlock(mutex);
151 }
152 
153 static inline void (qemu_rec_mutex_lock)(QemuRecMutex *mutex)
154 {
155     qemu_rec_mutex_lock(mutex);
156 }
157 
158 static inline int (qemu_rec_mutex_trylock)(QemuRecMutex *mutex)
159 {
160     return qemu_rec_mutex_trylock(mutex);
161 }
162 
163 static inline void (qemu_rec_mutex_unlock)(QemuRecMutex *mutex)
164 {
165     qemu_rec_mutex_unlock(mutex);
166 }
167 
168 void qemu_cond_init(QemuCond *cond);
169 void qemu_cond_destroy(QemuCond *cond);
170 
171 /*
172  * IMPORTANT: The implementation does not guarantee that pthread_cond_signal
173  * and pthread_cond_broadcast can be called except while the same mutex is
174  * held as in the corresponding pthread_cond_wait calls!
175  */
176 void qemu_cond_signal(QemuCond *cond);
177 void qemu_cond_broadcast(QemuCond *cond);
178 void TSA_NO_TSA qemu_cond_wait_impl(QemuCond *cond, QemuMutex *mutex,
179                                     const char *file, const int line);
180 bool qemu_cond_timedwait_impl(QemuCond *cond, QemuMutex *mutex, int ms,
181                               const char *file, const int line);
182 
183 static inline void (qemu_cond_wait)(QemuCond *cond, QemuMutex *mutex)
184 {
185     qemu_cond_wait(cond, mutex);
186 }
187 
188 /* Returns true if timeout has not expired, and false otherwise */
189 static inline bool (qemu_cond_timedwait)(QemuCond *cond, QemuMutex *mutex,
190                                          int ms)
191 {
192     return qemu_cond_timedwait(cond, mutex, ms);
193 }
194 
195 void qemu_sem_init(QemuSemaphore *sem, int init);
196 void qemu_sem_post(QemuSemaphore *sem);
197 void qemu_sem_wait(QemuSemaphore *sem);
198 int qemu_sem_timedwait(QemuSemaphore *sem, int ms);
199 void qemu_sem_destroy(QemuSemaphore *sem);
200 
201 void qemu_event_init(QemuEvent *ev, bool init);
202 void qemu_event_set(QemuEvent *ev);
203 void qemu_event_reset(QemuEvent *ev);
204 void qemu_event_wait(QemuEvent *ev);
205 void qemu_event_destroy(QemuEvent *ev);
206 
207 void qemu_thread_create(QemuThread *thread, const char *name,
208                         void *(*start_routine)(void *),
209                         void *arg, int mode);
210 int qemu_thread_set_affinity(QemuThread *thread, unsigned long *host_cpus,
211                              unsigned long nbits);
212 int qemu_thread_get_affinity(QemuThread *thread, unsigned long **host_cpus,
213                              unsigned long *nbits);
214 void *qemu_thread_join(QemuThread *thread);
215 void qemu_thread_get_self(QemuThread *thread);
216 bool qemu_thread_is_self(QemuThread *thread);
217 G_NORETURN void qemu_thread_exit(void *retval);
218 void qemu_thread_naming(bool enable);
219 
220 struct Notifier;
221 /**
222  * qemu_thread_atexit_add:
223  * @notifier: Notifier to add
224  *
225  * Add the specified notifier to a list which will be run via
226  * notifier_list_notify() when this thread exits (either by calling
227  * qemu_thread_exit() or by returning from its start_routine).
228  * The usual usage is that the caller passes a Notifier which is
229  * a per-thread variable; it can then use the callback to free
230  * other per-thread data.
231  *
232  * If the thread exits as part of the entire process exiting,
233  * it is unspecified whether notifiers are called or not.
234  */
235 void qemu_thread_atexit_add(struct Notifier *notifier);
236 /**
237  * qemu_thread_atexit_remove:
238  * @notifier: Notifier to remove
239  *
240  * Remove the specified notifier from the thread-exit notification
241  * list. It is not valid to try to remove a notifier which is not
242  * on the list.
243  */
244 void qemu_thread_atexit_remove(struct Notifier *notifier);
245 
246 #ifdef CONFIG_TSAN
247 #include <sanitizer/tsan_interface.h>
248 #endif
249 
250 struct QemuSpin {
251     int value;
252 };
253 
qemu_spin_init(QemuSpin * spin)254 static inline void qemu_spin_init(QemuSpin *spin)
255 {
256     qatomic_set(&spin->value, 0);
257 #ifdef CONFIG_TSAN
258     __tsan_mutex_create(spin, __tsan_mutex_not_static);
259 #endif
260 }
261 
qemu_spin_destroy(QemuSpin * spin)262 static inline void qemu_spin_destroy(QemuSpin *spin)
263 {
264 #ifdef CONFIG_TSAN
265     __tsan_mutex_destroy(spin, __tsan_mutex_not_static);
266 #endif
267 }
268 
qemu_spin_lock(QemuSpin * spin)269 static inline void qemu_spin_lock(QemuSpin *spin)
270 {
271 #ifdef CONFIG_TSAN
272     __tsan_mutex_pre_lock(spin, 0);
273 #endif
274     while (unlikely(qatomic_xchg(&spin->value, 1))) {
275         while (qatomic_read(&spin->value)) {
276             cpu_relax();
277         }
278     }
279 #ifdef CONFIG_TSAN
280     __tsan_mutex_post_lock(spin, 0, 0);
281 #endif
282 }
283 
qemu_spin_trylock(QemuSpin * spin)284 static inline bool qemu_spin_trylock(QemuSpin *spin)
285 {
286 #ifdef CONFIG_TSAN
287     __tsan_mutex_pre_lock(spin, __tsan_mutex_try_lock);
288 #endif
289     bool busy = qatomic_xchg(&spin->value, true);
290 #ifdef CONFIG_TSAN
291     unsigned flags = __tsan_mutex_try_lock;
292     flags |= busy ? __tsan_mutex_try_lock_failed : 0;
293     __tsan_mutex_post_lock(spin, flags, 0);
294 #endif
295     return busy;
296 }
297 
qemu_spin_locked(QemuSpin * spin)298 static inline bool qemu_spin_locked(QemuSpin *spin)
299 {
300     return qatomic_read(&spin->value);
301 }
302 
qemu_spin_unlock(QemuSpin * spin)303 static inline void qemu_spin_unlock(QemuSpin *spin)
304 {
305 #ifdef CONFIG_TSAN
306     __tsan_mutex_pre_unlock(spin, 0);
307 #endif
308     qatomic_store_release(&spin->value, 0);
309 #ifdef CONFIG_TSAN
310     __tsan_mutex_post_unlock(spin, 0);
311 #endif
312 }
313 
314 #endif
315