Implement DQ unit test rcudq
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Sun, 25 Aug 2013 18:22:15 +0000 (14:22 -0400)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Sun, 25 Aug 2013 18:59:30 +0000 (14:59 -0400)
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
tests/unit/Makefile.am
tests/unit/test_urcu_dq.c [new file with mode: 0644]

index 1fa8b71f047fefd2417681efdac45882d88ec46d..b394adf57a2a7181a4a56845e8bd44c806408102 100644 (file)
@@ -3,7 +3,8 @@ AM_CFLAGS=-I$(top_srcdir) -I$(top_builddir) -I$(top_srcdir)/tests/common -g
 
 noinst_PROGRAMS = test_uatomic \
        test_urcu_multiflavor \
-       test_urcu_multiflavor_dynlink
+       test_urcu_multiflavor_dynlink \
+       test_urcu_dq
 
 noinst_HEADERS = test_urcu_multiflavor.h
 
@@ -55,7 +56,11 @@ test_urcu_multiflavor_dynlink_CFLAGS = -DDYNAMIC_LINK_TEST $(AM_CFLAGS)
 test_urcu_multiflavor_dynlink_LDADD = $(URCU_LIB) $(URCU_MB_LIB) \
        $(URCU_SIGNAL_LIB) $(URCU_QSBR_LIB) $(URCU_BP_LIB)
 
+test_urcu_dq_SOURCES = test_urcu_dq.c $(COMPAT)
+test_urcu_dq_LDADD = $(URCU_LIB)
+
 check-am:
        ./test_uatomic
        ./test_urcu_multiflavor
        ./test_urcu_multiflavor_dynlink
