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