2 * QEMU posix-aio emulation
4 * Copyright IBM, Corp. 2008
7 * Anthony Liguori <aliguori@us.ibm.com>
9 * This work is licensed under the terms of the GNU GPL, version 2. See
10 * the COPYING file in the top-level directory.
23 #include "posix-aio-compat.h"
25 static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
26 static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
27 static pthread_t thread_id;
28 static pthread_attr_t attr;
29 static int max_threads = 64;
30 static int cur_threads = 0;
31 static int idle_threads = 0;
32 static TAILQ_HEAD(, qemu_paiocb) request_list;
34 static void die2(int err, const char *what)
36 fprintf(stderr, "%s failed: %s\n", what, strerror(err));
40 static void die(const char *what)
45 static void mutex_lock(pthread_mutex_t *mutex)
47 int ret = pthread_mutex_lock(mutex);
48 if (ret) die2(ret, "pthread_mutex_lock");
51 static void mutex_unlock(pthread_mutex_t *mutex)
53 int ret = pthread_mutex_unlock(mutex);
54 if (ret) die2(ret, "pthread_mutex_unlock");
57 static int cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
60 int ret = pthread_cond_timedwait(cond, mutex, ts);
61 if (ret && ret != ETIMEDOUT) die2(ret, "pthread_cond_timedwait");
65 static void cond_signal(pthread_cond_t *cond)
67 int ret = pthread_cond_signal(cond);
68 if (ret) die2(ret, "pthread_cond_signal");
71 static void thread_create(pthread_t *thread, pthread_attr_t *attr,
72 void *(*start_routine)(void*), void *arg)
74 int ret = pthread_create(thread, attr, start_routine, arg);
75 if (ret) die2(ret, "pthread_create");
78 static void *aio_thread(void *unused)
85 /* block all signals */
86 if (sigfillset(&set)) die("sigfillset");
87 if (sigprocmask(SIG_BLOCK, &set, NULL)) die("sigprocmask");
90 struct qemu_paiocb *aiocb;
96 qemu_gettimeofday(&tv);
97 ts.tv_sec = tv.tv_sec + 10;
102 while (TAILQ_EMPTY(&request_list) &&
103 !(ret == ETIMEDOUT)) {
104 ret = cond_timedwait(&cond, &lock, &ts);
107 if (TAILQ_EMPTY(&request_list))
110 aiocb = TAILQ_FIRST(&request_list);
111 TAILQ_REMOVE(&request_list, aiocb, node);
119 while (offset < aiocb->aio_nbytes) {
123 len = pwrite(aiocb->aio_fildes,
124 (const char *)aiocb->aio_buf + offset,
125 aiocb->aio_nbytes - offset,
126 aiocb->aio_offset + offset);
128 len = pread(aiocb->aio_fildes,
129 (char *)aiocb->aio_buf + offset,
130 aiocb->aio_nbytes - offset,
131 aiocb->aio_offset + offset);
133 if (len == -1 && errno == EINTR)
135 else if (len == -1) {
149 if (kill(pid, aiocb->ev_signo)) die("kill failed");
159 static void spawn_thread(void)
163 thread_create(&thread_id, &attr, aio_thread, NULL);
166 int qemu_paio_init(struct qemu_paioinit *aioinit)
170 ret = pthread_attr_init(&attr);
171 if (ret) die2(ret, "pthread_attr_init");
173 ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
174 if (ret) die2(ret, "pthread_attr_setdetachstate");
176 TAILQ_INIT(&request_list);
181 static int qemu_paio_submit(struct qemu_paiocb *aiocb, int is_write)
183 aiocb->is_write = is_write;
184 aiocb->ret = -EINPROGRESS;
187 if (idle_threads == 0 && cur_threads < max_threads)
189 TAILQ_INSERT_TAIL(&request_list, aiocb, node);
196 int qemu_paio_read(struct qemu_paiocb *aiocb)
198 return qemu_paio_submit(aiocb, 0);
201 int qemu_paio_write(struct qemu_paiocb *aiocb)
203 return qemu_paio_submit(aiocb, 1);
206 ssize_t qemu_paio_return(struct qemu_paiocb *aiocb)
217 int qemu_paio_error(struct qemu_paiocb *aiocb)
219 ssize_t ret = qemu_paio_return(aiocb);
229 int qemu_paio_cancel(int fd, struct qemu_paiocb *aiocb)
234 if (!aiocb->active) {
235 TAILQ_REMOVE(&request_list, aiocb, node);
236 aiocb->ret = -ECANCELED;
237 ret = QEMU_PAIO_CANCELED;
238 } else if (aiocb->ret == -EINPROGRESS)
239 ret = QEMU_PAIO_NOTCANCELED;
241 ret = QEMU_PAIO_ALLDONE;