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
   7typedef struct QemuCond QemuCond;
   8typedef struct QemuSemaphore QemuSemaphore;
   9typedef struct QemuEvent QemuEvent;
  10typedef struct QemuLockCnt QemuLockCnt;
  11typedef struct QemuThread QemuThread;
  12
  13#ifdef _WIN32
  14#include "qemu/thread-win32.h"
  15#else
  16#include "qemu/thread-posix.h"
  17#endif
  18
  19#define QEMU_THREAD_JOINABLE 0
  20#define QEMU_THREAD_DETACHED 1
  21
  22void qemu_mutex_init(QemuMutex *mutex);
  23void qemu_mutex_destroy(QemuMutex *mutex);
  24int qemu_mutex_trylock_impl(QemuMutex *mutex, const char *file, const int line);
  25void qemu_mutex_lock_impl(QemuMutex *mutex, const char *file, const int line);
  26void qemu_mutex_unlock_impl(QemuMutex *mutex, const char *file, const int line);
  27
  28#define qemu_mutex_lock(mutex) \
  29        qemu_mutex_lock_impl(mutex, __FILE__, __LINE__)
  30#define qemu_mutex_trylock(mutex) \
  31        qemu_mutex_trylock_impl(mutex, __FILE__, __LINE__)
  32#define qemu_mutex_unlock(mutex) \
  33        qemu_mutex_unlock_impl(mutex, __FILE__, __LINE__)
  34
  35static inline void (qemu_mutex_lock)(QemuMutex *mutex)
  36{
  37    qemu_mutex_lock(mutex);
  38}
  39
  40static inline int (qemu_mutex_trylock)(QemuMutex *mutex)
  41{
  42    return qemu_mutex_trylock(mutex);
  43}
  44
  45static inline void (qemu_mutex_unlock)(QemuMutex *mutex)
  46{
  47    qemu_mutex_unlock(mutex);
  48}
  49
  50/* Prototypes for other functions are in thread-posix.h/thread-win32.h.  */
  51void qemu_rec_mutex_init(QemuRecMutex *mutex);
  52
  53void qemu_cond_init(QemuCond *cond);
  54void qemu_cond_destroy(QemuCond *cond);
  55
  56/*
  57 * IMPORTANT: The implementation does not guarantee that pthread_cond_signal
  58 * and pthread_cond_broadcast can be called except while the same mutex is
  59 * held as in the corresponding pthread_cond_wait calls!
  60 */
  61void qemu_cond_signal(QemuCond *cond);
  62void qemu_cond_broadcast(QemuCond *cond);
  63void qemu_cond_wait_impl(QemuCond *cond, QemuMutex *mutex,
  64                         const char *file, const int line);
  65
  66#define qemu_cond_wait(cond, mutex) \
  67        qemu_cond_wait_impl(cond, mutex, __FILE__, __LINE__)
  68
  69static inline void (qemu_cond_wait)(QemuCond *cond, QemuMutex *mutex)
  70{
  71    qemu_cond_wait(cond, mutex);
  72}
  73
  74void qemu_sem_init(QemuSemaphore *sem, int init);
  75void qemu_sem_post(QemuSemaphore *sem);
  76void qemu_sem_wait(QemuSemaphore *sem);
  77int qemu_sem_timedwait(QemuSemaphore *sem, int ms);
  78void qemu_sem_destroy(QemuSemaphore *sem);
  79
  80void qemu_event_init(QemuEvent *ev, bool init);
  81void qemu_event_set(QemuEvent *ev);
  82void qemu_event_reset(QemuEvent *ev);
  83void qemu_event_wait(QemuEvent *ev);
  84void qemu_event_destroy(QemuEvent *ev);
  85
  86void qemu_thread_create(QemuThread *thread, const char *name,
  87                        void *(*start_routine)(void *),
  88                        void *arg, int mode);
  89void *qemu_thread_join(QemuThread *thread);
  90void qemu_thread_get_self(QemuThread *thread);
  91bool qemu_thread_is_self(QemuThread *thread);
  92void qemu_thread_exit(void *retval);
  93void qemu_thread_naming(bool enable);
  94
  95struct Notifier;
  96void qemu_thread_atexit_add(struct Notifier *notifier);
  97void qemu_thread_atexit_remove(struct Notifier *notifier);
  98
  99struct QemuSpin {
 100    int value;
 101};
 102
 103static inline void qemu_spin_init(QemuSpin *spin)
 104{
 105    __sync_lock_release(&spin->value);
 106}
 107
 108static inline void qemu_spin_lock(QemuSpin *spin)
 109{
 110    while (unlikely(__sync_lock_test_and_set(&spin->value, true))) {
 111        while (atomic_read(&spin->value)) {
 112            cpu_relax();
 113        }
 114    }
 115}
 116
 117static inline bool qemu_spin_trylock(QemuSpin *spin)
 118{
 119    return __sync_lock_test_and_set(&spin->value, true);
 120}
 121
 122static inline bool qemu_spin_locked(QemuSpin *spin)
 123{
 124    return atomic_read(&spin->value);
 125}
 126
 127static inline void qemu_spin_unlock(QemuSpin *spin)
 128{
 129    __sync_lock_release(&spin->value);
 130}
 131
 132struct QemuLockCnt {
 133#ifndef CONFIG_LINUX
 134    QemuMutex mutex;
 135#endif
 136    unsigned count;
 137};
 138
 139/**
 140 * qemu_lockcnt_init: initialize a QemuLockcnt
 141 * @lockcnt: the lockcnt to initialize
 142 *
 143 * Initialize lockcnt's counter to zero and prepare its mutex
 144 * for usage.
 145 */
 146void qemu_lockcnt_init(QemuLockCnt *lockcnt);
 147
 148/**
 149 * qemu_lockcnt_destroy: destroy a QemuLockcnt
 150 * @lockcnt: the lockcnt to destruct
 151 *
 152 * Destroy lockcnt's mutex.
 153 */
 154void qemu_lockcnt_destroy(QemuLockCnt *lockcnt);
 155
 156/**
 157 * qemu_lockcnt_inc: increment a QemuLockCnt's counter
 158 * @lockcnt: the lockcnt to operate on
 159 *
 160 * If the lockcnt's count is zero, wait for critical sections
 161 * to finish and increment lockcnt's count to 1.  If the count
 162 * is not zero, just increment it.
 163 *
 164 * Because this function can wait on the mutex, it must not be
 165 * called while the lockcnt's mutex is held by the current thread.
 166 * For the same reason, qemu_lockcnt_inc can also contribute to
 167 * AB-BA deadlocks.  This is a sample deadlock scenario:
 168 *
 169 *            thread 1                      thread 2
 170 *            -------------------------------------------------------
 171 *            qemu_lockcnt_lock(&lc1);
 172 *                                          qemu_lockcnt_lock(&lc2);
 173 *            qemu_lockcnt_inc(&lc2);
 174 *                                          qemu_lockcnt_inc(&lc1);
 175 */
 176void qemu_lockcnt_inc(QemuLockCnt *lockcnt);
 177
 178/**
 179 * qemu_lockcnt_dec: decrement a QemuLockCnt's counter
 180 * @lockcnt: the lockcnt to operate on
 181 */
 182void qemu_lockcnt_dec(QemuLockCnt *lockcnt);
 183
 184/**
 185 * qemu_lockcnt_dec_and_lock: decrement a QemuLockCnt's counter and
 186 * possibly lock it.
 187 * @lockcnt: the lockcnt to operate on
 188 *
 189 * Decrement lockcnt's count.  If the new count is zero, lock
 190 * the mutex and return true.  Otherwise, return false.
 191 */
 192bool qemu_lockcnt_dec_and_lock(QemuLockCnt *lockcnt);
 193
 194/**
 195 * qemu_lockcnt_dec_if_lock: possibly decrement a QemuLockCnt's counter and
 196 * lock it.
 197 * @lockcnt: the lockcnt to operate on
 198 *
 199 * If the count is 1, decrement the count to zero, lock
 200 * the mutex and return true.  Otherwise, return false.
 201 */
 202bool qemu_lockcnt_dec_if_lock(QemuLockCnt *lockcnt);
 203
 204/**
 205 * qemu_lockcnt_lock: lock a QemuLockCnt's mutex.
 206 * @lockcnt: the lockcnt to operate on
 207 *
 208 * Remember that concurrent visits are not blocked unless the count is
 209 * also zero.  You can use qemu_lockcnt_count to check for this inside a
 210 * critical section.
 211 */
 212void qemu_lockcnt_lock(QemuLockCnt *lockcnt);
 213
 214/**
 215 * qemu_lockcnt_unlock: release a QemuLockCnt's mutex.
 216 * @lockcnt: the lockcnt to operate on.
 217 */
 218void qemu_lockcnt_unlock(QemuLockCnt *lockcnt);
 219
 220/**
 221 * qemu_lockcnt_inc_and_unlock: combined unlock/increment on a QemuLockCnt.
 222 * @lockcnt: the lockcnt to operate on.
 223 *
 224 * This is the same as
 225 *
 226 *     qemu_lockcnt_unlock(lockcnt);
 227 *     qemu_lockcnt_inc(lockcnt);
 228 *
 229 * but more efficient.
 230 */
 231void qemu_lockcnt_inc_and_unlock(QemuLockCnt *lockcnt);
 232
 233/**
 234 * qemu_lockcnt_count: query a LockCnt's count.
 235 * @lockcnt: the lockcnt to query.
 236 *
 237 * Note that the count can change at any time.  Still, while the
 238 * lockcnt is locked, one can usefully check whether the count
 239 * is non-zero.
 240 */
 241unsigned qemu_lockcnt_count(QemuLockCnt *lockcnt);
 242
 243#endif
 244