Add write barriers
[fio.git] / engines / solarisaio.c
index ab27b55..dfaa375 100644 (file)
@@ -5,6 +5,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
+#include <signal.h>
 #include <errno.h>
 
 #include "../fio.h"
@@ -15,7 +16,9 @@
 
 struct solarisaio_data {
        struct io_u **aio_events;
+       unsigned int aio_pending;
        unsigned int nr;
+       unsigned int max_depth;
 };
 
 static int fio_solarisaio_cancel(struct thread_data fio_unused *td,
@@ -27,47 +30,79 @@ static int fio_solarisaio_cancel(struct thread_data fio_unused *td,
 static int fio_solarisaio_prep(struct thread_data fio_unused *td,
                            struct io_u *io_u)
 {
+       struct solarisaio_data *sd = td->io_ops->data;
+
        io_u->resultp.aio_return = AIO_INPROGRESS;
+       io_u->engine_data = sd;
        return 0;
 }
 
+static void wait_for_event(struct timeval *tv)
+{
+       struct solarisaio_data *sd;
+       struct io_u *io_u;
+       aio_result_t *res;
+
+       res = aiowait(tv);
+       if (res == (aio_result_t *) -1) {
+               int err = errno;
+
+               if (err != EINVAL) {
+                       log_err("fio: solarisaio got %d in aiowait\n", err);
+                       exit(err);
+               }
+               return;
+       } else if (!res)
+               return;
+
+       io_u = container_of(res, struct io_u, resultp);
+       sd = io_u->engine_data;
+
+       if (io_u->resultp.aio_return >= 0) {
+               io_u->resid = io_u->xfer_buflen - io_u->resultp.aio_return;
+               io_u->error = 0;
+       } else
+               io_u->error = io_u->resultp.aio_return;
+
+       /*
+        * For SIGIO, we need a write barrier between the two, so that
+        * the ->aio_pending store is seen after the ->aio_events store
+        */
+       sd->aio_events[sd->aio_pending] = io_u;
+       write_barrier();
+       sd->aio_pending++;
+       sd->nr--;
+}
+
+static void fio_solarisaio_sigio(int sig)
+{
+       wait_for_event(NULL);
+}
+
 static int fio_solarisaio_getevents(struct thread_data *td, unsigned int min,
                                    unsigned int max, struct timespec *t)
 {
        struct solarisaio_data *sd = td->io_ops->data;
        struct timeval tv;
-       unsigned int r;
-
-       r = 0;
-       do {
-               struct io_u *io_u;
-               aio_result_t *p;
-
-               if (!min || !t) {
-                       tv.tv_sec = 0;
-                       tv.tv_usec = 0;
-               } else {
-                       tv.tv_sec = t->tv_sec;
-                       tv.tv_usec = t->tv_nsec / 1000;
-               }
-
-               p = aiowait(&tv);
-               if (p) {
-                       io_u = container_of(p, struct io_u, resultp);
+       int ret;
 
-                       sd->aio_events[r++] = io_u;
-                       sd->nr--;
+       if (!min || !t) {
+               tv.tv_sec = 0;
+               tv.tv_usec = 0;
+       } else {
+               tv.tv_sec = t->tv_sec;
+               tv.tv_usec = t->tv_nsec / 1000;
+       }
 
-                       if (io_u->resultp.aio_return >= 0) {
-                               io_u->resid = io_u->xfer_buflen
-                                               - io_u->resultp.aio_return;
-                               io_u->error = 0;
-                       } else
-                               io_u->error = io_u->resultp.aio_return;
-               }
-       } while (r < min);
+       while (sd->aio_pending < min)
+               wait_for_event(&tv);
 
-       return r;
+       /*
+        * should be OK without locking, as int operations should be atomic
+        */
+       ret = sd->aio_pending;
+       sd->aio_pending -= ret;
+       return ret;
 }
 
 static struct io_u *fio_solarisaio_event(struct thread_data *td, int event)
@@ -96,7 +131,7 @@ static int fio_solarisaio_queue(struct thread_data fio_unused *td,
                return FIO_Q_COMPLETED;
        }
 
-       if (sd->nr == td->o.iodepth)
+       if (sd->nr == sd->max_depth)
                return FIO_Q_BUSY;
 
        off = io_u->offset;
@@ -126,13 +161,39 @@ static void fio_solarisaio_cleanup(struct thread_data *td)
        }
 }
 
+/*
+ * Set USE_SIGNAL_COMPLETIONS to use SIGIO as completion events.
+ */
+static void fio_solarisaio_init_sigio(void)
+{
+#ifdef USE_SIGNAL_COMPLETIONS
+       struct sigaction act;
+
+       memset(&act, 0, sizeof(act));
+       act.sa_handler = fio_solarisaio_sigio;
+       act.sa_flags = SA_RESTART;
+       sigaction(SIGIO, &act, NULL);
+#endif
+}
+
 static int fio_solarisaio_init(struct thread_data *td)
 {
        struct solarisaio_data *sd = malloc(sizeof(*sd));
+       unsigned int max_depth;
+
+       max_depth = td->o.iodepth;
+       if (max_depth > MAXASYNCHIO) {
+               max_depth = MAXASYNCHIO;
+               log_info("fio: lower depth to %d due to OS constraints\n",
+                                                       max_depth);
+       }
 
        memset(sd, 0, sizeof(*sd));
-       sd->aio_events = malloc(td->o.iodepth * sizeof(struct io_u *));
-       memset(sd->aio_events, 0, td->o.iodepth * sizeof(struct io_u *));
+       sd->aio_events = malloc(max_depth * sizeof(struct io_u *));
+       memset(sd->aio_events, 0, max_depth * sizeof(struct io_u *));
+       sd->max_depth = max_depth;
+
+       fio_solarisaio_init_sigio();
 
        td->io_ops->data = sd;
        return 0;