Statistics
| Branch: | Revision:

root / posix-aio-compat.c @ b42ec42d

History | View | Annotate | Download (5.5 kB)

1 3c529d93 aliguori
/*
2 3c529d93 aliguori
 * QEMU posix-aio emulation
3 3c529d93 aliguori
 *
4 3c529d93 aliguori
 * Copyright IBM, Corp. 2008
5 3c529d93 aliguori
 *
6 3c529d93 aliguori
 * Authors:
7 3c529d93 aliguori
 *  Anthony Liguori   <aliguori@us.ibm.com>
8 3c529d93 aliguori
 *
9 3c529d93 aliguori
 * This work is licensed under the terms of the GNU GPL, version 2.  See
10 3c529d93 aliguori
 * the COPYING file in the top-level directory.
11 3c529d93 aliguori
 *
12 3c529d93 aliguori
 */
13 3c529d93 aliguori
14 3c529d93 aliguori
#include <pthread.h>
15 3c529d93 aliguori
#include <unistd.h>
16 3c529d93 aliguori
#include <errno.h>
17 30525aff malc
#include <time.h>
18 8653c015 malc
#include <string.h>
19 8653c015 malc
#include <stdlib.h>
20 8653c015 malc
#include <stdio.h>
21 3c529d93 aliguori
#include "osdep.h"
22 3c529d93 aliguori
23 3c529d93 aliguori
#include "posix-aio-compat.h"
24 3c529d93 aliguori
25 3c529d93 aliguori
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
26 3c529d93 aliguori
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
27 3c529d93 aliguori
static pthread_t thread_id;
28 a8227a5a malc
static pthread_attr_t attr;
29 3c529d93 aliguori
static int max_threads = 64;
30 3c529d93 aliguori
static int cur_threads = 0;
31 3c529d93 aliguori
static int idle_threads = 0;
32 3c529d93 aliguori
static TAILQ_HEAD(, qemu_paiocb) request_list;
33 3c529d93 aliguori
34 8653c015 malc
static void die2(int err, const char *what)
35 8653c015 malc
{
36 8653c015 malc
    fprintf(stderr, "%s failed: %s\n", what, strerror(err));
37 8653c015 malc
    abort();
38 8653c015 malc
}
39 8653c015 malc
40 8653c015 malc
static void die(const char *what)
41 8653c015 malc
{
42 8653c015 malc
    die2(errno, what);
43 8653c015 malc
}
44 8653c015 malc
45 8653c015 malc
static void mutex_lock(pthread_mutex_t *mutex)
46 8653c015 malc
{
47 8653c015 malc
    int ret = pthread_mutex_lock(mutex);
48 8653c015 malc
    if (ret) die2(ret, "pthread_mutex_lock");
49 8653c015 malc
}
50 8653c015 malc
51 8653c015 malc
static void mutex_unlock(pthread_mutex_t *mutex)
52 8653c015 malc
{
53 8653c015 malc
    int ret = pthread_mutex_unlock(mutex);
54 8653c015 malc
    if (ret) die2(ret, "pthread_mutex_unlock");
55 8653c015 malc
}
56 8653c015 malc
57 8653c015 malc
static int cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
58 8653c015 malc
                           struct timespec *ts)
59 8653c015 malc
{
60 8653c015 malc
    int ret = pthread_cond_timedwait(cond, mutex, ts);
61 8653c015 malc
    if (ret && ret != ETIMEDOUT) die2(ret, "pthread_cond_timedwait");
62 8653c015 malc
    return ret;
63 8653c015 malc
}
64 8653c015 malc
65 5d47e372 malc
static void cond_signal(pthread_cond_t *cond)
66 8653c015 malc
{
67 5d47e372 malc
    int ret = pthread_cond_signal(cond);
68 5d47e372 malc
    if (ret) die2(ret, "pthread_cond_signal");
69 8653c015 malc
}
70 8653c015 malc
71 8653c015 malc
static void thread_create(pthread_t *thread, pthread_attr_t *attr,
72 8653c015 malc
                          void *(*start_routine)(void*), void *arg)
