This commit is contained in:
Nguyen Anh Quynh
2017-01-09 13:28:28 +08:00
parent ffa97dc2a1
commit d7ead1135d
21 changed files with 1 additions and 714 deletions

View File

@ -26,15 +26,6 @@
* THE SOFTWARE.
*/
/* The following block of code temporarily renames the daemon() function so the
compiler does not see the warning associated with it in stdlib.h on OSX */
#ifdef __APPLE__
#define daemon qemu_fake_daemon_function
#include <stdlib.h>
#undef daemon
extern int daemon(int, int);
#endif
#if defined(__linux__) && (defined(__x86_64__) || defined(__arm__))
/* Use 2 MiB alignment so transparent hugepages can be used by KVM.
Valgrind does not support alignments larger than 1 MiB,
@ -69,11 +60,6 @@ extern int daemon(int, int);
#include <sys/sysctl.h>
#endif
int qemu_daemon(int nochdir, int noclose)
{
return daemon(nochdir, noclose);
}
void *qemu_oom_check(void *ptr)
{
if (ptr == NULL) {

View File

@ -55,6 +55,7 @@ void qemu_mutex_destroy(QemuMutex *mutex)
error_exit(err, __func__);
}
void qemu_mutex_lock(QemuMutex *mutex)
{
int err;
@ -64,11 +65,6 @@ void qemu_mutex_lock(QemuMutex *mutex)
error_exit(err, __func__);
}
int qemu_mutex_trylock(QemuMutex *mutex)
{
return pthread_mutex_trylock(&mutex->lock);
}
void qemu_mutex_unlock(QemuMutex *mutex)
{
int err;
@ -114,281 +110,6 @@ void qemu_cond_broadcast(QemuCond *cond)
error_exit(err, __func__);
}
void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex)
{
int err;
err = pthread_cond_wait(&cond->cond, &mutex->lock);
if (err)
error_exit(err, __func__);
}
void qemu_sem_init(QemuSemaphore *sem, int init)
{
int rc;
#if defined(__APPLE__) || defined(__NetBSD__)
rc = pthread_mutex_init(&sem->lock, NULL);
if (rc != 0) {
error_exit(rc, __func__);
}
rc = pthread_cond_init(&sem->cond, NULL);
if (rc != 0) {
error_exit(rc, __func__);
}
if (init < 0) {
error_exit(EINVAL, __func__);
}
sem->count = init;
#else
rc = sem_init(&sem->sem, 0, init);
if (rc < 0) {
error_exit(errno, __func__);
}
#endif
}
void qemu_sem_destroy(QemuSemaphore *sem)
{
int rc;
#if defined(__APPLE__) || defined(__NetBSD__)
rc = pthread_cond_destroy(&sem->cond);
if (rc < 0) {
error_exit(rc, __func__);
}
rc = pthread_mutex_destroy(&sem->lock);
if (rc < 0) {
error_exit(rc, __func__);
}
#else
rc = sem_destroy(&sem->sem);
if (rc < 0) {
error_exit(errno, __func__);
}
#endif
}
void qemu_sem_post(QemuSemaphore *sem)
{
int rc;
#if defined(__APPLE__) || defined(__NetBSD__)
pthread_mutex_lock(&sem->lock);
if (sem->count == UINT_MAX) {
rc = EINVAL;
} else {
sem->count++;
rc = pthread_cond_signal(&sem->cond);
}
pthread_mutex_unlock(&sem->lock);
if (rc != 0) {
error_exit(rc, __func__);
}
#else
rc = sem_post(&sem->sem);
if (rc < 0) {
error_exit(errno, __func__);
}
#endif
}
static void compute_abs_deadline(struct timespec *ts, int ms)
{
struct timeval tv;
gettimeofday(&tv, NULL);
ts->tv_nsec = tv.tv_usec * 1000 + (ms % 1000) * 1000000;
ts->tv_sec = tv.tv_sec + ms / 1000;
if (ts->tv_nsec >= 1000000000) {
ts->tv_sec++;
ts->tv_nsec -= 1000000000;
}
}
int qemu_sem_timedwait(QemuSemaphore *sem, int ms)
{
int rc;
struct timespec ts;
#if defined(__APPLE__) || defined(__NetBSD__)
rc = 0;
compute_abs_deadline(&ts, ms);
pthread_mutex_lock(&sem->lock);
while (sem->count == 0) {
rc = pthread_cond_timedwait(&sem->cond, &sem->lock, &ts);
if (rc == ETIMEDOUT) {
break;
}
if (rc != 0) {
error_exit(rc, __func__);
}
}
if (rc != ETIMEDOUT) {
--sem->count;
}
pthread_mutex_unlock(&sem->lock);
return (rc == ETIMEDOUT ? -1 : 0);
#else
if (ms <= 0) {
/* This is cheaper than sem_timedwait. */
do {
rc = sem_trywait(&sem->sem);
} while (rc == -1 && errno == EINTR);
if (rc == -1 && errno == EAGAIN) {
return -1;
}
} else {
compute_abs_deadline(&ts, ms);
do {
rc = sem_timedwait(&sem->sem, &ts);
} while (rc == -1 && errno == EINTR);
if (rc == -1 && errno == ETIMEDOUT) {
return -1;
}
}
if (rc < 0) {
error_exit(errno, __func__);
}
return 0;
#endif
}
void qemu_sem_wait(QemuSemaphore *sem)
{
int rc;
#if defined(__APPLE__) || defined(__NetBSD__)
pthread_mutex_lock(&sem->lock);
while (sem->count == 0) {
rc = pthread_cond_wait(&sem->cond, &sem->lock);
if (rc != 0) {
error_exit(rc, __func__);
}
}
--sem->count;
pthread_mutex_unlock(&sem->lock);
#else
do {
rc = sem_wait(&sem->sem);
} while (rc == -1 && errno == EINTR);
if (rc < 0) {
error_exit(errno, __func__);
}
#endif
}
#ifdef __linux__
#define futex(...) syscall(__NR_futex, __VA_ARGS__)
static inline void futex_wake(QemuEvent *ev, int n)
{
futex(ev, FUTEX_WAKE, n, NULL, NULL, 0);
}
static inline void futex_wait(QemuEvent *ev, unsigned val)
{
futex(ev, FUTEX_WAIT, (int) val, NULL, NULL, 0);
}
#else
static inline void futex_wake(QemuEvent *ev, int n)
{
pthread_mutex_lock(&ev->lock);
if (n == 1) {
pthread_cond_signal(&ev->cond);
} else {
pthread_cond_broadcast(&ev->cond);
}
pthread_mutex_unlock(&ev->lock);
}
static inline void futex_wait(QemuEvent *ev, unsigned val)
{
pthread_mutex_lock(&ev->lock);
if (ev->value == val) {
pthread_cond_wait(&ev->cond, &ev->lock);
}
pthread_mutex_unlock(&ev->lock);
}
#endif
/* Valid transitions:
* - free->set, when setting the event
* - busy->set, when setting the event, followed by futex_wake
* - set->free, when resetting the event
* - free->busy, when waiting
*
* set->busy does not happen (it can be observed from the outside but
* it really is set->free->busy).
*
* busy->free provably cannot happen; to enforce it, the set->free transition
* is done with an OR, which becomes a no-op if the event has concurrently
* transitioned to free or busy.
*/
#define EV_SET 0
#define EV_FREE 1
#define EV_BUSY -1
void qemu_event_init(QemuEvent *ev, bool init)
{
#ifndef __linux__
pthread_mutex_init(&ev->lock, NULL);
pthread_cond_init(&ev->cond, NULL);
#endif
ev->value = (init ? EV_SET : EV_FREE);
}
void qemu_event_destroy(QemuEvent *ev)
{
#ifndef __linux__
pthread_mutex_destroy(&ev->lock);
pthread_cond_destroy(&ev->cond);
#endif
}
void qemu_event_set(QemuEvent *ev)
{
if (atomic_mb_read(&ev->value) != EV_SET) {
if (atomic_xchg(&ev->value, EV_SET) == EV_BUSY) {
/* There were waiters, wake them up. */
futex_wake(ev, INT_MAX);
}
}
}
void qemu_event_reset(QemuEvent *ev)
{
if (atomic_mb_read(&ev->value) == EV_SET) {
/*
* If there was a concurrent reset (or even reset+wait),
* do nothing. Otherwise change EV_SET->EV_FREE.
*/
atomic_or(&ev->value, EV_FREE);
}
}
void qemu_event_wait(QemuEvent *ev)
{
unsigned value;
value = atomic_mb_read(&ev->value);
if (value != EV_SET) {
if (value == EV_FREE) {
/*
* Leave the event reset and tell qemu_event_set that there
* are waiters. No need to retry, because there cannot be
* a concurent busy->free transition. After the CAS, the
* event will be either set or busy.
*/
if (atomic_cmpxchg(&ev->value, EV_FREE, EV_BUSY) == EV_SET) {
return;
}
}
futex_wait(ev, EV_BUSY);
}
}
int qemu_thread_create(struct uc_struct *uc, QemuThread *thread, const char *name,
void *(*start_routine)(void*),
void *arg, int mode)

