]> source.dussan.org Git - rspamd.git/commitdiff
Fix asynchronous IO API.
authorVsevolod Stakhov <vsevolod@rambler-co.ru>
Thu, 1 Mar 2012 17:57:09 +0000 (21:57 +0400)
committerVsevolod Stakhov <vsevolod@rambler-co.ru>
Thu, 1 Mar 2012 17:57:09 +0000 (21:57 +0400)
Write test case for aio.

src/aio_event.c
src/aio_event.h
test/CMakeLists.txt
test/rspamd_async_test.c [new file with mode: 0644]
test/rspamd_dns_test.c
test/rspamd_test_suite.c
test/tests.h

index 465ce4c79278d232340359bba15c0f8fc4260187..9bd952e1f03e2905ef437a8b550a2aa14e06e1a4 100644 (file)
@@ -35,6 +35,7 @@
 #define MAX_AIO_EV        32768
 
 struct io_cbdata {
+       gint fd;
        rspamd_aio_cb cb;
        gsize len;
        gpointer buf;
@@ -58,33 +59,53 @@ typedef enum io_iocb_cmd {
        IO_CMD_NOOP = 6,
 } io_iocb_cmd_t;
 
-struct io_iocb_common {
-       void *buf;
-       unsigned __pad1;
-       long nbytes;
-       unsigned __pad2;
-       long long offset;
-       long long __pad3;
-    unsigned flags;
-    unsigned resfd;
-}; /* result code is the amount read or -'ve errno */
+#if defined(__LITTLE_ENDIAN)
+#define PADDED(x,y)     x, y
+#elif defined(__BIG_ENDIAN)
+#define PADDED(x,y)     y, x
+#else
+#error edit for your odd byteorder.
+#endif
+
+/*
+ * we always use a 64bit off_t when communicating
+ * with userland.  its up to libraries to do the
+ * proper padding and aio_error abstraction
+ */
 
 struct iocb {
-       void *data;
-       unsigned key;
-       short aio_lio_opcode;
-       short aio_reqprio;
-       int aio_fildes;
-       union {
-               struct io_iocb_common c;
-       } u;
+       /* these are internal to the kernel/libc. */
+       guint64 aio_data; /* data to be returned in event's data */
+       guint32 PADDED(aio_key, aio_reserved1);
+       /* the kernel sets aio_key to the req # */
+
+       /* common fields */
+       guint16 aio_lio_opcode; /* see IOCB_CMD_ above */
+       gint16 aio_reqprio;
+       guint32 aio_fildes;
+
+       guint64 aio_buf;
+       guint64 aio_nbytes;
+       guint64 aio_offset;
+
+       /* extra parameters */
+       guint64 aio_reserved2; /* TODO: use this for a (struct sigevent *) */
+
+       /* flags for the "struct iocb" */
+       guint32 aio_flags;
+
+       /*
+        * if the IOCB_FLAG_RESFD flag of "aio_flags" is set, this is an
+        * eventfd to signal AIO readiness to
+        */
+       guint32 aio_resfd;
 };
 
 struct io_event {
-       uint64_t  data;  /* the data field from the iocb */
-       uint64_t  obj;   /* what iocb this event came from */
-       int64_t   res;   /* result code for this event */
-       int64_t   res2;  /* secondary result */
+       guint64  data;  /* the data field from the iocb */
+       guint64  obj;   /* what iocb this event came from */
+       gint64   res;   /* result code for this event */
+       gint64   res2;  /* secondary result */
 };
 
 /* Linux specific io calls */
@@ -178,7 +199,7 @@ rspamd_eventfdcb (gint fd, gshort what, gpointer ud)
                        for (i = 0; i < done; i ++) {
                                ev_data = (struct io_cbdata *) (uintptr_t) event[i].data;
                                /* Call this callback */
-                               ev_data->cb (event[i].res, ev_data->len, ev_data->buf, ev_data->ud);
+                               ev_data->cb (ev_data->fd, event[i].res, ev_data->len, ev_data->buf, ev_data->ud);
                        }
                }
                else if (done == 0) {
@@ -221,6 +242,7 @@ rspamd_aio_init (struct event_base *base)
                else {
                        event_set (&new->eventfd_ev, new->event_fd, EV_READ|EV_PERSIST, rspamd_eventfdcb, new);
                        event_base_set (new->base, &new->eventfd_ev);
+                       event_add (&new->eventfd_ev, NULL);
                        if (io_setup (MAX_AIO_EV, &new->io_ctx) == -1) {
                                msg_err ("io_setup failed: %s", strerror (errno));
                                close (new->event_fd);
@@ -278,18 +300,19 @@ rspamd_aio_read (gint fd, gpointer buf, gsize len, struct aio_context *ctx, rspa
                cbdata->buf = buf;
                cbdata->len = len;
                cbdata->ud = ud;
+               cbdata->fd = fd;
 
                iocb[0] = alloca (sizeof (struct iocb));
                memset (iocb[0], 0, sizeof (struct iocb));
                iocb[0]->aio_fildes = fd;
                iocb[0]->aio_lio_opcode = IO_CMD_PREAD;
                iocb[0]->aio_reqprio = 0;
-               iocb[0]->u.c.buf = buf;
-               iocb[0]->u.c.nbytes = len;
-               iocb[0]->u.c.offset = 0;
-               iocb[0]->u.c.flags |= (1 << 0) /* IOCB_FLAG_RESFD */;
-               iocb[0]->u.c.resfd = ctx->event_fd;
-               iocb[0]->data = cbdata;
+               iocb[0]->aio_buf = (guint64)((uintptr_t)buf);
+               iocb[0]->aio_nbytes = len;
+               iocb[0]->aio_offset = 0;
+               iocb[0]->aio_flags |= (1 << 0) /* IOCB_FLAG_RESFD */;
+               iocb[0]->aio_resfd = ctx->event_fd;
+               iocb[0]->aio_data = (guint64)((uintptr_t)cbdata);
 
                /* Iocb is copied to kernel internally, so it is safe to put it on stack */
                if (io_submit (ctx->io_ctx, 1, iocb) == 1) {
@@ -311,10 +334,10 @@ rspamd_aio_read (gint fd, gpointer buf, gsize len, struct aio_context *ctx, rspa
 blocking:
                r = read (fd, buf, len);
                if (r >= 0) {
-                       cb (0, r, buf, ud);
+                       cb (fd, 0, r, buf, ud);
                }
                else {
-                       cb (r, -1, buf, ud);
+                       cb (fd, r, -1, buf, ud);
                }
        }
 
@@ -339,18 +362,19 @@ rspamd_aio_write (gint fd, gpointer buf, gsize len, struct aio_context *ctx, rsp
                cbdata->buf = buf;
                cbdata->len = len;
                cbdata->ud = ud;
+               cbdata->fd = fd;
 
                iocb[0] = alloca (sizeof (struct iocb));
                memset (iocb[0], 0, sizeof (struct iocb));
                iocb[0]->aio_fildes = fd;
                iocb[0]->aio_lio_opcode = IO_CMD_PWRITE;
                iocb[0]->aio_reqprio = 0;
-               iocb[0]->u.c.buf = buf;
-               iocb[0]->u.c.nbytes = len;
-               iocb[0]->u.c.offset = 0;
-               iocb[0]->u.c.flags |= (1 << 0) /* IOCB_FLAG_RESFD */;
-               iocb[0]->u.c.resfd = ctx->event_fd;
-               iocb[0]->data = cbdata;
+               iocb[0]->aio_buf = (guint64)((uintptr_t)buf);
+               iocb[0]->aio_nbytes = len;
+               iocb[0]->aio_offset = 0;
+               iocb[0]->aio_flags |= (1 << 0) /* IOCB_FLAG_RESFD */;
+               iocb[0]->aio_resfd = ctx->event_fd;
+               iocb[0]->aio_data = (guint64)((uintptr_t)cbdata);
 
                /* Iocb is copied to kernel internally, so it is safe to put it on stack */
                if (io_submit (ctx->io_ctx, 1, iocb) == 1) {
@@ -372,10 +396,10 @@ rspamd_aio_write (gint fd, gpointer buf, gsize len, struct aio_context *ctx, rsp
 blocking:
                r = write (fd, buf, len);
                if (r >= 0) {
-                       cb (0, r, buf, ud);
+                       cb (fd, 0, r, buf, ud);
                }
                else {
-                       cb (r, -1, buf, ud);
+                       cb (fd, r, -1, buf, ud);
                }
        }
 
index 3149174b9337e74011ec97c7cc6d1069a087b0bd..7350d102e74f9ccfb0286197e176c0518e58cb6f 100644 (file)
@@ -35,7 +35,7 @@ struct aio_context;
 /**
  * Callback for notifying
  */
-typedef void (*rspamd_aio_cb) (gint res, gsize len, gpointer data, gpointer ud);
+typedef void (*rspamd_aio_cb) (gint fd, gint res, gsize len, gpointer data, gpointer ud);
 
 /**
  * Initialize aio with specified event base
index c15f77b753f54827b25bc585f4ec23b1ce8bf31b..f63f6402b7d2df4991166359acd2b3881d991d02 100644 (file)
@@ -5,7 +5,8 @@ SET(TESTSRC             rspamd_expression_test.c
                                rspamd_fuzzy_test.c
                                rspamd_test_suite.c
                                rspamd_url_test.c
-                               rspamd_dns_test.c)
+                               rspamd_dns_test.c
+                               rspamd_async_test.c)
 
 ADD_EXECUTABLE(rspamd-test EXCLUDE_FROM_ALL ${TESTSRC})
 SET_TARGET_PROPERTIES(rspamd-test PROPERTIES LINKER_LANGUAGE C)
diff --git a/test/rspamd_async_test.c b/test/rspamd_async_test.c
new file mode 100644 (file)
index 0000000..f2c6e64
--- /dev/null
@@ -0,0 +1,87 @@
+/* Copyright (c) 2011, Vsevolod Stakhov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *       * Redistributions of source code must retain the above copyright
+ *         notice, this list of conditions and the following disclaimer.
+ *       * Redistributions in binary form must reproduce the above copyright
+ *         notice, this list of conditions and the following disclaimer in the
+ *         documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "tests.h"
+#include "main.h"
+#include "aio_event.h"
+
+
+extern struct event_base *base;
+
+static void
+aio_read_cb (gint fd, gint res, gsize len, gpointer data, gpointer ud)
+{
+       guchar *p = data;
+       guint i;
+
+       g_assert (res != -1);
+
+       g_assert (len == BUFSIZ);
+       for (i = 0; i < len; i ++) {
+               g_assert (p[i] == 0xef);
+       }
+
+       event_base_loopbreak (base);
+}
+
+static void
+aio_write_cb (gint fd, gint res, gsize len, gpointer data, gpointer ud)
+{
+       struct aio_context *aio_ctx = ud;
+       static gchar testbuf[BUFSIZ];
+
+       g_assert (res != -1);
+
+       g_assert (rspamd_aio_read (fd, testbuf, sizeof (testbuf), aio_ctx, aio_read_cb, aio_ctx) != -1);
+}
+
+void
+rspamd_async_test_func ()
+{
+       struct aio_context *aio_ctx;
+       gchar *tmpfile;
+       static gchar testbuf[BUFSIZ];
+       gint fd, afd, ret;
+
+       aio_ctx = rspamd_aio_init (base);
+
+       g_assert (aio_ctx != NULL);
+
+       fd = g_file_open_tmp ("raXXXXXX", &tmpfile, NULL);
+       g_assert (fd != -1);
+
+       afd = rspamd_aio_open (aio_ctx, tmpfile, O_RDWR);
+       g_assert (fd != -1);
+
+       /* Write some data */
+       memset (testbuf, 0xef, sizeof (testbuf));
+       ret = rspamd_aio_write (afd, testbuf, sizeof (testbuf), aio_ctx, aio_write_cb, aio_ctx);
+       g_assert (ret != -1);
+
+       event_base_loop (base, 0);
+
+       close (afd);
+       close (fd);
+       unlink (tmpfile);
+}
index 839c00a79ea9472fdc6548fd3d5f586a1dc36c92..9fa1d490164587e24fd4c690b7db1592fe6003c8 100644 (file)
@@ -69,6 +69,7 @@ rspamd_dns_test_func ()
        struct config_file *cfg;
        memory_pool_t *pool;
        struct rspamd_async_session *s;
+       struct in_addr ina;
 
        cfg = (struct config_file *)g_malloc (sizeof (struct config_file));
        bzero (cfg, sizeof (struct config_file));
@@ -78,15 +79,16 @@ rspamd_dns_test_func ()
 
        pool = memory_pool_new (memory_pool_get_size ());
 
-       event_init ();
        s = new_async_session (pool, session_fin, NULL, NULL, NULL);
 
        resolver = dns_resolver_init (base, cfg);
 
+       ina.s_addr = inet_addr ("81.19.70.3");
+
        requests ++;
        g_assert (make_dns_request (resolver, s, pool, test_dns_cb, NULL, DNS_REQUEST_A, "google.com"));
        requests ++;
-       g_assert (make_dns_request (resolver, s, pool, test_dns_cb, NULL, DNS_REQUEST_PTR, inet_addr ("81.19.70.3")));
+       g_assert (make_dns_request (resolver, s, pool, test_dns_cb, NULL, DNS_REQUEST_PTR, &ina));
        requests ++;
        g_assert (make_dns_request (resolver, s, pool, test_dns_cb, NULL, DNS_REQUEST_MX, "rambler.ru"));
        requests ++;
index f035fcb8181cdc2eed01d6c6b4666c04d6a37658..c23f6fca201bf5db4d55ae5c42fb06b93884a23c 100644 (file)
@@ -63,6 +63,7 @@ main (int argc, char **argv)
        g_test_add_func ("/rspamd/expression", rspamd_expression_test_func);
        g_test_add_func ("/rspamd/statfile", rspamd_statfile_test_func);
        g_test_add_func ("/rspamd/dns", rspamd_dns_test_func);
+       g_test_add_func ("/rspamd/aio", rspamd_async_test_func);
 
        g_test_run ();
 
index ee05c903d849e0303277d74fb0439835c37fb2ef..be2c29fcadc2a0fb2772625ef50e4b96a1e24dc5 100644 (file)
@@ -26,4 +26,7 @@ void rspamd_statfile_test_func ();
 /* DNS resolving */
 void rspamd_dns_test_func ();
 
+/* Async IO */
+void rspamd_async_test_func ();
+
 #endif