#ifndef QEMU_THREAD_H #define QEMU_THREAD_H #include "qemu/processor.h" #include "qemu/atomic.h" typedef struct QemuCond QemuCond; typedef struct QemuSemaphore QemuSemaphore; typedef struct QemuEvent QemuEvent; typedef struct QemuLockCnt QemuLockCnt; typedef struct QemuThread QemuThread; #ifdef _WIN32 #include "qemu/thread-win32.h" #else #include "qemu/thread-posix.h" #endif /* include QSP header once QemuMutex, QemuCond etc. are defined */ #include "qemu/qsp.h" #define QEMU_THREAD_JOINABLE 0 #define QEMU_THREAD_DETACHED 1 void qemu_mutex_init(QemuMutex *mutex); void qemu_mutex_destroy(QemuMutex *mutex); int qemu_mutex_trylock_impl(QemuMutex *mutex, const char *file, const int line); void qemu_mutex_lock_impl(QemuMutex *mutex, const char *file, const int line); void qemu_mutex_unlock_impl(QemuMutex *mutex, const char *file, const int line); typedef void (*QemuMutexLockFunc)(QemuMutex *m, const char *f, int l); typedef int (*QemuMutexTrylockFunc)(QemuMutex *m, const char *f, int l); typedef void (*QemuRecMutexLockFunc)(QemuRecMutex *m, const char *f, int l); typedef int (*QemuRecMutexTrylockFunc)(QemuRecMutex *m, const char *f, int l); typedef void (*QemuCondWaitFunc)(QemuCond *c, QemuMutex *m, const char *f, int l); typedef bool (*QemuCondTimedWaitFunc)(QemuCond *c, QemuMutex *m, int ms, const char *f, int l); extern QemuMutexLockFunc qemu_bql_mutex_lock_func; extern QemuMutexLockFunc qemu_mutex_lock_func; extern QemuMutexTrylockFunc qemu_mutex_trylock_func; extern QemuRecMutexLockFunc qemu_rec_mutex_lock_func; extern QemuRecMutexTrylockFunc qemu_rec_mutex_trylock_func; extern QemuCondWaitFunc qemu_cond_wait_func; extern QemuCondTimedWaitFunc qemu_cond_timedwait_func; /* convenience macros to bypass the profiler */ #define qemu_mutex_lock__raw(m) \ qemu_mutex_lock_impl(m, __FILE__, __LINE__) #define qemu_mutex_trylock__raw(m) \ qemu_mutex_trylock_impl(m, __FILE__, __LINE__) #ifdef __COVERITY__ /* * Coverity is severely confused by the indirect function calls, * hide them. */ #define qemu_mutex_lock(m) \ qemu_mutex_lock_impl(m, __FILE__, __LINE__); #define qemu_mutex_trylock(m) \ qemu_mutex_trylock_impl(m, __FILE__, __LINE__); #define qemu_rec_mutex_lock(m) \ qemu_rec_mutex_lock_impl(m, __FILE__, __LINE__); #define qemu_rec_mutex_trylock(m) \ qemu_rec_mutex_trylock_impl(m, __FILE__, __LINE__); #define qemu_cond_wait(c, m) \ qemu_cond_wait_impl(c, m, __FILE__, __LINE__); #define qemu_cond_timedwait(c, m, ms) \ qemu_cond_wait_impl(c, m, ms, __FILE__, __LINE__); #else #define qemu_mutex_lock(m) ({ \ QemuMutexLockFunc _f = atomic_read(&qemu_mutex_lock_func); \ _f(m, __FILE__, __LINE__); \ }) #define qemu_mutex_trylock(m) ({ \ QemuMutexTrylockFunc _f = atomic_read(&qemu_mutex_trylock_func); \ _f(m, __FILE__, __LINE__); \ }) #define qemu_rec_mutex_lock(m) ({ \ QemuRecMutexLockFunc _f = atomic_read(&qemu_rec_mutex_lock_func); \ _f(m, __FILE__, __LINE__); \ }) #define qemu_rec_mutex_trylock(m) ({ \ QemuRecMutexTrylockFunc _f; \ _f = atomic_read(&qemu_rec_mutex_trylock_func); \ _f(m, __FILE__, __LINE__); \ }) #define qemu_cond_wait(c, m) ({ \ QemuCondWaitFunc _f = atomic_read(&qemu_cond_wait_func); \ _f(c, m, __FILE__, __LINE__); \ }) #define qemu_cond_timedwait(c, m, ms) ({ \ QemuCondTimedWaitFunc _f = atomic_read(&qemu_cond_timedwait_func); \ _f(c, m, ms, __FILE__, __LINE__); \ }) #endif #define qemu_mutex_unlock(mutex) \ qemu_mutex_unlock_impl(mutex, __FILE__, __LINE__) static inline void (qemu_mutex_lock)(QemuMutex *mutex) { qemu_mutex_lock(mutex); } static inline int (qemu_mutex_trylock)(QemuMutex *mutex) { return qemu_mutex_trylock(mutex); } static inline void (qemu_mutex_unlock)(QemuMutex *mutex) { qemu_mutex_unlock(mutex); } static inline void (qemu_rec_mutex_lock)(QemuRecMutex *mutex) { qemu_rec_mutex_lock(mutex); } static inline int (qemu_rec_mutex_trylock)(QemuRecMutex *mutex) { return qemu_rec_mutex_trylock(mutex); } /* Prototypes for other functions are in thread-posix.h/thread-win32.h. */ void qemu_rec_mutex_init(QemuRecMutex *mutex); void qemu_cond_init(QemuCond *cond); void qemu_cond_destroy(QemuCond *cond); /* * IMPORTANT: The implementation does not guarantee that pthread_cond_signal * and pthread_cond_broadcast can be called except while the same mutex is * held as in the corresponding pthread_cond_wait calls! */ void qemu_cond_signal(QemuCond *cond); void qemu_cond_broadcast(QemuCond *cond); void qemu_cond_wait_impl(QemuCond *cond, QemuMutex *mutex, const char *file, const int line); bool qemu_cond_timedwait_impl(QemuCond *cond, QemuMutex *mutex, int ms, const char *file, const int line); static inline void (qemu_cond_wait)(QemuCond *cond, QemuMutex *mutex) { qemu_cond_wait(cond, mutex); } /* Returns true if timeout has not expired, and false otherwise */ static inline bool (qemu_cond_timedwait)(QemuCond *cond, QemuMutex *mutex, int ms) { return qemu_cond_timedwait(cond, mutex, ms); } void qemu_sem_init(QemuSemaphore *sem, int init); void qemu_sem_post(QemuSemaphore *sem); void qemu_sem_wait(QemuSemaphore *sem); int qemu_sem_timedwait(QemuSemaphore *sem, int ms); void qemu_sem_destroy(QemuSemaphore *sem); void qemu_event_init(QemuEvent *ev, bool init); void qemu_event_set(QemuEvent *ev); void qemu_event_reset(QemuEvent *ev); void qemu_event_wait(QemuEvent *ev); void qemu_event_destroy(QemuEvent *ev); void qemu_thread_create(QemuThread *thread, const char *name, void *(*start_routine)(void *), void *arg, int mode); void *qemu_thread_join(QemuThread *thread); void qemu_thread_get_self(QemuThread *thread); bool qemu_thread_is_self(QemuThread *thread); void qemu_thread_exit(void *retval); void qemu_thread_naming(bool enable); struct Notifier; /** * qemu_thread_atexit_add: * @notifier: Notifier to add * * Add the specified notifier to a list which will be run via * notifier_list_notify() when this thread exits (either by calling * qemu_thread_exit() or by returning from its start_routine). * The usual usage is that the caller passes a Notifier which is * a per-thread variable; it can then use the callback to free * other per-thread data. * * If the thread exits as part of the entire process exiting, * it is unspecified whether notifiers are called or not. */ void qemu_thread_atexit_add(struct Notifier *notifier); /** * qemu_thread_atexit_remove: * @notifier: Notifier to remove * * Remove the specified notifier from the thread-exit notification * list. It is not valid to try to remove a notifier which is not * on the list. */ void qemu_thread_atexit_remove(struct Notifier *notifier); struct QemuSpin { int value; }; static inline void qemu_spin_init(QemuSpin *spin) { __sync_lock_release(&spin->value); } static inline void qemu_spin_lock(QemuSpin *spin) { while (unlikely(__sync_lock_test_and_set(&spin->value, true))) { while (atomic_read(&spin->value)) { cpu_relax(); } } } static inline bool qemu_spin_trylock(QemuSpin *spin) { return __sync_lock_test_and_set(&spin->value, true); } static inline bool qemu_spin_locked(QemuSpin *spin) { return atomic_read(&spin->value); } static inline void qemu_spin_unlock(QemuSpin *spin) { __sync_lock_release(&spin->value); } struct QemuLockCnt { #ifndef CONFIG_LINUX QemuMutex mutex; #endif unsigned count; }; /** * qemu_lockcnt_init: initialize a QemuLockcnt * @lockcnt: the lockcnt to initialize * * Initialize lockcnt's counter to zero and prepare its mutex * for usage. */ void qemu_lockcnt_init(QemuLockCnt *lockcnt); /** * qemu_lockcnt_destroy: destroy a QemuLockcnt * @lockcnt: the lockcnt to destruct * * Destroy lockcnt's mutex. */ void qemu_lockcnt_destroy(QemuLockCnt *lockcnt); /** * qemu_lockcnt_inc: increment a QemuLockCnt's counter * @lockcnt: the lockcnt to operate on * * If the lockcnt's count is zero, wait for critical sections * to finish and increment lockcnt's count to 1. If the count * is not zero, just increment it. * * Because this function can wait on the mutex, it must not be * called while the lockcnt's mutex is held by the current thread. * For the same reason, qemu_lockcnt_inc can also contribute to * AB-BA deadlocks. This is a sample deadlock scenario: * * thread 1 thread 2 * ------------------------------------------------------- * qemu_lockcnt_lock(&lc1); * qemu_lockcnt_lock(&lc2); * qemu_lockcnt_inc(&lc2); * qemu_lockcnt_inc(&lc1); */ void qemu_lockcnt_inc(QemuLockCnt *lockcnt); /** * qemu_lockcnt_dec: decrement a QemuLockCnt's counter * @lockcnt: the lockcnt to operate on */ void qemu_lockcnt_dec(QemuLockCnt *lockcnt); /** * qemu_lockcnt_dec_and_lock: decrement a QemuLockCnt's counter and * possibly lock it. * @lockcnt: the lockcnt to operate on * * Decrement lockcnt's count. If the new count is zero, lock * the mutex and return true. Otherwise, return false. */ bool qemu_lockcnt_dec_and_lock(QemuLockCnt *lockcnt); /** * qemu_lockcnt_dec_if_lock: possibly decrement a QemuLockCnt's counter and * lock it. * @lockcnt: the lockcnt to operate on * * If the count is 1, decrement the count to zero, lock * the mutex and return true. Otherwise, return false. */ bool qemu_lockcnt_dec_if_lock(QemuLockCnt *lockcnt); /** * qemu_lockcnt_lock: lock a QemuLockCnt's mutex. * @lockcnt: the lockcnt to operate on * * Remember that concurrent visits are not blocked unless the count is * also zero. You can use qemu_lockcnt_count to check for this inside a * critical section. */ void qemu_lockcnt_lock(QemuLockCnt *lockcnt); /** * qemu_lockcnt_unlock: release a QemuLockCnt's mutex. * @lockcnt: the lockcnt to operate on. */ void qemu_lockcnt_unlock(QemuLockCnt *lockcnt); /** * qemu_lockcnt_inc_and_unlock: combined unlock/increment on a QemuLockCnt. * @lockcnt: the lockcnt to operate on. * * This is the same as * * qemu_lockcnt_unlock(lockcnt); * qemu_lockcnt_inc(lockcnt); * * but more efficient. */ void qemu_lockcnt_inc_and_unlock(QemuLockCnt *lockcnt); /** * qemu_lockcnt_count: query a LockCnt's count. * @lockcnt: the lockcnt to query. * * Note that the count can change at any time. Still, while the * lockcnt is locked, one can usefully check whether the count * is non-zero. */ unsigned qemu_lockcnt_count(QemuLockCnt *lockcnt); #endif