73 8653c015 malc
{
74 8653c015 malc
    int ret = pthread_create(thread, attr, start_routine, arg);
75 8653c015 malc
    if (ret) die2(ret, "pthread_create");
76 8653c015 malc
}
77 8653c015 malc
78 3c529d93 aliguori
static void *aio_thread(void *unused)
79 3c529d93 aliguori
{
80 a8227a5a malc
    pid_t pid;
81 3c529d93 aliguori
    sigset_t set;
82 3c529d93 aliguori
83 a8227a5a malc
    pid = getpid();
84 a8227a5a malc
85 3c529d93 aliguori
    /* block all signals */
86 8653c015 malc
    if (sigfillset(&set)) die("sigfillset");
87 8653c015 malc
    if (sigprocmask(SIG_BLOCK, &set, NULL)) die("sigprocmask");
88 3c529d93 aliguori
89 3c529d93 aliguori
    while (1) {
90 3c529d93 aliguori
        struct qemu_paiocb *aiocb;
91 3c529d93 aliguori
        size_t offset;
92 3c529d93 aliguori
        int ret = 0;
93 30525aff malc
        qemu_timeval tv;
94 30525aff malc
        struct timespec ts;
95 30525aff malc
96 30525aff malc
        qemu_gettimeofday(&tv);
97 30525aff malc
        ts.tv_sec = tv.tv_sec + 10;
98 30525aff malc
        ts.tv_nsec = 0;
99 3c529d93 aliguori
100 8653c015 malc
        mutex_lock(&lock);
101 3c529d93 aliguori
102 3c529d93 aliguori
        while (TAILQ_EMPTY(&request_list) &&
103 3c529d93 aliguori
               !(ret == ETIMEDOUT)) {
104 8653c015 malc
            ret = cond_timedwait(&cond, &lock, &ts);
105 3c529d93 aliguori
        }
106 3c529d93 aliguori
107 514f7a27 malc
        if (TAILQ_EMPTY(&request_list))
108 3c529d93 aliguori
            break;
109 3c529d93 aliguori
110 3c529d93 aliguori
        aiocb = TAILQ_FIRST(&request_list);
111 3c529d93 aliguori
        TAILQ_REMOVE(&request_list, aiocb, node);
112 3c529d93 aliguori
113 3c529d93 aliguori
        offset = 0;
114 3c529d93 aliguori
        aiocb->active = 1;
115 3c529d93 aliguori
116 3c529d93 aliguori
        idle_threads--;
117 8653c015 malc
        mutex_unlock(&lock);
118 3c529d93 aliguori
119 3c529d93 aliguori
        while (offset < aiocb->aio_nbytes) {
120 3c529d93 aliguori
            ssize_t len;
121 3c529d93 aliguori
122 3c529d93 aliguori
            if (aiocb->is_write)
123 3c529d93 aliguori
                len = pwrite(aiocb->aio_fildes,
124 3c529d93 aliguori
                             (const char *)aiocb->aio_buf + offset,
125 3c529d93 aliguori
                             aiocb->aio_nbytes - offset,
126 3c529d93 aliguori
                             aiocb->aio_offset + offset);
127 3c529d93 aliguori
            else
128 3c529d93 aliguori
                len = pread(aiocb->aio_fildes,
129 3c529d93 aliguori
                            (char *)aiocb->aio_buf + offset,
130 3c529d93 aliguori
                            aiocb->aio_nbytes - offset,
131 3c529d93 aliguori
                            aiocb->aio_offset + offset);
132 3c529d93 aliguori
133 3c529d93 aliguori
            if (len == -1 && errno == EINTR)
134 3c529d93 aliguori
                continue;
135 3c529d93 aliguori
            else if (len == -1) {
136 f094a782 aliguori
                offset = -errno;
137 3c529d93 aliguori
                break;
138 3c529d93 aliguori
            } else if (len == 0)
139 3c529d93 aliguori
                break;
140 3c529d93 aliguori
141 3c529d93 aliguori
            offset += len;
142 3c529d93 aliguori
        }
143 3c529d93 aliguori
144 8653c015 malc
        mutex_lock(&lock);
145 f094a782 aliguori
        aiocb->ret = offset;
146 3c529d93 aliguori
        idle_threads++;
147 8653c015 malc
        mutex_unlock(&lock);
148 3c529d93 aliguori
149 a8227a5a malc
        if (kill(pid, aiocb->ev_signo)) die("kill failed");
150 3c529d93 aliguori
    }
151 3c529d93 aliguori
152 3c529d93 aliguori
    idle_threads--;
153 3c529d93 aliguori
    cur_threads--;
154 8653c015 malc
    mutex_unlock(&lock);
155 3c529d93 aliguori
156 3c529d93 aliguori
    return NULL;
157 3c529d93 aliguori
}
158 3c529d93 aliguori
159 8653c015 malc
static void spawn_thread(void)
160 3c529d93 aliguori
{
161 3c529d93 aliguori
    cur_threads++;
162 3c529d93 aliguori
    idle_threads++;
163 8653c015 malc
    thread_create(&thread_id, &attr, aio_thread, NULL);
164 3c529d93 aliguori
}
165 3c529d93 aliguori
166 3c529d93 aliguori
int qemu_paio_init(struct qemu_paioinit *aioinit)
167 3c529d93 aliguori
{
168 a8227a5a malc
    int ret;
169 a8227a5a malc
170 a8227a5a malc
    ret = pthread_attr_init(&attr);
171 a8227a5a malc
    if (ret) die2(ret, "pthread_attr_init");
172 a8227a5a malc
173 a8227a5a malc
    ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
174 a8227a5a malc
    if (ret) die2(ret, "pthread_attr_setdetachstate");
175 a8227a5a malc
176 3c529d93 aliguori
    TAILQ_INIT(&request_list);
177 3c529d93 aliguori
178 3c529d93 aliguori
    return 0;
179 3c529d93 aliguori
}
180 3c529d93 aliguori
181 3c529d93 aliguori
static int qemu_paio_submit(struct qemu_paiocb *aiocb, int is_write)
182 3c529d93 aliguori
{
183 3c529d93 aliguori
    aiocb->is_write = is_write;
184 3c529d93 aliguori
    aiocb->ret = -EINPROGRESS;
185 3c529d93 aliguori
    aiocb->active = 0;
186 8653c015 malc
    mutex_lock(&lock);
187 3c529d93 aliguori
    if (idle_threads == 0 && cur_threads < max_threads)
188 3c529d93 aliguori
        spawn_thread();
189 3c529d93 aliguori
    TAILQ_INSERT_TAIL(&request_list, aiocb, node);
190 8653c015 malc
    mutex_unlock(&lock);
191 5d47e372 malc
    cond_signal(&cond);
192 3c529d93 aliguori
193 3c529d93 aliguori
    return 0;
194 3c529d93 aliguori
}
195 3c529d93 aliguori
196 3c529d93 aliguori
int qemu_paio_read(struct qemu_paiocb *aiocb)
197 3c529d93 aliguori
{
198 3c529d93 aliguori
    return qemu_paio_submit(aiocb, 0);
199 3c529d93 aliguori
}
200 3c529d93 aliguori
201 3c529d93 aliguori
int qemu_paio_write(struct qemu_paiocb *aiocb)
202 3c529d93 aliguori
{
203 3c529d93 aliguori
    return qemu_paio_submit(aiocb, 1);
204 3c529d93 aliguori
}
205 3c529d93 aliguori
206 3c529d93 aliguori
ssize_t qemu_paio_return(struct qemu_paiocb *aiocb)
207 3c529d93 aliguori
{
208 3c529d93 aliguori
    ssize_t ret;
209 3c529d93 aliguori
210 8653c015 malc
    mutex_lock(&lock);
211 3c529d93 aliguori
    ret = aiocb->ret;
212 8653c015 malc
    mutex_unlock(&lock);
213 3c529d93 aliguori
214 3c529d93 aliguori
    return ret;
215 3c529d93 aliguori
}
216 3c529d93 aliguori
217 3c529d93 aliguori
int qemu_paio_error(struct qemu_paiocb *aiocb)
218 3c529d93 aliguori
{
219 3c529d93 aliguori
    ssize_t ret = qemu_paio_return(aiocb);
220 3c529d93 aliguori
221 3c529d93 aliguori
    if (ret < 0)
222 3c529d93 aliguori
        ret = -ret;
223 3c529d93 aliguori
    else
224 3c529d93 aliguori
        ret = 0;
225 3c529d93 aliguori
226 3c529d93 aliguori
    return ret;
227 3c529d93 aliguori
}
228 3c529d93 aliguori
229 3c529d93 aliguori
int qemu_paio_cancel(int fd, struct qemu_paiocb *aiocb)
230 3c529d93 aliguori
{
231 3c529d93 aliguori
    int ret;
232 3c529d93 aliguori
233 8653c015 malc
    mutex_lock(&lock);
234 3c529d93 aliguori
    if (!aiocb->active) {
235 3c529d93 aliguori
        TAILQ_REMOVE(&request_list, aiocb, node);
236 3c529d93 aliguori
        aiocb->ret = -ECANCELED;
237 3c529d93 aliguori
        ret = QEMU_PAIO_CANCELED;
238 3c529d93 aliguori
    } else if (aiocb->ret == -EINPROGRESS)
239 3c529d93 aliguori
        ret = QEMU_PAIO_NOTCANCELED;
240 3c529d93 aliguori
    else
241 3c529d93 aliguori
        ret = QEMU_PAIO_ALLDONE;
242 8653c015 malc
    mutex_unlock(&lock);
243 3c529d93 aliguori
244 3c529d93 aliguori
    return ret;
245 3c529d93 aliguori
}