xref: /openbmc/qemu/util/qemu-thread-posix.c (revision 30b6852c)
1 /*
2  * Wrappers around mutex/cond/thread functions
3  *
4  * Copyright Red Hat, Inc. 2009
5  *
6  * Author:
7  *  Marcelo Tosatti <mtosatti@redhat.com>
8  *
9  * This work is licensed under the terms of the GNU GPL, version 2 or later.
10  * See the COPYING file in the top-level directory.
11  *
12  */
13 #include "qemu/osdep.h"
14 #include "qemu/thread.h"
15 #include "qemu/atomic.h"
16 #include "qemu/notify.h"
17 #include "qemu-thread-common.h"
18 #include "qemu/tsan.h"
19 
20 static bool name_threads;
21 
22 void qemu_thread_naming(bool enable)
23 {
24     name_threads = enable;
25 
26 #ifndef CONFIG_THREAD_SETNAME_BYTHREAD
27     /* This is a debugging option, not fatal */
28     if (enable) {
29         fprintf(stderr, "qemu: thread naming not supported on this host\n");
30     }
31 #endif
32 }
33 
34 static void error_exit(int err, const char *msg)
35 {
36     fprintf(stderr, "qemu: %s: %s\n", msg, strerror(err));
37     abort();
38 }
39 
40 static void compute_abs_deadline(struct timespec *ts, int ms)
41 {
42     struct timeval tv;
43     gettimeofday(&tv, NULL);
44     ts->tv_nsec = tv.tv_usec * 1000 + (ms % 1000) * 1000000;
45     ts->tv_sec = tv.tv_sec + ms / 1000;
46     if (ts->tv_nsec >= 1000000000) {
47         ts->tv_sec++;
48         ts->tv_nsec -= 1000000000;
49     }
50 }
51 
52 void qemu_mutex_init(QemuMutex *mutex)
53 {
54     int err;
55 
56     err = pthread_mutex_init(&mutex->lock, NULL);
57     if (err)
58         error_exit(err, __func__);
59     qemu_mutex_post_init(mutex);
60 }
61 
62 void qemu_mutex_destroy(QemuMutex *mutex)
63 {
64     int err;
65 
66     assert(mutex->initialized);
67     mutex->initialized = false;
68     err = pthread_mutex_destroy(&mutex->lock);
69     if (err)
70         error_exit(err, __func__);
71 }
72 
73 void qemu_mutex_lock_impl(QemuMutex *mutex, const char *file, const int line)
74 {
75     int err;
76 
77     assert(mutex->initialized);
78     qemu_mutex_pre_lock(mutex, file, line);
79     err = pthread_mutex_lock(&mutex->lock);
80     if (err)
81         error_exit(err, __func__);
82     qemu_mutex_post_lock(mutex, file, line);
83 }
84 
85 int qemu_mutex_trylock_impl(QemuMutex *mutex, const char *file, const int line)
86 {
87     int err;
88 
89     assert(mutex->initialized);
90     err = pthread_mutex_trylock(&mutex->lock);
91     if (err == 0) {
92         qemu_mutex_post_lock(mutex, file, line);
93         return 0;
94     }
95     if (err != EBUSY) {
96         error_exit(err, __func__);
97     }
98     return -EBUSY;
99 }
100 
101 void qemu_mutex_unlock_impl(QemuMutex *mutex, const char *file, const int line)
102 {
103     int err;
104 
105     assert(mutex->initialized);
106     qemu_mutex_pre_unlock(mutex, file, line);
107     err = pthread_mutex_unlock(&mutex->lock);
108     if (err)
109         error_exit(err, __func__);
110 }
111 
112 void qemu_rec_mutex_init(QemuRecMutex *mutex)
113 {
114     int err;
115     pthread_mutexattr_t attr;
116 
117     pthread_mutexattr_init(&attr);
118     pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
119     err = pthread_mutex_init(&mutex->m.lock, &attr);
120     pthread_mutexattr_destroy(&attr);
121     if (err) {
122         error_exit(err, __func__);
123     }
124     mutex->m.initialized = true;
125 }
126 
127 void qemu_rec_mutex_destroy(QemuRecMutex *mutex)
128 {
129     qemu_mutex_destroy(&mutex->m);
130 }
131 
132 void qemu_rec_mutex_lock_impl(QemuRecMutex *mutex, const char *file, int line)
133 {
134     qemu_mutex_lock_impl(&mutex->m, file, line);
135 }
136 
137 int qemu_rec_mutex_trylock_impl(QemuRecMutex *mutex, const char *file, int line)
138 {
139     return qemu_mutex_trylock_impl(&mutex->m, file, line);
140 }
141 
142 void qemu_rec_mutex_unlock_impl(QemuRecMutex *mutex, const char *file, int line)
143 {
144     qemu_mutex_unlock_impl(&mutex->m, file, line);
145 }
146 
147 void qemu_cond_init(QemuCond *cond)
148 {
149     int err;
150 
151     err = pthread_cond_init(&cond->cond, NULL);
152     if (err)
153         error_exit(err, __func__);
154     cond->initialized = true;
155 }
156 
157 void qemu_cond_destroy(QemuCond *cond)
158 {
159     int err;
160 
161     assert(cond->initialized);
162     cond->initialized = false;
163     err = pthread_cond_destroy(&cond->cond);
164     if (err)
165         error_exit(err, __func__);
166 }
167 
168 void qemu_cond_signal(QemuCond *cond)
169 {
170     int err;
171 
172     assert(cond->initialized);
173     err = pthread_cond_signal(&cond->cond);
174     if (err)
175         error_exit(err, __func__);
176 }
177 
178 void qemu_cond_broadcast(QemuCond *cond)
179 {
180     int err;
181 
182     assert(cond->initialized);
183     err = pthread_cond_broadcast(&cond->cond);
184     if (err)
185         error_exit(err, __func__);
186 }
187 
188 void qemu_cond_wait_impl(QemuCond *cond, QemuMutex *mutex, const char *file, const int line)
189 {
190     int err;
191 
192     assert(cond->initialized);
193     qemu_mutex_pre_unlock(mutex, file, line);
194     err = pthread_cond_wait(&cond->cond, &mutex->lock);
195     qemu_mutex_post_lock(mutex, file, line);
196     if (err)
197         error_exit(err, __func__);
198 }
199 
200 bool qemu_cond_timedwait_impl(QemuCond *cond, QemuMutex *mutex, int ms,
201                               const char *file, const int line)
202 {
203     int err;
204     struct timespec ts;
205 
206     assert(cond->initialized);
207     trace_qemu_mutex_unlock(mutex, file, line);
208     compute_abs_deadline(&ts, ms);
209     err = pthread_cond_timedwait(&cond->cond, &mutex->lock, &ts);
210     trace_qemu_mutex_locked(mutex, file, line);
211     if (err && err != ETIMEDOUT) {
212         error_exit(err, __func__);
213     }
214     return err != ETIMEDOUT;
215 }
216 
217 void qemu_sem_init(QemuSemaphore *sem, int init)
218 {
219     int rc;
220 
221 #ifndef CONFIG_SEM_TIMEDWAIT
222     rc = pthread_mutex_init(&sem->lock, NULL);
223     if (rc != 0) {
224         error_exit(rc, __func__);
225     }
226     rc = pthread_cond_init(&sem->cond, NULL);
227     if (rc != 0) {
228         error_exit(rc, __func__);
229     }
230     if (init < 0) {
231         error_exit(EINVAL, __func__);
232     }
233     sem->count = init;
234 #else
235     rc = sem_init(&sem->sem, 0, init);
236     if (rc < 0) {
237         error_exit(errno, __func__);
238     }
239 #endif
240     sem->initialized = true;
241 }
242 
243 void qemu_sem_destroy(QemuSemaphore *sem)
244 {
245     int rc;
246 
247     assert(sem->initialized);
248     sem->initialized = false;
249 #ifndef CONFIG_SEM_TIMEDWAIT
250     rc = pthread_cond_destroy(&sem->cond);
251     if (rc < 0) {
252         error_exit(rc, __func__);
253     }
254     rc = pthread_mutex_destroy(&sem->lock);
255     if (rc < 0) {
256         error_exit(rc, __func__);
257     }
258 #else
259     rc = sem_destroy(&sem->sem);
260     if (rc < 0) {
261         error_exit(errno, __func__);
262     }
263 #endif
264 }
265 
266 void qemu_sem_post(QemuSemaphore *sem)
267 {
268     int rc;
269 
270     assert(sem->initialized);
271 #ifndef CONFIG_SEM_TIMEDWAIT
272     pthread_mutex_lock(&sem->lock);
273     if (sem->count == UINT_MAX) {
274         rc = EINVAL;
275     } else {
276         sem->count++;
277         rc = pthread_cond_signal(&sem->cond);
278     }
279     pthread_mutex_unlock(&sem->lock);
280     if (rc != 0) {
281         error_exit(rc, __func__);
282     }
283 #else
284     rc = sem_post(&sem->sem);
285     if (rc < 0) {
286         error_exit(errno, __func__);
287     }
288 #endif
289 }
290 
291 int qemu_sem_timedwait(QemuSemaphore *sem, int ms)
292 {
293     int rc;
294     struct timespec ts;
295 
296     assert(sem->initialized);
297 #ifndef CONFIG_SEM_TIMEDWAIT
298     rc = 0;
299     compute_abs_deadline(&ts, ms);
300     pthread_mutex_lock(&sem->lock);
301     while (sem->count == 0) {
302         rc = pthread_cond_timedwait(&sem->cond, &sem->lock, &ts);
303         if (rc == ETIMEDOUT) {
304             break;
305         }
306         if (rc != 0) {
307             error_exit(rc, __func__);
308         }
309     }
310     if (rc != ETIMEDOUT) {
311         --sem->count;
312     }
313     pthread_mutex_unlock(&sem->lock);
314     return (rc == ETIMEDOUT ? -1 : 0);
315 #else
316     if (ms <= 0) {
317         /* This is cheaper than sem_timedwait.  */
318         do {
319             rc = sem_trywait(&sem->sem);
320         } while (rc == -1 && errno == EINTR);
321         if (rc == -1 && errno == EAGAIN) {
322             return -1;
323         }
324     } else {
325         compute_abs_deadline(&ts, ms);
326         do {
327             rc = sem_timedwait(&sem->sem, &ts);
328         } while (rc == -1 && errno == EINTR);
329         if (rc == -1 && errno == ETIMEDOUT) {
330             return -1;
331         }
332     }
333     if (rc < 0) {
334         error_exit(errno, __func__);
335     }
336     return 0;
337 #endif
338 }
339 
340 void qemu_sem_wait(QemuSemaphore *sem)
341 {
342     int rc;
343 
344     assert(sem->initialized);
345 #ifndef CONFIG_SEM_TIMEDWAIT
346     pthread_mutex_lock(&sem->lock);
347     while (sem->count == 0) {
348         rc = pthread_cond_wait(&sem->cond, &sem->lock);
349         if (rc != 0) {
350             error_exit(rc, __func__);
351         }
352     }
353     --sem->count;
354     pthread_mutex_unlock(&sem->lock);
355 #else
356     do {
357         rc = sem_wait(&sem->sem);
358     } while (rc == -1 && errno == EINTR);
359     if (rc < 0) {
360         error_exit(errno, __func__);
361     }
362 #endif
363 }
364 
365 #ifdef __linux__
366 #include "qemu/futex.h"
367 #else
368 static inline void qemu_futex_wake(QemuEvent *ev, int n)
369 {
370     assert(ev->initialized);
371     pthread_mutex_lock(&ev->lock);
372     if (n == 1) {
373         pthread_cond_signal(&ev->cond);
374     } else {
375         pthread_cond_broadcast(&ev->cond);
376     }
377     pthread_mutex_unlock(&ev->lock);
378 }
379 
380 static inline void qemu_futex_wait(QemuEvent *ev, unsigned val)
381 {
382     assert(ev->initialized);
383     pthread_mutex_lock(&ev->lock);
384     if (ev->value == val) {
385         pthread_cond_wait(&ev->cond, &ev->lock);
386     }
387     pthread_mutex_unlock(&ev->lock);
388 }
389 #endif
390 
391 /* Valid transitions:
392  * - free->set, when setting the event
393  * - busy->set, when setting the event, followed by qemu_futex_wake
394  * - set->free, when resetting the event
395  * - free->busy, when waiting
396  *
397  * set->busy does not happen (it can be observed from the outside but
398  * it really is set->free->busy).
399  *
400  * busy->free provably cannot happen; to enforce it, the set->free transition
401  * is done with an OR, which becomes a no-op if the event has concurrently
402  * transitioned to free or busy.
403  */
404 
405 #define EV_SET         0
406 #define EV_FREE        1
407 #define EV_BUSY       -1
408 
409 void qemu_event_init(QemuEvent *ev, bool init)
410 {
411 #ifndef __linux__
412     pthread_mutex_init(&ev->lock, NULL);
413     pthread_cond_init(&ev->cond, NULL);
414 #endif
415 
416     ev->value = (init ? EV_SET : EV_FREE);
417     ev->initialized = true;
418 }
419 
420 void qemu_event_destroy(QemuEvent *ev)
421 {
422     assert(ev->initialized);
423     ev->initialized = false;
424 #ifndef __linux__
425     pthread_mutex_destroy(&ev->lock);
426     pthread_cond_destroy(&ev->cond);
427 #endif
428 }
429 
430 void qemu_event_set(QemuEvent *ev)
431 {
432     /* qemu_event_set has release semantics, but because it *loads*
433      * ev->value we need a full memory barrier here.
434      */
435     assert(ev->initialized);
436     smp_mb();
437     if (qatomic_read(&ev->value) != EV_SET) {
438         if (qatomic_xchg(&ev->value, EV_SET) == EV_BUSY) {
439             /* There were waiters, wake them up.  */
440             qemu_futex_wake(ev, INT_MAX);
441         }
442     }
443 }
444 
445 void qemu_event_reset(QemuEvent *ev)
446 {
447     unsigned value;
448 
449     assert(ev->initialized);
450     value = qatomic_read(&ev->value);
451     smp_mb_acquire();
452     if (value == EV_SET) {
453         /*
454          * If there was a concurrent reset (or even reset+wait),
455          * do nothing.  Otherwise change EV_SET->EV_FREE.
456          */
457         qatomic_or(&ev->value, EV_FREE);
458     }
459 }
460 
461 void qemu_event_wait(QemuEvent *ev)
462 {
463     unsigned value;
464 
465     assert(ev->initialized);
466     value = qatomic_read(&ev->value);
467     smp_mb_acquire();
468     if (value != EV_SET) {
469         if (value == EV_FREE) {
470             /*
471              * Leave the event reset and tell qemu_event_set that there
472              * are waiters.  No need to retry, because there cannot be
473              * a concurrent busy->free transition.  After the CAS, the
474              * event will be either set or busy.
475              */
476             if (qatomic_cmpxchg(&ev->value, EV_FREE, EV_BUSY) == EV_SET) {
477                 return;
478             }
479         }
480         qemu_futex_wait(ev, EV_BUSY);
481     }
482 }
483 
484 static __thread NotifierList thread_exit;
485 
486 /*
487  * Note that in this implementation you can register a thread-exit
488  * notifier for the main thread, but it will never be called.
489  * This is OK because main thread exit can only happen when the
490  * entire process is exiting, and the API allows notifiers to not
491  * be called on process exit.
492  */
493 void qemu_thread_atexit_add(Notifier *notifier)
494 {
495     notifier_list_add(&thread_exit, notifier);
496 }
497 
498 void qemu_thread_atexit_remove(Notifier *notifier)
499 {
500     notifier_remove(notifier);
501 }
502 
503 static void qemu_thread_atexit_notify(void *arg)
504 {
505     /*
506      * Called when non-main thread exits (via qemu_thread_exit()
507      * or by returning from its start routine.)
508      */
509     notifier_list_notify(&thread_exit, NULL);
510 }
511 
512 typedef struct {
513     void *(*start_routine)(void *);
514     void *arg;
515     char *name;
516 } QemuThreadArgs;
517 
518 static void *qemu_thread_start(void *args)
519 {
520     QemuThreadArgs *qemu_thread_args = args;
521     void *(*start_routine)(void *) = qemu_thread_args->start_routine;
522     void *arg = qemu_thread_args->arg;
523     void *r;
524 
525 #ifdef CONFIG_THREAD_SETNAME_BYTHREAD
526     /* Attempt to set the threads name; note that this is for debug, so
527      * we're not going to fail if we can't set it.
528      */
529     if (name_threads && qemu_thread_args->name) {
530 # if defined(CONFIG_PTHREAD_SETNAME_NP_W_TID)
531         pthread_setname_np(pthread_self(), qemu_thread_args->name);
532 # elif defined(CONFIG_PTHREAD_SETNAME_NP_WO_TID)
533         pthread_setname_np(qemu_thread_args->name);
534 # endif
535     }
536 #endif
537     QEMU_TSAN_ANNOTATE_THREAD_NAME(qemu_thread_args->name);
538     g_free(qemu_thread_args->name);
539     g_free(qemu_thread_args);
540 
541     /*
542      * GCC 11 with glibc 2.17 on PowerPC reports
543      *
544      * qemu-thread-posix.c:540:5: error: ‘__sigsetjmp’ accessing 656 bytes
545      *   in a region of size 528 [-Werror=stringop-overflow=]
546      * 540 |     pthread_cleanup_push(qemu_thread_atexit_notify, NULL);
547      *     |     ^~~~~~~~~~~~~~~~~~~~
548      *
549      * which is clearly nonsense.
550      */
551 #pragma GCC diagnostic push
552 #ifndef __clang__
553 #pragma GCC diagnostic ignored "-Wstringop-overflow"
554 #endif
555 
556     pthread_cleanup_push(qemu_thread_atexit_notify, NULL);
557     r = start_routine(arg);
558     pthread_cleanup_pop(1);
559 
560 #pragma GCC diagnostic pop
561 
562     return r;
563 }
564 
565 void qemu_thread_create(QemuThread *thread, const char *name,
566                        void *(*start_routine)(void*),
567                        void *arg, int mode)
568 {
569     sigset_t set, oldset;
570     int err;
571     pthread_attr_t attr;
572     QemuThreadArgs *qemu_thread_args;
573 
574     err = pthread_attr_init(&attr);
575     if (err) {
576         error_exit(err, __func__);
577     }
578 
579     if (mode == QEMU_THREAD_DETACHED) {
580         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
581     }
582 
583     /* Leave signal handling to the iothread.  */
584     sigfillset(&set);
585     /* Blocking the signals can result in undefined behaviour. */
586     sigdelset(&set, SIGSEGV);
587     sigdelset(&set, SIGFPE);
588     sigdelset(&set, SIGILL);
589     /* TODO avoid SIGBUS loss on macOS */
590     pthread_sigmask(SIG_SETMASK, &set, &oldset);
591 
592     qemu_thread_args = g_new0(QemuThreadArgs, 1);
593     qemu_thread_args->name = g_strdup(name);
594     qemu_thread_args->start_routine = start_routine;
595     qemu_thread_args->arg = arg;
596 
597     err = pthread_create(&thread->thread, &attr,
598                          qemu_thread_start, qemu_thread_args);
599 
600     if (err)
601         error_exit(err, __func__);
602 
603     pthread_sigmask(SIG_SETMASK, &oldset, NULL);
604 
605     pthread_attr_destroy(&attr);
606 }
607 
608 void qemu_thread_get_self(QemuThread *thread)
609 {
610     thread->thread = pthread_self();
611 }
612 
613 bool qemu_thread_is_self(QemuThread *thread)
614 {
615    return pthread_equal(pthread_self(), thread->thread);
616 }
617 
618 void qemu_thread_exit(void *retval)
619 {
620     pthread_exit(retval);
621 }
622 
623 void *qemu_thread_join(QemuThread *thread)
624 {
625     int err;
626     void *ret;
627 
628     err = pthread_join(thread->thread, &ret);
629     if (err) {
630         error_exit(err, __func__);
631     }
632     return ret;
633 }
634