qemu-thread: add QemuSemaphore
The new thread pool will use semaphores instead of condition variables, because QemuCond does not have qemu_cond_timedwait. (I also like it more this way). Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
		
							parent
							
								
									c90caf25e2
								
							
						
					
					
						commit
						38b14db34e
					
				| 
						 | 
				
			
			@ -17,6 +17,9 @@
 | 
			
		|||
#include <signal.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <sys/time.h>
 | 
			
		||||
#include "qemu-thread.h"
 | 
			
		||||
 | 
			
		||||
static void error_exit(int err, const char *msg)
 | 
			
		||||
| 
						 | 
				
			
			@ -115,6 +118,83 @@ void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex)
 | 
			
		|||
        error_exit(err, __func__);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void qemu_sem_init(QemuSemaphore *sem, int init)
 | 
			
		||||
{
 | 
			
		||||
    int rc;
 | 
			
		||||
 | 
			
		||||
    rc = sem_init(&sem->sem, 0, init);
 | 
			
		||||
    if (rc < 0) {
 | 
			
		||||
        error_exit(errno, __func__);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void qemu_sem_destroy(QemuSemaphore *sem)
 | 
			
		||||
{
 | 
			
		||||
    int rc;
 | 
			
		||||
 | 
			
		||||
    rc = sem_destroy(&sem->sem);
 | 
			
		||||
    if (rc < 0) {
 | 
			
		||||
        error_exit(errno, __func__);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void qemu_sem_post(QemuSemaphore *sem)
 | 
			
		||||
{
 | 
			
		||||
    int rc;
 | 
			
		||||
 | 
			
		||||
    rc = sem_post(&sem->sem);
 | 
			
		||||
    if (rc < 0) {
 | 
			
		||||
        error_exit(errno, __func__);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int qemu_sem_timedwait(QemuSemaphore *sem, int ms)
 | 
			
		||||
{
 | 
			
		||||
    int rc;
 | 
			
		||||
 | 
			
		||||
    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 {
 | 
			
		||||
        struct timeval tv;
 | 
			
		||||
        struct timespec ts;
 | 
			
		||||
        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;
 | 
			
		||||
        }
 | 
			
		||||
        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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void qemu_sem_wait(QemuSemaphore *sem)
 | 
			
		||||
{
 | 
			
		||||
    int rc;
 | 
			
		||||
 | 
			
		||||
    do {
 | 
			
		||||
        rc = sem_wait(&sem->sem);
 | 
			
		||||
    } while (rc == -1 && errno == EINTR);
 | 
			
		||||
    if (rc < 0) {
 | 
			
		||||
        error_exit(errno, __func__);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void qemu_thread_create(QemuThread *thread,
 | 
			
		||||
                       void *(*start_routine)(void*),
 | 
			
		||||
                       void *arg, int mode)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,7 @@
 | 
			
		|||
#ifndef __QEMU_THREAD_POSIX_H
 | 
			
		||||
#define __QEMU_THREAD_POSIX_H 1
 | 
			
		||||
#include "pthread.h"
 | 
			
		||||
#include <semaphore.h>
 | 
			
		||||
 | 
			
		||||
struct QemuMutex {
 | 
			
		||||
    pthread_mutex_t lock;
 | 
			
		||||
| 
						 | 
				
			
			@ -10,6 +11,10 @@ struct QemuCond {
 | 
			
		|||
    pthread_cond_t cond;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct QemuSemaphore {
 | 
			
		||||
    sem_t sem;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct QemuThread {
 | 
			
		||||
    pthread_t thread;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -192,6 +192,41 @@ void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex)
 | 
			
		|||
    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__);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct QemuThreadData {
 | 
			
		||||
    /* Passed to win32_start_routine.  */
 | 
			
		||||
    void             *(*start_routine)(void *);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,6 +13,10 @@ struct QemuCond {
 | 
			
		|||
    HANDLE continue_event;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct QemuSemaphore {
 | 
			
		||||
    HANDLE sema;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef struct QemuThreadData QemuThreadData;
 | 
			
		||||
struct QemuThread {
 | 
			
		||||
    QemuThreadData *data;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,6 +6,7 @@
 | 
			
		|||
 | 
			
		||||
typedef struct QemuMutex QemuMutex;
 | 
			
		||||
typedef struct QemuCond QemuCond;
 | 
			
		||||
typedef struct QemuSemaphore QemuSemaphore;
 | 
			
		||||
typedef struct QemuThread QemuThread;
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
| 
						 | 
				
			
			@ -38,6 +39,12 @@ void qemu_cond_signal(QemuCond *cond);
 | 
			
		|||
void qemu_cond_broadcast(QemuCond *cond);
 | 
			
		||||
void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex);
 | 
			
		||||
 | 
			
		||||
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_thread_create(QemuThread *thread,
 | 
			
		||||
                        void *(*start_routine)(void *),
 | 
			
		||||
                        void *arg, int mode);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue