|
|
|
@ -15,6 +15,9 @@ |
|
|
|
#include <unistd.h> |
|
|
|
#include <errno.h> |
|
|
|
#include <sys/time.h> |
|
|
|
#include <string.h> |
|
|
|
#include <stdlib.h> |
|
|
|
#include <stdio.h> |
|
|
|
#include "osdep.h" |
|
|
|
|
|
|
|
#include "posix-aio-compat.h" |
|
|
|
@ -27,20 +30,64 @@ static int cur_threads = 0; |
|
|
|
static int idle_threads = 0; |
|
|
|
static TAILQ_HEAD(, qemu_paiocb) request_list; |
|
|
|
|
|
|
|
static void die2(int err, const char *what) |
|
|
|
{ |
|
|
|
fprintf(stderr, "%s failed: %s\n", what, strerror(err)); |
|
|
|
abort(); |
|
|
|
} |
|
|
|
|
|
|
|
static void die(const char *what) |
|
|
|
{ |
|
|
|
die2(errno, what); |
|
|
|
} |
|
|
|
|
|
|
|
static void mutex_lock(pthread_mutex_t *mutex) |
|
|
|
{ |
|
|
|
int ret = pthread_mutex_lock(mutex); |
|
|
|
if (ret) die2(ret, "pthread_mutex_lock"); |
|
|
|
} |
|
|
|
|
|
|
|
static void mutex_unlock(pthread_mutex_t *mutex) |
|
|
|
{ |
|
|
|
int ret = pthread_mutex_unlock(mutex); |
|
|
|
if (ret) die2(ret, "pthread_mutex_unlock"); |
|
|
|
} |
|
|
|
|
|
|
|
static int cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, |
|
|
|
struct timespec *ts) |
|
|
|
{ |
|
|
|
int ret = pthread_cond_timedwait(cond, mutex, ts); |
|
|
|
if (ret && ret != ETIMEDOUT) die2(ret, "pthread_cond_timedwait"); |
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
static void cond_broadcast(pthread_cond_t *cond) |
|
|
|
{ |
|
|
|
int ret = pthread_cond_broadcast(cond); |
|
|
|
if (ret) die2(ret, "pthread_cond_broadcast"); |
|
|
|
} |
|
|
|
|
|
|
|
static void thread_create(pthread_t *thread, pthread_attr_t *attr, |
|
|
|
void *(*start_routine)(void*), void *arg) |
|
|
|
{ |
|
|
|
int ret = pthread_create(thread, attr, start_routine, arg); |
|
|
|
if (ret) die2(ret, "pthread_create"); |
|
|
|
} |
|
|
|
|
|
|
|
static void *aio_thread(void *unused) |
|
|
|
{ |
|
|
|
sigset_t set; |
|
|
|
|
|
|
|
/* block all signals */ |
|
|
|
sigfillset(&set); |
|
|
|
sigprocmask(SIG_BLOCK, &set, NULL); |
|
|
|
if (sigfillset(&set)) die("sigfillset"); |
|
|
|
if (sigprocmask(SIG_BLOCK, &set, NULL)) die("sigprocmask"); |
|
|
|
|
|
|
|
while (1) { |
|
|
|
struct qemu_paiocb *aiocb; |
|
|
|
size_t offset; |
|
|
|
int ret = 0; |
|
|
|
|
|
|
|
pthread_mutex_lock(&lock); |
|
|
|
mutex_lock(&lock); |
|
|
|
|
|
|
|
while (TAILQ_EMPTY(&request_list) && |
|
|
|
!(ret == ETIMEDOUT)) { |
|
|
|
@ -49,7 +96,7 @@ static void *aio_thread(void *unused) |
|
|
|
|
|
|
|
qemu_gettimeofday(&tv); |
|
|
|
ts.tv_sec = tv.tv_sec + 10; |
|
|
|
ret = pthread_cond_timedwait(&cond, &lock, &ts); |
|
|
|
ret = cond_timedwait(&cond, &lock, &ts); |
|
|
|
} |
|
|
|
|
|
|
|
if (ret == ETIMEDOUT) |
|
|
|
@ -62,7 +109,7 @@ static void *aio_thread(void *unused) |
|
|
|
aiocb->active = 1; |
|
|
|
|
|
|
|
idle_threads--; |
|
|
|
pthread_mutex_unlock(&lock); |
|
|
|
mutex_unlock(&lock); |
|
|
|
|
|
|
|
while (offset < aiocb->aio_nbytes) { |
|
|
|
ssize_t len; |
|
|
|
@ -89,35 +136,36 @@ static void *aio_thread(void *unused) |
|
|
|
offset += len; |
|
|
|
} |
|
|
|
|
|
|
|
pthread_mutex_lock(&lock); |
|
|
|
mutex_lock(&lock); |
|
|
|
aiocb->ret = offset; |
|
|
|
idle_threads++; |
|
|
|
pthread_mutex_unlock(&lock); |
|
|
|
mutex_unlock(&lock); |
|
|
|
|
|
|
|
kill(getpid(), aiocb->ev_signo); |
|
|
|
if (kill(getpid(), aiocb->ev_signo)) die("kill failed"); |
|
|
|
} |
|
|
|
|
|
|
|
idle_threads--; |
|
|
|
cur_threads--; |
|
|
|
pthread_mutex_unlock(&lock); |
|
|
|
mutex_unlock(&lock); |
|
|
|
|
|
|
|
return NULL; |
|
|
|
} |
|
|
|
|
|
|
|
static int spawn_thread(void) |
|
|
|
static void spawn_thread(void) |
|
|
|
{ |
|
|
|
pthread_attr_t attr; |
|
|
|
int ret; |
|
|
|
pthread_attr_t attr; |
|
|
|
|
|
|
|
cur_threads++; |
|
|
|
idle_threads++; |
|
|
|
|
|
|
|
pthread_attr_init(&attr); |
|
|
|
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); |
|
|
|
ret = pthread_create(&thread_id, &attr, aio_thread, NULL); |
|
|
|
pthread_attr_destroy(&attr); |
|
|
|
|
|
|
|
return ret; |
|
|
|
ret = pthread_attr_init(&attr); |
|
|
|
if (ret) die2 (ret, "pthread_attr_init"); |
|
|
|
ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); |
|
|
|
if (ret) die2 (ret, "pthread_attr_setdetachstate"); |
|
|
|
thread_create(&thread_id, &attr, aio_thread, NULL); |
|
|
|
ret = pthread_attr_destroy(&attr); |
|
|
|
if (ret) die2 (ret, "pthread_attr_destroy"); |
|
|
|
} |
|
|
|
|
|
|
|
int qemu_paio_init(struct qemu_paioinit *aioinit) |
|
|
|
@ -132,12 +180,12 @@ static int qemu_paio_submit(struct qemu_paiocb *aiocb, int is_write) |
|
|
|
aiocb->is_write = is_write; |
|
|
|
aiocb->ret = -EINPROGRESS; |
|
|
|
aiocb->active = 0; |
|
|
|
pthread_mutex_lock(&lock); |
|
|
|
mutex_lock(&lock); |
|
|
|
if (idle_threads == 0 && cur_threads < max_threads) |
|
|
|
spawn_thread(); |
|
|
|
TAILQ_INSERT_TAIL(&request_list, aiocb, node); |
|
|
|
pthread_mutex_unlock(&lock); |
|
|
|
pthread_cond_broadcast(&cond); |
|
|
|
mutex_unlock(&lock); |
|
|
|
cond_broadcast(&cond); |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
@ -156,9 +204,9 @@ ssize_t qemu_paio_return(struct qemu_paiocb *aiocb) |
|
|
|
{ |
|
|
|
ssize_t ret; |
|
|
|
|
|
|
|
pthread_mutex_lock(&lock); |
|
|
|
mutex_lock(&lock); |
|
|
|
ret = aiocb->ret; |
|
|
|
pthread_mutex_unlock(&lock); |
|
|
|
mutex_unlock(&lock); |
|
|
|
|
|
|
|
return ret; |
|
|
|
} |
|
|
|
@ -179,7 +227,7 @@ int qemu_paio_cancel(int fd, struct qemu_paiocb *aiocb) |
|
|
|
{ |
|
|
|
int ret; |
|
|
|
|
|
|
|
pthread_mutex_lock(&lock); |
|
|
|
mutex_lock(&lock); |
|
|
|
if (!aiocb->active) { |
|
|
|
TAILQ_REMOVE(&request_list, aiocb, node); |
|
|
|
aiocb->ret = -ECANCELED; |
|
|
|
@ -188,7 +236,7 @@ int qemu_paio_cancel(int fd, struct qemu_paiocb *aiocb) |
|
|
|
ret = QEMU_PAIO_NOTCANCELED; |
|
|
|
else |
|
|
|
ret = QEMU_PAIO_ALLDONE; |
|
|
|
pthread_mutex_unlock(&lock); |
|
|
|
mutex_unlock(&lock); |
|
|
|
|
|
|
|
return ret; |
|
|
|
} |
|
|
|
|