xref: /openbmc/qemu/util/qemu-thread-posix.c (revision 9586a132)
1baacf047SPaolo Bonzini /*
2baacf047SPaolo Bonzini  * Wrappers around mutex/cond/thread functions
3baacf047SPaolo Bonzini  *
4baacf047SPaolo Bonzini  * Copyright Red Hat, Inc. 2009
5baacf047SPaolo Bonzini  *
6baacf047SPaolo Bonzini  * Author:
7baacf047SPaolo Bonzini  *  Marcelo Tosatti <mtosatti@redhat.com>
8baacf047SPaolo Bonzini  *
9baacf047SPaolo Bonzini  * This work is licensed under the terms of the GNU GPL, version 2 or later.
10baacf047SPaolo Bonzini  * See the COPYING file in the top-level directory.
11baacf047SPaolo Bonzini  *
12baacf047SPaolo Bonzini  */
13aafd7584SPeter Maydell #include "qemu/osdep.h"
14baacf047SPaolo Bonzini #include "qemu/thread.h"
15c7c4d063SPaolo Bonzini #include "qemu/atomic.h"
16ef57137fSPaolo Bonzini #include "qemu/notify.h"
17f1aff7aaSPeter Xu #include "qemu-thread-common.h"
18ce9f0e5bSRobert Foley #include "qemu/tsan.h"
197730f32cSDavid Hildenbrand #include "qemu/bitmap.h"
20baacf047SPaolo Bonzini 
213ada67a3SBrad Smith #ifdef CONFIG_PTHREAD_SET_NAME_NP
223ada67a3SBrad Smith #include <pthread_np.h>
233ada67a3SBrad Smith #endif
243ada67a3SBrad Smith 
258f480de0SDr. David Alan Gilbert static bool name_threads;
268f480de0SDr. David Alan Gilbert 
qemu_thread_naming(bool enable)278f480de0SDr. David Alan Gilbert void qemu_thread_naming(bool enable)
288f480de0SDr. David Alan Gilbert {
298f480de0SDr. David Alan Gilbert     name_threads = enable;
305c312079SDr. David Alan Gilbert 
3110f6b231SPaolo Bonzini #if !defined CONFIG_PTHREAD_SETNAME_NP_W_TID && \
323ada67a3SBrad Smith     !defined CONFIG_PTHREAD_SETNAME_NP_WO_TID && \
333ada67a3SBrad Smith     !defined CONFIG_PTHREAD_SET_NAME_NP
345c312079SDr. David Alan Gilbert     /* This is a debugging option, not fatal */
355c312079SDr. David Alan Gilbert     if (enable) {
365c312079SDr. David Alan Gilbert         fprintf(stderr, "qemu: thread naming not supported on this host\n");
375c312079SDr. David Alan Gilbert     }
385c312079SDr. David Alan Gilbert #endif
398f480de0SDr. David Alan Gilbert }
408f480de0SDr. David Alan Gilbert 
error_exit(int err,const char * msg)41baacf047SPaolo Bonzini static void error_exit(int err, const char *msg)
42baacf047SPaolo Bonzini {
43baacf047SPaolo Bonzini     fprintf(stderr, "qemu: %s: %s\n", msg, strerror(err));
44baacf047SPaolo Bonzini     abort();
45baacf047SPaolo Bonzini }
46baacf047SPaolo Bonzini 
qemu_timedwait_clockid(void)47657ac98bSLongpeng(Mike) static inline clockid_t qemu_timedwait_clockid(void)
48657ac98bSLongpeng(Mike) {
49657ac98bSLongpeng(Mike) #ifdef CONFIG_PTHREAD_CONDATTR_SETCLOCK
50657ac98bSLongpeng(Mike)     return CLOCK_MONOTONIC;
51657ac98bSLongpeng(Mike) #else
52657ac98bSLongpeng(Mike)     return CLOCK_REALTIME;
53657ac98bSLongpeng(Mike) #endif
54657ac98bSLongpeng(Mike) }
55657ac98bSLongpeng(Mike) 
compute_abs_deadline(struct timespec * ts,int ms)563dcc9c6eSYury Kotov static void compute_abs_deadline(struct timespec *ts, int ms)
573dcc9c6eSYury Kotov {
58657ac98bSLongpeng(Mike)     clock_gettime(qemu_timedwait_clockid(), ts);
59657ac98bSLongpeng(Mike)     ts->tv_nsec += (ms % 1000) * 1000000;
60657ac98bSLongpeng(Mike)     ts->tv_sec += ms / 1000;
613dcc9c6eSYury Kotov     if (ts->tv_nsec >= 1000000000) {
623dcc9c6eSYury Kotov         ts->tv_sec++;
633dcc9c6eSYury Kotov         ts->tv_nsec -= 1000000000;
643dcc9c6eSYury Kotov     }
653dcc9c6eSYury Kotov }
663dcc9c6eSYury Kotov 
qemu_mutex_init(QemuMutex * mutex)67baacf047SPaolo Bonzini void qemu_mutex_init(QemuMutex *mutex)
68baacf047SPaolo Bonzini {
69baacf047SPaolo Bonzini     int err;
70baacf047SPaolo Bonzini 
7124fa9049SPaolo Bonzini     err = pthread_mutex_init(&mutex->lock, NULL);
72baacf047SPaolo Bonzini     if (err)
73baacf047SPaolo Bonzini         error_exit(err, __func__);
74f1aff7aaSPeter Xu     qemu_mutex_post_init(mutex);
75baacf047SPaolo Bonzini }
76baacf047SPaolo Bonzini 
qemu_mutex_destroy(QemuMutex * mutex)77baacf047SPaolo Bonzini void qemu_mutex_destroy(QemuMutex *mutex)
78baacf047SPaolo Bonzini {
79baacf047SPaolo Bonzini     int err;
80baacf047SPaolo Bonzini 
81c096358eSFam Zheng     assert(mutex->initialized);
82c096358eSFam Zheng     mutex->initialized = false;
83baacf047SPaolo Bonzini     err = pthread_mutex_destroy(&mutex->lock);
84baacf047SPaolo Bonzini     if (err)
85baacf047SPaolo Bonzini         error_exit(err, __func__);
86baacf047SPaolo Bonzini }
87baacf047SPaolo Bonzini 
qemu_mutex_lock_impl(QemuMutex * mutex,const char * file,const int line)886c27a0deSAlex Bennée void qemu_mutex_lock_impl(QemuMutex *mutex, const char *file, const int line)
89baacf047SPaolo Bonzini {
90baacf047SPaolo Bonzini     int err;
91baacf047SPaolo Bonzini 
92c096358eSFam Zheng     assert(mutex->initialized);
93f1aff7aaSPeter Xu     qemu_mutex_pre_lock(mutex, file, line);
94baacf047SPaolo Bonzini     err = pthread_mutex_lock(&mutex->lock);
95baacf047SPaolo Bonzini     if (err)
96baacf047SPaolo Bonzini         error_exit(err, __func__);
97f1aff7aaSPeter Xu     qemu_mutex_post_lock(mutex, file, line);
98baacf047SPaolo Bonzini }
99baacf047SPaolo Bonzini 
qemu_mutex_trylock_impl(QemuMutex * mutex,const char * file,const int line)1006c27a0deSAlex Bennée int qemu_mutex_trylock_impl(QemuMutex *mutex, const char *file, const int line)
101baacf047SPaolo Bonzini {
10231f5a726SJose Ricardo Ziviani     int err;
10331f5a726SJose Ricardo Ziviani 
104c096358eSFam Zheng     assert(mutex->initialized);
10531f5a726SJose Ricardo Ziviani     err = pthread_mutex_trylock(&mutex->lock);
10631f5a726SJose Ricardo Ziviani     if (err == 0) {
107f1aff7aaSPeter Xu         qemu_mutex_post_lock(mutex, file, line);
10831f5a726SJose Ricardo Ziviani         return 0;
10931f5a726SJose Ricardo Ziviani     }
11031f5a726SJose Ricardo Ziviani     if (err != EBUSY) {
11131f5a726SJose Ricardo Ziviani         error_exit(err, __func__);
11231f5a726SJose Ricardo Ziviani     }
11331f5a726SJose Ricardo Ziviani     return -EBUSY;
114baacf047SPaolo Bonzini }
115baacf047SPaolo Bonzini 
qemu_mutex_unlock_impl(QemuMutex * mutex,const char * file,const int line)1166c27a0deSAlex Bennée void qemu_mutex_unlock_impl(QemuMutex *mutex, const char *file, const int line)
117baacf047SPaolo Bonzini {
118baacf047SPaolo Bonzini     int err;
119baacf047SPaolo Bonzini 
120c096358eSFam Zheng     assert(mutex->initialized);
121f1aff7aaSPeter Xu     qemu_mutex_pre_unlock(mutex, file, line);
122baacf047SPaolo Bonzini     err = pthread_mutex_unlock(&mutex->lock);
123baacf047SPaolo Bonzini     if (err)
124baacf047SPaolo Bonzini         error_exit(err, __func__);
125baacf047SPaolo Bonzini }
126baacf047SPaolo Bonzini 
qemu_rec_mutex_init(QemuRecMutex * mutex)127feadec63SPaolo Bonzini void qemu_rec_mutex_init(QemuRecMutex *mutex)
128feadec63SPaolo Bonzini {
129feadec63SPaolo Bonzini     int err;
130feadec63SPaolo Bonzini     pthread_mutexattr_t attr;
131feadec63SPaolo Bonzini 
132feadec63SPaolo Bonzini     pthread_mutexattr_init(&attr);
133feadec63SPaolo Bonzini     pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
1346c98635eSRichard Henderson     err = pthread_mutex_init(&mutex->m.lock, &attr);
135feadec63SPaolo Bonzini     pthread_mutexattr_destroy(&attr);
136feadec63SPaolo Bonzini     if (err) {
137feadec63SPaolo Bonzini         error_exit(err, __func__);
138feadec63SPaolo Bonzini     }
1396c98635eSRichard Henderson     mutex->m.initialized = true;
140feadec63SPaolo Bonzini }
141feadec63SPaolo Bonzini 
qemu_rec_mutex_destroy(QemuRecMutex * mutex)1424b193bb7SRichard Henderson void qemu_rec_mutex_destroy(QemuRecMutex *mutex)
1434b193bb7SRichard Henderson {
1446c98635eSRichard Henderson     qemu_mutex_destroy(&mutex->m);
1454b193bb7SRichard Henderson }
1464b193bb7SRichard Henderson 
qemu_rec_mutex_lock_impl(QemuRecMutex * mutex,const char * file,int line)1474b193bb7SRichard Henderson void qemu_rec_mutex_lock_impl(QemuRecMutex *mutex, const char *file, int line)
1484b193bb7SRichard Henderson {
1496c98635eSRichard Henderson     qemu_mutex_lock_impl(&mutex->m, file, line);
1504b193bb7SRichard Henderson }
1514b193bb7SRichard Henderson 
qemu_rec_mutex_trylock_impl(QemuRecMutex * mutex,const char * file,int line)1524b193bb7SRichard Henderson int qemu_rec_mutex_trylock_impl(QemuRecMutex *mutex, const char *file, int line)
1534b193bb7SRichard Henderson {
1546c98635eSRichard Henderson     return qemu_mutex_trylock_impl(&mutex->m, file, line);
1554b193bb7SRichard Henderson }
1564b193bb7SRichard Henderson 
qemu_rec_mutex_unlock_impl(QemuRecMutex * mutex,const char * file,int line)1579c75bae7SRichard Henderson void qemu_rec_mutex_unlock_impl(QemuRecMutex *mutex, const char *file, int line)
1584b193bb7SRichard Henderson {
1596c98635eSRichard Henderson     qemu_mutex_unlock_impl(&mutex->m, file, line);
1604b193bb7SRichard Henderson }
1614b193bb7SRichard Henderson 
qemu_cond_init(QemuCond * cond)162baacf047SPaolo Bonzini void qemu_cond_init(QemuCond *cond)
163baacf047SPaolo Bonzini {
164657ac98bSLongpeng(Mike)     pthread_condattr_t attr;
165baacf047SPaolo Bonzini     int err;
166baacf047SPaolo Bonzini 
167657ac98bSLongpeng(Mike)     err = pthread_condattr_init(&attr);
168657ac98bSLongpeng(Mike)     if (err) {
169baacf047SPaolo Bonzini         error_exit(err, __func__);
170657ac98bSLongpeng(Mike)     }
171657ac98bSLongpeng(Mike) #ifdef CONFIG_PTHREAD_CONDATTR_SETCLOCK
172657ac98bSLongpeng(Mike)     err = pthread_condattr_setclock(&attr, qemu_timedwait_clockid());
173657ac98bSLongpeng(Mike)     if (err) {
174657ac98bSLongpeng(Mike)         error_exit(err, __func__);
175657ac98bSLongpeng(Mike)     }
176657ac98bSLongpeng(Mike) #endif
177657ac98bSLongpeng(Mike)     err = pthread_cond_init(&cond->cond, &attr);
178657ac98bSLongpeng(Mike)     if (err) {
179657ac98bSLongpeng(Mike)         error_exit(err, __func__);
180657ac98bSLongpeng(Mike)     }
181657ac98bSLongpeng(Mike)     err = pthread_condattr_destroy(&attr);
182657ac98bSLongpeng(Mike)     if (err) {
183657ac98bSLongpeng(Mike)         error_exit(err, __func__);
184657ac98bSLongpeng(Mike)     }
185c096358eSFam Zheng     cond->initialized = true;
186baacf047SPaolo Bonzini }
187baacf047SPaolo Bonzini 
qemu_cond_destroy(QemuCond * cond)188baacf047SPaolo Bonzini void qemu_cond_destroy(QemuCond *cond)
189baacf047SPaolo Bonzini {
190baacf047SPaolo Bonzini     int err;
191baacf047SPaolo Bonzini 
192c096358eSFam Zheng     assert(cond->initialized);
193c096358eSFam Zheng     cond->initialized = false;
194baacf047SPaolo Bonzini     err = pthread_cond_destroy(&cond->cond);
195baacf047SPaolo Bonzini     if (err)
196baacf047SPaolo Bonzini         error_exit(err, __func__);
197baacf047SPaolo Bonzini }
198baacf047SPaolo Bonzini 
qemu_cond_signal(QemuCond * cond)199baacf047SPaolo Bonzini void qemu_cond_signal(QemuCond *cond)
200baacf047SPaolo Bonzini {
201baacf047SPaolo Bonzini     int err;
202baacf047SPaolo Bonzini 
203c096358eSFam Zheng     assert(cond->initialized);
204baacf047SPaolo Bonzini     err = pthread_cond_signal(&cond->cond);
205baacf047SPaolo Bonzini     if (err)
206baacf047SPaolo Bonzini         error_exit(err, __func__);
207baacf047SPaolo Bonzini }
208baacf047SPaolo Bonzini 
qemu_cond_broadcast(QemuCond * cond)209baacf047SPaolo Bonzini void qemu_cond_broadcast(QemuCond *cond)
210baacf047SPaolo Bonzini {
211baacf047SPaolo Bonzini     int err;
212baacf047SPaolo Bonzini 
213c096358eSFam Zheng     assert(cond->initialized);
214baacf047SPaolo Bonzini     err = pthread_cond_broadcast(&cond->cond);
215baacf047SPaolo Bonzini     if (err)
216baacf047SPaolo Bonzini         error_exit(err, __func__);
217baacf047SPaolo Bonzini }
218baacf047SPaolo Bonzini 
qemu_cond_wait_impl(QemuCond * cond,QemuMutex * mutex,const char * file,const int line)2196c27a0deSAlex Bennée void qemu_cond_wait_impl(QemuCond *cond, QemuMutex *mutex, const char *file, const int line)
220baacf047SPaolo Bonzini {
221baacf047SPaolo Bonzini     int err;
222baacf047SPaolo Bonzini 
223c096358eSFam Zheng     assert(cond->initialized);
224f1aff7aaSPeter Xu     qemu_mutex_pre_unlock(mutex, file, line);
225baacf047SPaolo Bonzini     err = pthread_cond_wait(&cond->cond, &mutex->lock);
226f1aff7aaSPeter Xu     qemu_mutex_post_lock(mutex, file, line);
227baacf047SPaolo Bonzini     if (err)
228baacf047SPaolo Bonzini         error_exit(err, __func__);
229baacf047SPaolo Bonzini }
230baacf047SPaolo Bonzini 
231deb9c2adSEmanuele Giuseppe Esposito static bool TSA_NO_TSA
qemu_cond_timedwait_ts(QemuCond * cond,QemuMutex * mutex,struct timespec * ts,const char * file,const int line)232a0d45db8SLongpeng(Mike) qemu_cond_timedwait_ts(QemuCond *cond, QemuMutex *mutex, struct timespec *ts,
2333dcc9c6eSYury Kotov                        const char *file, const int line)
2343dcc9c6eSYury Kotov {
2353dcc9c6eSYury Kotov     int err;
2363dcc9c6eSYury Kotov 
2373dcc9c6eSYury Kotov     assert(cond->initialized);
2383dcc9c6eSYury Kotov     trace_qemu_mutex_unlock(mutex, file, line);
239a0d45db8SLongpeng(Mike)     err = pthread_cond_timedwait(&cond->cond, &mutex->lock, ts);
2403dcc9c6eSYury Kotov     trace_qemu_mutex_locked(mutex, file, line);
2413dcc9c6eSYury Kotov     if (err && err != ETIMEDOUT) {
2423dcc9c6eSYury Kotov         error_exit(err, __func__);
2433dcc9c6eSYury Kotov     }
2443dcc9c6eSYury Kotov     return err != ETIMEDOUT;
2453dcc9c6eSYury Kotov }
2463dcc9c6eSYury Kotov 
qemu_cond_timedwait_impl(QemuCond * cond,QemuMutex * mutex,int ms,const char * file,const int line)247a0d45db8SLongpeng(Mike) bool qemu_cond_timedwait_impl(QemuCond *cond, QemuMutex *mutex, int ms,
248a0d45db8SLongpeng(Mike)                               const char *file, const int line)
249a0d45db8SLongpeng(Mike) {
250a0d45db8SLongpeng(Mike)     struct timespec ts;
251a0d45db8SLongpeng(Mike) 
252a0d45db8SLongpeng(Mike)     compute_abs_deadline(&ts, ms);
253a0d45db8SLongpeng(Mike)     return qemu_cond_timedwait_ts(cond, mutex, &ts, file, line);
254a0d45db8SLongpeng(Mike) }
255a0d45db8SLongpeng(Mike) 
qemu_sem_init(QemuSemaphore * sem,int init)256baacf047SPaolo Bonzini void qemu_sem_init(QemuSemaphore *sem, int init)
257baacf047SPaolo Bonzini {
258a0d45db8SLongpeng(Mike)     qemu_mutex_init(&sem->mutex);
259a0d45db8SLongpeng(Mike)     qemu_cond_init(&sem->cond);
260baacf047SPaolo Bonzini 
261baacf047SPaolo Bonzini     if (init < 0) {
262baacf047SPaolo Bonzini         error_exit(EINVAL, __func__);
263baacf047SPaolo Bonzini     }
264baacf047SPaolo Bonzini     sem->count = init;
265baacf047SPaolo Bonzini }
266baacf047SPaolo Bonzini 
qemu_sem_destroy(QemuSemaphore * sem)267baacf047SPaolo Bonzini void qemu_sem_destroy(QemuSemaphore *sem)
268baacf047SPaolo Bonzini {
269a0d45db8SLongpeng(Mike)     qemu_cond_destroy(&sem->cond);
270a0d45db8SLongpeng(Mike)     qemu_mutex_destroy(&sem->mutex);
271baacf047SPaolo Bonzini }
272baacf047SPaolo Bonzini 
qemu_sem_post(QemuSemaphore * sem)273baacf047SPaolo Bonzini void qemu_sem_post(QemuSemaphore *sem)
274baacf047SPaolo Bonzini {
275a0d45db8SLongpeng(Mike)     qemu_mutex_lock(&sem->mutex);
27679761c66SIzumi Tsutsui     if (sem->count == UINT_MAX) {
277a0d45db8SLongpeng(Mike)         error_exit(EINVAL, __func__);
278baacf047SPaolo Bonzini     } else {
27979761c66SIzumi Tsutsui         sem->count++;
280a0d45db8SLongpeng(Mike)         qemu_cond_signal(&sem->cond);
281baacf047SPaolo Bonzini     }
282a0d45db8SLongpeng(Mike)     qemu_mutex_unlock(&sem->mutex);
283baacf047SPaolo Bonzini }
284baacf047SPaolo Bonzini 
qemu_sem_timedwait(QemuSemaphore * sem,int ms)285baacf047SPaolo Bonzini int qemu_sem_timedwait(QemuSemaphore *sem, int ms)
286baacf047SPaolo Bonzini {
287a0d45db8SLongpeng(Mike)     bool rc = true;
288baacf047SPaolo Bonzini     struct timespec ts;
289baacf047SPaolo Bonzini 
290baacf047SPaolo Bonzini     compute_abs_deadline(&ts, ms);
291a0d45db8SLongpeng(Mike)     qemu_mutex_lock(&sem->mutex);
29279761c66SIzumi Tsutsui     while (sem->count == 0) {
2938ab30264SPaolo Bonzini         if (ms == 0) {
2948ab30264SPaolo Bonzini             rc = false;
2958ab30264SPaolo Bonzini         } else {
296a0d45db8SLongpeng(Mike)             rc = qemu_cond_timedwait_ts(&sem->cond, &sem->mutex, &ts,
297a0d45db8SLongpeng(Mike)                                         __FILE__, __LINE__);
2988ab30264SPaolo Bonzini         }
299a0d45db8SLongpeng(Mike)         if (!rc) { /* timeout */
300baacf047SPaolo Bonzini             break;
301baacf047SPaolo Bonzini         }
302baacf047SPaolo Bonzini     }
303a0d45db8SLongpeng(Mike)     if (rc) {
30479761c66SIzumi Tsutsui         --sem->count;
30579761c66SIzumi Tsutsui     }
306a0d45db8SLongpeng(Mike)     qemu_mutex_unlock(&sem->mutex);
307a0d45db8SLongpeng(Mike)     return (rc ? 0 : -1);
308baacf047SPaolo Bonzini }
309baacf047SPaolo Bonzini 
qemu_sem_wait(QemuSemaphore * sem)310baacf047SPaolo Bonzini void qemu_sem_wait(QemuSemaphore *sem)
311baacf047SPaolo Bonzini {
312a0d45db8SLongpeng(Mike)     qemu_mutex_lock(&sem->mutex);
31379761c66SIzumi Tsutsui     while (sem->count == 0) {
314a0d45db8SLongpeng(Mike)         qemu_cond_wait(&sem->cond, &sem->mutex);
31579761c66SIzumi Tsutsui     }
31679761c66SIzumi Tsutsui     --sem->count;
317a0d45db8SLongpeng(Mike)     qemu_mutex_unlock(&sem->mutex);
318baacf047SPaolo Bonzini }
319baacf047SPaolo Bonzini 
320c7c4d063SPaolo Bonzini #ifdef __linux__
321fbcc3e50SPaolo Bonzini #include "qemu/futex.h"
322c7c4d063SPaolo Bonzini #else
qemu_futex_wake(QemuEvent * ev,int n)323fbcc3e50SPaolo Bonzini static inline void qemu_futex_wake(QemuEvent *ev, int n)
324c7c4d063SPaolo Bonzini {
325c096358eSFam Zheng     assert(ev->initialized);
326158ef8cbSPaolo Bonzini     pthread_mutex_lock(&ev->lock);
327c7c4d063SPaolo Bonzini     if (n == 1) {
328c7c4d063SPaolo Bonzini         pthread_cond_signal(&ev->cond);
329c7c4d063SPaolo Bonzini     } else {
330c7c4d063SPaolo Bonzini         pthread_cond_broadcast(&ev->cond);
331c7c4d063SPaolo Bonzini     }
332158ef8cbSPaolo Bonzini     pthread_mutex_unlock(&ev->lock);
333c7c4d063SPaolo Bonzini }
334c7c4d063SPaolo Bonzini 
qemu_futex_wait(QemuEvent * ev,unsigned val)335fbcc3e50SPaolo Bonzini static inline void qemu_futex_wait(QemuEvent *ev, unsigned val)
336c7c4d063SPaolo Bonzini {
337c096358eSFam Zheng     assert(ev->initialized);
338c7c4d063SPaolo Bonzini     pthread_mutex_lock(&ev->lock);
339c7c4d063SPaolo Bonzini     if (ev->value == val) {
340c7c4d063SPaolo Bonzini         pthread_cond_wait(&ev->cond, &ev->lock);
341c7c4d063SPaolo Bonzini     }
342c7c4d063SPaolo Bonzini     pthread_mutex_unlock(&ev->lock);
343c7c4d063SPaolo Bonzini }
344c7c4d063SPaolo Bonzini #endif
345c7c4d063SPaolo Bonzini 
346c7c4d063SPaolo Bonzini /* Valid transitions:
347c7c4d063SPaolo Bonzini  * - free->set, when setting the event
348fbcc3e50SPaolo Bonzini  * - busy->set, when setting the event, followed by qemu_futex_wake
349c7c4d063SPaolo Bonzini  * - set->free, when resetting the event
350c7c4d063SPaolo Bonzini  * - free->busy, when waiting
351c7c4d063SPaolo Bonzini  *
352c7c4d063SPaolo Bonzini  * set->busy does not happen (it can be observed from the outside but
353c7c4d063SPaolo Bonzini  * it really is set->free->busy).
354c7c4d063SPaolo Bonzini  *
355c7c4d063SPaolo Bonzini  * busy->free provably cannot happen; to enforce it, the set->free transition
356c7c4d063SPaolo Bonzini  * is done with an OR, which becomes a no-op if the event has concurrently
357c7c4d063SPaolo Bonzini  * transitioned to free or busy.
358c7c4d063SPaolo Bonzini  */
359c7c4d063SPaolo Bonzini 
360c7c4d063SPaolo Bonzini #define EV_SET         0
361c7c4d063SPaolo Bonzini #define EV_FREE        1
362c7c4d063SPaolo Bonzini #define EV_BUSY       -1
363c7c4d063SPaolo Bonzini 
qemu_event_init(QemuEvent * ev,bool init)364c7c4d063SPaolo Bonzini void qemu_event_init(QemuEvent *ev, bool init)
365c7c4d063SPaolo Bonzini {
366c7c4d063SPaolo Bonzini #ifndef __linux__
367c7c4d063SPaolo Bonzini     pthread_mutex_init(&ev->lock, NULL);
368c7c4d063SPaolo Bonzini     pthread_cond_init(&ev->cond, NULL);
369c7c4d063SPaolo Bonzini #endif
370c7c4d063SPaolo Bonzini 
371c7c4d063SPaolo Bonzini     ev->value = (init ? EV_SET : EV_FREE);
372c096358eSFam Zheng     ev->initialized = true;
373c7c4d063SPaolo Bonzini }
374c7c4d063SPaolo Bonzini 
qemu_event_destroy(QemuEvent * ev)375c7c4d063SPaolo Bonzini void qemu_event_destroy(QemuEvent *ev)
376c7c4d063SPaolo Bonzini {
377c096358eSFam Zheng     assert(ev->initialized);
378c096358eSFam Zheng     ev->initialized = false;
379c7c4d063SPaolo Bonzini #ifndef __linux__
380c7c4d063SPaolo Bonzini     pthread_mutex_destroy(&ev->lock);
381c7c4d063SPaolo Bonzini     pthread_cond_destroy(&ev->cond);
382c7c4d063SPaolo Bonzini #endif
383c7c4d063SPaolo Bonzini }
384c7c4d063SPaolo Bonzini 
qemu_event_set(QemuEvent * ev)385c7c4d063SPaolo Bonzini void qemu_event_set(QemuEvent *ev)
386c7c4d063SPaolo Bonzini {
387*9586a132SPaolo Bonzini     assert(ev->initialized);
388*9586a132SPaolo Bonzini 
389*9586a132SPaolo Bonzini     /*
390*9586a132SPaolo Bonzini      * Pairs with both qemu_event_reset() and qemu_event_wait().
391*9586a132SPaolo Bonzini      *
392*9586a132SPaolo Bonzini      * qemu_event_set has release semantics, but because it *loads*
393374293caSPaolo Bonzini      * ev->value we need a full memory barrier here.
394374293caSPaolo Bonzini      */
395374293caSPaolo Bonzini     smp_mb();
396d73415a3SStefan Hajnoczi     if (qatomic_read(&ev->value) != EV_SET) {
397*9586a132SPaolo Bonzini         int old = qatomic_xchg(&ev->value, EV_SET);
398*9586a132SPaolo Bonzini 
399*9586a132SPaolo Bonzini         /* Pairs with memory barrier in kernel futex_wait system call.  */
400*9586a132SPaolo Bonzini         smp_mb__after_rmw();
401*9586a132SPaolo Bonzini         if (old == EV_BUSY) {
402c7c4d063SPaolo Bonzini             /* There were waiters, wake them up.  */
403fbcc3e50SPaolo Bonzini             qemu_futex_wake(ev, INT_MAX);
404c7c4d063SPaolo Bonzini         }
405c7c4d063SPaolo Bonzini     }
406c7c4d063SPaolo Bonzini }
407c7c4d063SPaolo Bonzini 
qemu_event_reset(QemuEvent * ev)408c7c4d063SPaolo Bonzini void qemu_event_reset(QemuEvent *ev)
409c7c4d063SPaolo Bonzini {
410c096358eSFam Zheng     assert(ev->initialized);
411*9586a132SPaolo Bonzini 
412c7c4d063SPaolo Bonzini     /*
413c7c4d063SPaolo Bonzini      * If there was a concurrent reset (or even reset+wait),
414c7c4d063SPaolo Bonzini      * do nothing.  Otherwise change EV_SET->EV_FREE.
415c7c4d063SPaolo Bonzini      */
416d73415a3SStefan Hajnoczi     qatomic_or(&ev->value, EV_FREE);
417*9586a132SPaolo Bonzini 
418*9586a132SPaolo Bonzini     /*
419*9586a132SPaolo Bonzini      * Order reset before checking the condition in the caller.
420*9586a132SPaolo Bonzini      * Pairs with the first memory barrier in qemu_event_set().
421*9586a132SPaolo Bonzini      */
422*9586a132SPaolo Bonzini     smp_mb__after_rmw();
423c7c4d063SPaolo Bonzini }
424c7c4d063SPaolo Bonzini 
qemu_event_wait(QemuEvent * ev)425c7c4d063SPaolo Bonzini void qemu_event_wait(QemuEvent *ev)
426c7c4d063SPaolo Bonzini {
427c7c4d063SPaolo Bonzini     unsigned value;
428c7c4d063SPaolo Bonzini 
429c096358eSFam Zheng     assert(ev->initialized);
430*9586a132SPaolo Bonzini 
431*9586a132SPaolo Bonzini     /*
432*9586a132SPaolo Bonzini      * qemu_event_wait must synchronize with qemu_event_set even if it does
433*9586a132SPaolo Bonzini      * not go down the slow path, so this load-acquire is needed that
434*9586a132SPaolo Bonzini      * synchronizes with the first memory barrier in qemu_event_set().
435*9586a132SPaolo Bonzini      *
436*9586a132SPaolo Bonzini      * If we do go down the slow path, there is no requirement at all: we
437*9586a132SPaolo Bonzini      * might miss a qemu_event_set() here but ultimately the memory barrier in
438*9586a132SPaolo Bonzini      * qemu_futex_wait() will ensure the check is done correctly.
439*9586a132SPaolo Bonzini      */
440*9586a132SPaolo Bonzini     value = qatomic_load_acquire(&ev->value);
441c7c4d063SPaolo Bonzini     if (value != EV_SET) {
442c7c4d063SPaolo Bonzini         if (value == EV_FREE) {
443c7c4d063SPaolo Bonzini             /*
444*9586a132SPaolo Bonzini              * Leave the event reset and tell qemu_event_set that there are
445*9586a132SPaolo Bonzini              * waiters.  No need to retry, because there cannot be a concurrent
446*9586a132SPaolo Bonzini              * busy->free transition.  After the CAS, the event will be either
447*9586a132SPaolo Bonzini              * set or busy.
448*9586a132SPaolo Bonzini              *
449*9586a132SPaolo Bonzini              * This cmpxchg doesn't have particular ordering requirements if it
450*9586a132SPaolo Bonzini              * succeeds (moving the store earlier can only cause qemu_event_set()
451*9586a132SPaolo Bonzini              * to issue _more_ wakeups), the failing case needs acquire semantics
452*9586a132SPaolo Bonzini              * like the load above.
453c7c4d063SPaolo Bonzini              */
454d73415a3SStefan Hajnoczi             if (qatomic_cmpxchg(&ev->value, EV_FREE, EV_BUSY) == EV_SET) {
455c7c4d063SPaolo Bonzini                 return;
456c7c4d063SPaolo Bonzini             }
457c7c4d063SPaolo Bonzini         }
458*9586a132SPaolo Bonzini 
459*9586a132SPaolo Bonzini         /*
460*9586a132SPaolo Bonzini          * This is the final check for a concurrent set, so it does need
461*9586a132SPaolo Bonzini          * a smp_mb() pairing with the second barrier of qemu_event_set().
462*9586a132SPaolo Bonzini          * The barrier is inside the FUTEX_WAIT system call.
463*9586a132SPaolo Bonzini          */
464fbcc3e50SPaolo Bonzini         qemu_futex_wait(ev, EV_BUSY);
465c7c4d063SPaolo Bonzini     }
466c7c4d063SPaolo Bonzini }
467c7c4d063SPaolo Bonzini 
468a458774aSPeter Maydell static __thread NotifierList thread_exit;
469ef57137fSPaolo Bonzini 
470a458774aSPeter Maydell /*
471a458774aSPeter Maydell  * Note that in this implementation you can register a thread-exit
472a458774aSPeter Maydell  * notifier for the main thread, but it will never be called.
473a458774aSPeter Maydell  * This is OK because main thread exit can only happen when the
474a458774aSPeter Maydell  * entire process is exiting, and the API allows notifiers to not
475a458774aSPeter Maydell  * be called on process exit.
476a458774aSPeter Maydell  */
qemu_thread_atexit_add(Notifier * notifier)477ef57137fSPaolo Bonzini void qemu_thread_atexit_add(Notifier *notifier)
478ef57137fSPaolo Bonzini {
479a458774aSPeter Maydell     notifier_list_add(&thread_exit, notifier);
480ef57137fSPaolo Bonzini }
481ef57137fSPaolo Bonzini 
qemu_thread_atexit_remove(Notifier * notifier)482ef57137fSPaolo Bonzini void qemu_thread_atexit_remove(Notifier *notifier)
483ef57137fSPaolo Bonzini {
484ef57137fSPaolo Bonzini     notifier_remove(notifier);
485ef57137fSPaolo Bonzini }
486ef57137fSPaolo Bonzini 
qemu_thread_atexit_notify(void * arg)487a458774aSPeter Maydell static void qemu_thread_atexit_notify(void *arg)
488ef57137fSPaolo Bonzini {
489a458774aSPeter Maydell     /*
490a458774aSPeter Maydell      * Called when non-main thread exits (via qemu_thread_exit()
491a458774aSPeter Maydell      * or by returning from its start routine.)
492a458774aSPeter Maydell      */
493a458774aSPeter Maydell     notifier_list_notify(&thread_exit, NULL);
494ef57137fSPaolo Bonzini }
495ef57137fSPaolo Bonzini 
49668a93982Slinzhecheng typedef struct {
49768a93982Slinzhecheng     void *(*start_routine)(void *);
49868a93982Slinzhecheng     void *arg;
49968a93982Slinzhecheng     char *name;
50068a93982Slinzhecheng } QemuThreadArgs;
50168a93982Slinzhecheng 
qemu_thread_start(void * args)50268a93982Slinzhecheng static void *qemu_thread_start(void *args)
50368a93982Slinzhecheng {
50468a93982Slinzhecheng     QemuThreadArgs *qemu_thread_args = args;
50568a93982Slinzhecheng     void *(*start_routine)(void *) = qemu_thread_args->start_routine;
50668a93982Slinzhecheng     void *arg = qemu_thread_args->arg;
507a458774aSPeter Maydell     void *r;
50868a93982Slinzhecheng 
5095c312079SDr. David Alan Gilbert     /* Attempt to set the threads name; note that this is for debug, so
5105c312079SDr. David Alan Gilbert      * we're not going to fail if we can't set it.
5115c312079SDr. David Alan Gilbert      */
512d820fa5bSPeter Xu     if (name_threads && qemu_thread_args->name) {
513479a5747SRoman Bolshakov # if defined(CONFIG_PTHREAD_SETNAME_NP_W_TID)
51468a93982Slinzhecheng         pthread_setname_np(pthread_self(), qemu_thread_args->name);
515479a5747SRoman Bolshakov # elif defined(CONFIG_PTHREAD_SETNAME_NP_WO_TID)
516479a5747SRoman Bolshakov         pthread_setname_np(qemu_thread_args->name);
5173ada67a3SBrad Smith # elif defined(CONFIG_PTHREAD_SET_NAME_NP)
5183ada67a3SBrad Smith         pthread_set_name_np(pthread_self(), qemu_thread_args->name);
519479a5747SRoman Bolshakov # endif
520d820fa5bSPeter Xu     }
521ce9f0e5bSRobert Foley     QEMU_TSAN_ANNOTATE_THREAD_NAME(qemu_thread_args->name);
52268a93982Slinzhecheng     g_free(qemu_thread_args->name);
52368a93982Slinzhecheng     g_free(qemu_thread_args);
52437daf1baSRichard Henderson 
52537daf1baSRichard Henderson     /*
52637daf1baSRichard Henderson      * GCC 11 with glibc 2.17 on PowerPC reports
52737daf1baSRichard Henderson      *
52837daf1baSRichard Henderson      * qemu-thread-posix.c:540:5: error: ‘__sigsetjmp’ accessing 656 bytes
52937daf1baSRichard Henderson      *   in a region of size 528 [-Werror=stringop-overflow=]
53037daf1baSRichard Henderson      * 540 |     pthread_cleanup_push(qemu_thread_atexit_notify, NULL);
53137daf1baSRichard Henderson      *     |     ^~~~~~~~~~~~~~~~~~~~
53237daf1baSRichard Henderson      *
53337daf1baSRichard Henderson      * which is clearly nonsense.
53437daf1baSRichard Henderson      */
53537daf1baSRichard Henderson #pragma GCC diagnostic push
53637daf1baSRichard Henderson #ifndef __clang__
53737daf1baSRichard Henderson #pragma GCC diagnostic ignored "-Wstringop-overflow"
53837daf1baSRichard Henderson #endif
53937daf1baSRichard Henderson 
540a458774aSPeter Maydell     pthread_cleanup_push(qemu_thread_atexit_notify, NULL);
541a458774aSPeter Maydell     r = start_routine(arg);
542a458774aSPeter Maydell     pthread_cleanup_pop(1);
54337daf1baSRichard Henderson 
54437daf1baSRichard Henderson #pragma GCC diagnostic pop
54537daf1baSRichard Henderson 
546a458774aSPeter Maydell     return r;
5475c312079SDr. David Alan Gilbert }
5485c312079SDr. David Alan Gilbert 
qemu_thread_create(QemuThread * thread,const char * name,void * (* start_routine)(void *),void * arg,int mode)5494900116eSDr. David Alan Gilbert void qemu_thread_create(QemuThread *thread, const char *name,
550baacf047SPaolo Bonzini                        void *(*start_routine)(void*),
551baacf047SPaolo Bonzini                        void *arg, int mode)
552baacf047SPaolo Bonzini {
553baacf047SPaolo Bonzini     sigset_t set, oldset;
554baacf047SPaolo Bonzini     int err;
555baacf047SPaolo Bonzini     pthread_attr_t attr;
556d820fa5bSPeter Xu     QemuThreadArgs *qemu_thread_args;
557baacf047SPaolo Bonzini 
558baacf047SPaolo Bonzini     err = pthread_attr_init(&attr);
559baacf047SPaolo Bonzini     if (err) {
560baacf047SPaolo Bonzini         error_exit(err, __func__);
561baacf047SPaolo Bonzini     }
562baacf047SPaolo Bonzini 
56368a93982Slinzhecheng     if (mode == QEMU_THREAD_DETACHED) {
56468a93982Slinzhecheng         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
56568a93982Slinzhecheng     }
56668a93982Slinzhecheng 
567baacf047SPaolo Bonzini     /* Leave signal handling to the iothread.  */
568baacf047SPaolo Bonzini     sigfillset(&set);
56921a43af0SRoman Bolshakov     /* Blocking the signals can result in undefined behaviour. */
57021a43af0SRoman Bolshakov     sigdelset(&set, SIGSEGV);
57121a43af0SRoman Bolshakov     sigdelset(&set, SIGFPE);
57221a43af0SRoman Bolshakov     sigdelset(&set, SIGILL);
57321a43af0SRoman Bolshakov     /* TODO avoid SIGBUS loss on macOS */
574baacf047SPaolo Bonzini     pthread_sigmask(SIG_SETMASK, &set, &oldset);
57568a93982Slinzhecheng 
57668a93982Slinzhecheng     qemu_thread_args = g_new0(QemuThreadArgs, 1);
57768a93982Slinzhecheng     qemu_thread_args->name = g_strdup(name);
57868a93982Slinzhecheng     qemu_thread_args->start_routine = start_routine;
57968a93982Slinzhecheng     qemu_thread_args->arg = arg;
58068a93982Slinzhecheng 
58168a93982Slinzhecheng     err = pthread_create(&thread->thread, &attr,
58268a93982Slinzhecheng                          qemu_thread_start, qemu_thread_args);
58368a93982Slinzhecheng 
584baacf047SPaolo Bonzini     if (err)
585baacf047SPaolo Bonzini         error_exit(err, __func__);
586baacf047SPaolo Bonzini 
587baacf047SPaolo Bonzini     pthread_sigmask(SIG_SETMASK, &oldset, NULL);
588baacf047SPaolo Bonzini 
589baacf047SPaolo Bonzini     pthread_attr_destroy(&attr);
590baacf047SPaolo Bonzini }
591baacf047SPaolo Bonzini 
qemu_thread_set_affinity(QemuThread * thread,unsigned long * host_cpus,unsigned long nbits)5927730f32cSDavid Hildenbrand int qemu_thread_set_affinity(QemuThread *thread, unsigned long *host_cpus,
5937730f32cSDavid Hildenbrand                              unsigned long nbits)
5947730f32cSDavid Hildenbrand {
5957730f32cSDavid Hildenbrand #if defined(CONFIG_PTHREAD_AFFINITY_NP)
5967730f32cSDavid Hildenbrand     const size_t setsize = CPU_ALLOC_SIZE(nbits);
5977730f32cSDavid Hildenbrand     unsigned long value;
5987730f32cSDavid Hildenbrand     cpu_set_t *cpuset;
5997730f32cSDavid Hildenbrand     int err;
6007730f32cSDavid Hildenbrand 
6017730f32cSDavid Hildenbrand     cpuset = CPU_ALLOC(nbits);
6027730f32cSDavid Hildenbrand     g_assert(cpuset);
6037730f32cSDavid Hildenbrand 
6047730f32cSDavid Hildenbrand     CPU_ZERO_S(setsize, cpuset);
6057730f32cSDavid Hildenbrand     value = find_first_bit(host_cpus, nbits);
6067730f32cSDavid Hildenbrand     while (value < nbits) {
6077730f32cSDavid Hildenbrand         CPU_SET_S(value, setsize, cpuset);
6087730f32cSDavid Hildenbrand         value = find_next_bit(host_cpus, nbits, value + 1);
6097730f32cSDavid Hildenbrand     }
6107730f32cSDavid Hildenbrand 
6117730f32cSDavid Hildenbrand     err = pthread_setaffinity_np(thread->thread, setsize, cpuset);
6127730f32cSDavid Hildenbrand     CPU_FREE(cpuset);
6137730f32cSDavid Hildenbrand     return err;
6147730f32cSDavid Hildenbrand #else
6157730f32cSDavid Hildenbrand     return -ENOSYS;
6167730f32cSDavid Hildenbrand #endif
6177730f32cSDavid Hildenbrand }
6187730f32cSDavid Hildenbrand 
qemu_thread_get_affinity(QemuThread * thread,unsigned long ** host_cpus,unsigned long * nbits)6197730f32cSDavid Hildenbrand int qemu_thread_get_affinity(QemuThread *thread, unsigned long **host_cpus,
6207730f32cSDavid Hildenbrand                              unsigned long *nbits)
6217730f32cSDavid Hildenbrand {
6227730f32cSDavid Hildenbrand #if defined(CONFIG_PTHREAD_AFFINITY_NP)
6237730f32cSDavid Hildenbrand     unsigned long tmpbits;
6247730f32cSDavid Hildenbrand     cpu_set_t *cpuset;
6257730f32cSDavid Hildenbrand     size_t setsize;
6267730f32cSDavid Hildenbrand     int i, err;
6277730f32cSDavid Hildenbrand 
6287730f32cSDavid Hildenbrand     tmpbits = CPU_SETSIZE;
6297730f32cSDavid Hildenbrand     while (true) {
6307730f32cSDavid Hildenbrand         setsize = CPU_ALLOC_SIZE(tmpbits);
6317730f32cSDavid Hildenbrand         cpuset = CPU_ALLOC(tmpbits);
6327730f32cSDavid Hildenbrand         g_assert(cpuset);
6337730f32cSDavid Hildenbrand 
6347730f32cSDavid Hildenbrand         err = pthread_getaffinity_np(thread->thread, setsize, cpuset);
6357730f32cSDavid Hildenbrand         if (err) {
6367730f32cSDavid Hildenbrand             CPU_FREE(cpuset);
6377730f32cSDavid Hildenbrand             if (err != -EINVAL) {
6387730f32cSDavid Hildenbrand                 return err;
6397730f32cSDavid Hildenbrand             }
6407730f32cSDavid Hildenbrand             tmpbits *= 2;
6417730f32cSDavid Hildenbrand         } else {
6427730f32cSDavid Hildenbrand             break;
6437730f32cSDavid Hildenbrand         }
6447730f32cSDavid Hildenbrand     }
6457730f32cSDavid Hildenbrand 
6467730f32cSDavid Hildenbrand     /* Convert the result into a proper bitmap. */
6477730f32cSDavid Hildenbrand     *nbits = tmpbits;
6487730f32cSDavid Hildenbrand     *host_cpus = bitmap_new(tmpbits);
6497730f32cSDavid Hildenbrand     for (i = 0; i < tmpbits; i++) {
6507730f32cSDavid Hildenbrand         if (CPU_ISSET(i, cpuset)) {
6517730f32cSDavid Hildenbrand             set_bit(i, *host_cpus);
6527730f32cSDavid Hildenbrand         }
6537730f32cSDavid Hildenbrand     }
6547730f32cSDavid Hildenbrand     CPU_FREE(cpuset);
6557730f32cSDavid Hildenbrand     return 0;
6567730f32cSDavid Hildenbrand #else
6577730f32cSDavid Hildenbrand     return -ENOSYS;
6587730f32cSDavid Hildenbrand #endif
6597730f32cSDavid Hildenbrand }
6607730f32cSDavid Hildenbrand 
qemu_thread_get_self(QemuThread * thread)661baacf047SPaolo Bonzini void qemu_thread_get_self(QemuThread *thread)
662baacf047SPaolo Bonzini {
663baacf047SPaolo Bonzini     thread->thread = pthread_self();
664baacf047SPaolo Bonzini }
665baacf047SPaolo Bonzini 
qemu_thread_is_self(QemuThread * thread)666baacf047SPaolo Bonzini bool qemu_thread_is_self(QemuThread *thread)
667baacf047SPaolo Bonzini {
668baacf047SPaolo Bonzini    return pthread_equal(pthread_self(), thread->thread);
669baacf047SPaolo Bonzini }
670baacf047SPaolo Bonzini 
qemu_thread_exit(void * retval)671baacf047SPaolo Bonzini void qemu_thread_exit(void *retval)
672baacf047SPaolo Bonzini {
673baacf047SPaolo Bonzini     pthread_exit(retval);
674baacf047SPaolo Bonzini }
675baacf047SPaolo Bonzini 
qemu_thread_join(QemuThread * thread)676baacf047SPaolo Bonzini void *qemu_thread_join(QemuThread *thread)
677baacf047SPaolo Bonzini {
678baacf047SPaolo Bonzini     int err;
679baacf047SPaolo Bonzini     void *ret;
680baacf047SPaolo Bonzini 
681baacf047SPaolo Bonzini     err = pthread_join(thread->thread, &ret);
682baacf047SPaolo Bonzini     if (err) {
683baacf047SPaolo Bonzini         error_exit(err, __func__);
684baacf047SPaolo Bonzini     }
685baacf047SPaolo Bonzini     return ret;
686baacf047SPaolo Bonzini }
687