qemu/include/qemu/thread.h
<<
>>
Prefs
   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
   8typedef struct QemuCond QemuCond;
   9typedef struct QemuSemaphore QemuSemaphore;
  10typedef struct QemuLockCnt QemuLockCnt;
  11typedef 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 */
  23typedef 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
  44void qemu_mutex_init(QemuMutex *mutex);
  45void qemu_mutex_destroy(QemuMutex *mutex);
  46int TSA_NO_TSA qemu_mutex_trylock_impl(QemuMutex *mutex, const char *file,
  47                                       const int line);
  48void TSA_NO_TSA qemu_mutex_lock_impl(QemuMutex *mutex, const char *file,
  49                                     const int line);
  50void TSA_NO_TSA qemu_mutex_unlock_impl(QemuMutex *mutex, const char *file,
  51                                       const int line);
  52
  53void qemu_rec_mutex_init(QemuRecMutex *mutex);
  54void qemu_rec_mutex_destroy(QemuRecMutex *mutex);
  55void qemu_rec_mutex_lock_impl(QemuRecMutex *mutex, const char *file, int line);
  56int qemu_rec_mutex_trylock_impl(QemuRecMutex *mutex, const char *file, int line);
  57void qemu_rec_mutex_unlock_impl(QemuRecMutex *mutex, const char *file, int line);
  58
  59typedef void (*QemuMutexLockFunc)(QemuMutex *m, const char *f, int l);
  60typedef int (*QemuMutexTrylockFunc)(QemuMutex *m, const char *f, int l);
  61typedef void (*QemuRecMutexLockFunc)(QemuRecMutex *m, const char *f, int l);
  62typedef int (*QemuRecMutexTrylockFunc)(QemuRecMutex *m, const char *f, int l);
  63typedef void (*QemuCondWaitFunc)(QemuCond *c, QemuMutex *m, const char *f,
  64                                 int l);
  65typedef bool (*QemuCondTimedWaitFunc)(QemuCond *c, QemuMutex *m, int ms,
  66                                      const char *f, int l);
  67
  68extern QemuMutexLockFunc bql_mutex_lock_func;
  69extern QemuMutexLockFunc qemu_mutex_lock_func;
  70extern QemuMutexTrylockFunc qemu_mutex_trylock_func;
  71extern QemuRecMutexLockFunc qemu_rec_mutex_lock_func;
  72extern QemuRecMutexTrylockFunc qemu_rec_mutex_trylock_func;
  73extern QemuCondWaitFunc qemu_cond_wait_func;
  74extern 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
 138static inline void (qemu_mutex_lock)(QemuMutex *mutex)
 139{
 140    qemu_mutex_lock(mutex);
 141}
 142
 143static inline int (qemu_mutex_trylock)(QemuMutex *mutex)
 144{
 145    return qemu_mutex_trylock(mutex);
 146}
 147
 148static inline void (qemu_mutex_unlock)(QemuMutex *mutex)
 149{
 150    qemu_mutex_unlock(mutex);
 151}
 152
 153static inline void (qemu_rec_mutex_lock)(QemuRecMutex *mutex)
 154{
 155    qemu_rec_mutex_lock(mutex);
 156}
 157
 158static inline int (qemu_rec_mutex_trylock)(QemuRecMutex *mutex)
 159{
 160    return qemu_rec_mutex_trylock(mutex);
 161}
 162
 163static inline void (qemu_rec_mutex_unlock)(QemuRecMutex *mutex)
 164{
 165    qemu_rec_mutex_unlock(mutex);
 166}
 167
 168void qemu_cond_init(QemuCond *cond);
 169void 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 */
 176void qemu_cond_signal(QemuCond *cond);
 177void qemu_cond_broadcast(QemuCond *cond);
 178void TSA_NO_TSA qemu_cond_wait_impl(QemuCond *cond, QemuMutex *mutex,
 179                                    const char *file, const int line);
 180bool qemu_cond_timedwait_impl(QemuCond *cond, QemuMutex *mutex, int ms,
 181                              const char *file, const int line);
 182
 183static 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 */
 189static inline bool (qemu_cond_timedwait)(QemuCond *cond, QemuMutex *mutex,
 190                                         int ms)
 191{
 192    return qemu_cond_timedwait(cond, mutex, ms);
 193}
 194
 195void qemu_sem_init(QemuSemaphore *sem, int init);
 196void qemu_sem_post(QemuSemaphore *sem);
 197void qemu_sem_wait(QemuSemaphore *sem);
 198int qemu_sem_timedwait(QemuSemaphore *sem, int ms);
 199void qemu_sem_destroy(QemuSemaphore *sem);
 200
 201void qemu_event_init(QemuEvent *ev, bool init);
 202void qemu_event_set(QemuEvent *ev);
 203void qemu_event_reset(QemuEvent *ev);
 204void qemu_event_wait(QemuEvent *ev);
 205void qemu_event_destroy(QemuEvent *ev);
 206
 207void qemu_thread_create(QemuThread *thread, const char *name,
 208                        void *(*start_routine)(void *),
 209                        void *arg, int mode);
 210int qemu_thread_set_affinity(QemuThread *thread, unsigned long *host_cpus,
 211                             unsigned long nbits);
 212int qemu_thread_get_affinity(QemuThread *thread, unsigned long **host_cpus,
 213                             unsigned long *nbits);
 214void *qemu_thread_join(QemuThread *thread);
 215void qemu_thread_get_self(QemuThread *thread);
 216bool qemu_thread_is_self(QemuThread *thread);
 217G_NORETURN void qemu_thread_exit(void *retval);
 218void qemu_thread_naming(bool enable);
 219
 220struct 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 */
 235void 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 */
 244void qemu_thread_atexit_remove(struct Notifier *notifier);
 245
 246#ifdef CONFIG_TSAN
 247#include <sanitizer/tsan_interface.h>
 248#endif
 249
 250struct QemuSpin {
 251    int value;
 252};
 253
 254static 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
 262static 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
 269static 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
 284static 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
 298static inline bool qemu_spin_locked(QemuSpin *spin)
 299{
 300    return qatomic_read(&spin->value);
 301}
 302
 303static 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