Statistics
| Branch: | Revision:

root / posix-aio-compat.c @ c72d5bf8

History | View | Annotate | Download (4.4 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 3c529d93 aliguori
#include <sys/time.h>
18 3c529d93 aliguori
#include "osdep.h"
19 3c529d93 aliguori
20 3c529d93 aliguori
#include "posix-aio-compat.h"
21 3c529d93 aliguori
22 3c529d93 aliguori
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
23 3c529d93 aliguori
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
24 3c529d93 aliguori
static pthread_t thread_id;
25 3c529d93 aliguori
static int max_threads = 64;
26 3c529d93 aliguori
static int cur_threads = 0;
27 3c529d93 aliguori
static int idle_threads = 0;
28 3c529d93 aliguori
static TAILQ_HEAD(, qemu_paiocb) request_list;
29 3c529d93 aliguori
30 3c529d93 aliguori
static void *aio_thread(void *unused)
31 3c529d93 aliguori
{
32 3c529d93 aliguori
    sigset_t set;
33 3c529d93 aliguori
34 3c529d93 aliguori
    /* block all signals */
35 3c529d93 aliguori
    sigfillset(&set);
36 3c529d93 aliguori
    sigprocmask(SIG_BLOCK, &set, NULL);
37 3c529d93 aliguori
38 3c529d93 aliguori
    while (1) {
39 3c529d93 aliguori
        struct qemu_paiocb *aiocb;
40 3c529d93 aliguori
        size_t offset;
41 3c529d93 aliguori
        int ret = 0;
42 3c529d93 aliguori
43 3c529d93 aliguori
        pthread_mutex_lock(&lock);
44 3c529d93 aliguori
45 3c529d93 aliguori
        while (TAILQ_EMPTY(&request_list) &&
46 3c529d93 aliguori
               !(ret == ETIMEDOUT)) {
47 3c529d93 aliguori
            struct timespec ts = { 0 };
48 3c529d93 aliguori
            qemu_timeval tv;
49 3c529d93 aliguori
50 3c529d93 aliguori
            qemu_gettimeofday(&tv);
51 3c529d93 aliguori
            ts.tv_sec = tv.tv_sec + 10;
52 3c529d93 aliguori
            ret = pthread_cond_timedwait(&cond, &lock, &ts);
53 3c529d93 aliguori
        }
54 3c529d93 aliguori
55 3c529d93 aliguori
        if (ret == ETIMEDOUT)
56 3c529d93 aliguori
            break;
57 3c529d93 aliguori
58 3c529d93 aliguori
        aiocb = TAILQ_FIRST(&request_list);
59 3c529d93 aliguori
        TAILQ_REMOVE(&request_list, aiocb, node);
60 3c529d93 aliguori
61 3c529d93 aliguori
        offset = 0;
62 3c529d93 aliguori
        aiocb->active = 1;
63 3c529d93 aliguori
64 3c529d93 aliguori
        idle_threads--;
65 3c529d93 aliguori
        pthread_mutex_unlock(&lock);
66 3c529d93 aliguori
67 3c529d93 aliguori
        while (offset < aiocb->aio_nbytes) {
68 3c529d93 aliguori
            ssize_t len;
69 3c529d93 aliguori
70 3c529d93 aliguori
            if (aiocb->is_write)
71 3c529d93 aliguori
                len = pwrite(aiocb->aio_fildes,
72 3c529d93 aliguori
                             (const char *)aiocb->aio_buf + offset,
73 3c529d93 aliguori
                             aiocb->aio_nbytes - offset,
74 3c529d93 aliguori
                             aiocb->aio_offset + offset);
75 3c529d93 aliguori
            else
76 3c529d93 aliguori
                len = pread(aiocb->aio_fildes,
77 3c529d93 aliguori
                            (char *)aiocb->aio_buf + offset,
78 3c529d93 aliguori
                            aiocb->aio_nbytes - offset,
79 3c529d93 aliguori
                            aiocb->aio_offset + offset);
80 3c529d93 aliguori
81 3c529d93 aliguori
            if (len == -1 && errno == EINTR)
82 3c529d93 aliguori
                continue;
83 3c529d93 aliguori
            else if (len == -1) {
84 f094a782 aliguori
                offset = -errno;
85 3c529d93 aliguori
                break;
86 3c529d93 aliguori
            } else if (len == 0)
87 3c529d93 aliguori
                break;
88 3c529d93 aliguori
89 3c529d93 aliguori
            offset += len;
90 3c529d93 aliguori
        }
91 3c529d93 aliguori
92 3c529d93 aliguori
        pthread_mutex_lock(&lock);
93 f094a782 aliguori
        aiocb->ret = offset;
94 3c529d93 aliguori
        idle_threads++;
95 3c529d93 aliguori
        pthread_mutex_unlock(&lock);
96 3c529d93 aliguori
97 3c529d93 aliguori
        sigqueue(getpid(),
98 3c529d93 aliguori
                 aiocb->aio_sigevent.sigev_signo,
99 3c529d93 aliguori
                 aiocb->aio_sigevent.sigev_value);
100 3c529d93 aliguori
    }
101 3c529d93 aliguori
102 3c529d93 aliguori
    idle_threads--;
103 3c529d93 aliguori
    cur_threads--;
104 3c529d93 aliguori
    pthread_mutex_unlock(&lock);
105 3c529d93 aliguori
106 3c529d93 aliguori
    return NULL;
107 3c529d93 aliguori
}
108 3c529d93 aliguori
109 3c529d93 aliguori
static int spawn_thread(void)
110 3c529d93 aliguori
{
111 3c529d93 aliguori
    pthread_attr_t attr;
112 3c529d93 aliguori
    int ret;
113 3c529d93 aliguori
114 3c529d93 aliguori
    cur_threads++;
115 3c529d93 aliguori
    idle_threads++;
116 3c529d93 aliguori
117 3c529d93 aliguori
    pthread_attr_init(&attr);
118 3c529d93 aliguori
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
119 3c529d93 aliguori
    ret = pthread_create(&thread_id, &attr, aio_thread, NULL);
120 3c529d93 aliguori
    pthread_attr_destroy(&attr);
121 3c529d93 aliguori
122 3c529d93 aliguori
    return ret;
123 3c529d93 aliguori
}
124 3c529d93 aliguori
125 3c529d93 aliguori
int qemu_paio_init(struct qemu_paioinit *aioinit)
126 3c529d93 aliguori
{
127 3c529d93 aliguori
    TAILQ_INIT(&request_list);
128 3c529d93 aliguori
129 3c529d93 aliguori
    return 0;
130 3c529d93 aliguori
}
131 3c529d93 aliguori
132 3c529d93 aliguori
static int qemu_paio_submit(struct qemu_paiocb *aiocb, int is_write)
133 3c529d93 aliguori
{
134 3c529d93 aliguori
    aiocb->is_write = is_write;
135 3c529d93 aliguori
    aiocb->ret = -EINPROGRESS;
136 3c529d93 aliguori
    aiocb->active = 0;
137 3c529d93 aliguori
    pthread_mutex_lock(&lock);
138 3c529d93 aliguori
    if (idle_threads == 0 && cur_threads < max_threads)
139 3c529d93 aliguori
        spawn_thread();
140 3c529d93 aliguori
    TAILQ_INSERT_TAIL(&request_list, aiocb, node);
141 3c529d93 aliguori
    pthread_mutex_unlock(&lock);
142 3c529d93 aliguori
    pthread_cond_broadcast(&cond);
143 3c529d93 aliguori
144 3c529d93 aliguori
    return 0;
145 3c529d93 aliguori
}
146 3c529d93 aliguori
147 3c529d93 aliguori
int qemu_paio_read(struct qemu_paiocb *aiocb)
148 3c529d93 aliguori
{
149 3c529d93 aliguori
    return qemu_paio_submit(aiocb, 0);
150 3c529d93 aliguori
}
151 3c529d93 aliguori
152 3c529d93 aliguori
int qemu_paio_write(struct qemu_paiocb *aiocb)
153 3c529d93 aliguori
{
154 3c529d93 aliguori
    return qemu_paio_submit(aiocb, 1);
155 3c529d93 aliguori
}
156 3c529d93 aliguori
157 3c529d93 aliguori
ssize_t qemu_paio_return(struct qemu_paiocb *aiocb)
158 3c529d93 aliguori
{
159 3c529d93 aliguori
    ssize_t ret;
160 3c529d93 aliguori
161 3c529d93 aliguori
    pthread_mutex_lock(&lock);
162 3c529d93 aliguori
    ret = aiocb->ret;
163 3c529d93 aliguori
    pthread_mutex_unlock(&lock);
164 3c529d93 aliguori
165 3c529d93 aliguori
    return ret;
166 3c529d93 aliguori
}
167 3c529d93 aliguori
168 3c529d93 aliguori
int qemu_paio_error(struct qemu_paiocb *aiocb)
169 3c529d93 aliguori
{
170 3c529d93 aliguori
    ssize_t ret = qemu_paio_return(aiocb);
171 3c529d93 aliguori
172 3c529d93 aliguori
    if (ret < 0)
173 3c529d93 aliguori
        ret = -ret;
174 3c529d93 aliguori
    else
175 3c529d93 aliguori
        ret = 0;
176 3c529d93 aliguori
177 3c529d93 aliguori
    return ret;
178 3c529d93 aliguori
}
179 3c529d93 aliguori
180 3c529d93 aliguori
int qemu_paio_cancel(int fd, struct qemu_paiocb *aiocb)
181 3c529d93 aliguori
{
182 3c529d93 aliguori
    int ret;
183 3c529d93 aliguori
184 3c529d93 aliguori
    pthread_mutex_lock(&lock);
185 3c529d93 aliguori
    if (!aiocb->active) {
186 3c529d93 aliguori
        TAILQ_REMOVE(&request_list, aiocb, node);
187 3c529d93 aliguori
        aiocb->ret = -ECANCELED;
188 3c529d93 aliguori
        ret = QEMU_PAIO_CANCELED;
189 3c529d93 aliguori
    } else if (aiocb->ret == -EINPROGRESS)
190 3c529d93 aliguori
        ret = QEMU_PAIO_NOTCANCELED;
191 3c529d93 aliguori
    else
192 3c529d93 aliguori
        ret = QEMU_PAIO_ALLDONE;
193 3c529d93 aliguori
    pthread_mutex_unlock(&lock);
194 3c529d93 aliguori
195 3c529d93 aliguori
    return ret;
196 3c529d93 aliguori
}