View File

@ -53,18 +53,6 @@ void qemu_mutex_lock(QemuMutex *mutex)
mutex->owner = GetCurrentThreadId();
}
int qemu_mutex_trylock(QemuMutex *mutex)
{
int owned;
owned = TryEnterCriticalSection(&mutex->lock);
if (owned) {
assert(mutex->owner == 0);
mutex->owner = GetCurrentThreadId();
}
return !owned;
}
void qemu_mutex_unlock(QemuMutex *mutex)
{
assert(mutex->owner == GetCurrentThreadId());
@ -159,103 +147,6 @@ void qemu_cond_broadcast(QemuCond *cond)
WaitForSingleObject(cond->continue_event, INFINITE);
}
void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex)
{
/*
* This access is protected under the mutex.
*/
cond->waiters++;
/*
* Unlock external mutex and wait for signal.
* NOTE: we've held mutex locked long enough to increment
* waiters count above, so there's no problem with
* leaving mutex unlocked before we wait on semaphore.
*/
qemu_mutex_unlock(mutex);
WaitForSingleObject(cond->sema, INFINITE);
/* Now waiters must rendez-vous with the signaling thread and
* let it continue. For cond_broadcast this has heavy contention
* and triggers thundering herd. So goes life.
*
* Decrease waiters count. The mutex is not taken, so we have
* to do this atomically.
*
* All waiters contend for the mutex at the end of this function
* until the signaling thread relinquishes it. To ensure
* each waiter consumes exactly one slice of the semaphore,
* the signaling thread stops until it is told by the last
* waiter that it can go on.
*/
if (InterlockedDecrement(&cond->waiters) == cond->target) {
SetEvent(cond->continue_event);
}
qemu_mutex_lock(mutex);
}
void qemu_sem_init(QemuSemaphore *sem, int init)
{
/* Manual reset. */
sem->sema = CreateSemaphore(NULL, init, LONG_MAX, NULL);
}
void qemu_sem_destroy(QemuSemaphore *sem)
{
CloseHandle(sem->sema);
}
void qemu_sem_post(QemuSemaphore *sem)
{
ReleaseSemaphore(sem->sema, 1, NULL);
}
int qemu_sem_timedwait(QemuSemaphore *sem, int ms)
{
int rc = WaitForSingleObject(sem->sema, ms);
if (rc == WAIT_OBJECT_0) {
return 0;
}
if (rc != WAIT_TIMEOUT) {
error_exit(GetLastError(), __func__);
}
return -1;
}
void qemu_sem_wait(QemuSemaphore *sem)
{
if (WaitForSingleObject(sem->sema, INFINITE) != WAIT_OBJECT_0) {
error_exit(GetLastError(), __func__);
}
}
void qemu_event_init(QemuEvent *ev, bool init)
{
/* Manual reset. */
ev->event = CreateEvent(NULL, TRUE, init, NULL);
}
void qemu_event_destroy(QemuEvent *ev)
{
CloseHandle(ev->event);
}
void qemu_event_set(QemuEvent *ev)
{
SetEvent(ev->event);
}
void qemu_event_reset(QemuEvent *ev)
{
ResetEvent(ev->event);
}
void qemu_event_wait(QemuEvent *ev)
{
WaitForSingleObject(ev->event, INFINITE);
}
struct QemuThreadData {
/* Passed to win32_start_routine. */
void *(*start_routine)(void *);