+       ./test_urcu_dq
diff --git a/tests/unit/test_urcu_dq.c b/tests/unit/test_urcu_dq.c
new file mode 100644 (file)
index 0000000..8ef6f78
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * test_urcu_dq.c
+ *
+ * Userspace RCU library - double-ended queue unit test
+ *
+ * Copyright 2013 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <urcu.h>
+#include <urcu/rcudq.h>
+#include <urcu/compiler.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define err_printf(fmt, args...)       \
+       fprintf(stderr, "[error in %s@%d:%s()] " fmt, __FILE__, __LINE__, __func__, ## args)
+
+struct myobj {
+       int a;
+       int b;
+       struct cds_rcudq_head node;
+       struct rcu_head rcu_head;
+};
+
+static CDS_RCUDQ_HEAD(dq);
+
+static
+struct myobj *create_obj(int a, int b)
+{
+       struct myobj *obj;
+
+       obj = malloc(sizeof(*obj));
+       if (!obj)
+               return NULL;
+       obj->a = a;
+       obj->b = b;
+       CDS_INIT_RCUDQ_HEAD(&obj->node);
+       return obj;
+}
+
+static
+void poison_head(struct cds_rcudq_head *head)
+{
+       memset(head, 42, sizeof(*head));
+}
+
+static
+void print_obj(struct myobj *obj)
+{
+       printf("(%d, %d) ", obj->a, obj->b);
+}
+
+static
+void free_obj(struct rcu_head *rcu_head)
+{
+       struct myobj *obj = caa_container_of(rcu_head, struct myobj, rcu_head);
+
+       free(obj);
+}
+
+int main(int argc, char **argv)
+{
+       struct myobj *obj, *tmp;
+       struct cds_rcudq_head *pos, *p;
+       unsigned int i, j;
+
+       rcu_register_thread();
+
+       if (!cds_rcudq_empty(&dq)) {
+               err_printf("Queue is not empty as expected\n");
+               goto error;
+       }
+
+       poison_head(&dq);
+       CDS_INIT_RCUDQ_HEAD(&dq);
+       if (!cds_rcudq_empty(&dq)) {
+               err_printf("Queue is not empty as expected\n");
+               goto error;
+       }
+
+       /* Single updater */
+       for (i = 0; i < 4; i++) {
+               for (j = 0; j < 4; j++) {
+                       obj = create_obj(i, j);
+                       if (!obj)
+                               goto error;
+                       /* Add to tail */
+                       cds_rcudq_add_tail(&obj->node, &dq);
+               }
+       }
+       for (i = 42; i < 46; i++) {
+               obj = create_obj(i, i);
+               if (!obj)
+                       goto error;
+               /* Add to head */
+               cds_rcudq_add(&obj->node, &dq);
+       }
+
+       printf("cds_rcudq_first_entry()\n");
+       obj = cds_rcudq_first_entry(&dq, struct myobj, node);
+       print_obj(obj);
+       printf("\n");
+
+       printf("cds_rcudq_for_each()\n");
+       cds_rcudq_for_each(pos, &dq) {
+               obj = cds_rcudq_entry(pos, struct myobj, node);
+               print_obj(obj);
+       }
+       printf("\n");
+
+       printf("cds_rcudq_for_each_safe()\n");
+       cds_rcudq_for_each_safe(pos, p, &dq) {
+               obj = cds_rcudq_entry(pos, struct myobj, node);
+               print_obj(obj);
+               if (obj->a == 42) {
+                       printf("(removing) ");
+                       cds_rcudq_del(&obj->node);
+                       call_rcu(&obj->rcu_head, free_obj);
+               }
+       }
+       printf("\n");
+
+       printf("cds_rcudq_for_each_entry()\n");
+       cds_rcudq_for_each_entry(obj, &dq, node) {
+               print_obj(obj);
+       }
+       printf("\n");
+
+       printf("cds_rcudq_for_each_entry_safe()\n");
+       cds_rcudq_for_each_entry_safe(obj, tmp, &dq, node) {
+               print_obj(obj);
+               if (obj->a == 43) {
+                       printf("(removing) ");
+                       cds_rcudq_del(&obj->node);
+                       call_rcu(&obj->rcu_head, free_obj);
+               }
+       }
+       printf("\n");
+
+       printf("cds_rcudq_for_each_reverse()\n");
+       cds_rcudq_for_each_reverse(pos, &dq) {
+               obj = cds_rcudq_entry(pos, struct myobj, node);
+               print_obj(obj);
+       }
+       printf("\n");
+
+       printf("cds_rcudq_for_each_reverse_safe()\n");
+       cds_rcudq_for_each_reverse_safe(pos, p, &dq) {
+               obj = cds_rcudq_entry(pos, struct myobj, node);
+               print_obj(obj);
+               if (obj->a == 44) {
+                       printf("(removing) ");
+                       cds_rcudq_del(&obj->node);
+                       call_rcu(&obj->rcu_head, free_obj);
+               }
+       }
+       printf("\n");
+
+       printf("cds_rcudq_for_each_entry_reverse()\n");
+       cds_rcudq_for_each_entry_reverse(obj, &dq, node) {
+               print_obj(obj);
+       }
+       printf("\n");
+
+       printf("cds_rcudq_for_each_entry_reverse_safe()\n");
+       cds_rcudq_for_each_entry_reverse_safe(obj, tmp, &dq, node) {
+               print_obj(obj);
+               if (obj->a == 45) {
+                       printf("(removing) ");
+                       cds_rcudq_del(&obj->node);
+                       call_rcu(&obj->rcu_head, free_obj);
+               }
+       }
+       printf("\n");
+
+
+       rcu_read_lock();
+
+       printf("cds_rcudq_for_each_rcu()\n");
+       cds_rcudq_for_each_rcu(pos, &dq) {
+               obj = cds_rcudq_entry(pos, struct myobj, node);
+               print_obj(obj);
+       }
+       printf("\n");
+
+       printf("cds_rcudq_for_each_entry_rcu()\n");
+       cds_rcudq_for_each_entry_rcu(obj, &dq, node) {
+               print_obj(obj);
+       }
+       printf("\n");
+
+       printf("cds_rcudq_for_each_reverse_rcu()\n");
+       cds_rcudq_for_each_reverse_rcu(pos, &dq) {
+               obj = cds_rcudq_entry(pos, struct myobj, node);
+               print_obj(obj);
+       }
+       printf("\n");
+
+       printf("cds_rcudq_for_each_entry_reverse_rcu()\n");
+       cds_rcudq_for_each_entry_reverse_rcu(obj, &dq, node) {
+               print_obj(obj);
+       }
+       printf("\n");
+
+       rcu_read_unlock();
+
+       cds_rcudq_for_each_entry_safe(obj, tmp, &dq, node) {
+               cds_rcudq_del(&obj->node);
+               call_rcu(&obj->rcu_head, free_obj);
+       }
+
+       if (!cds_rcudq_empty(&dq)) {
+               err_printf("Queue is not empty as expected\n");
+               goto error;
+       }
+
+       /* Free memory (in flight call_rcu callback execution) before exiting */
+       rcu_barrier();
+
+       rcu_unregister_thread();
+
+       exit(EXIT_SUCCESS);
+
+error:
+       exit(EXIT_FAILURE);
+}
This page took 0.028774 seconds and 4 git commands to generate.