-liburcu.so
-test_rwlock_timing
-test_urcu
-test_urcu_dynamic_link
-test_urcu_timing
-test_urcu_yield
-urcu-asm.o
-urcu-asm.S
-urcu.o
-urcutorture
-urcutorture-yield
-urcu-yield.o
-tests/api.h
urcu/arch.h
urcu/uatomic.h
-liburcu-defer.so
-liburcu-mb.so
-liburcu-qsbr.so
-urcu-defer.o
-urcu-mb.o
-urcu-qsbr.o
+tests/api.h
+
+tests/urcutorture
+tests/urcutorture-yield
+tests/urcu-asm.S
+tests/test_rwlock_timing
+tests/test_urcu
+tests/test_urcu_dynamic_link
+tests/test_urcu_timing
+tests/test_urcu_yield
tests/test_looplen
tests/test_mutex
tests/test_perthreadlock
tests/test_urcu_wfq_dynlink
tests/test_urcu_wfs
tests/test_urcu_wfs_dynlink
+tests/test_urcu_fork
+tests/test_urcu_ja
+tests/test_urcu_ja_range
+tests/test_urcu_lfs_rcu
+tests/test_urcu_lfs_rcu_dynlink
+tests/test_urcu_multiflavor
+tests/test_urcu_multiflavor_dynlink
+tests/test_urcu_wfcq
+tests/test_urcu_wfcq_dynlink
tests/*.log
+*.so
+
+doc/examples/urcu-flavors/qsbr
+doc/examples/urcu-flavors/mb
+doc/examples/urcu-flavors/membarrier
+doc/examples/urcu-flavors/signal
+doc/examples/urcu-flavors/bp
+
+doc/examples/list/cds_list_add_rcu
+doc/examples/list/cds_list_add_tail_rcu
+doc/examples/list/cds_list_del_rcu
+doc/examples/list/cds_list_for_each_rcu
+doc/examples/list/cds_list_for_each_entry_rcu
+doc/examples/list/cds_list_replace_rcu
+
+doc/examples/hlist/cds_hlist_add_head_rcu
+doc/examples/hlist/cds_hlist_del_rcu
+doc/examples/hlist/cds_hlist_for_each_rcu
+doc/examples/hlist/cds_hlist_for_each_entry_rcu
+
+doc/examples/wfcqueue/cds_wfcq_enqueue
+doc/examples/wfcqueue/cds_wfcq_dequeue
+doc/examples/wfcqueue/cds_wfcq_splice
+
+doc/examples/rculfqueue/cds_lfq_enqueue
+doc/examples/rculfqueue/cds_lfq_dequeue
+
+doc/examples/wfstack/cds_wfs_push
+doc/examples/wfstack/cds_wfs_pop
+doc/examples/wfstack/cds_wfs_pop_all_blocking
+
+doc/examples/lfstack/cds_lfs_push
+doc/examples/lfstack/cds_lfs_pop_blocking
+doc/examples/lfstack/cds_lfs_pop_all_blocking
+
+doc/examples/rculfhash/cds_lfht_add
+doc/examples/rculfhash/cds_lfht_add_unique
+doc/examples/rculfhash/cds_lfht_add_replace
+doc/examples/rculfhash/cds_lfht_del
+doc/examples/rculfhash/cds_lfht_destroy
+doc/examples/rculfhash/cds_lfht_lookup
+doc/examples/rculfhash/cds_lfht_for_each_entry_duplicate
#automake
/config.h
AM_CONDITIONAL([COMPAT_FUTEX], [test "x$compat_futex_test" = "x1"])
AM_CONDITIONAL([COMPAT_ARCH], [test "x$SUBARCHTYPE" = "xx86compat"])
+AM_CONDITIONAL([NO_SHARED], [test "x$enable_shared" = "xno"])
# smp-support configure option
AC_ARG_ENABLE([smp-support],
-SUBDIRS = qsbr-minimal
-
doc_examplesdir = ${docdir}/examples
-doc_examples_qsbr_minimaldir = ${doc_examplesdir}/qsbr-minimal
+doc_examples_urcu_flavorsdir = ${doc_examplesdir}/urcu-flavors
+
+dist_doc_examples_urcu_flavors_DATA = \
+ urcu-flavors/Makefile \
+ urcu-flavors/Makefile.qsbr \
+ urcu-flavors/Makefile.mb \
+ urcu-flavors/Makefile.membarrier \
+ urcu-flavors/Makefile.signal \
+ urcu-flavors/Makefile.bp \
+ urcu-flavors/qsbr.c \
+ urcu-flavors/mb.c \
+ urcu-flavors/membarrier.c \
+ urcu-flavors/signal.c \
+ urcu-flavors/bp.c
+
+dist_doc_examples_DATA = \
+ dist-files/Makefile \
+ Makefile.examples.template
+
+doc_examples_listdir = ${doc_examplesdir}/list
+
+dist_doc_examples_list_DATA = \
+ list/Makefile \
+ list/Makefile.cds_list_add_rcu \
+ list/Makefile.cds_list_add_tail_rcu \
+ list/Makefile.cds_list_del_rcu \
+ list/Makefile.cds_list_for_each_rcu \
+ list/Makefile.cds_list_for_each_entry_rcu \
+ list/Makefile.cds_list_replace_rcu \
+ list/cds_list_add_rcu.c \
+ list/cds_list_add_tail_rcu.c \
+ list/cds_list_del_rcu.c \
+ list/cds_list_for_each_rcu.c \
+ list/cds_list_for_each_entry_rcu.c \
+ list/cds_list_replace_rcu.c
+
+doc_examples_hlistdir = ${doc_examplesdir}/hlist
+
+dist_doc_examples_hlist_DATA = \
+ hlist/Makefile \
+ hlist/Makefile.cds_hlist_add_head_rcu \
+ hlist/Makefile.cds_hlist_del_rcu \
+ hlist/Makefile.cds_hlist_for_each_rcu \
+ hlist/Makefile.cds_hlist_for_each_entry_rcu \
+ hlist/cds_hlist_add_head_rcu.c \
+ hlist/cds_hlist_del_rcu.c \
+ hlist/cds_hlist_for_each_rcu.c \
+ hlist/cds_hlist_for_each_entry_rcu.c
+
+doc_examples_wfcqueuedir = ${doc_examplesdir}/wfcqueue
+
+dist_doc_examples_wfcqueue_DATA = \
+ wfcqueue/Makefile \
+ wfcqueue/Makefile.cds_wfcq_enqueue \
+ wfcqueue/Makefile.cds_wfcq_dequeue \
+ wfcqueue/Makefile.cds_wfcq_splice \
+ wfcqueue/cds_wfcq_enqueue.c \
+ wfcqueue/cds_wfcq_dequeue.c \
+ wfcqueue/cds_wfcq_splice.c
+
+doc_examples_wfstackdir = ${doc_examplesdir}/wfstack
+
+dist_doc_examples_wfstack_DATA = \
+ wfstack/Makefile \
+ wfstack/Makefile.cds_wfs_push \
+ wfstack/Makefile.cds_wfs_pop \
+ wfstack/Makefile.cds_wfs_pop_all_blocking \
+ wfstack/cds_wfs_push.c \
+ wfstack/cds_wfs_pop.c \
+ wfstack/cds_wfs_pop_all_blocking.c
+
+doc_examples_lfstackdir = ${doc_examplesdir}/lfstack
+
+dist_doc_examples_lfstack_DATA = \
+ lfstack/Makefile \
+ lfstack/Makefile.cds_lfs_push \
+ lfstack/Makefile.cds_lfs_pop_blocking \
+ lfstack/Makefile.cds_lfs_pop_all_blocking \
+ lfstack/cds_lfs_push.c \
+ lfstack/cds_lfs_pop_blocking.c \
+ lfstack/cds_lfs_pop_all_blocking.c
+
+doc_examples_rculfqueuedir = ${doc_examplesdir}/rculfqueue
+
+dist_doc_examples_rculfqueue_DATA = \
+ rculfqueue/Makefile \
+ rculfqueue/Makefile.cds_lfq_enqueue \
+ rculfqueue/Makefile.cds_lfq_dequeue \
+ rculfqueue/cds_lfq_enqueue.c \
+ rculfqueue/cds_lfq_dequeue.c
+
+doc_examples_rculfhashdir = ${doc_examplesdir}/rculfhash
+
+dist_doc_examples_rculfhash_DATA = \
+ rculfhash/Makefile \
+ rculfhash/jhash.h \
+ rculfhash/Makefile.cds_lfht_add \
+ rculfhash/Makefile.cds_lfht_add_unique \
+ rculfhash/Makefile.cds_lfht_add_replace \
+ rculfhash/Makefile.cds_lfht_del \
+ rculfhash/Makefile.cds_lfht_destroy \
+ rculfhash/Makefile.cds_lfht_lookup \
+ rculfhash/Makefile.cds_lfht_for_each_entry_duplicate \
+ rculfhash/cds_lfht_add.c \
+ rculfhash/cds_lfht_add_unique.c \
+ rculfhash/cds_lfht_add_replace.c \
+ rculfhash/cds_lfht_del.c \
+ rculfhash/cds_lfht_destroy.c \
+ rculfhash/cds_lfht_lookup.c \
+ rculfhash/cds_lfht_for_each_entry_duplicate.c
-doc_examples_qsbr_minimal_DATA = \
- qsbr-minimal/Makefile \
- qsbr-minimal/qsbr-minimal.c
+if NO_SHARED
+# Don't build examples if shared libraries support was explicitly
+# disabled.
+else
+all-local:
+ $(MAKE) -f dist-files/Makefile AM_CPPFLAGS="-I../../../urcu/ -I../../../" AM_LDFLAGS='-L../../../.libs/ -Wl,-rpath="$(PWD)/../../.libs/"' $(AM_MAKEFLAGS) all
-BUILD_EXAMPLES_FROM_TREE = 1
-export
+clean-local:
+ $(MAKE) -f dist-files/Makefile $(AM_MAKEFLAGS) clean;
+endif
--- /dev/null
+# Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+#
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+#
+# Permission is hereby granted to use or copy this program for any
+# purpose, provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is
+# granted, provided the above notices are retained, and a notice that
+# the code was modified is included with the above copyright notice.
+#
+# This makefile is purposefully kept simple to support GNU and BSD make.
+
+CC = gcc
+CFLAGS = -g -O2 -Wall
+
+all: $(BINARY)
+
+$(BINARY): $(OBJECTS)
+ $(CC) $(CFLAGS) $(LDFLAGS) $(AM_CFLAGS) $(AM_LDFLAGS) \
+ $(LIBS) -o $@ $(OBJECTS)
+
+$(OBJECTS): $(SOURCES) $(DEPS)
+ $(CC) $(CPPFLAGS) $(CFLAGS) $(AM_CPPFLAGS) $(AM_CFLAGS) \
+ -c -o $@ $(SOURCES)
+
+.PHONY: clean
+clean:
+ rm -f *.o $(BINARY)
--- /dev/null
+# Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+#
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+#
+# Permission is hereby granted to use or copy this program for any
+# purpose, provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is
+# granted, provided the above notices are retained, and a notice that
+# the code was modified is included with the above copyright notice.
+#
+# This makefile is purposefully kept simple to support GNU and BSD make.
+
+all:
+ $(MAKE) -C hlist
+ $(MAKE) -C list
+ $(MAKE) -C urcu-flavors
+ $(MAKE) -C wfcqueue
+ $(MAKE) -C rculfqueue
+ $(MAKE) -C wfstack
+ $(MAKE) -C lfstack
+ $(MAKE) -C rculfhash
+
+.PHONY: clean
+clean:
+ $(MAKE) -C hlist clean
+ $(MAKE) -C list clean
+ $(MAKE) -C urcu-flavors clean
+ $(MAKE) -C wfcqueue clean
+ $(MAKE) -C rculfqueue clean
+ $(MAKE) -C wfstack clean
+ $(MAKE) -C lfstack clean
+ $(MAKE) -C rculfhash clean
--- /dev/null
+# Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+#
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+#
+# Permission is hereby granted to use or copy this program for any
+# purpose, provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is
+# granted, provided the above notices are retained, and a notice that
+# the code was modified is included with the above copyright notice.
+#
+# This makefile is purposefully kept simple to support GNU and BSD make.
+
+all:
+ $(MAKE) -f Makefile.cds_hlist_add_head_rcu
+ $(MAKE) -f Makefile.cds_hlist_del_rcu
+ $(MAKE) -f Makefile.cds_hlist_for_each_rcu
+ $(MAKE) -f Makefile.cds_hlist_for_each_entry_rcu
+
+.PHONY: clean
+clean:
+ $(MAKE) -f Makefile.cds_hlist_add_head_rcu clean
+ $(MAKE) -f Makefile.cds_hlist_del_rcu clean
+ $(MAKE) -f Makefile.cds_hlist_for_each_rcu clean
+ $(MAKE) -f Makefile.cds_hlist_for_each_entry_rcu clean
--- /dev/null
+# Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+#
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+#
+# Permission is hereby granted to use or copy this program for any
+# purpose, provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is
+# granted, provided the above notices are retained, and a notice that
+# the code was modified is included with the above copyright notice.
+#
+# This makefile is purposefully kept simple to support GNU and BSD make.
+
+EXAMPLE_NAME = cds_hlist_add_head_rcu
+
+SOURCES = $(EXAMPLE_NAME).c
+OBJECTS = $(EXAMPLE_NAME).o
+BINARY = $(EXAMPLE_NAME)
+LIBS = -lurcu
+
+include ../Makefile.examples.template
--- /dev/null
+# Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+#
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+#
+# Permission is hereby granted to use or copy this program for any
+# purpose, provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is
+# granted, provided the above notices are retained, and a notice that
+# the code was modified is included with the above copyright notice.
+#
+# This makefile is purposefully kept simple to support GNU and BSD make.
+
+EXAMPLE_NAME = cds_hlist_del_rcu
+
+SOURCES = $(EXAMPLE_NAME).c
+OBJECTS = $(EXAMPLE_NAME).o
+BINARY = $(EXAMPLE_NAME)
+LIBS = -lurcu
+
+include ../Makefile.examples.template
--- /dev/null
+# Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+#
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+#
+# Permission is hereby granted to use or copy this program for any
+# purpose, provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is
+# granted, provided the above notices are retained, and a notice that
+# the code was modified is included with the above copyright notice.
+#
+# This makefile is purposefully kept simple to support GNU and BSD make.
+
+EXAMPLE_NAME = cds_hlist_for_each_entry_rcu
+
+SOURCES = $(EXAMPLE_NAME).c
+OBJECTS = $(EXAMPLE_NAME).o
+BINARY = $(EXAMPLE_NAME)
+LIBS = -lurcu
+
+include ../Makefile.examples.template
--- /dev/null
+# Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+#
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+#
+# Permission is hereby granted to use or copy this program for any
+# purpose, provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is
+# granted, provided the above notices are retained, and a notice that
+# the code was modified is included with the above copyright notice.
+#
+# This makefile is purposefully kept simple to support GNU and BSD make.
+
+EXAMPLE_NAME = cds_hlist_for_each_rcu
+
+SOURCES = $(EXAMPLE_NAME).c
+OBJECTS = $(EXAMPLE_NAME).o
+BINARY = $(EXAMPLE_NAME)
+LIBS = -lurcu
+
+include ../Makefile.examples.template
--- /dev/null
+/*
+ * Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program for any
+ * purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is
+ * granted, provided the above notices are retained, and a notice that
+ * the code was modified is included with the above copyright notice.
+ *
+ * This example shows how to add into a non-circular linked-list safely
+ * against concurrent RCU traversals.
+ */
+
+#include <stdio.h>
+
+#include <urcu.h> /* Userspace RCU flavor */
+#include <urcu/rcuhlist.h> /* RCU hlist */
+#include <urcu/compiler.h> /* For CAA_ARRAY_SIZE */
+
+/*
+ * Nodes populated into the list.
+ */
+struct mynode {
+ int value; /* Node content */
+ struct cds_hlist_node node; /* Linked-list chaining */
+};
+
+int main(int argc, char **argv)
+{
+ int values[] = { -5, 42, 36, 24, };
+ CDS_HLIST_HEAD(mylist); /* Defines an empty hlist head */
+ unsigned int i;
+ int ret = 0;
+ struct mynode *node;
+
+ /*
+ * Adding nodes to the linked-list. Safe against concurrent
+ * RCU traversals, require mutual exclusion with list updates.
+ */
+ for (i = 0; i < CAA_ARRAY_SIZE(values); i++) {
+ node = malloc(sizeof(*node));
+ if (!node) {
+ ret = -1;
+ goto end;
+ }
+ node->value = values[i];
+ cds_hlist_add_head_rcu(&node->node, &mylist);
+ }
+
+ /*
+ * Just show the list content. This is _not_ an RCU-safe
+ * iteration on the list.
+ */
+ printf("mylist content:");
+ cds_hlist_for_each_entry_2(node, &mylist, node) {
+ printf(" %d", node->value);
+ }
+ printf("\n");
+end:
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program for any
+ * purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is
+ * granted, provided the above notices are retained, and a notice that
+ * the code was modified is included with the above copyright notice.
+ *
+ * This example shows how to remove from a non-circular linked-list
+ * safely against concurrent RCU traversals.
+ */
+
+#include <stdio.h>
+
+#include <urcu.h> /* Userspace RCU flavor */
+#include <urcu/rcuhlist.h> /* RCU hlist */
+#include <urcu/compiler.h> /* For CAA_ARRAY_SIZE */
+
+/*
+ * Nodes populated into the list.
+ */
+struct mynode {
+ int value; /* Node content */
+ struct cds_hlist_node node; /* Linked-list chaining */
+ struct rcu_head rcu_head; /* For call_rcu() */
+};
+
+static
+void free_node_rcu(struct rcu_head *head)
+{
+ struct mynode *node = caa_container_of(head, struct mynode, rcu_head);
+
+ free(node);
+}
+
+int main(int argc, char **argv)
+{
+ int values[] = { -5, 42, 36, 24, };
+ CDS_HLIST_HEAD(mylist); /* Defines an empty hlist head */
+ unsigned int i;
+ int ret = 0;
+ struct mynode *node, *n;
+
+ /*
+ * Adding nodes to the linked-list. Safe against concurrent
+ * RCU traversals, require mutual exclusion with list updates.
+ */
+ for (i = 0; i < CAA_ARRAY_SIZE(values); i++) {
+ node = malloc(sizeof(*node));
+ if (!node) {
+ ret = -1;
+ goto end;
+ }
+ node->value = values[i];
+ cds_hlist_add_head_rcu(&node->node, &mylist);
+ }
+
+ /*
+ * Removing all positive values. Safe against concurrent RCU
+ * traversals, require mutual exclusion with list updates.
+ * Notice the "safe" iteration: it is safe against removal of
+ * nodes as we iterate on the list.
+ */
+ cds_hlist_for_each_entry_safe_2(node, n, &mylist, node) {
+ if (node->value > 0) {
+ cds_hlist_del_rcu(&node->node);
+ /*
+ * We can only reclaim memory after a grace
+ * period has passed after cds_hlist_del_rcu().
+ */
+ call_rcu(&node->rcu_head, free_node_rcu);
+ }
+ }
+
+ /*
+ * Just show the list content. This is _not_ an RCU-safe
+ * iteration on the list.
+ */
+ printf("mylist content:");
+ cds_hlist_for_each_entry_2(node, &mylist, node) {
+ printf(" %d", node->value);
+ }
+ printf("\n");
+end:
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program for any
+ * purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is
+ * granted, provided the above notices are retained, and a notice that
+ * the code was modified is included with the above copyright notice.
+ *
+ * This example shows how to do a non-circular RCU linked list
+ * traversal, safely against concurrent RCU updates.
+ */
+
+#include <stdio.h>
+
+#include <urcu.h> /* Userspace RCU flavor */
+#include <urcu/rcuhlist.h> /* RCU hlist */
+#include <urcu/compiler.h> /* For CAA_ARRAY_SIZE */
+
+/*
+ * Nodes populated into the list.
+ */
+struct mynode {
+ int value; /* Node content */
+ struct cds_hlist_node node; /* Linked-list chaining */
+};
+
+int main(int argc, char **argv)
+{
+ int values[] = { -5, 42, 36, 24, };
+ CDS_HLIST_HEAD(mylist); /* Defines an empty hlist head */
+ unsigned int i;
+ int ret = 0;
+ struct mynode *node;
+
+ /*
+ * Each thread need using RCU read-side need to be explicitly
+ * registered.
+ */
+ rcu_register_thread();
+
+ /*
+ * Adding nodes to the linked-list. Safe against concurrent
+ * RCU traversals, require mutual exclusion with list updates.
+ */
+ for (i = 0; i < CAA_ARRAY_SIZE(values); i++) {
+ node = malloc(sizeof(*node));
+ if (!node) {
+ ret = -1;
+ goto end;
+ }
+ node->value = values[i];
+ cds_hlist_add_head_rcu(&node->node, &mylist);
+ }
+
+ /*
+ * RCU-safe iteration on the list.
+ */
+ printf("mylist content:");
+
+ /*
+ * Surround the RCU read-side critical section with rcu_read_lock()
+ * and rcu_read_unlock().
+ */
+ rcu_read_lock();
+
+ /*
+ * This traversal can be performed concurrently with RCU
+ * updates.
+ */
+ cds_hlist_for_each_entry_rcu_2(node, &mylist, node) {
+ printf(" %d", node->value);
+ }
+
+ rcu_read_unlock();
+
+ printf("\n");
+end:
+ rcu_unregister_thread();
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program for any
+ * purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is
+ * granted, provided the above notices are retained, and a notice that
+ * the code was modified is included with the above copyright notice.
+ *
+ * This example shows how to do a non-circular RCU linked list
+ * traversal, safely against concurrent RCU updates.
+ * cds_hlist_for_each_rcu() iterates on struct cds_hlist_node, and thus,
+ * either caa_container_of() or cds_hlist_entry() are needed to access
+ * the container structure.
+ */
+
+#include <stdio.h>
+
+#include <urcu.h> /* Userspace RCU flavor */
+#include <urcu/rcuhlist.h> /* RCU hlist */
+#include <urcu/compiler.h> /* For CAA_ARRAY_SIZE */
+
+/*
+ * Nodes populated into the list.
+ */
+struct mynode {
+ int value; /* Node content */
+ struct cds_hlist_node node; /* Linked-list chaining */
+};
+
+int main(int argc, char **argv)
+{
+ int values[] = { -5, 42, 36, 24, };
+ CDS_HLIST_HEAD(mylist); /* Defines an empty hlist head */
+ unsigned int i;
+ int ret = 0;
+ struct cds_hlist_node *pos;
+
+ /*
+ * Each thread need using RCU read-side need to be explicitly
+ * registered.
+ */
+ rcu_register_thread();
+
+ /*
+ * Adding nodes to the linked-list. Safe against concurrent
+ * RCU traversals, require mutual exclusion with list updates.
+ */
+ for (i = 0; i < CAA_ARRAY_SIZE(values); i++) {
+ struct mynode *node;
+
+ node = malloc(sizeof(*node));
+ if (!node) {
+ ret = -1;
+ goto end;
+ }
+ node->value = values[i];
+ cds_hlist_add_head_rcu(&node->node, &mylist);
+ }
+
+ /*
+ * RCU-safe iteration on the list.
+ */
+ printf("mylist content:");
+
+ /*
+ * Surround the RCU read-side critical section with rcu_read_lock()
+ * and rcu_read_unlock().
+ */
+ rcu_read_lock();
+
+ /*
+ * This traversal can be performed concurrently with RCU
+ * updates.
+ */
+ cds_hlist_for_each_rcu(pos, &mylist) {
+ struct mynode *node = cds_hlist_entry(pos, struct mynode, node);
+
+ printf(" %d", node->value);
+ }
+
+ rcu_read_unlock();
+
+ printf("\n");
+end:
+ rcu_unregister_thread();
+ return ret;
+}
--- /dev/null
+# Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+#
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+#
+# Permission is hereby granted to use or copy this program for any
+# purpose, provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is
+# granted, provided the above notices are retained, and a notice that
+# the code was modified is included with the above copyright notice.
+#
+# This makefile is purposefully kept simple to support GNU and BSD make.
+
+all:
+ $(MAKE) -f Makefile.cds_lfs_push
+ $(MAKE) -f Makefile.cds_lfs_pop_blocking
+ $(MAKE) -f Makefile.cds_lfs_pop_all_blocking
+
+.PHONY: clean
+clean:
+ $(MAKE) -f Makefile.cds_lfs_push clean
+ $(MAKE) -f Makefile.cds_lfs_pop_blocking clean
+ $(MAKE) -f Makefile.cds_lfs_pop_all_blocking clean
--- /dev/null
+# Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+#
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+#
+# Permission is hereby granted to use or copy this program for any
+# purpose, provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is
+# granted, provided the above notices are retained, and a notice that
+# the code was modified is included with the above copyright notice.
+#
+# This makefile is purposefully kept simple to support GNU and BSD make.
+
+EXAMPLE_NAME = cds_lfs_pop_all_blocking
+
+SOURCES = $(EXAMPLE_NAME).c
+OBJECTS = $(EXAMPLE_NAME).o
+BINARY = $(EXAMPLE_NAME)
+LIBS = -lurcu-cds
+
+include ../Makefile.examples.template
--- /dev/null
+# Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+#
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+#
+# Permission is hereby granted to use or copy this program for any
+# purpose, provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is
+# granted, provided the above notices are retained, and a notice that
+# the code was modified is included with the above copyright notice.
+#
+# This makefile is purposefully kept simple to support GNU and BSD make.
+
+EXAMPLE_NAME = cds_lfs_pop_blocking
+
+SOURCES = $(EXAMPLE_NAME).c
+OBJECTS = $(EXAMPLE_NAME).o
+BINARY = $(EXAMPLE_NAME)
+LIBS = -lurcu-cds
+
+include ../Makefile.examples.template
--- /dev/null
+# Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+#
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+#
+# Permission is hereby granted to use or copy this program for any
+# purpose, provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is
+# granted, provided the above notices are retained, and a notice that
+# the code was modified is included with the above copyright notice.
+#
+# This makefile is purposefully kept simple to support GNU and BSD make.
+
+EXAMPLE_NAME = cds_lfs_push
+
+SOURCES = $(EXAMPLE_NAME).c
+OBJECTS = $(EXAMPLE_NAME).o
+BINARY = $(EXAMPLE_NAME)
+LIBS = -lurcu-cds
+
+include ../Makefile.examples.template
--- /dev/null
+/*
+ * Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program for any
+ * purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is
+ * granted, provided the above notices are retained, and a notice that
+ * the code was modified is included with the above copyright notice.
+ *
+ * This example shows how to pop all nodes from a lfstack.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <urcu/lfstack.h> /* Lock-free stack */
+#include <urcu/compiler.h> /* For CAA_ARRAY_SIZE */
+
+/*
+ * Nodes populated into the stack.
+ */
+struct mynode {
+ int value; /* Node content */
+ struct cds_lfs_node node; /* Chaining in stack */
+};
+
+int main(int argc, char **argv)
+{
+ int values[] = { -5, 42, 36, 24, };
+ struct cds_lfs_stack mystack; /* Stack */
+ unsigned int i;
+ int ret = 0;
+ struct cds_lfs_node *snode, *sn;
+ struct cds_lfs_head *shead;
+
+ cds_lfs_init(&mystack);
+
+ /*
+ * Push nodes.
+ */
+ for (i = 0; i < CAA_ARRAY_SIZE(values); i++) {
+ struct mynode *node;
+
+ node = malloc(sizeof(*node));
+ if (!node) {
+ ret = -1;
+ goto end;
+ }
+
+ cds_lfs_node_init(&node->node);
+ node->value = values[i];
+ cds_lfs_push(&mystack, &node->node);
+ }
+
+ /*
+ * Pop all nodes from mystack into shead. The head can the be
+ * used for iteration.
+ */
+ shead = cds_lfs_pop_all_blocking(&mystack);
+
+ /*
+ * Show the stack content, iterate in reverse order of push,
+ * from newest to oldest. Use cds_lfs_for_each_safe() so we can
+ * free the nodes as we iterate.
+ */
+ printf("mystack content:");
+ cds_lfs_for_each_safe(shead, snode, sn) {
+ struct mynode *node =
+ caa_container_of(snode, struct mynode, node);
+ printf(" %d", node->value);
+ free(node);
+ }
+ printf("\n");
+end:
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program for any
+ * purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is
+ * granted, provided the above notices are retained, and a notice that
+ * the code was modified is included with the above copyright notice.
+ *
+ * This example shows how to pop nodes from a lfstack.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <urcu/lfstack.h> /* Wait-free stack */
+#include <urcu/compiler.h> /* For CAA_ARRAY_SIZE */
+
+/*
+ * Nodes populated into the stack.
+ */
+struct mynode {
+ int value; /* Node content */
+ struct cds_lfs_node node; /* Chaining in stack */
+};
+
+int main(int argc, char **argv)
+{
+ int values[] = { -5, 42, 36, 24, };
+ struct cds_lfs_stack mystack; /* Stack */
+ unsigned int i;
+ int ret = 0;
+
+ cds_lfs_init(&mystack);
+
+ /*
+ * Push nodes.
+ */
+ for (i = 0; i < CAA_ARRAY_SIZE(values); i++) {
+ struct mynode *node;
+
+ node = malloc(sizeof(*node));
+ if (!node) {
+ ret = -1;
+ goto end;
+ }
+
+ cds_lfs_node_init(&node->node);
+ node->value = values[i];
+ cds_lfs_push(&mystack, &node->node);
+ }
+
+ /*
+ * Pop nodes from the stack, one by one, from newest to oldest.
+ */
+ printf("pop each mystack node:");
+ for (;;) {
+ struct cds_lfs_node *snode;
+ struct mynode *node;
+
+ snode = cds_lfs_pop_blocking(&mystack);
+ if (!snode) {
+ break;
+ }
+ node = caa_container_of(snode, struct mynode, node);
+ printf(" %d", node->value);
+ free(node);
+ }
+ printf("\n");
+end:
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program for any
+ * purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is
+ * granted, provided the above notices are retained, and a notice that
+ * the code was modified is included with the above copyright notice.
+ *
+ * This example shows how to push nodes into a lfstack.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <urcu/lfstack.h> /* Lock-free stack */
+#include <urcu/compiler.h> /* For CAA_ARRAY_SIZE */
+
+/*
+ * Nodes populated into the stack.
+ */
+struct mynode {
+ int value; /* Node content */
+ struct cds_lfs_node node; /* Chaining in stack */
+};
+
+int main(int argc, char **argv)
+{
+ int values[] = { -5, 42, 36, 24, };
+ struct cds_lfs_stack mystack; /* Stack */
+ unsigned int i;
+ int ret = 0;
+ struct cds_lfs_node *snode;
+ struct cds_lfs_head *shead;
+
+ cds_lfs_init(&mystack);
+
+ /*
+ * Push nodes.
+ */
+ for (i = 0; i < CAA_ARRAY_SIZE(values); i++) {
+ struct mynode *node;
+
+ node = malloc(sizeof(*node));
+ if (!node) {
+ ret = -1;
+ goto end;
+ }
+
+ cds_lfs_node_init(&node->node);
+ node->value = values[i];
+ cds_lfs_push(&mystack, &node->node);
+ }
+
+ /*
+ * Show the stack content, iterate in reverse order of push,
+ * from newest to oldest.
+ */
+ printf("mystack content:");
+ shead = cds_lfs_pop_all_blocking(&mystack);
+ cds_lfs_for_each(shead, snode) {
+ struct mynode *node =
+ caa_container_of(snode, struct mynode, node);
+ printf(" %d", node->value);
+ }
+ printf("\n");
+end:
+ return ret;
+}
--- /dev/null
+# Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+#
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+#
+# Permission is hereby granted to use or copy this program for any
+# purpose, provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is
+# granted, provided the above notices are retained, and a notice that
+# the code was modified is included with the above copyright notice.
+#
+# This makefile is purposefully kept simple to support GNU and BSD make.
+
+all:
+ $(MAKE) -f Makefile.cds_list_add_rcu
+ $(MAKE) -f Makefile.cds_list_add_tail_rcu
+ $(MAKE) -f Makefile.cds_list_del_rcu
+ $(MAKE) -f Makefile.cds_list_for_each_rcu
+ $(MAKE) -f Makefile.cds_list_for_each_entry_rcu
+ $(MAKE) -f Makefile.cds_list_replace_rcu
+
+.PHONY: clean
+clean:
+ $(MAKE) -f Makefile.cds_list_add_rcu clean
+ $(MAKE) -f Makefile.cds_list_add_tail_rcu clean
+ $(MAKE) -f Makefile.cds_list_del_rcu clean
+ $(MAKE) -f Makefile.cds_list_for_each_rcu clean
+ $(MAKE) -f Makefile.cds_list_for_each_entry_rcu clean
+ $(MAKE) -f Makefile.cds_list_replace_rcu clean
--- /dev/null
+# Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+#
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+#
+# Permission is hereby granted to use or copy this program for any
+# purpose, provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is
+# granted, provided the above notices are retained, and a notice that
+# the code was modified is included with the above copyright notice.
+#
+# This makefile is purposefully kept simple to support GNU and BSD make.
+
+EXAMPLE_NAME = cds_list_add_rcu
+
+SOURCES = $(EXAMPLE_NAME).c
+OBJECTS = $(EXAMPLE_NAME).o
+BINARY = $(EXAMPLE_NAME)
+LIBS = -lurcu
+
+include ../Makefile.examples.template
--- /dev/null
+# Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+#
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+#
+# Permission is hereby granted to use or copy this program for any
+# purpose, provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is
+# granted, provided the above notices are retained, and a notice that
+# the code was modified is included with the above copyright notice.
+#
+# This makefile is purposefully kept simple to support GNU and BSD make.
+
+EXAMPLE_NAME = cds_list_add_tail_rcu
+
+SOURCES = $(EXAMPLE_NAME).c
+OBJECTS = $(EXAMPLE_NAME).o
+BINARY = $(EXAMPLE_NAME)
+LIBS = -lurcu
+
+include ../Makefile.examples.template
--- /dev/null
+# Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+#
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+#
+# Permission is hereby granted to use or copy this program for any
+# purpose, provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is
+# granted, provided the above notices are retained, and a notice that
+# the code was modified is included with the above copyright notice.
+#
+# This makefile is purposefully kept simple to support GNU and BSD make.
+
+EXAMPLE_NAME = cds_list_del_rcu
+
+SOURCES = $(EXAMPLE_NAME).c
+OBJECTS = $(EXAMPLE_NAME).o
+BINARY = $(EXAMPLE_NAME)
+LIBS = -lurcu
+
+include ../Makefile.examples.template
--- /dev/null
+# Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+#
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+#
+# Permission is hereby granted to use or copy this program for any
+# purpose, provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is
+# granted, provided the above notices are retained, and a notice that
+# the code was modified is included with the above copyright notice.
+#
+# This makefile is purposefully kept simple to support GNU and BSD make.
+
+EXAMPLE_NAME = cds_list_for_each_entry_rcu
+
+SOURCES = $(EXAMPLE_NAME).c
+OBJECTS = $(EXAMPLE_NAME).o
+BINARY = $(EXAMPLE_NAME)
+LIBS = -lurcu
+
+include ../Makefile.examples.template
--- /dev/null
+# Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+#
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+#
+# Permission is hereby granted to use or copy this program for any
+# purpose, provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is
+# granted, provided the above notices are retained, and a notice that
+# the code was modified is included with the above copyright notice.
+#
+# This makefile is purposefully kept simple to support GNU and BSD make.
+
+EXAMPLE_NAME = cds_list_for_each_rcu
+
+SOURCES = $(EXAMPLE_NAME).c
+OBJECTS = $(EXAMPLE_NAME).o
+BINARY = $(EXAMPLE_NAME)
+LIBS = -lurcu
+
+include ../Makefile.examples.template
--- /dev/null
+# Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+#
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+#
+# Permission is hereby granted to use or copy this program for any
+# purpose, provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is
+# granted, provided the above notices are retained, and a notice that
+# the code was modified is included with the above copyright notice.
+#
+# This makefile is purposefully kept simple to support GNU and BSD make.
+
+EXAMPLE_NAME = cds_list_replace_rcu
+
+SOURCES = $(EXAMPLE_NAME).c
+OBJECTS = $(EXAMPLE_NAME).o
+BINARY = $(EXAMPLE_NAME)
+LIBS = -lurcu
+
+include ../Makefile.examples.template
--- /dev/null
+/*
+ * Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program for any
+ * purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is
+ * granted, provided the above notices are retained, and a notice that
+ * the code was modified is included with the above copyright notice.
+ *
+ * This example shows how to add into a linked-list safely against
+ * concurrent RCU traversals.
+ */
+
+#include <stdio.h>
+
+#include <urcu.h> /* Userspace RCU flavor */
+#include <urcu/rculist.h> /* RCU list */
+#include <urcu/compiler.h> /* For CAA_ARRAY_SIZE */
+
+/*
+ * Nodes populated into the list.
+ */
+struct mynode {
+ int value; /* Node content */
+ struct cds_list_head node; /* Linked-list chaining */
+};
+
+int main(int argc, char **argv)
+{
+ int values[] = { -5, 42, 36, 24, };
+ CDS_LIST_HEAD(mylist); /* Defines an empty list head */
+ unsigned int i;
+ int ret = 0;
+ struct mynode *node;
+
+ /*
+ * Adding nodes to the linked-list. Safe against concurrent
+ * RCU traversals, require mutual exclusion with list updates.
+ */
+ for (i = 0; i < CAA_ARRAY_SIZE(values); i++) {
+ node = malloc(sizeof(*node));
+ if (!node) {
+ ret = -1;
+ goto end;
+ }
+ node->value = values[i];
+ cds_list_add_rcu(&node->node, &mylist);
+ }
+
+ /*
+ * Just show the list content. This is _not_ an RCU-safe
+ * iteration on the list.
+ */
+ printf("mylist content:");
+ cds_list_for_each_entry(node, &mylist, node) {
+ printf(" %d", node->value);
+ }
+ printf("\n");
+end:
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program for any
+ * purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is
+ * granted, provided the above notices are retained, and a notice that
+ * the code was modified is included with the above copyright notice.
+ *
+ * This example shows how to add into tail of a linked-list safely
+ * against concurrent RCU traversals.
+ */
+
+#include <stdio.h>
+
+#include <urcu.h> /* Userspace RCU flavor */
+#include <urcu/rculist.h> /* RCU list */
+#include <urcu/compiler.h> /* For CAA_ARRAY_SIZE */
+
+/*
+ * Nodes populated into the list.
+ */
+struct mynode {
+ int value; /* Node content */
+ struct cds_list_head node; /* Linked-list chaining */
+};
+
+int main(int argc, char **argv)
+{
+ int values[] = { -5, 42, 36, 24, };
+ CDS_LIST_HEAD(mylist); /* Defines an empty list head */
+ unsigned int i;
+ int ret = 0;
+ struct mynode *node;
+
+ /*
+ * Adding nodes to the linked-list. Safe against concurrent
+ * RCU traversals, require mutual exclusion with list updates.
+ */
+ for (i = 0; i < CAA_ARRAY_SIZE(values); i++) {
+ node = malloc(sizeof(*node));
+ if (!node) {
+ ret = -1;
+ goto end;
+ }
+ node->value = values[i];
+ cds_list_add_tail_rcu(&node->node, &mylist);
+ }
+
+ /*
+ * Just show the list content. This is _not_ an RCU-safe
+ * iteration on the list.
+ */
+ printf("mylist content:");
+ cds_list_for_each_entry(node, &mylist, node) {
+ printf(" %d", node->value);
+ }
+ printf("\n");
+end:
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program for any
+ * purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is
+ * granted, provided the above notices are retained, and a notice that
+ * the code was modified is included with the above copyright notice.
+ *
+ * This example shows how to remove from a linked-list safely against
+ * concurrent RCU traversals.
+ */
+
+#include <stdio.h>
+
+#include <urcu.h> /* Userspace RCU flavor */
+#include <urcu/rculist.h> /* RCU list */
+#include <urcu/compiler.h> /* For CAA_ARRAY_SIZE */
+
+/*
+ * Nodes populated into the list.
+ */
+struct mynode {
+ int value; /* Node content */
+ struct cds_list_head node; /* Linked-list chaining */
+ struct rcu_head rcu_head; /* For call_rcu() */
+};
+
+static
+void free_node_rcu(struct rcu_head *head)
+{
+ struct mynode *node = caa_container_of(head, struct mynode, rcu_head);
+
+ free(node);
+}
+
+int main(int argc, char **argv)
+{
+ int values[] = { -5, 42, 36, 24, };
+ CDS_LIST_HEAD(mylist); /* Defines an empty list head */
+ unsigned int i;
+ int ret = 0;
+ struct mynode *node, *n;
+
+ /*
+ * Adding nodes to the linked-list. Safe against concurrent
+ * RCU traversals, require mutual exclusion with list updates.
+ */
+ for (i = 0; i < CAA_ARRAY_SIZE(values); i++) {
+ node = malloc(sizeof(*node));
+ if (!node) {
+ ret = -1;
+ goto end;
+ }
+ node->value = values[i];
+ cds_list_add_rcu(&node->node, &mylist);
+ }
+
+ /*
+ * Removing all positive values. Safe against concurrent RCU
+ * traversals, require mutual exclusion with list updates.
+ * Notice the "safe" iteration: it is safe against removal of
+ * nodes as we iterate on the list.
+ */
+ cds_list_for_each_entry_safe(node, n, &mylist, node) {
+ if (node->value > 0) {
+ cds_list_del_rcu(&node->node);
+ /*
+ * We can only reclaim memory after a grace
+ * period has passed after cds_list_del_rcu().
+ */
+ call_rcu(&node->rcu_head, free_node_rcu);
+ }
+ }
+
+ /*
+ * Just show the list content. This is _not_ an RCU-safe
+ * iteration on the list.
+ */
+ printf("mylist content:");
+ cds_list_for_each_entry(node, &mylist, node) {
+ printf(" %d", node->value);
+ }
+ printf("\n");
+end:
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program for any
+ * purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is
+ * granted, provided the above notices are retained, and a notice that
+ * the code was modified is included with the above copyright notice.
+ *
+ * This example shows how to do a RCU linked list traversal, safely
+ * against concurrent RCU updates.
+ */
+
+#include <stdio.h>
+
+#include <urcu.h> /* Userspace RCU flavor */
+#include <urcu/rculist.h> /* RCU list */
+#include <urcu/compiler.h> /* For CAA_ARRAY_SIZE */
+
+/*
+ * Nodes populated into the list.
+ */
+struct mynode {
+ int value; /* Node content */
+ struct cds_list_head node; /* Linked-list chaining */
+};
+
+int main(int argc, char **argv)
+{
+ int values[] = { -5, 42, 36, 24, };
+ CDS_LIST_HEAD(mylist); /* Defines an empty list head */
+ unsigned int i;
+ int ret = 0;
+ struct mynode *node;
+
+ /*
+ * Each thread need using RCU read-side need to be explicitly
+ * registered.
+ */
+ rcu_register_thread();
+
+ /*
+ * Adding nodes to the linked-list. Safe against concurrent
+ * RCU traversals, require mutual exclusion with list updates.
+ */
+ for (i = 0; i < CAA_ARRAY_SIZE(values); i++) {
+ node = malloc(sizeof(*node));
+ if (!node) {
+ ret = -1;
+ goto end;
+ }
+ node->value = values[i];
+ cds_list_add_tail_rcu(&node->node, &mylist);
+ }
+
+ /*
+ * RCU-safe iteration on the list.
+ */
+ printf("mylist content:");
+
+ /*
+ * Surround the RCU read-side critical section with rcu_read_lock()
+ * and rcu_read_unlock().
+ */
+ rcu_read_lock();
+
+ /*
+ * This traversal can be performed concurrently with RCU
+ * updates.
+ */
+ cds_list_for_each_entry_rcu(node, &mylist, node) {
+ printf(" %d", node->value);
+ }
+
+ rcu_read_unlock();
+
+ printf("\n");
+end:
+ rcu_unregister_thread();
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program for any
+ * purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is
+ * granted, provided the above notices are retained, and a notice that
+ * the code was modified is included with the above copyright notice.
+ *
+ * This example shows how to do a RCU linked list traversal, safely
+ * against concurrent RCU updates. cds_list_for_each_rcu() iterates on
+ * struct cds_list_head, and thus, either caa_container_of() or
+ * cds_list_entry() are needed to access the container structure.
+ */
+
+#include <stdio.h>
+
+#include <urcu.h> /* Userspace RCU flavor */
+#include <urcu/rculist.h> /* RCU list */
+#include <urcu/compiler.h> /* For CAA_ARRAY_SIZE */
+
+/*
+ * Nodes populated into the list.
+ */
+struct mynode {
+ int value; /* Node content */
+ struct cds_list_head node; /* Linked-list chaining */
+};
+
+int main(int argc, char **argv)
+{
+ int values[] = { -5, 42, 36, 24, };
+ CDS_LIST_HEAD(mylist); /* Defines an empty list head */
+ unsigned int i;
+ int ret = 0;
+ struct cds_list_head *pos;
+
+ /*
+ * Each thread need using RCU read-side need to be explicitly
+ * registered.
+ */
+ rcu_register_thread();
+
+ /*
+ * Adding nodes to the linked-list. Safe against concurrent
+ * RCU traversals, require mutual exclusion with list updates.
+ */
+ for (i = 0; i < CAA_ARRAY_SIZE(values); i++) {
+ struct mynode *node;
+
+ node = malloc(sizeof(*node));
+ if (!node) {
+ ret = -1;
+ goto end;
+ }
+ node->value = values[i];
+ cds_list_add_tail_rcu(&node->node, &mylist);
+ }
+
+ /*
+ * RCU-safe iteration on the list.
+ */
+ printf("mylist content:");
+
+ /*
+ * Surround the RCU read-side critical section with rcu_read_lock()
+ * and rcu_read_unlock().
+ */
+ rcu_read_lock();
+
+ /*
+ * This traversal can be performed concurrently with RCU
+ * updates.
+ */
+ cds_list_for_each_rcu(pos, &mylist) {
+ struct mynode *node = cds_list_entry(pos, struct mynode, node);
+
+ printf(" %d", node->value);
+ }
+
+ rcu_read_unlock();
+
+ printf("\n");
+end:
+ rcu_unregister_thread();
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program for any
+ * purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is
+ * granted, provided the above notices are retained, and a notice that
+ * the code was modified is included with the above copyright notice.
+ *
+ * This example shows how to replace a node within a linked-list safely
+ * against concurrent RCU traversals.
+ */
+
+#include <stdio.h>
+
+#include <urcu.h> /* Userspace RCU flavor */
+#include <urcu/rculist.h> /* RCU list */
+#include <urcu/compiler.h> /* For CAA_ARRAY_SIZE */
+
+/*
+ * Nodes populated into the list.
+ */
+struct mynode {
+ int value; /* Node content */
+ struct cds_list_head node; /* Linked-list chaining */
+ struct rcu_head rcu_head; /* For call_rcu() */
+};
+
+static
+void free_node_rcu(struct rcu_head *head)
+{
+ struct mynode *node = caa_container_of(head, struct mynode, rcu_head);
+
+ free(node);
+}
+
+int main(int argc, char **argv)
+{
+ int values[] = { -5, 42, 36, 24, };
+ CDS_LIST_HEAD(mylist); /* Defines an empty list head */
+ unsigned int i;
+ int ret = 0;
+ struct mynode *node, *n;
+
+ /*
+ * Adding nodes to the linked-list. Safe against concurrent
+ * RCU traversals, require mutual exclusion with list updates.
+ */
+ for (i = 0; i < CAA_ARRAY_SIZE(values); i++) {
+ node = malloc(sizeof(*node));
+ if (!node) {
+ ret = -1;
+ goto end;
+ }
+ node->value = values[i];
+ cds_list_add_tail_rcu(&node->node, &mylist);
+ }
+
+ /*
+ * Replacing all values by their negated value. Safe against
+ * concurrent RCU traversals, require mutual exclusion with list
+ * updates. Notice the "safe" iteration: it is safe against
+ * removal (and thus replacement) of nodes as we iterate on the
+ * list.
+ */
+ cds_list_for_each_entry_safe(node, n, &mylist, node) {
+ struct mynode *new_node;
+
+ new_node = malloc(sizeof(*node));
+ if (!new_node) {
+ ret = -1;
+ goto end;
+ }
+ /* Replacement node value is negated original value. */
+ new_node->value = -node->value;
+ cds_list_replace_rcu(&node->node, &new_node->node);
+ call_rcu(&node->rcu_head, free_node_rcu);
+ }
+
+ /*
+ * Just show the list content. This is _not_ an RCU-safe
+ * iteration on the list.
+ */
+ printf("mylist content:");
+ cds_list_for_each_entry(node, &mylist, node) {
+ printf(" %d", node->value);
+ }
+ printf("\n");
+end:
+ return ret;
+}
+++ /dev/null
-# Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
-#
-# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
-# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
-#
-# Permission is hereby granted to use or copy this program for any
-# purpose, provided the above notices are retained on all copies.
-# Permission to modify the code and to distribute modified code is
-# granted, provided the above notices are retained, and a notice that
-# the code was modified is included with the above copyright notice.
-
-CC = gcc
-LIBS = -lurcu-qsbr
-CFLAGS = -g -O2 -Wall
-
-# Only necessary when building from the source tree and userspace RCU is
-# not installed
-ifdef BUILD_EXAMPLES_FROM_TREE
-LOCAL_CPPFLAGS += -I../../../urcu/ -I../../../
-LIBURCU_QSBR_PATH = ../../../.libs/
-override LDFLAGS += -L$(LIBURCU_QSBR_PATH) -Wl,-rpath='$$ORIGIN/$(LIBURCU_QSBR_PATH)'
-
-# Third-party Makefiles have to define these targets to integrate with an
-# automake project
-EMPTY_AUTOMAKE_TARGETS = distdir install install-data install-exec uninstall \
- install-dvi install-html install-info install-ps install-pdf \
- installdirs check installcheck mostlyclean distclean maintainer-clean \
- dvi pdf ps info tags ctags
-.PHONY: $(EMPTY_AUTOMAKE_TARGETS)
-$(EMPTY_AUTOMAKE_TARGETS):
-endif
-
-all: qsbr-minimal
-
-qsbr-minimal: qsbr-minimal.o
- $(CC) -o $@ $^ $(LDFLAGS) $(LIBS)
-
-qsbr-minimal.o: qsbr-minimal.c
- $(CC) $(CPPFLAGS) $(LOCAL_CPPFLAGS) $(CFLAGS) -c -o $@ $<
-
-.PHONY: clean
-clean:
- rm -f *.o qsbr-minimal
+++ /dev/null
-/*
- * Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#define _LGPL_SOURCE
-#include <urcu-qsbr.h>
-#include <urcu/rculist.h>
-#include <urcu/compiler.h>
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <inttypes.h>
-
-/*
- * This is a mock-up example where updates and RCU traversals are
- * performed by the same thread to keep things simple on purpose.
- */
-
-static CDS_LIST_HEAD(mylist);
-
-struct mynode {
- uint64_t value;
- struct cds_list_head node; /* linked-list chaining */
- struct rcu_head rcu_head; /* for call_rcu() */
-};
-
-static
-int add_node(uint64_t v)
-{
- struct mynode *node;
-
- node = calloc(sizeof(*node), 1);
- if (!node)
- return -1;
- node->value = v;
- cds_list_add_rcu(&node->node, &mylist);
- return 0;
-}
-
-static
-void rcu_free_node(struct rcu_head *rh)
-{
- struct mynode *node = caa_container_of(rh, struct mynode, rcu_head);
-
- free(node);
-}
-
-int main(int argc, char **argv)
-{
- uint64_t values[] = { 42, 36, 24, };
- unsigned int i;
- int ret;
- struct mynode *node, *n;
-
- /*
- * Each thread need using RCU read-side need to be explicitely
- * registered.
- */
- rcu_register_thread();
-
- /*
- * Adding nodes to the linked-list. Safe against concurrent
- * RCU traversals, require mutual exclusion with list updates.
- */
- for (i = 0; i < CAA_ARRAY_SIZE(values); i++) {
- ret = add_node(values[i]);
- if (ret)
- goto end;
- }
-
- /*
- * For all RCU flavors except QSBR, we need to explicitly mark
- * RCU read-side critical sections with rcu_read_lock() and
- * rcu_read_unlock(). They can be nested. Those are no-ops for
- * the QSBR flavor.
- */
- rcu_read_lock();
-
- /*
- * RCU traversal of the linked list.
- */
- cds_list_for_each_entry_rcu(node, &mylist, node) {
- printf("Value: %" PRIu64 "\n", node->value);
- }
- rcu_read_unlock();
-
- /*
- * Removing nodes from linked list. Safe against concurrent RCU
- * traversals, require mutual exclusion with list updates.
- */
- cds_list_for_each_entry_safe(node, n, &mylist, node) {
- cds_list_del_rcu(&node->node);
- call_rcu(&node->rcu_head, rcu_free_node);
- }
-
- /*
- * For QSBR flavor, we need to explicitly announce quiescent
- * states.
- */
- rcu_quiescent_state();
-
- /*
- * For QSBR flavor, when a thread needs to be in a quiescent
- * state for a long period of time, we use rcu_thread_offline()
- * and rcu_thread_online().
- */
- rcu_thread_offline();
-
- sleep(1);
-
- rcu_thread_online();
-
- /*
- * Waiting for previously called call_rcu handlers to complete
- * before program exits is a good practice.
- */
- rcu_barrier();
-
-end:
- rcu_unregister_thread();
- return ret;
-}
--- /dev/null
+# Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+#
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+#
+# Permission is hereby granted to use or copy this program for any
+# purpose, provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is
+# granted, provided the above notices are retained, and a notice that
+# the code was modified is included with the above copyright notice.
+#
+# This makefile is purposefully kept simple to support GNU and BSD make.
+
+all:
+ $(MAKE) -f Makefile.cds_lfht_add
+ $(MAKE) -f Makefile.cds_lfht_add_unique
+ $(MAKE) -f Makefile.cds_lfht_add_replace
+ $(MAKE) -f Makefile.cds_lfht_del
+ $(MAKE) -f Makefile.cds_lfht_destroy
+ $(MAKE) -f Makefile.cds_lfht_lookup
+ $(MAKE) -f Makefile.cds_lfht_for_each_entry_duplicate
+
+.PHONY: clean
+clean:
+ $(MAKE) -f Makefile.cds_lfht_add clean
+ $(MAKE) -f Makefile.cds_lfht_add_unique clean
+ $(MAKE) -f Makefile.cds_lfht_add_replace clean
+ $(MAKE) -f Makefile.cds_lfht_del clean
+ $(MAKE) -f Makefile.cds_lfht_destroy clean
+ $(MAKE) -f Makefile.cds_lfht_lookup clean
+ $(MAKE) -f Makefile.cds_lfht_for_each_entry_duplicate clean
--- /dev/null
+# Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+#
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+#
+# Permission is hereby granted to use or copy this program for any
+# purpose, provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is
+# granted, provided the above notices are retained, and a notice that
+# the code was modified is included with the above copyright notice.
+#
+# This makefile is purposefully kept simple to support GNU and BSD make.
+
+EXAMPLE_NAME = cds_lfht_add
+
+SOURCES = $(EXAMPLE_NAME).c
+DEPS = jhash.h
+OBJECTS = $(EXAMPLE_NAME).o
+BINARY = $(EXAMPLE_NAME)
+LIBS = -lurcu-cds -lurcu
+
+include ../Makefile.examples.template
--- /dev/null
+# Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+#
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+#
+# Permission is hereby granted to use or copy this program for any
+# purpose, provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is
+# granted, provided the above notices are retained, and a notice that
+# the code was modified is included with the above copyright notice.
+#
+# This makefile is purposefully kept simple to support GNU and BSD make.
+
+EXAMPLE_NAME = cds_lfht_add_replace
+
+SOURCES = $(EXAMPLE_NAME).c
+DEPS = jhash.h
+OBJECTS = $(EXAMPLE_NAME).o
+BINARY = $(EXAMPLE_NAME)
+LIBS = -lurcu-cds -lurcu
+
+include ../Makefile.examples.template
--- /dev/null
+# Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+#
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+#
+# Permission is hereby granted to use or copy this program for any
+# purpose, provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is
+# granted, provided the above notices are retained, and a notice that
+# the code was modified is included with the above copyright notice.
+#
+# This makefile is purposefully kept simple to support GNU and BSD make.
+
+EXAMPLE_NAME = cds_lfht_add_unique
+
+SOURCES = $(EXAMPLE_NAME).c
+DEPS = jhash.h
+OBJECTS = $(EXAMPLE_NAME).o
+BINARY = $(EXAMPLE_NAME)
+LIBS = -lurcu-cds -lurcu
+
+include ../Makefile.examples.template
--- /dev/null
+# Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+#
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+#
+# Permission is hereby granted to use or copy this program for any
+# purpose, provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is
+# granted, provided the above notices are retained, and a notice that
+# the code was modified is included with the above copyright notice.
+#
+# This makefile is purposefully kept simple to support GNU and BSD make.
+
+EXAMPLE_NAME = cds_lfht_del
+
+SOURCES = $(EXAMPLE_NAME).c
+DEPS = jhash.h
+OBJECTS = $(EXAMPLE_NAME).o
+BINARY = $(EXAMPLE_NAME)
+LIBS = -lurcu-cds -lurcu
+
+include ../Makefile.examples.template
--- /dev/null
+# Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+#
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+#
+# Permission is hereby granted to use or copy this program for any
+# purpose, provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is
+# granted, provided the above notices are retained, and a notice that
+# the code was modified is included with the above copyright notice.
+#
+# This makefile is purposefully kept simple to support GNU and BSD make.
+
+EXAMPLE_NAME = cds_lfht_destroy
+
+SOURCES = $(EXAMPLE_NAME).c
+DEPS = jhash.h
+OBJECTS = $(EXAMPLE_NAME).o
+BINARY = $(EXAMPLE_NAME)
+LIBS = -lurcu-cds -lurcu
+
+include ../Makefile.examples.template
--- /dev/null
+# Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+#
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+#
+# Permission is hereby granted to use or copy this program for any
+# purpose, provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is
+# granted, provided the above notices are retained, and a notice that
+# the code was modified is included with the above copyright notice.
+#
+# This makefile is purposefully kept simple to support GNU and BSD make.
+
+EXAMPLE_NAME = cds_lfht_for_each_entry_duplicate
+
+SOURCES = $(EXAMPLE_NAME).c
+DEPS = jhash.h
+OBJECTS = $(EXAMPLE_NAME).o
+BINARY = $(EXAMPLE_NAME)
+LIBS = -lurcu-cds -lurcu
+
+include ../Makefile.examples.template
--- /dev/null
+# Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+#
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+#
+# Permission is hereby granted to use or copy this program for any
+# purpose, provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is
+# granted, provided the above notices are retained, and a notice that
+# the code was modified is included with the above copyright notice.
+#
+# This makefile is purposefully kept simple to support GNU and BSD make.
+
+EXAMPLE_NAME = cds_lfht_lookup
+
+SOURCES = $(EXAMPLE_NAME).c
+DEPS = jhash.h
+OBJECTS = $(EXAMPLE_NAME).o
+BINARY = $(EXAMPLE_NAME)
+LIBS = -lurcu-cds -lurcu
+
+include ../Makefile.examples.template
--- /dev/null
+/*
+ * Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program for any
+ * purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is
+ * granted, provided the above notices are retained, and a notice that
+ * the code was modified is included with the above copyright notice.
+ *
+ * This example shows how to add nodes (allowing duplicate keys) into a
+ * RCU lock-free hash table.
+ * This hash table requires using a RCU scheme.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include <urcu.h> /* RCU flavor */
+#include <urcu/rculfhash.h> /* RCU Lock-free hash table */
+#include <urcu/compiler.h> /* For CAA_ARRAY_SIZE */
+#include "jhash.h" /* Example hash function */
+
+/*
+ * Nodes populated into the hash table.
+ */
+struct mynode {
+ int value; /* Node content */
+ struct cds_lfht_node node; /* Chaining in hash table */
+};
+
+int main(int argc, char **argv)
+{
+ int values[] = { -5, 42, 42, 36, 24, }; /* 42 is duplicated */
+ struct cds_lfht *ht; /* Hash table */
+ unsigned int i;
+ int ret = 0;
+ uint32_t seed;
+ struct cds_lfht_iter iter; /* For iteration on hash table */
+ struct mynode *node;
+
+ /*
+ * Each thread need using RCU read-side need to be explicitly
+ * registered.
+ */
+ rcu_register_thread();
+
+ /* Use time as seed for hash table hashing. */
+ seed = (uint32_t) time(NULL);
+
+ /*
+ * Allocate hash table.
+ */
+ ht = cds_lfht_new(1, 1, 0,
+ CDS_LFHT_AUTO_RESIZE | CDS_LFHT_ACCOUNTING,
+ NULL);
+ if (!ht) {
+ printf("Error allocating hash table\n");
+ ret = -1;
+ goto end;
+ }
+
+ /*
+ * Add nodes to hash table.
+ */
+ for (i = 0; i < CAA_ARRAY_SIZE(values); i++) {
+ unsigned long hash;
+
+ node = malloc(sizeof(*node));
+ if (!node) {
+ ret = -1;
+ goto end;
+ }
+
+ cds_lfht_node_init(&node->node);
+ node->value = values[i];
+ hash = jhash(&values[i], sizeof(values[i]), seed);
+
+ /*
+ * cds_lfht_add() needs to be called from RCU read-side
+ * critical section.
+ */
+ rcu_read_lock();
+ cds_lfht_add(ht, hash, &node->node);
+ rcu_read_unlock();
+ }
+
+ /*
+ * Iterate over each hash table node. Those will appear in
+ * random order, depending on the hash seed. Iteration needs to
+ * be performed within RCU read-side critical section.
+ */
+ printf("hash table content (random order):");
+ rcu_read_lock();
+ cds_lfht_for_each_entry(ht, &iter, node, node) {
+ printf(" %d", node->value);
+ }
+ rcu_read_unlock();
+ printf("\n");
+end:
+ rcu_unregister_thread();
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program for any
+ * purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is
+ * granted, provided the above notices are retained, and a notice that
+ * the code was modified is included with the above copyright notice.
+ *
+ * This example shows how to add nodes into a RCU lock-free hash table
+ * with cds_lfht_add_replace(), which replaces existing nodes with the
+ * same key if found.
+ * We use a "seqnum" field to show which node is staying in the hash
+ * table. This hash table requires using a RCU scheme.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include <urcu.h> /* RCU flavor */
+#include <urcu/rculfhash.h> /* RCU Lock-free hash table */
+#include <urcu/compiler.h> /* For CAA_ARRAY_SIZE */
+#include "jhash.h" /* Example hash function */
+
+/*
+ * Nodes populated into the hash table.
+ */
+struct mynode {
+ int value; /* Node content */
+ int seqnum; /* Our node sequence number */
+ struct cds_lfht_node node; /* Chaining in hash table */
+ struct rcu_head rcu_head; /* For call_rcu() */
+};
+
+static
+int match(struct cds_lfht_node *ht_node, const void *_key)
+{
+ struct mynode *node =
+ caa_container_of(ht_node, struct mynode, node);
+ const unsigned int *key = _key;
+
+ return *key == node->value;
+}
+
+static
+void free_node(struct rcu_head *head)
+{
+ struct mynode *node = caa_container_of(head, struct mynode, rcu_head);
+
+ free(node);
+}
+
+int main(int argc, char **argv)
+{
+ int values[] = { -5, 42, 42, 36, 24, }; /* 42 is duplicated */
+ struct cds_lfht *ht; /* Hash table */
+ unsigned int i;
+ int ret = 0, seqnum = 0;
+ uint32_t seed;
+ struct cds_lfht_iter iter; /* For iteration on hash table */
+ struct cds_lfht_node *ht_node;
+ struct mynode *node;
+
+ /*
+ * Each thread need using RCU read-side need to be explicitly
+ * registered.
+ */
+ rcu_register_thread();
+
+ /* Use time as seed for hash table hashing. */
+ seed = (uint32_t) time(NULL);
+
+ /*
+ * Allocate hash table.
+ */
+ ht = cds_lfht_new(1, 1, 0,
+ CDS_LFHT_AUTO_RESIZE | CDS_LFHT_ACCOUNTING,
+ NULL);
+ if (!ht) {
+ printf("Error allocating hash table\n");
+ ret = -1;
+ goto end;
+ }
+
+ /*
+ * Add nodes to hash table.
+ */
+ for (i = 0; i < CAA_ARRAY_SIZE(values); i++) {
+ unsigned long hash;
+ int value;
+
+ node = malloc(sizeof(*node));
+ if (!node) {
+ ret = -1;
+ goto end;
+ }
+
+ cds_lfht_node_init(&node->node);
+ value = values[i];
+ node->value = value;
+ node->seqnum = seqnum++;
+ hash = jhash(&value, sizeof(value), seed);
+
+ /*
+ * cds_lfht_add() needs to be called from RCU read-side
+ * critical section.
+ */
+ rcu_read_lock();
+ ht_node = cds_lfht_add_replace(ht, hash, match, &value,
+ &node->node);
+ if (ht_node) {
+ struct mynode *ret_node =
+ caa_container_of(ht_node, struct mynode, node);
+
+ printf("Replaced node (key: %d, seqnum: %d) by (key: %d, seqnum: %d)\n",
+ ret_node->value, ret_node->seqnum,
+ node->value, node->seqnum);
+ call_rcu(&ret_node->rcu_head, free_node);
+ } else {
+ printf("Add (key: %d, seqnum: %d)\n",
+ node->value, node->seqnum);
+ }
+ rcu_read_unlock();
+ }
+
+ /*
+ * Iterate over each hash table node. Those will appear in
+ * random order, depending on the hash seed. Iteration needs to
+ * be performed within RCU read-side critical section.
+ */
+ printf("hash table content (random order):");
+ rcu_read_lock();
+ cds_lfht_for_each_entry(ht, &iter, node, node) {
+ printf(" (key: %d, seqnum: %d)",
+ node->value, node->seqnum);
+ }
+ rcu_read_unlock();
+ printf("\n");
+
+end:
+ rcu_unregister_thread();
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program for any
+ * purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is
+ * granted, provided the above notices are retained, and a notice that
+ * the code was modified is included with the above copyright notice.
+ *
+ * This example shows how to add unique nodes into a RCU lock-free hash
+ * table. We use a "seqnum" field to show which node is staying in the
+ * hash table. This hash table requires using a RCU scheme.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include <urcu.h> /* RCU flavor */
+#include <urcu/rculfhash.h> /* RCU Lock-free hash table */
+#include <urcu/compiler.h> /* For CAA_ARRAY_SIZE */
+#include "jhash.h" /* Example hash function */
+
+/*
+ * Nodes populated into the hash table.
+ */
+struct mynode {
+ int value; /* Node content */
+ int seqnum; /* Our node sequence number */
+ struct cds_lfht_node node; /* Chaining in hash table */
+};
+
+static
+int match(struct cds_lfht_node *ht_node, const void *_key)
+{
+ struct mynode *node =
+ caa_container_of(ht_node, struct mynode, node);
+ const unsigned int *key = _key;
+
+ return *key == node->value;
+}
+
+int main(int argc, char **argv)
+{
+ int values[] = { -5, 42, 42, 36, 24, }; /* 42 is duplicated */
+ struct cds_lfht *ht; /* Hash table */
+ unsigned int i;
+ int ret = 0, seqnum = 0;
+ uint32_t seed;
+ struct cds_lfht_iter iter; /* For iteration on hash table */
+ struct cds_lfht_node *ht_node;
+ struct mynode *node;
+
+ /*
+ * Each thread need using RCU read-side need to be explicitly
+ * registered.
+ */
+ rcu_register_thread();
+
+ /* Use time as seed for hash table hashing. */
+ seed = (uint32_t) time(NULL);
+
+ /*
+ * Allocate hash table.
+ */
+ ht = cds_lfht_new(1, 1, 0,
+ CDS_LFHT_AUTO_RESIZE | CDS_LFHT_ACCOUNTING,
+ NULL);
+ if (!ht) {
+ printf("Error allocating hash table\n");
+ ret = -1;
+ goto end;
+ }
+
+ /*
+ * Add nodes to hash table.
+ */
+ for (i = 0; i < CAA_ARRAY_SIZE(values); i++) {
+ unsigned long hash;
+ int value;
+
+ node = malloc(sizeof(*node));
+ if (!node) {
+ ret = -1;
+ goto end;
+ }
+
+ cds_lfht_node_init(&node->node);
+ value = values[i];
+ node->value = value;
+ node->seqnum = seqnum++;
+ hash = jhash(&value, sizeof(value), seed);
+
+ /*
+ * cds_lfht_add() needs to be called from RCU read-side
+ * critical section.
+ */
+ rcu_read_lock();
+ ht_node = cds_lfht_add_unique(ht, hash, match, &value,
+ &node->node);
+ /*
+ * cds_lfht_add_unique() returns the added node if not
+ * already present, else returns the node matching the
+ * key.
+ */
+ if (ht_node != &node->node) {
+ /*
+ * We found a match. Therefore, to ensure we
+ * don't add duplicates, cds_lfht_add_unique()
+ * acted as a RCU lookup, returning the found
+ * match. It did not add the new node to the
+ * hash table, so we can free it on the spot.
+ */
+ printf("Not adding duplicate (key: %d, seqnum: %d)\n",
+ node->value, node->seqnum);
+ free(node);
+ } else {
+ printf("Add (key: %d, seqnum: %d)\n",
+ node->value, node->seqnum);
+ }
+ rcu_read_unlock();
+ }
+
+ /*
+ * Iterate over each hash table node. Those will appear in
+ * random order, depending on the hash seed. Iteration needs to
+ * be performed within RCU read-side critical section.
+ */
+ printf("hash table content (random order):");
+ rcu_read_lock();
+ cds_lfht_for_each_entry(ht, &iter, node, node) {
+ printf(" (key: %d, seqnum: %d)",
+ node->value, node->seqnum);
+ }
+ rcu_read_unlock();
+ printf("\n");
+
+end:
+ rcu_unregister_thread();
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program for any
+ * purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is
+ * granted, provided the above notices are retained, and a notice that
+ * the code was modified is included with the above copyright notice.
+ *
+ * This example shows how to remove nodes from a RCU lock-free hash table.
+ * This hash table requires using a RCU scheme.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include <urcu.h> /* RCU flavor */
+#include <urcu/rculfhash.h> /* RCU Lock-free hash table */
+#include <urcu/compiler.h> /* For CAA_ARRAY_SIZE */
+#include "jhash.h" /* Example hash function */
+
+/*
+ * Nodes populated into the hash table.
+ */
+struct mynode {
+ int value; /* Node content */
+ struct cds_lfht_node node; /* Chaining in hash table */
+ struct rcu_head rcu_head; /* For call_rcu() */
+};
+
+static
+int match(struct cds_lfht_node *ht_node, const void *_key)
+{
+ struct mynode *node =
+ caa_container_of(ht_node, struct mynode, node);
+ const unsigned int *key = _key;
+
+ return *key == node->value;
+}
+
+static
+void free_node(struct rcu_head *head)
+{
+ struct mynode *node = caa_container_of(head, struct mynode, rcu_head);
+
+ free(node);
+}
+
+int main(int argc, char **argv)
+{
+ int values[] = { -5, 42, 42, 36, 24, }; /* 42 is duplicated */
+ int remove_values[] = { 42, 36, 24, 123, };
+ struct cds_lfht *ht; /* Hash table */
+ unsigned int i;
+ int ret = 0;
+ uint32_t seed;
+ struct cds_lfht_iter iter; /* For iteration on hash table */
+ struct cds_lfht_node *ht_node;
+ struct mynode *node;
+
+ /*
+ * Each thread need using RCU read-side need to be explicitly
+ * registered.
+ */
+ rcu_register_thread();
+
+ /* Use time as seed for hash table hashing. */
+ seed = (uint32_t) time(NULL);
+
+ /*
+ * Allocate hash table.
+ */
+ ht = cds_lfht_new(1, 1, 0,
+ CDS_LFHT_AUTO_RESIZE | CDS_LFHT_ACCOUNTING,
+ NULL);
+ if (!ht) {
+ printf("Error allocating hash table\n");
+ ret = -1;
+ goto end;
+ }
+
+ /*
+ * Add nodes to hash table.
+ */
+ for (i = 0; i < CAA_ARRAY_SIZE(values); i++) {
+ unsigned long hash;
+ int value;
+
+ node = malloc(sizeof(*node));
+ if (!node) {
+ ret = -1;
+ goto end;
+ }
+
+ cds_lfht_node_init(&node->node);
+ value = values[i];
+ node->value = value;
+ hash = jhash(&value, sizeof(value), seed);
+
+ /*
+ * cds_lfht_add() needs to be called from RCU read-side
+ * critical section.
+ */
+ rcu_read_lock();
+ cds_lfht_add(ht, hash, &node->node);
+ rcu_read_unlock();
+ }
+
+ /*
+ * Iterate over each hash table node. Those will appear in
+ * random order, depending on the hash seed. Iteration needs to
+ * be performed within RCU read-side critical section.
+ */
+ printf("hash table content (random order):");
+ rcu_read_lock();
+ cds_lfht_for_each_entry(ht, &iter, node, node) {
+ printf(" %d", node->value);
+ }
+ rcu_read_unlock();
+ printf("\n");
+
+ /*
+ * Remove one node for each key, if such a node is present.
+ */
+ printf("removing keys (single key, not duplicates):");
+ for (i = 0; i < CAA_ARRAY_SIZE(remove_values); i++) {
+ unsigned long hash;
+ int value;
+
+ value = remove_values[i];
+ hash = jhash(&value, sizeof(value), seed);
+ printf(" %d", value);
+ rcu_read_lock();
+ cds_lfht_lookup(ht, hash, match, &value, &iter);
+ ht_node = cds_lfht_iter_get_node(&iter);
+ if (ht_node) {
+ ret = cds_lfht_del(ht, ht_node);
+ if (ret) {
+ printf(" (concurrently deleted)");
+ } else {
+ struct mynode *del_node =
+ caa_container_of(ht_node,
+ struct mynode, node);
+ call_rcu(&del_node->rcu_head, free_node);
+ }
+ } else {
+ printf(" (not found)");
+ }
+ rcu_read_unlock();
+ }
+ printf("\n");
+
+ printf("hash table content (random order):");
+ rcu_read_lock();
+ cds_lfht_for_each_entry(ht, &iter, node, node) {
+ printf(" %d", node->value);
+ }
+ rcu_read_unlock();
+ printf("\n");
+
+end:
+ rcu_unregister_thread();
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program for any
+ * purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is
+ * granted, provided the above notices are retained, and a notice that
+ * the code was modified is included with the above copyright notice.
+ *
+ * This example shows how to use cds_lfht_destroy() to clear memory used
+ * by a a RCU lock-free hash table. This hash table requires using a
+ * RCU scheme.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include <urcu.h> /* RCU flavor */
+#include <urcu/rculfhash.h> /* RCU Lock-free hash table */
+#include <urcu/compiler.h> /* For CAA_ARRAY_SIZE */
+#include "jhash.h" /* Example hash function */
+
+/*
+ * Nodes populated into the hash table.
+ */
+struct mynode {
+ int value; /* Node content */
+ struct cds_lfht_node node; /* Chaining in hash table */
+ struct rcu_head rcu_head; /* For call_rcu() */
+};
+
+static
+void free_node(struct rcu_head *head)
+{
+ struct mynode *node = caa_container_of(head, struct mynode, rcu_head);
+
+ free(node);
+}
+
+int main(int argc, char **argv)
+{
+ int values[] = { -5, 42, 42, 36, 24, }; /* 42 is duplicated */
+ struct cds_lfht *ht; /* Hash table */
+ unsigned int i;
+ int ret = 0;
+ uint32_t seed;
+ struct cds_lfht_iter iter; /* For iteration on hash table */
+ struct cds_lfht_node *ht_node;
+ struct mynode *node;
+
+ /*
+ * Each thread need using RCU read-side need to be explicitly
+ * registered.
+ */
+ rcu_register_thread();
+
+ /* Use time as seed for hash table hashing. */
+ seed = (uint32_t) time(NULL);
+
+ /*
+ * Allocate hash table.
+ */
+ ht = cds_lfht_new(1, 1, 0,
+ CDS_LFHT_AUTO_RESIZE | CDS_LFHT_ACCOUNTING,
+ NULL);
+ if (!ht) {
+ printf("Error allocating hash table\n");
+ ret = -1;
+ goto end;
+ }
+
+ /*
+ * Add nodes to hash table.
+ */
+ for (i = 0; i < CAA_ARRAY_SIZE(values); i++) {
+ unsigned long hash;
+ int value;
+
+ node = malloc(sizeof(*node));
+ if (!node) {
+ ret = -1;
+ goto end;
+ }
+
+ cds_lfht_node_init(&node->node);
+ value = values[i];
+ node->value = value;
+ hash = jhash(&value, sizeof(value), seed);
+
+ /*
+ * cds_lfht_add() needs to be called from RCU read-side
+ * critical section.
+ */
+ rcu_read_lock();
+ cds_lfht_add(ht, hash, &node->node);
+ rcu_read_unlock();
+ }
+
+ /*
+ * Iterate over each hash table node. Those will appear in
+ * random order, depending on the hash seed. Iteration needs to
+ * be performed within RCU read-side critical section.
+ */
+ printf("hash table content (random order):");
+ rcu_read_lock();
+ cds_lfht_for_each_entry(ht, &iter, node, node) {
+ printf(" %d", node->value);
+ }
+ rcu_read_unlock();
+ printf("\n");
+
+
+ /*
+ * Make sure all hash table nodes are removed before destroying.
+ */
+ printf("removing all nodes:");
+ rcu_read_lock();
+ cds_lfht_for_each_entry(ht, &iter, node, node) {
+ ht_node = cds_lfht_iter_get_node(&iter);
+ ret = cds_lfht_del(ht, ht_node);
+ printf(" %d", node->value);
+ if (ret) {
+ printf(" (concurrently deleted)");
+ } else {
+ call_rcu(&node->rcu_head, free_node);
+ }
+ }
+ rcu_read_unlock();
+ printf("\n");
+
+ /*
+ * cds_lfht_destroy() must be called from a very specific
+ * context: it needs to be called from a registered RCU reader
+ * thread. However, this thread should _not_ be within a RCU
+ * read-side critical section. Also, it should _not_ be called
+ * from a call_rcu thread.
+ */
+ ret = cds_lfht_destroy(ht, NULL);
+ if (ret) {
+ printf("Destroying hash table failed\n");
+ }
+end:
+ rcu_unregister_thread();
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program for any
+ * purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is
+ * granted, provided the above notices are retained, and a notice that
+ * the code was modified is included with the above copyright notice.
+ *
+ * This example shows how to iterate on duplicate keys within a RCU
+ * lock-free hash table. This hash table requires using a RCU scheme.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include <urcu.h> /* RCU flavor */
+#include <urcu/rculfhash.h> /* RCU Lock-free hash table */
+#include <urcu/compiler.h> /* For CAA_ARRAY_SIZE */
+#include "jhash.h" /* Example hash function */
+
+/*
+ * Nodes populated into the hash table.
+ */
+struct mynode {
+ int value; /* Node content */
+ int seqnum; /* Our node sequence number */
+ struct cds_lfht_node node; /* Chaining in hash table */
+};
+
+static
+int match(struct cds_lfht_node *ht_node, const void *_key)
+{
+ struct mynode *node =
+ caa_container_of(ht_node, struct mynode, node);
+ const unsigned int *key = _key;
+
+ return *key == node->value;
+}
+
+int main(int argc, char **argv)
+{
+ int values[] = { -5, 42, 42, 36, 24, }; /* 42 is duplicated */
+ int lookup_values[] = { 42, 200, 36, };
+ struct cds_lfht *ht; /* Hash table */
+ unsigned int i;
+ int ret = 0, seqnum = 0;
+ uint32_t seed;
+ struct cds_lfht_iter iter; /* For iteration on hash table */
+ struct mynode *node;
+
+ /*
+ * Each thread need using RCU read-side need to be explicitly
+ * registered.
+ */
+ rcu_register_thread();
+
+ /* Use time as seed for hash table hashing. */
+ seed = (uint32_t) time(NULL);
+
+ /*
+ * Allocate hash table.
+ */
+ ht = cds_lfht_new(1, 1, 0,
+ CDS_LFHT_AUTO_RESIZE | CDS_LFHT_ACCOUNTING,
+ NULL);
+ if (!ht) {
+ printf("Error allocating hash table\n");
+ ret = -1;
+ goto end;
+ }
+
+ /*
+ * Add nodes to hash table.
+ */
+ for (i = 0; i < CAA_ARRAY_SIZE(values); i++) {
+ unsigned long hash;
+ int value;
+
+ node = malloc(sizeof(*node));
+ if (!node) {
+ ret = -1;
+ goto end;
+ }
+
+ cds_lfht_node_init(&node->node);
+ value = values[i];
+ node->value = value;
+ node->seqnum = seqnum++;
+ hash = jhash(&value, sizeof(value), seed);
+
+ /*
+ * cds_lfht_add() needs to be called from RCU read-side
+ * critical section.
+ */
+ rcu_read_lock();
+ cds_lfht_add(ht, hash, &node->node);
+ printf("Add (key: %d, seqnum: %d)\n",
+ node->value, node->seqnum);
+ rcu_read_unlock();
+ }
+
+ /*
+ * Iterate over each hash table node. Those will appear in
+ * random order, depending on the hash seed. Iteration needs to
+ * be performed within RCU read-side critical section.
+ */
+ printf("hash table content (random order):");
+ rcu_read_lock();
+ cds_lfht_for_each_entry(ht, &iter, node, node) {
+ printf(" (key: %d, seqnum: %d)",
+ node->value, node->seqnum);
+ }
+ rcu_read_unlock();
+ printf("\n");
+
+ /*
+ * Lookup queries. Note that which node (seqnum) within
+ * duplicates will be found by lookup is random.
+ */
+ printf("Lookups, with iteration on duplicates:\n");
+ for (i = 0; i < CAA_ARRAY_SIZE(lookup_values); i++) {
+ int value = lookup_values[i];
+ unsigned long hash = jhash(&value, sizeof(value), seed);
+
+ printf("lookup key: %d\n", value);
+ rcu_read_lock();
+ cds_lfht_for_each_entry_duplicate(ht, hash, match,
+ &value, &iter, node, node) {
+ printf(" (key %d, seqnum %d) found\n",
+ node->value, node->seqnum);
+ }
+ rcu_read_unlock();
+ }
+
+end:
+ rcu_unregister_thread();
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program for any
+ * purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is
+ * granted, provided the above notices are retained, and a notice that
+ * the code was modified is included with the above copyright notice.
+ *
+ * This example shows how to lookup keys within a RCU lock-free hash
+ * table. This hash table requires using a RCU scheme.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include <urcu.h> /* RCU flavor */
+#include <urcu/rculfhash.h> /* RCU Lock-free hash table */
+#include <urcu/compiler.h> /* For CAA_ARRAY_SIZE */
+#include "jhash.h" /* Example hash function */
+
+/*
+ * Nodes populated into the hash table.
+ */
+struct mynode {
+ int value; /* Node content */
+ int seqnum; /* Our node sequence number */
+ struct cds_lfht_node node; /* Chaining in hash table */
+};
+
+static
+int match(struct cds_lfht_node *ht_node, const void *_key)
+{
+ struct mynode *node =
+ caa_container_of(ht_node, struct mynode, node);
+ const unsigned int *key = _key;
+
+ return *key == node->value;
+}
+
+int main(int argc, char **argv)
+{
+ int values[] = { -5, 42, 42, 36, 24, }; /* 42 is duplicated */
+ int lookup_values[] = { 42, 200, 36, };
+ struct cds_lfht *ht; /* Hash table */
+ unsigned int i;
+ int ret = 0, seqnum = 0;
+ uint32_t seed;
+ struct cds_lfht_iter iter; /* For iteration on hash table */
+ struct cds_lfht_node *ht_node;
+ struct mynode *node;
+
+ /*
+ * Each thread need using RCU read-side need to be explicitly
+ * registered.
+ */
+ rcu_register_thread();
+
+ /* Use time as seed for hash table hashing. */
+ seed = (uint32_t) time(NULL);
+
+ /*
+ * Allocate hash table.
+ */
+ ht = cds_lfht_new(1, 1, 0,
+ CDS_LFHT_AUTO_RESIZE | CDS_LFHT_ACCOUNTING,
+ NULL);
+ if (!ht) {
+ printf("Error allocating hash table\n");
+ ret = -1;
+ goto end;
+ }
+
+ /*
+ * Add nodes to hash table.
+ */
+ for (i = 0; i < CAA_ARRAY_SIZE(values); i++) {
+ unsigned long hash;
+ int value;
+
+ node = malloc(sizeof(*node));
+ if (!node) {
+ ret = -1;
+ goto end;
+ }
+
+ cds_lfht_node_init(&node->node);
+ value = values[i];
+ node->value = value;
+ node->seqnum = seqnum++;
+ hash = jhash(&value, sizeof(value), seed);
+
+ /*
+ * cds_lfht_add() needs to be called from RCU read-side
+ * critical section.
+ */
+ rcu_read_lock();
+ cds_lfht_add(ht, hash, &node->node);
+ printf("Add (key: %d, seqnum: %d)\n",
+ node->value, node->seqnum);
+ rcu_read_unlock();
+ }
+
+ /*
+ * Iterate over each hash table node. Those will appear in
+ * random order, depending on the hash seed. Iteration needs to
+ * be performed within RCU read-side critical section.
+ */
+ printf("hash table content (random order):");
+ rcu_read_lock();
+ cds_lfht_for_each_entry(ht, &iter, node, node) {
+ printf(" (key: %d, seqnum: %d)",
+ node->value, node->seqnum);
+ }
+ rcu_read_unlock();
+ printf("\n");
+
+ /*
+ * Lookup queries. Note that which node (seqnum) within
+ * duplicates will be found by lookup is random.
+ */
+ printf("Lookups:\n");
+ for (i = 0; i < CAA_ARRAY_SIZE(lookup_values); i++) {
+ int value = lookup_values[i];
+ unsigned long hash = jhash(&value, sizeof(value), seed);
+
+ rcu_read_lock();
+ cds_lfht_lookup(ht, hash, match, &value, &iter);
+ ht_node = cds_lfht_iter_get_node(&iter);
+ if (!ht_node) {
+ printf("Key %d not found\n", value);
+ } else {
+ node = caa_container_of(ht_node, struct mynode, node);
+ printf("(key %d, seqnum %d) found\n",
+ node->value, node->seqnum);
+ }
+ rcu_read_unlock();
+ }
+
+end:
+ rcu_unregister_thread();
+ return ret;
+}
--- /dev/null
+#ifndef _JHASH_H
+#define _JHASH_H
+
+/*
+ * jhash.h
+ *
+ * Example hash function.
+ *
+ * Copyright 2009-2012 - Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program for any
+ * purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is
+ * granted, provided the above notices are retained, and a notice that
+ * the code was modified is included with the above copyright notice.
+ */
+
+/*
+ * Hash function
+ * Source: http://burtleburtle.net/bob/c/lookup3.c
+ * Originally Public Domain
+ */
+
+#define rot(x, k) (((x) << (k)) | ((x) >> (32 - (k))))
+
+#define mix(a, b, c) \
+do { \
+ a -= c; a ^= rot(c, 4); c += b; \
+ b -= a; b ^= rot(a, 6); a += c; \
+ c -= b; c ^= rot(b, 8); b += a; \
+ a -= c; a ^= rot(c, 16); c += b; \
+ b -= a; b ^= rot(a, 19); a += c; \
+ c -= b; c ^= rot(b, 4); b += a; \
+} while (0)
+
+#define final(a, b, c) \
+{ \
+ c ^= b; c -= rot(b, 14); \
+ a ^= c; a -= rot(c, 11); \
+ b ^= a; b -= rot(a, 25); \
+ c ^= b; c -= rot(b, 16); \
+ a ^= c; a -= rot(c, 4); \
+ b ^= a; b -= rot(a, 14); \
+ c ^= b; c -= rot(b, 24); \
+}
+
+#if (BYTE_ORDER == LITTLE_ENDIAN)
+#define HASH_LITTLE_ENDIAN 1
+#else
+#define HASH_LITTLE_ENDIAN 0
+#endif
+
+/*
+ *
+ * hashlittle() -- hash a variable-length key into a 32-bit value
+ * k : the key (the unaligned variable-length array of bytes)
+ * length : the length of the key, counting by bytes
+ * initval : can be any 4-byte value
+ * Returns a 32-bit value. Every bit of the key affects every bit of
+ * the return value. Two keys differing by one or two bits will have
+ * totally different hash values.
+ *
+ * The best hash table sizes are powers of 2. There is no need to do
+ * mod a prime (mod is sooo slow!). If you need less than 32 bits,
+ * use a bitmask. For example, if you need only 10 bits, do
+ * h = (h & hashmask(10));
+ * In which case, the hash table should have hashsize(10) elements.
+ *
+ * If you are hashing n strings (uint8_t **)k, do it like this:
+ * for (i = 0, h = 0; i < n; ++i) h = hashlittle(k[i], len[i], h);
+ *
+ * By Bob Jenkins, 2006. bob_jenkins@burtleburtle.net. You may use this
+ * code any way you wish, private, educational, or commercial. It's free.
+ *
+ * Use for hash table lookup, or anything where one collision in 2^^32 is
+ * acceptable. Do NOT use for cryptographic purposes.
+ */
+static
+uint32_t hashlittle(const void *key, size_t length, uint32_t initval)
+{
+ uint32_t a, b, c; /* internal state */
+ union {
+ const void *ptr;
+ size_t i;
+ } u;
+
+ /* Set up the internal state */
+ a = b = c = 0xdeadbeef + ((uint32_t)length) + initval;
+
+ u.ptr = key;
+ if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) {
+ const uint32_t *k = (const uint32_t *) key; /* read 32-bit chunks */
+
+ /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
+ while (length > 12) {
+ a += k[0];
+ b += k[1];
+ c += k[2];
+ mix(a, b, c);
+ length -= 12;
+ k += 3;
+ }
+
+ /*----------------------------- handle the last (probably partial) block */
+ /*
+ * "k[2]&0xffffff" actually reads beyond the end of the string, but
+ * then masks off the part it's not allowed to read. Because the
+ * string is aligned, the masked-off tail is in the same word as the
+ * rest of the string. Every machine with memory protection I've seen
+ * does it on word boundaries, so is OK with this. But VALGRIND will
+ * still catch it and complain. The masking trick does make the hash
+ * noticably faster for short strings (like English words).
+ */
+#ifndef VALGRIND
+
+ switch (length) {
+ case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+ case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break;
+ case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break;
+ case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break;
+ case 8 : b+=k[1]; a+=k[0]; break;
+ case 7 : b+=k[1]&0xffffff; a+=k[0]; break;
+ case 6 : b+=k[1]&0xffff; a+=k[0]; break;
+ case 5 : b+=k[1]&0xff; a+=k[0]; break;
+ case 4 : a+=k[0]; break;
+ case 3 : a+=k[0]&0xffffff; break;
+ case 2 : a+=k[0]&0xffff; break;
+ case 1 : a+=k[0]&0xff; break;
+ case 0 : return c; /* zero length strings require no mixing */
+ }
+
+#else /* make valgrind happy */
+ {
+ const uint8_t *k8;
+
+ k8 = (const uint8_t *) k;
+ switch (length) {
+ case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+ case 11: c+=((uint32_t) k8[10])<<16; /* fall through */
+ case 10: c+=((uint32_t) k8[9])<<8; /* fall through */
+ case 9 : c+=k8[8]; /* fall through */
+ case 8 : b+=k[1]; a+=k[0]; break;
+ case 7 : b+=((uint32_t) k8[6])<<16; /* fall through */
+ case 6 : b+=((uint32_t) k8[5])<<8; /* fall through */
+ case 5 : b+=k8[4]; /* fall through */
+ case 4 : a+=k[0]; break;
+ case 3 : a+=((uint32_t) k8[2])<<16; /* fall through */
+ case 2 : a+=((uint32_t) k8[1])<<8; /* fall through */
+ case 1 : a+=k8[0]; break;
+ case 0 : return c;
+ }
+ }
+#endif /* !valgrind */
+
+ } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) {
+ const uint16_t *k = (const uint16_t *) key; /* read 16-bit chunks */
+ const uint8_t *k8;
+
+ /*--------------- all but last block: aligned reads and different mixing */
+ while (length > 12)
+ {
+ a += k[0] + (((uint32_t) k[1])<<16);
+ b += k[2] + (((uint32_t) k[3])<<16);
+ c += k[4] + (((uint32_t) k[5])<<16);
+ mix(a, b, c);
+ length -= 12;
+ k += 6;
+ }
+
+ /*----------------------------- handle the last (probably partial) block */
+ k8 = (const uint8_t *) k;
+ switch(length)
+ {
+ case 12: c+=k[4]+(((uint32_t) k[5])<<16);
+ b+=k[2]+(((uint32_t) k[3])<<16);
+ a+=k[0]+(((uint32_t) k[1])<<16);
+ break;
+ case 11: c+=((uint32_t) k8[10])<<16; /* fall through */
+ case 10: c+=k[4];
+ b+=k[2]+(((uint32_t) k[3])<<16);
+ a+=k[0]+(((uint32_t) k[1])<<16);
+ break;
+ case 9 : c+=k8[8]; /* fall through */
+ case 8 : b+=k[2]+(((uint32_t) k[3])<<16);
+ a+=k[0]+(((uint32_t) k[1])<<16);
+ break;
+ case 7 : b+=((uint32_t) k8[6])<<16; /* fall through */
+ case 6 : b+=k[2];
+ a+=k[0]+(((uint32_t) k[1])<<16);
+ break;
+ case 5 : b+=k8[4]; /* fall through */
+ case 4 : a+=k[0]+(((uint32_t) k[1])<<16);
+ break;
+ case 3 : a+=((uint32_t) k8[2])<<16; /* fall through */
+ case 2 : a+=k[0];
+ break;
+ case 1 : a+=k8[0];
+ break;
+ case 0 : return c; /* zero length requires no mixing */
+ }
+
+ } else { /* need to read the key one byte at a time */
+ const uint8_t *k = (const uint8_t *)key;
+
+ /*--------------- all but the last block: affect some 32 bits of (a, b, c) */
+ while (length > 12) {
+ a += k[0];
+ a += ((uint32_t) k[1])<<8;
+ a += ((uint32_t) k[2])<<16;
+ a += ((uint32_t) k[3])<<24;
+ b += k[4];
+ b += ((uint32_t) k[5])<<8;
+ b += ((uint32_t) k[6])<<16;
+ b += ((uint32_t) k[7])<<24;
+ c += k[8];
+ c += ((uint32_t) k[9])<<8;
+ c += ((uint32_t) k[10])<<16;
+ c += ((uint32_t) k[11])<<24;
+ mix(a,b,c);
+ length -= 12;
+ k += 12;
+ }
+
+ /*-------------------------------- last block: affect all 32 bits of (c) */
+ switch (length) { /* all the case statements fall through */
+ case 12: c+=((uint32_t) k[11])<<24;
+ case 11: c+=((uint32_t) k[10])<<16;
+ case 10: c+=((uint32_t) k[9])<<8;
+ case 9 : c+=k[8];
+ case 8 : b+=((uint32_t) k[7])<<24;
+ case 7 : b+=((uint32_t) k[6])<<16;
+ case 6 : b+=((uint32_t) k[5])<<8;
+ case 5 : b+=k[4];
+ case 4 : a+=((uint32_t) k[3])<<24;
+ case 3 : a+=((uint32_t) k[2])<<16;
+ case 2 : a+=((uint32_t) k[1])<<8;
+ case 1 : a+=k[0];
+ break;
+ case 0 : return c;
+ }
+ }
+
+ final(a, b, c);
+ return c;
+}
+
+static inline
+uint32_t jhash(const void *key, size_t length, uint32_t seed)
+{
+ return hashlittle(key, length, seed);
+}
+
+#endif /* _JHASH_H */
--- /dev/null
+# Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+#
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+#
+# Permission is hereby granted to use or copy this program for any
+# purpose, provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is
+# granted, provided the above notices are retained, and a notice that
+# the code was modified is included with the above copyright notice.
+#
+# This makefile is purposefully kept simple to support GNU and BSD make.
+
+all:
+ $(MAKE) -f Makefile.cds_lfq_enqueue
+ $(MAKE) -f Makefile.cds_lfq_dequeue
+
+.PHONY: clean
+clean:
+ $(MAKE) -f Makefile.cds_lfq_enqueue clean
+ $(MAKE) -f Makefile.cds_lfq_dequeue clean
--- /dev/null
+# Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+#
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+#
+# Permission is hereby granted to use or copy this program for any
+# purpose, provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is
+# granted, provided the above notices are retained, and a notice that
+# the code was modified is included with the above copyright notice.
+#
+# This makefile is purposefully kept simple to support GNU and BSD make.
+
+EXAMPLE_NAME = cds_lfq_dequeue
+
+SOURCES = $(EXAMPLE_NAME).c
+OBJECTS = $(EXAMPLE_NAME).o
+BINARY = $(EXAMPLE_NAME)
+LIBS = -lurcu-cds -lurcu
+
+include ../Makefile.examples.template
--- /dev/null
+# Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+#
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+#
+# Permission is hereby granted to use or copy this program for any
+# purpose, provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is
+# granted, provided the above notices are retained, and a notice that
+# the code was modified is included with the above copyright notice.
+#
+# This makefile is purposefully kept simple to support GNU and BSD make.
+
+EXAMPLE_NAME = cds_lfq_enqueue
+
+SOURCES = $(EXAMPLE_NAME).c
+OBJECTS = $(EXAMPLE_NAME).o
+BINARY = $(EXAMPLE_NAME)
+LIBS = -lurcu-cds -lurcu
+
+include ../Makefile.examples.template
--- /dev/null
+/*
+ * Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program for any
+ * purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is
+ * granted, provided the above notices are retained, and a notice that
+ * the code was modified is included with the above copyright notice.
+ *
+ * This example shows how to dequeue nodes from a RCU lock-free queue.
+ * This queue requires using a RCU scheme.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <urcu.h> /* RCU flavor */
+#include <urcu/rculfqueue.h> /* RCU Lock-free queue */
+#include <urcu/compiler.h> /* For CAA_ARRAY_SIZE */
+
+/*
+ * Nodes populated into the queue.
+ */
+struct mynode {
+ int value; /* Node content */
+ struct cds_lfq_node_rcu node; /* Chaining in queue */
+ struct rcu_head rcu_head; /* For call_rcu() */
+};
+
+static
+void free_node(struct rcu_head *head)
+{
+ struct mynode *node =
+ caa_container_of(head, struct mynode, rcu_head);
+
+ free(node);
+}
+
+int main(int argc, char **argv)
+{
+ int values[] = { -5, 42, 36, 24, };
+ struct cds_lfq_queue_rcu myqueue; /* Queue */
+ unsigned int i;
+ int ret = 0;
+
+ /*
+ * Each thread need using RCU read-side need to be explicitly
+ * registered.
+ */
+ rcu_register_thread();
+
+ cds_lfq_init_rcu(&myqueue, call_rcu);
+
+ /*
+ * Enqueue nodes.
+ */
+ for (i = 0; i < CAA_ARRAY_SIZE(values); i++) {
+ struct mynode *node;
+
+ node = malloc(sizeof(*node));
+ if (!node) {
+ ret = -1;
+ goto end;
+ }
+
+ cds_lfq_node_init_rcu(&node->node);
+ node->value = values[i];
+ /*
+ * Both enqueue and dequeue need to be called within RCU
+ * read-side critical section.
+ */
+ rcu_read_lock();
+ cds_lfq_enqueue_rcu(&myqueue, &node->node);
+ rcu_read_unlock();
+ }
+
+ /*
+ * Dequeue each node from the queue. Those will be dequeued from
+ * the oldest (first enqueued) to the newest (last enqueued).
+ */
+ printf("dequeued content:");
+ for (;;) {
+ struct cds_lfq_node_rcu *qnode;
+ struct mynode *node;
+
+ /*
+ * Both enqueue and dequeue need to be called within RCU
+ * read-side critical section.
+ */
+ rcu_read_lock();
+ qnode = cds_lfq_dequeue_rcu(&myqueue);
+ rcu_read_unlock();
+ if (!qnode) {
+ break; /* Queue is empty. */
+ }
+ /* Getting the container structure from the node */
+ node = caa_container_of(qnode, struct mynode, node);
+ printf(" %d", node->value);
+ call_rcu(&node->rcu_head, free_node);
+ }
+ printf("\n");
+ /*
+ * Release memory used by the queue.
+ */
+ ret = cds_lfq_destroy_rcu(&myqueue);
+ if (ret) {
+ printf("Error destroying queue (non-empty)\n");
+ }
+end:
+ rcu_unregister_thread();
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program for any
+ * purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is
+ * granted, provided the above notices are retained, and a notice that
+ * the code was modified is included with the above copyright notice.
+ *
+ * This example shows how to enqueue nodes into a RCU lock-free queue.
+ * This queue requires using a RCU scheme.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <urcu.h> /* RCU flavor */
+#include <urcu/rculfqueue.h> /* RCU Lock-free queue */
+#include <urcu/compiler.h> /* For CAA_ARRAY_SIZE */
+
+/*
+ * Nodes populated into the queue.
+ */
+struct mynode {
+ int value; /* Node content */
+ struct cds_lfq_node_rcu node; /* Chaining in queue */
+};
+
+int main(int argc, char **argv)
+{
+ int values[] = { -5, 42, 36, 24, };
+ struct cds_lfq_queue_rcu myqueue; /* Queue */
+ unsigned int i;
+ int ret = 0;
+
+ /*
+ * Each thread need using RCU read-side need to be explicitly
+ * registered.
+ */
+ rcu_register_thread();
+
+ cds_lfq_init_rcu(&myqueue, call_rcu);
+
+ /*
+ * Enqueue nodes.
+ */
+ for (i = 0; i < CAA_ARRAY_SIZE(values); i++) {
+ struct mynode *node;
+
+ node = malloc(sizeof(*node));
+ if (!node) {
+ ret = -1;
+ goto end;
+ }
+
+ cds_lfq_node_init_rcu(&node->node);
+ node->value = values[i];
+ /*
+ * Both enqueue and dequeue need to be called within RCU
+ * read-side critical section.
+ */
+ rcu_read_lock();
+ cds_lfq_enqueue_rcu(&myqueue, &node->node);
+ rcu_read_unlock();
+ }
+
+end:
+ rcu_unregister_thread();
+ return ret;
+}
--- /dev/null
+# Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+#
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+#
+# Permission is hereby granted to use or copy this program for any
+# purpose, provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is
+# granted, provided the above notices are retained, and a notice that
+# the code was modified is included with the above copyright notice.
+#
+# This makefile is purposefully kept simple to support GNU and BSD make.
+
+all:
+ $(MAKE) -f Makefile.qsbr
+ $(MAKE) -f Makefile.mb
+ $(MAKE) -f Makefile.membarrier
+ $(MAKE) -f Makefile.signal
+ $(MAKE) -f Makefile.bp
+
+.PHONY: clean
+clean:
+ $(MAKE) -f Makefile.qsbr clean
+ $(MAKE) -f Makefile.mb clean
+ $(MAKE) -f Makefile.membarrier clean
+ $(MAKE) -f Makefile.signal clean
+ $(MAKE) -f Makefile.bp clean
--- /dev/null
+# Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+#
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+#
+# Permission is hereby granted to use or copy this program for any
+# purpose, provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is
+# granted, provided the above notices are retained, and a notice that
+# the code was modified is included with the above copyright notice.
+#
+# This makefile is purposefully kept simple to support GNU and BSD make.
+
+EXAMPLE_NAME = bp
+
+SOURCES = $(EXAMPLE_NAME).c
+OBJECTS = $(EXAMPLE_NAME).o
+BINARY = $(EXAMPLE_NAME)
+LIBS = -lurcu-bp
+
+include ../Makefile.examples.template
--- /dev/null
+# Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+#
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+#
+# Permission is hereby granted to use or copy this program for any
+# purpose, provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is
+# granted, provided the above notices are retained, and a notice that
+# the code was modified is included with the above copyright notice.
+#
+# This makefile is purposefully kept simple to support GNU and BSD make.
+
+EXAMPLE_NAME = mb
+
+SOURCES = $(EXAMPLE_NAME).c
+OBJECTS = $(EXAMPLE_NAME).o
+BINARY = $(EXAMPLE_NAME)
+LIBS = -lurcu-mb
+
+include ../Makefile.examples.template
--- /dev/null
+# Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+#
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+#
+# Permission is hereby granted to use or copy this program for any
+# purpose, provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is
+# granted, provided the above notices are retained, and a notice that
+# the code was modified is included with the above copyright notice.
+#
+# This makefile is purposefully kept simple to support GNU and BSD make.
+
+EXAMPLE_NAME = membarrier
+
+SOURCES = $(EXAMPLE_NAME).c
+OBJECTS = $(EXAMPLE_NAME).o
+BINARY = $(EXAMPLE_NAME)
+LIBS = -lurcu
+
+include ../Makefile.examples.template
--- /dev/null
+# Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+#
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+#
+# Permission is hereby granted to use or copy this program for any
+# purpose, provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is
+# granted, provided the above notices are retained, and a notice that
+# the code was modified is included with the above copyright notice.
+#
+# This makefile is purposefully kept simple to support GNU and BSD make.
+
+EXAMPLE_NAME = qsbr
+
+SOURCES = $(EXAMPLE_NAME).c
+OBJECTS = $(EXAMPLE_NAME).o
+BINARY = $(EXAMPLE_NAME)
+LIBS = -lurcu-qsbr
+
+include ../Makefile.examples.template
--- /dev/null
+# Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+#
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+#
+# Permission is hereby granted to use or copy this program for any
+# purpose, provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is
+# granted, provided the above notices are retained, and a notice that
+# the code was modified is included with the above copyright notice.
+#
+# This makefile is purposefully kept simple to support GNU and BSD make.
+
+EXAMPLE_NAME = signal
+
+SOURCES = $(EXAMPLE_NAME).c
+OBJECTS = $(EXAMPLE_NAME).o
+BINARY = $(EXAMPLE_NAME)
+LIBS = -lurcu-signal
+
+include ../Makefile.examples.template
--- /dev/null
+/*
+ * Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <inttypes.h>
+
+#include <urcu-bp.h> /* Bulletproof RCU flavor */
+#include <urcu/rculist.h> /* List example */
+#include <urcu/compiler.h> /* For CAA_ARRAY_SIZE */
+
+/*
+ * Example showing how to use the Bulletproof Userspace RCU flavor.
+ *
+ * This is a mock-up example where updates and RCU traversals are
+ * performed by the same thread to keep things simple on purpose.
+ */
+
+static CDS_LIST_HEAD(mylist);
+
+struct mynode {
+ uint64_t value;
+ struct cds_list_head node; /* linked-list chaining */
+ struct rcu_head rcu_head; /* for call_rcu() */
+};
+
+static
+int add_node(uint64_t v)
+{
+ struct mynode *node;
+
+ node = calloc(sizeof(*node), 1);
+ if (!node)
+ return -1;
+ node->value = v;
+ cds_list_add_rcu(&node->node, &mylist);
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ uint64_t values[] = { 42, 36, 24, };
+ unsigned int i;
+ int ret;
+ struct mynode *node, *n;
+
+ /*
+ * Notice that with the bulletproof flavor, there is no need to
+ * register/unregister RCU reader threads.
+ */
+
+ /*
+ * Adding nodes to the linked-list. Safe against concurrent
+ * RCU traversals, require mutual exclusion with list updates.
+ */
+ for (i = 0; i < CAA_ARRAY_SIZE(values); i++) {
+ ret = add_node(values[i]);
+ if (ret)
+ goto end;
+ }
+
+ /*
+ * We need to explicitly mark RCU read-side critical sections
+ * with rcu_read_lock() and rcu_read_unlock(). They can be
+ * nested. Those are no-ops for the QSBR flavor.
+ */
+ rcu_read_lock();
+
+ /*
+ * RCU traversal of the linked list.
+ */
+ cds_list_for_each_entry_rcu(node, &mylist, node) {
+ printf("Value: %" PRIu64 "\n", node->value);
+ }
+ rcu_read_unlock();
+
+ /*
+ * Removing nodes from linked list. Safe against concurrent RCU
+ * traversals, require mutual exclusion with list updates.
+ */
+ cds_list_for_each_entry_safe(node, n, &mylist, node) {
+ cds_list_del_rcu(&node->node);
+
+ /*
+ * Using synchronize_rcu() directly for synchronization
+ * so we keep a minimal impact on the system by not
+ * spawning any call_rcu() thread. It is slower though,
+ * since there is no batching.
+ */
+ synchronize_rcu();
+ free(node);
+ }
+
+ sleep(1);
+
+end:
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <inttypes.h>
+
+#define RCU_MB /* Memory barrier RCU flavor */
+#include <urcu.h>
+#include <urcu/rculist.h> /* List example */
+#include <urcu/compiler.h> /* For CAA_ARRAY_SIZE */
+
+/*
+ * Example showing how to use the memory-barrier-based Userspace RCU
+ * flavor.
+ *
+ * This is a mock-up example where updates and RCU traversals are
+ * performed by the same thread to keep things simple on purpose.
+ */
+
+static CDS_LIST_HEAD(mylist);
+
+struct mynode {
+ uint64_t value;
+ struct cds_list_head node; /* linked-list chaining */
+ struct rcu_head rcu_head; /* for call_rcu() */
+};
+
+static
+int add_node(uint64_t v)
+{
+ struct mynode *node;
+
+ node = calloc(sizeof(*node), 1);
+ if (!node)
+ return -1;
+ node->value = v;
+ cds_list_add_rcu(&node->node, &mylist);
+ return 0;
+}
+
+static
+void rcu_free_node(struct rcu_head *rh)
+{
+ struct mynode *node = caa_container_of(rh, struct mynode, rcu_head);
+
+ free(node);
+}
+
+int main(int argc, char **argv)
+{
+ uint64_t values[] = { 42, 36, 24, };
+ unsigned int i;
+ int ret;
+ struct mynode *node, *n;
+
+ /*
+ * Each thread need using RCU read-side need to be explicitly
+ * registered.
+ */
+ rcu_register_thread();
+
+ /*
+ * Adding nodes to the linked-list. Safe against concurrent
+ * RCU traversals, require mutual exclusion with list updates.
+ */
+ for (i = 0; i < CAA_ARRAY_SIZE(values); i++) {
+ ret = add_node(values[i]);
+ if (ret)
+ goto end;
+ }
+
+ /*
+ * We need to explicitly mark RCU read-side critical sections
+ * with rcu_read_lock() and rcu_read_unlock(). They can be
+ * nested. Those are no-ops for the QSBR flavor.
+ */
+ rcu_read_lock();
+
+ /*
+ * RCU traversal of the linked list.
+ */
+ cds_list_for_each_entry_rcu(node, &mylist, node) {
+ printf("Value: %" PRIu64 "\n", node->value);
+ }
+ rcu_read_unlock();
+
+ /*
+ * Removing nodes from linked list. Safe against concurrent RCU
+ * traversals, require mutual exclusion with list updates.
+ */
+ cds_list_for_each_entry_safe(node, n, &mylist, node) {
+ cds_list_del_rcu(&node->node);
+ /*
+ * call_rcu() will ensure that the handler
+ * "rcu_free_node" is executed after a grace period.
+ * call_rcu() can be called from RCU read-side critical
+ * sections.
+ */
+ call_rcu(&node->rcu_head, rcu_free_node);
+ }
+
+ /*
+ * We can also wait for a quiescent state by calling
+ * synchronize_rcu() rather than using call_rcu(). It is usually
+ * a slower approach than call_rcu(), because the latter can
+ * batch work. Moreover, call_rcu() can be called from a RCU
+ * read-side critical section, but synchronize_rcu() should not.
+ */
+ synchronize_rcu();
+
+ sleep(1);
+
+ /*
+ * Waiting for previously called call_rcu handlers to complete
+ * before program exits, or in library destructors, is a good
+ * practice.
+ */
+ rcu_barrier();
+
+end:
+ rcu_unregister_thread();
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <inttypes.h>
+
+#include <urcu.h> /* Default: sys_membarrier() RCU flavor */
+#include <urcu/rculist.h> /* List example */
+#include <urcu/compiler.h> /* For CAA_ARRAY_SIZE */
+
+/*
+ * Example showing how to use the sys_membarrier()-based Userspace RCU
+ * flavor.
+ *
+ * This is a mock-up example where updates and RCU traversals are
+ * performed by the same thread to keep things simple on purpose.
+ */
+
+static CDS_LIST_HEAD(mylist);
+
+struct mynode {
+ uint64_t value;
+ struct cds_list_head node; /* linked-list chaining */
+ struct rcu_head rcu_head; /* for call_rcu() */
+};
+
+static
+int add_node(uint64_t v)
+{
+ struct mynode *node;
+
+ node = calloc(sizeof(*node), 1);
+ if (!node)
+ return -1;
+ node->value = v;
+ cds_list_add_rcu(&node->node, &mylist);
+ return 0;
+}
+
+static
+void rcu_free_node(struct rcu_head *rh)
+{
+ struct mynode *node = caa_container_of(rh, struct mynode, rcu_head);
+
+ free(node);
+}
+
+int main(int argc, char **argv)
+{
+ uint64_t values[] = { 42, 36, 24, };
+ unsigned int i;
+ int ret;
+ struct mynode *node, *n;
+
+ /*
+ * Each thread need using RCU read-side need to be explicitly
+ * registered.
+ */
+ rcu_register_thread();
+
+ /*
+ * Adding nodes to the linked-list. Safe against concurrent
+ * RCU traversals, require mutual exclusion with list updates.
+ */
+ for (i = 0; i < CAA_ARRAY_SIZE(values); i++) {
+ ret = add_node(values[i]);
+ if (ret)
+ goto end;
+ }
+
+ /*
+ * We need to explicitly mark RCU read-side critical sections
+ * with rcu_read_lock() and rcu_read_unlock(). They can be
+ * nested. Those are no-ops for the QSBR flavor.
+ */
+ rcu_read_lock();
+
+ /*
+ * RCU traversal of the linked list.
+ */
+ cds_list_for_each_entry_rcu(node, &mylist, node) {
+ printf("Value: %" PRIu64 "\n", node->value);
+ }
+ rcu_read_unlock();
+
+ /*
+ * Removing nodes from linked list. Safe against concurrent RCU
+ * traversals, require mutual exclusion with list updates.
+ */
+ cds_list_for_each_entry_safe(node, n, &mylist, node) {
+ cds_list_del_rcu(&node->node);
+ /*
+ * call_rcu() will ensure that the handler
+ * "rcu_free_node" is executed after a grace period.
+ * call_rcu() can be called from RCU read-side critical
+ * sections.
+ */
+ call_rcu(&node->rcu_head, rcu_free_node);
+ }
+
+ /*
+ * We can also wait for a quiescent state by calling
+ * synchronize_rcu() rather than using call_rcu(). It is usually
+ * a slower approach than call_rcu(), because the latter can
+ * batch work. Moreover, call_rcu() can be called from a RCU
+ * read-side critical section, but synchronize_rcu() should not.
+ */
+ synchronize_rcu();
+
+ sleep(1);
+
+ /*
+ * Waiting for previously called call_rcu handlers to complete
+ * before program exits, or in library destructors, is a good
+ * practice.
+ */
+ rcu_barrier();
+
+end:
+ rcu_unregister_thread();
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <inttypes.h>
+
+#include <urcu-qsbr.h> /* QSBR RCU flavor */
+#include <urcu/rculist.h> /* List example */
+#include <urcu/compiler.h> /* For CAA_ARRAY_SIZE */
+
+/*
+ * Example showing how to use the QSBR Userspace RCU flavor.
+ *
+ * This is a mock-up example where updates and RCU traversals are
+ * performed by the same thread to keep things simple on purpose.
+ */
+
+static CDS_LIST_HEAD(mylist);
+
+struct mynode {
+ uint64_t value;
+ struct cds_list_head node; /* linked-list chaining */
+ struct rcu_head rcu_head; /* for call_rcu() */
+};
+
+static
+int add_node(uint64_t v)
+{
+ struct mynode *node;
+
+ node = calloc(sizeof(*node), 1);
+ if (!node)
+ return -1;
+ node->value = v;
+ cds_list_add_rcu(&node->node, &mylist);
+ return 0;
+}
+
+static
+void rcu_free_node(struct rcu_head *rh)
+{
+ struct mynode *node = caa_container_of(rh, struct mynode, rcu_head);
+
+ free(node);
+}
+
+int main(int argc, char **argv)
+{
+ uint64_t values[] = { 42, 36, 24, };
+ unsigned int i;
+ int ret;
+ struct mynode *node, *n;
+
+ /*
+ * Each thread need using RCU read-side need to be explicitly
+ * registered.
+ */
+ rcu_register_thread();
+
+ /*
+ * Adding nodes to the linked-list. Safe against concurrent
+ * RCU traversals, require mutual exclusion with list updates.
+ */
+ for (i = 0; i < CAA_ARRAY_SIZE(values); i++) {
+ ret = add_node(values[i]);
+ if (ret)
+ goto end;
+ }
+
+ /*
+ * RCU traversal of the linked list.
+ */
+ cds_list_for_each_entry_rcu(node, &mylist, node) {
+ printf("Value: %" PRIu64 "\n", node->value);
+ }
+
+ /*
+ * Removing nodes from linked list. Safe against concurrent RCU
+ * traversals, require mutual exclusion with list updates.
+ */
+ cds_list_for_each_entry_safe(node, n, &mylist, node) {
+ cds_list_del_rcu(&node->node);
+ /*
+ * call_rcu() will ensure that the handler
+ * "rcu_free_node" is executed after a grace period.
+ * call_rcu() can be called from RCU read-side critical
+ * sections.
+ */
+ call_rcu(&node->rcu_head, rcu_free_node);
+ }
+
+ /*
+ * For QSBR flavor, we need to explicitly announce quiescent
+ * states. Here is how it is done. This should be performed by
+ * every online registered RCU threads in the program
+ * periodically.
+ */
+ rcu_quiescent_state();
+
+ /*
+ * For QSBR flavor, when a thread needs to be in a quiescent
+ * state for a long period of time, we use rcu_thread_offline()
+ * and rcu_thread_online().
+ */
+ rcu_thread_offline();
+
+ sleep(1);
+
+ rcu_thread_online();
+
+ /*
+ * We can also wait for a quiescent state by calling
+ * synchronize_rcu() rather than using call_rcu(). It is usually
+ * a slower approach than call_rcu(), because the latter can
+ * batch work. Moreover, call_rcu() can be called from a RCU
+ * read-side critical section, but synchronize_rcu() ensures the
+ * caller thread is offline, thus acting as a quiescent state.
+ */
+ synchronize_rcu();
+
+ /*
+ * Waiting for previously called call_rcu handlers to complete
+ * before program exits, or in library destructors, is a good
+ * practice.
+ */
+ rcu_barrier();
+
+end:
+ rcu_unregister_thread();
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <inttypes.h>
+
+#define RCU_SIGNAL /* Signal-based RCU flavor */
+#include <urcu.h>
+#include <urcu/rculist.h> /* List example */
+#include <urcu/compiler.h> /* For CAA_ARRAY_SIZE */
+
+/*
+ * Example showing how to use the signal-based Userspace RCU flavor.
+ *
+ * This is a mock-up example where updates and RCU traversals are
+ * performed by the same thread to keep things simple on purpose.
+ */
+
+static CDS_LIST_HEAD(mylist);
+
+struct mynode {
+ uint64_t value;
+ struct cds_list_head node; /* linked-list chaining */
+ struct rcu_head rcu_head; /* for call_rcu() */
+};
+
+static
+int add_node(uint64_t v)
+{
+ struct mynode *node;
+
+ node = calloc(sizeof(*node), 1);
+ if (!node)
+ return -1;
+ node->value = v;
+ cds_list_add_rcu(&node->node, &mylist);
+ return 0;
+}
+
+static
+void rcu_free_node(struct rcu_head *rh)
+{
+ struct mynode *node = caa_container_of(rh, struct mynode, rcu_head);
+
+ free(node);
+}
+
+int main(int argc, char **argv)
+{
+ uint64_t values[] = { 42, 36, 24, };
+ unsigned int i;
+ int ret;
+ struct mynode *node, *n;
+
+ /*
+ * Each thread need using RCU read-side need to be explicitly
+ * registered.
+ */
+ rcu_register_thread();
+
+ /*
+ * Adding nodes to the linked-list. Safe against concurrent
+ * RCU traversals, require mutual exclusion with list updates.
+ */
+ for (i = 0; i < CAA_ARRAY_SIZE(values); i++) {
+ ret = add_node(values[i]);
+ if (ret)
+ goto end;
+ }
+
+ /*
+ * We need to explicitly mark RCU read-side critical sections
+ * with rcu_read_lock() and rcu_read_unlock(). They can be
+ * nested. Those are no-ops for the QSBR flavor.
+ */
+ rcu_read_lock();
+
+ /*
+ * RCU traversal of the linked list.
+ */
+ cds_list_for_each_entry_rcu(node, &mylist, node) {
+ printf("Value: %" PRIu64 "\n", node->value);
+ }
+ rcu_read_unlock();
+
+ /*
+ * Removing nodes from linked list. Safe against concurrent RCU
+ * traversals, require mutual exclusion with list updates.
+ */
+ cds_list_for_each_entry_safe(node, n, &mylist, node) {
+ cds_list_del_rcu(&node->node);
+ /*
+ * call_rcu() will ensure that the handler
+ * "rcu_free_node" is executed after a grace period.
+ * call_rcu() can be called from RCU read-side critical
+ * sections.
+ */
+ call_rcu(&node->rcu_head, rcu_free_node);
+ }
+
+ /*
+ * We can also wait for a quiescent state by calling
+ * synchronize_rcu() rather than using call_rcu(). It is usually
+ * a slower approach than call_rcu(), because the latter can
+ * batch work. Moreover, call_rcu() can be called from a RCU
+ * read-side critical section, but synchronize_rcu() should not.
+ */
+ synchronize_rcu();
+
+ sleep(1);
+
+ /*
+ * Waiting for previously called call_rcu handlers to complete
+ * before program exits, or in library destructors, is a good
+ * practice.
+ */
+ rcu_barrier();
+
+end:
+ rcu_unregister_thread();
+ return ret;
+}
--- /dev/null
+# Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+#
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+#
+# Permission is hereby granted to use or copy this program for any
+# purpose, provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is
+# granted, provided the above notices are retained, and a notice that
+# the code was modified is included with the above copyright notice.
+#
+# This makefile is purposefully kept simple to support GNU and BSD make.
+
+all:
+ $(MAKE) -f Makefile.cds_wfcq_enqueue
+ $(MAKE) -f Makefile.cds_wfcq_dequeue
+ $(MAKE) -f Makefile.cds_wfcq_splice
+
+.PHONY: clean
+clean:
+ $(MAKE) -f Makefile.cds_wfcq_enqueue clean
+ $(MAKE) -f Makefile.cds_wfcq_dequeue clean
+ $(MAKE) -f Makefile.cds_wfcq_splice clean
--- /dev/null
+# Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+#
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+#
+# Permission is hereby granted to use or copy this program for any
+# purpose, provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is
+# granted, provided the above notices are retained, and a notice that
+# the code was modified is included with the above copyright notice.
+#
+# This makefile is purposefully kept simple to support GNU and BSD make.
+
+EXAMPLE_NAME = cds_wfcq_dequeue
+
+SOURCES = $(EXAMPLE_NAME).c
+OBJECTS = $(EXAMPLE_NAME).o
+BINARY = $(EXAMPLE_NAME)
+LIBS = -lurcu-common
+
+include ../Makefile.examples.template
--- /dev/null
+# Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+#
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+#
+# Permission is hereby granted to use or copy this program for any
+# purpose, provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is
+# granted, provided the above notices are retained, and a notice that
+# the code was modified is included with the above copyright notice.
+#
+# This makefile is purposefully kept simple to support GNU and BSD make.
+
+EXAMPLE_NAME = cds_wfcq_enqueue
+
+SOURCES = $(EXAMPLE_NAME).c
+OBJECTS = $(EXAMPLE_NAME).o
+BINARY = $(EXAMPLE_NAME)
+LIBS = -lurcu-common
+
+include ../Makefile.examples.template
--- /dev/null
+# Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+#
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+#
+# Permission is hereby granted to use or copy this program for any
+# purpose, provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is
+# granted, provided the above notices are retained, and a notice that
+# the code was modified is included with the above copyright notice.
+#
+# This makefile is purposefully kept simple to support GNU and BSD make.
+
+EXAMPLE_NAME = cds_wfcq_splice
+
+SOURCES = $(EXAMPLE_NAME).c
+OBJECTS = $(EXAMPLE_NAME).o
+BINARY = $(EXAMPLE_NAME)
+LIBS = -lurcu-common
+
+include ../Makefile.examples.template
--- /dev/null
+/*
+ * Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program for any
+ * purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is
+ * granted, provided the above notices are retained, and a notice that
+ * the code was modified is included with the above copyright notice.
+ *
+ * This example shows how to dequeue nodes from a wfcqueue.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <urcu/wfcqueue.h> /* Wait-free concurrent queue */
+#include <urcu/compiler.h> /* For CAA_ARRAY_SIZE */
+
+/*
+ * Nodes populated into the queue.
+ */
+struct mynode {
+ int value; /* Node content */
+ struct cds_wfcq_node node; /* Chaining in queue */
+};
+
+int main(int argc, char **argv)
+{
+ int values[] = { -5, 42, 36, 24, };
+ struct cds_wfcq_head myqueue_head; /* Queue head */
+ struct cds_wfcq_tail myqueue_tail; /* Queue tail */
+ unsigned int i;
+ int ret = 0;
+
+ cds_wfcq_init(&myqueue_head, &myqueue_tail);
+
+ /*
+ * Enqueue nodes.
+ */
+ for (i = 0; i < CAA_ARRAY_SIZE(values); i++) {
+ struct mynode *node;
+
+ node = malloc(sizeof(*node));
+ if (!node) {
+ ret = -1;
+ goto end;
+ }
+
+ cds_wfcq_node_init(&node->node);
+ node->value = values[i];
+ cds_wfcq_enqueue(&myqueue_head, &myqueue_tail,
+ &node->node);
+ }
+
+ /*
+ * Dequeue each node from the queue. Those will be dequeued from
+ * the oldest (first enqueued) to the newest (last enqueued).
+ */
+ printf("dequeued content:");
+ for (;;) {
+ struct cds_wfcq_node *qnode;
+ struct mynode *node;
+
+ qnode = cds_wfcq_dequeue_blocking(&myqueue_head, &myqueue_tail);
+ if (!qnode) {
+ break; /* Queue is empty. */
+ }
+ /* Getting the container structure from the node */
+ node = caa_container_of(qnode, struct mynode, node);
+ printf(" %d", node->value);
+ free(node);
+ }
+ printf("\n");
+end:
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program for any
+ * purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is
+ * granted, provided the above notices are retained, and a notice that
+ * the code was modified is included with the above copyright notice.
+ *
+ * This example shows how to enqueue nodes into a wfcqueue.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <urcu/wfcqueue.h> /* Wait-free concurrent queue */
+#include <urcu/compiler.h> /* For CAA_ARRAY_SIZE */
+
+/*
+ * Nodes populated into the queue.
+ */
+struct mynode {
+ int value; /* Node content */
+ struct cds_wfcq_node node; /* Chaining in queue */
+};
+
+int main(int argc, char **argv)
+{
+ int values[] = { -5, 42, 36, 24, };
+ struct cds_wfcq_head myqueue_head; /* Queue head */
+ struct cds_wfcq_tail myqueue_tail; /* Queue tail */
+ unsigned int i;
+ int ret = 0;
+ struct cds_wfcq_node *qnode;
+
+ cds_wfcq_init(&myqueue_head, &myqueue_tail);
+
+ /*
+ * Enqueue nodes.
+ */
+ for (i = 0; i < CAA_ARRAY_SIZE(values); i++) {
+ struct mynode *node;
+
+ node = malloc(sizeof(*node));
+ if (!node) {
+ ret = -1;
+ goto end;
+ }
+
+ cds_wfcq_node_init(&node->node);
+ node->value = values[i];
+ cds_wfcq_enqueue(&myqueue_head, &myqueue_tail,
+ &node->node);
+ }
+
+ /*
+ * Show the queue content, iterate in the same order nodes were
+ * enqueued, from oldest to newest.
+ */
+ printf("myqueue content:");
+ __cds_wfcq_for_each_blocking(&myqueue_head, &myqueue_tail, qnode) {
+ struct mynode *node =
+ caa_container_of(qnode, struct mynode, node);
+ printf(" %d", node->value);
+ }
+ printf("\n");
+end:
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program for any
+ * purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is
+ * granted, provided the above notices are retained, and a notice that
+ * the code was modified is included with the above copyright notice.
+ *
+ * This example shows how to splice nodes from a source wfcqueue A into
+ * a destination wfcqueue B.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <urcu/wfcqueue.h> /* Wait-free concurrent queue */
+#include <urcu/compiler.h> /* For CAA_ARRAY_SIZE */
+
+/*
+ * Nodes populated into the queue.
+ */
+struct mynode {
+ int value; /* Node content */
+ struct cds_wfcq_node node; /* Chaining in queue */
+};
+
+static
+int enqueue_values(struct cds_wfcq_head *head,
+ struct cds_wfcq_tail *tail,
+ int *values,
+ size_t nr_values)
+{
+ int ret = 0;
+ unsigned int i;
+
+ for (i = 0; i < nr_values; i++) {
+ struct mynode *node;
+
+ node = malloc(sizeof(*node));
+ if (!node) {
+ ret = -1;
+ goto end;
+ }
+ cds_wfcq_node_init(&node->node);
+ node->value = values[i];
+ cds_wfcq_enqueue(head, tail, &node->node);
+ }
+end:
+ return ret;
+}
+
+static
+void print_queue(struct cds_wfcq_head *head,
+ struct cds_wfcq_tail *tail,
+ const char *qname)
+{
+ struct cds_wfcq_node *qnode;
+
+ printf("%s:", qname);
+ __cds_wfcq_for_each_blocking(head, tail, qnode) {
+ struct mynode *node =
+ caa_container_of(qnode, struct mynode, node);
+ printf(" %d", node->value);
+ }
+ printf("\n");
+}
+
+int main(int argc, char **argv)
+{
+ int values_A[] = { -5, 42, 36, 24, };
+ int values_B[] = { 200, 300, 400, };
+ struct cds_wfcq_head head_A; /* Queue A head */
+ struct cds_wfcq_tail tail_A; /* Queue A tail */
+ struct cds_wfcq_head head_B; /* Queue B head */
+ struct cds_wfcq_tail tail_B; /* Queue B tail */
+ int ret = 0;
+
+ cds_wfcq_init(&head_A, &tail_A);
+ /* Enqueue nodes into A. */
+ ret = enqueue_values(&head_A, &tail_A, values_A,
+ CAA_ARRAY_SIZE(values_A));
+ if (ret)
+ goto end;
+ cds_wfcq_init(&head_B, &tail_B);
+ /* Enqueue nodes into B. */
+ ret = enqueue_values(&head_B, &tail_B, values_B,
+ CAA_ARRAY_SIZE(values_B));
+ if (ret)
+ goto end;
+
+ print_queue(&head_A, &tail_A, "queue A content before splice");
+ print_queue(&head_B, &tail_B, "queue B content before splice");
+
+ /*
+ * Splice nodes from A into B.
+ */
+ printf("Splicing queue A into queue B\n");
+ (void) cds_wfcq_splice_blocking(&head_B, &tail_B,
+ &head_A, &tail_A);
+
+ print_queue(&head_A, &tail_A, "queue A content after splice");
+ print_queue(&head_B, &tail_B, "queue B content after splice");
+end:
+ return ret;
+}
--- /dev/null
+# Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+#
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+#
+# Permission is hereby granted to use or copy this program for any
+# purpose, provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is
+# granted, provided the above notices are retained, and a notice that
+# the code was modified is included with the above copyright notice.
+#
+# This makefile is purposefully kept simple to support GNU and BSD make.
+
+all:
+ $(MAKE) -f Makefile.cds_wfs_push
+ $(MAKE) -f Makefile.cds_wfs_pop
+ $(MAKE) -f Makefile.cds_wfs_pop_all_blocking
+
+.PHONY: clean
+clean:
+ $(MAKE) -f Makefile.cds_wfs_push clean
+ $(MAKE) -f Makefile.cds_wfs_pop clean
+ $(MAKE) -f Makefile.cds_wfs_pop_all_blocking clean
--- /dev/null
+# Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+#
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+#
+# Permission is hereby granted to use or copy this program for any
+# purpose, provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is
+# granted, provided the above notices are retained, and a notice that
+# the code was modified is included with the above copyright notice.
+#
+# This makefile is purposefully kept simple to support GNU and BSD make.
+
+EXAMPLE_NAME = cds_wfs_pop
+
+SOURCES = $(EXAMPLE_NAME).c
+OBJECTS = $(EXAMPLE_NAME).o
+BINARY = $(EXAMPLE_NAME)
+LIBS = -lurcu-common
+
+include ../Makefile.examples.template
--- /dev/null
+# Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+#
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+#
+# Permission is hereby granted to use or copy this program for any
+# purpose, provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is
+# granted, provided the above notices are retained, and a notice that
+# the code was modified is included with the above copyright notice.
+#
+# This makefile is purposefully kept simple to support GNU and BSD make.
+
+EXAMPLE_NAME = cds_wfs_pop_all_blocking
+
+SOURCES = $(EXAMPLE_NAME).c
+OBJECTS = $(EXAMPLE_NAME).o
+BINARY = $(EXAMPLE_NAME)
+LIBS = -lurcu-common
+
+include ../Makefile.examples.template
--- /dev/null
+# Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+#
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+#
+# Permission is hereby granted to use or copy this program for any
+# purpose, provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is
+# granted, provided the above notices are retained, and a notice that
+# the code was modified is included with the above copyright notice.
+#
+# This makefile is purposefully kept simple to support GNU and BSD make.
+
+EXAMPLE_NAME = cds_wfs_push
+
+SOURCES = $(EXAMPLE_NAME).c
+OBJECTS = $(EXAMPLE_NAME).o
+BINARY = $(EXAMPLE_NAME)
+LIBS = -lurcu-common
+
+include ../Makefile.examples.template
--- /dev/null
+/*
+ * Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program for any
+ * purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is
+ * granted, provided the above notices are retained, and a notice that
+ * the code was modified is included with the above copyright notice.
+ *
+ * This example shows how to pop nodes from a wfstack.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <urcu/wfstack.h> /* Wait-free stack */
+#include <urcu/compiler.h> /* For CAA_ARRAY_SIZE */
+
+/*
+ * Nodes populated into the stack.
+ */
+struct mynode {
+ int value; /* Node content */
+ struct cds_wfs_node node; /* Chaining in stack */
+};
+
+int main(int argc, char **argv)
+{
+ int values[] = { -5, 42, 36, 24, };
+ struct cds_wfs_stack mystack; /* Stack */
+ unsigned int i;
+ int ret = 0;
+
+ cds_wfs_init(&mystack);
+
+ /*
+ * Push nodes.
+ */
+ for (i = 0; i < CAA_ARRAY_SIZE(values); i++) {
+ struct mynode *node;
+
+ node = malloc(sizeof(*node));
+ if (!node) {
+ ret = -1;
+ goto end;
+ }
+
+ cds_wfs_node_init(&node->node);
+ node->value = values[i];
+ cds_wfs_push(&mystack, &node->node);
+ }
+
+ /*
+ * Pop nodes from the stack, one by one, from newest to oldest.
+ */
+ printf("pop each mystack node:");
+ for (;;) {
+ struct cds_wfs_node *snode;
+ struct mynode *node;
+
+ snode = cds_wfs_pop_blocking(&mystack);
+ if (!snode) {
+ break;
+ }
+ node = caa_container_of(snode, struct mynode, node);
+ printf(" %d", node->value);
+ free(node);
+ }
+ printf("\n");
+end:
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program for any
+ * purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is
+ * granted, provided the above notices are retained, and a notice that
+ * the code was modified is included with the above copyright notice.
+ *
+ * This example shows how to pop all nodes from a wfstack.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <urcu/wfstack.h> /* Wait-free stack */
+#include <urcu/compiler.h> /* For CAA_ARRAY_SIZE */
+
+/*
+ * Nodes populated into the stack.
+ */
+struct mynode {
+ int value; /* Node content */
+ struct cds_wfs_node node; /* Chaining in stack */
+};
+
+int main(int argc, char **argv)
+{
+ int values[] = { -5, 42, 36, 24, };
+ struct cds_wfs_stack mystack; /* Stack */
+ unsigned int i;
+ int ret = 0;
+ struct cds_wfs_node *snode, *sn;
+ struct cds_wfs_head *shead;
+
+ cds_wfs_init(&mystack);
+
+ /*
+ * Push nodes.
+ */
+ for (i = 0; i < CAA_ARRAY_SIZE(values); i++) {
+ struct mynode *node;
+
+ node = malloc(sizeof(*node));
+ if (!node) {
+ ret = -1;
+ goto end;
+ }
+
+ cds_wfs_node_init(&node->node);
+ node->value = values[i];
+ cds_wfs_push(&mystack, &node->node);
+ }
+
+ /*
+ * Pop all nodes from mystack into shead. The head can the be
+ * used for iteration.
+ */
+ shead = cds_wfs_pop_all_blocking(&mystack);
+
+ /*
+ * Show the stack content, iterate in reverse order of push,
+ * from newest to oldest. Use cds_wfs_for_each_blocking_safe()
+ * so we can free the nodes as we iterate.
+ */
+ printf("mystack content:");
+ cds_wfs_for_each_blocking_safe(shead, snode, sn) {
+ struct mynode *node =
+ caa_container_of(snode, struct mynode, node);
+ printf(" %d", node->value);
+ free(node);
+ }
+ printf("\n");
+end:
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program for any
+ * purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is
+ * granted, provided the above notices are retained, and a notice that
+ * the code was modified is included with the above copyright notice.
+ *
+ * This example shows how to push nodes into a wfstack.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <urcu/wfstack.h> /* Wait-free stack */
+#include <urcu/compiler.h> /* For CAA_ARRAY_SIZE */
+
+/*
+ * Nodes populated into the stack.
+ */
+struct mynode {
+ int value; /* Node content */
+ struct cds_wfs_node node; /* Chaining in stack */
+};
+
+int main(int argc, char **argv)
+{
+ int values[] = { -5, 42, 36, 24, };
+ struct cds_wfs_stack mystack; /* Stack */
+ unsigned int i;
+ int ret = 0;
+ struct cds_wfs_node *snode;
+ struct cds_wfs_head *shead;
+
+ cds_wfs_init(&mystack);
+
+ /*
+ * Push nodes.
+ */
+ for (i = 0; i < CAA_ARRAY_SIZE(values); i++) {
+ struct mynode *node;
+
+ node = malloc(sizeof(*node));
+ if (!node) {
+ ret = -1;
+ goto end;
+ }
+
+ cds_wfs_node_init(&node->node);
+ node->value = values[i];
+ cds_wfs_push(&mystack, &node->node);
+ }
+
+ /*
+ * Show the stack content, iterate in reverse order of push,
+ * from newest to oldest.
+ */
+ printf("mystack content:");
+ shead = cds_wfs_pop_all_blocking(&mystack);
+ cds_wfs_for_each_blocking(shead, snode) {
+ struct mynode *node =
+ caa_container_of(snode, struct mynode, node);
+ printf(" %d", node->value);
+ }
+ printf("\n");
+end:
+ return ret;
+}
test_urcu_multiflavor test_urcu_multiflavor_dynlink \
test_urcu_fork \
test_urcu_ja test_urcu_ja_range
-noinst_HEADERS = rcutorture.h test_urcu_multiflavor.h cpuset.h
+noinst_HEADERS = rcutorture.h test_urcu_multiflavor.h cpuset.h thread-id.h
if COMPAT_ARCH
COMPAT=$(top_srcdir)/compat_arch_@ARCHTYPE@.c
#include <urcu/arch.h>
-#ifdef __linux__
-#include <syscall.h>
-#endif
-
-#if defined(_syscall0)
-_syscall0(pid_t, gettid)
-#elif defined(__NR_gettid)
-static inline pid_t gettid(void)
-{
- return syscall(__NR_gettid);
-}
-#else
-#warning "use pid as tid"
-static inline pid_t gettid(void)
-{
- return getpid();
-}
-#endif
-
#ifndef DYNAMIC_LINK_TEST
#define _LGPL_SOURCE
#else
#include <urcu/arch.h>
#include <urcu/tls-compat.h>
#include "cpuset.h"
-
-#ifdef __linux__
-#include <syscall.h>
-#endif
+#include "thread-id.h"
/* hardcoded number of CPUs */
#define NR_CPUS 16384
-#if defined(_syscall0)
-_syscall0(pid_t, gettid)
-#elif defined(__NR_gettid)
-static inline pid_t gettid(void)
-{
- return syscall(__NR_gettid);
-}
-#else
-#warning "use pid as tid"
-static inline pid_t gettid(void)
-{
- return getpid();
-}
-#endif
-
#ifndef DYNAMIC_LINK_TEST
#define _LGPL_SOURCE
#else
{
unsigned long tidx = (unsigned long)data;
- printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
- "reader", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
set_affinity();
}
tot_nr_reads[tidx] = URCU_TLS(nr_reads);
- printf_verbose("thread_end %s, thread id : %lx, tid %lu\n",
- "reader", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_end %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
return ((void*)1);
}
{
unsigned long wtidx = (unsigned long)data;
- printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
- "writer", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
set_affinity();
loop_sleep(wdelay);
}
- printf_verbose("thread_end %s, thread id : %lx, tid %lu\n",
- "writer", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_end %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
tot_nr_writes[wtidx] = URCU_TLS(nr_writes);
return ((void*)2);
}
duration, nr_readers, nr_writers);
printf_verbose("Writer delay : %lu loops.\n", wdelay);
printf_verbose("Reader duration : %lu loops.\n", rduration);
- printf_verbose("thread %-6s, thread id : %lx, tid %lu\n",
- "main", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread %-6s, tid %lu\n",
+ "main", urcu_get_thread_id());
tid_reader = malloc(sizeof(*tid_reader) * nr_readers);
tid_writer = malloc(sizeof(*tid_writer) * nr_writers);
#include <urcu/arch.h>
#include <urcu/tls-compat.h>
#include "cpuset.h"
-
-#ifdef __linux__
-#include <syscall.h>
-#endif
+#include "thread-id.h"
/* hardcoded number of CPUs */
#define NR_CPUS 16384
-#if defined(_syscall0)
-_syscall0(pid_t, gettid)
-#elif defined(__NR_gettid)
-static inline pid_t gettid(void)
-{
- return syscall(__NR_gettid);
-}
-#else
-#warning "use pid as tid"
-static inline pid_t gettid(void)
-{
- return getpid();
-}
-#endif
-
#ifndef DYNAMIC_LINK_TEST
#define _LGPL_SOURCE
#else
{
unsigned long tidx = (unsigned long)data;
- printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
- "reader", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
set_affinity();
}
tot_nr_reads[tidx] = URCU_TLS(nr_reads);
- printf_verbose("thread_end %s, thread id : %lx, tid %lu\n",
- "reader", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_end %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
return ((void*)1);
}
unsigned long wtidx = (unsigned long)data;
long tidx;
- printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
- "writer", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
set_affinity();
loop_sleep(wdelay);
}
- printf_verbose("thread_end %s, thread id : %lx, tid %lu\n",
- "writer", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_end %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
tot_nr_writes[wtidx] = URCU_TLS(nr_writes);
return ((void*)2);
}
duration, nr_readers, nr_writers);
printf_verbose("Writer delay : %lu loops.\n", wdelay);
printf_verbose("Reader duration : %lu loops.\n", rduration);
- printf_verbose("thread %-6s, thread id : %lx, tid %lu\n",
- "main", (unsigned long) pthread_self(), (unsigned long) gettid());
+ printf_verbose("thread %-6s, tid %lu\n",
+ "main", urcu_get_thread_id());
tid_reader = malloc(sizeof(*tid_reader) * nr_readers);
tid_writer = malloc(sizeof(*tid_writer) * nr_writers);
#include <urcu/arch.h>
-#ifdef __linux__
-#include <syscall.h>
-#endif
-
-#if defined(_syscall0)
-_syscall0(pid_t, gettid)
-#elif defined(__NR_gettid)
-static inline pid_t gettid(void)
-{
- return syscall(__NR_gettid);
-}
-#else
-#warning "use pid as tid"
-static inline pid_t gettid(void)
-{
- return getpid();
-}
-#endif
+#include "thread-id.h"
#include <urcu.h>
cycles_t time1, time2;
long tidx = (long)arg;
- printf("thread_begin %s, thread id : %lx, tid %lu\n",
- "reader", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf("thread_begin %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
sleep(2);
time1 = caa_get_cycles();
reader_time[tidx] = time2 - time1;
sleep(2);
- printf("thread_end %s, thread id : %lx, tid %lu\n",
- "reader", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf("thread_end %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
return ((void*)1);
}
long tidx;
cycles_t time1, time2;
- printf("thread_begin %s, thread id : %lx, tid %lu\n",
- "writer", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf("thread_begin %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
sleep(2);
for (i = 0; i < OUTER_WRITE_LOOP; i++) {
}
}
- printf("thread_end %s, thread id : %lx, tid %lu\n",
- "writer", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf("thread_end %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
return ((void*)2);
}
tid_reader = malloc(sizeof(*tid_reader) * num_read);
tid_writer = malloc(sizeof(*tid_writer) * num_write);
- printf("thread %-6s, thread id : %lx, tid %lu\n",
- "main", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf("thread %-6s, tid %lu\n",
+ "main", urcu_get_thread_id());
per_thread_lock = malloc(sizeof(struct per_thread_lock) * NR_READ);
#include <urcu/arch.h>
#include <urcu/tls-compat.h>
#include "cpuset.h"
-
-#ifdef __linux__
-#include <syscall.h>
-#endif
+#include "thread-id.h"
/* hardcoded number of CPUs */
#define NR_CPUS 16384
-#if defined(_syscall0)
-_syscall0(pid_t, gettid)
-#elif defined(__NR_gettid)
-static inline pid_t gettid(void)
-{
- return syscall(__NR_gettid);
-}
-#else
-#warning "use pid as tid"
-static inline pid_t gettid(void)
-{
- return getpid();
-}
-#endif
-
#ifndef DYNAMIC_LINK_TEST
#define _LGPL_SOURCE
#else
{
unsigned long long *count = _count;
- printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
- "reader", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
set_affinity();
}
*count = URCU_TLS(nr_reads);
- printf_verbose("thread_end %s, thread id : %lx, tid %lu\n",
- "reader", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_end %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
return ((void*)1);
}
{
unsigned long long *count = _count;
- printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
- "writer", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
set_affinity();
loop_sleep(wdelay);
}
- printf_verbose("thread_end %s, thread id : %lx, tid %lu\n",
- "writer", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_end %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
*count = URCU_TLS(nr_writes);
return ((void*)2);
}
duration, nr_readers, nr_writers);
printf_verbose("Writer delay : %lu loops.\n", wdelay);
printf_verbose("Reader duration : %lu loops.\n", rduration);
- printf_verbose("thread %-6s, thread id : %lx, tid %lu\n",
- "main", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread %-6s, tid %lu\n",
+ "main", urcu_get_thread_id());
tid_reader = malloc(sizeof(*tid_reader) * nr_readers);
tid_writer = malloc(sizeof(*tid_writer) * nr_writers);
#include <urcu/arch.h>
-#ifdef __linux__
-#include <syscall.h>
-#endif
-
-#if defined(_syscall0)
-_syscall0(pid_t, gettid)
-#elif defined(__NR_gettid)
-static inline pid_t gettid(void)
-{
- return syscall(__NR_gettid);
-}
-#else
-#warning "use pid as tid"
-static inline pid_t gettid(void)
-{
- return getpid();
-}
-#endif
+#include "thread-id.h"
#include <urcu.h>
int i, j;
cycles_t time1, time2;
- printf("thread_begin %s, thread id : %lx, tid %lu\n",
- "reader", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf("thread_begin %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
sleep(2);
time1 = caa_get_cycles();
reader_time[(unsigned long)arg] = time2 - time1;
sleep(2);
- printf("thread_end %s, thread id : %lx, tid %lu\n",
- "reader", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf("thread_end %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
return ((void*)1);
}
int i, j;
cycles_t time1, time2;
- printf("thread_begin %s, thread id : %lx, tid %lu\n",
- "writer", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf("thread_begin %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
sleep(2);
for (i = 0; i < OUTER_WRITE_LOOP; i++) {
}
}
- printf("thread_end %s, thread id : %lx, tid %lu\n",
- "writer", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf("thread_end %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
return ((void*)2);
}
tid_reader = malloc(sizeof(*tid_reader) * num_read);
tid_writer = malloc(sizeof(*tid_writer) * num_write);
- printf("thread %-6s, thread id : %lx, tid %lu\n",
- "main", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf("thread %-6s, tid %lu\n",
+ "main", urcu_get_thread_id());
for (i = 0; i < NR_READ; i++) {
err = pthread_create(&tid_reader[i], NULL, thr_reader,
#include <urcu/arch.h>
#include <urcu/tls-compat.h>
#include "cpuset.h"
-
-#ifdef __linux__
-#include <syscall.h>
-#endif
+#include "thread-id.h"
/* hardcoded number of CPUs */
#define NR_CPUS 16384
-#if defined(_syscall0)
-_syscall0(pid_t, gettid)
-#elif defined(__NR_gettid)
-static inline pid_t gettid(void)
-{
- return syscall(__NR_gettid);
-}
-#else
-#warning "use pid as tid"
-static inline pid_t gettid(void)
-{
- return getpid();
-}
-#endif
-
#ifndef DYNAMIC_LINK_TEST
#define _LGPL_SOURCE
#else
unsigned long long *count = _count;
int *local_ptr;
- printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
- "reader", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
set_affinity();
rcu_unregister_thread();
*count = URCU_TLS(nr_reads);
- printf_verbose("thread_end %s, thread id : %lx, tid %lu\n",
- "reader", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_end %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
return ((void*)1);
}
unsigned long long *count = _count;
int *new, *old;
- printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
- "writer", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
set_affinity();
loop_sleep(wdelay);
}
- printf_verbose("thread_end %s, thread id : %lx, tid %lu\n",
- "writer", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_end %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
*count = URCU_TLS(nr_writes);
return ((void*)2);
}
duration, nr_readers, nr_writers);
printf_verbose("Writer delay : %lu loops.\n", wdelay);
printf_verbose("Reader duration : %lu loops.\n", rduration);
- printf_verbose("thread %-6s, thread id : %lx, tid %lu\n",
- "main", (unsigned long) pthread_self(),
- (unsigned long)gettid());
+ printf_verbose("thread %-6s, tid %lu\n",
+ "main", urcu_get_thread_id());
tid_reader = malloc(sizeof(*tid_reader) * nr_readers);
tid_writer = malloc(sizeof(*tid_writer) * nr_writers);
#include <urcu/arch.h>
#include <urcu/tls-compat.h>
#include "cpuset.h"
-
-#ifdef __linux__
-#include <syscall.h>
-#endif
+#include "thread-id.h"
/* hardcoded number of CPUs */
#define NR_CPUS 16384
-#if defined(_syscall0)
-_syscall0(pid_t, gettid)
-#elif defined(__NR_gettid)
-static inline pid_t gettid(void)
-{
- return syscall(__NR_gettid);
-}
-#else
-#warning "use pid as tid"
-static inline pid_t gettid(void)
-{
- return getpid();
-}
-#endif
-
#ifndef DYNAMIC_LINK_TEST
#define _LGPL_SOURCE
#else
unsigned long long *count = _count;
struct test_array *local_ptr;
- printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
- "reader", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
set_affinity();
rcu_unregister_thread();
*count = URCU_TLS(nr_reads);
- printf_verbose("thread_end %s, thread id : %lx, tid %lu\n",
- "reader", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_end %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
return ((void*)1);
}
unsigned long long *count = _count;
struct test_array *new, *old;
- printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
- "writer", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
set_affinity();
loop_sleep(wdelay);
}
- printf_verbose("thread_end %s, thread id : %lx, tid %lu\n",
- "writer", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_end %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
*count = URCU_TLS(nr_writes);
return ((void*)2);
}
duration, nr_readers, nr_writers);
printf_verbose("Writer delay : %lu loops.\n", wdelay);
printf_verbose("Reader duration : %lu loops.\n", rduration);
- printf_verbose("thread %-6s, thread id : %lx, tid %lu\n",
- "main", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread %-6s, tid %lu\n",
+ "main", urcu_get_thread_id());
test_array = calloc(1, sizeof(*test_array) * ARRAY_SIZE);
tid_reader = malloc(sizeof(*tid_reader) * nr_readers);
#include <urcu/arch.h>
#include <urcu/tls-compat.h>
#include "cpuset.h"
-
-#ifdef __linux__
-#include <syscall.h>
-#endif
+#include "thread-id.h"
/* hardcoded number of CPUs */
#define NR_CPUS 16384
-#if defined(_syscall0)
-_syscall0(pid_t, gettid)
-#elif defined(__NR_gettid)
-static inline pid_t gettid(void)
-{
- return syscall(__NR_gettid);
-}
-#else
-#warning "use pid as tid"
-static inline pid_t gettid(void)
-{
- return getpid();
-}
-#endif
-
#ifndef DYNAMIC_LINK_TEST
#define _LGPL_SOURCE
#else
unsigned long long *count = _count;
int *local_ptr;
- printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
- "reader", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
set_affinity();
rcu_unregister_thread();
*count = URCU_TLS(nr_reads);
- printf_verbose("thread_end %s, thread id : %lx, tid %lu\n",
- "reader", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_end %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
return ((void*)1);
}
unsigned long long *count = _count;
int *new, *old;
- printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
- "writer", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
set_affinity();
loop_sleep(wdelay);
}
- printf_verbose("thread_end %s, thread id : %lx, tid %lu\n",
- "writer", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_end %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
*count = URCU_TLS(nr_writes);
return ((void*)2);
}
duration, nr_readers, nr_writers);
printf_verbose("Writer delay : %lu loops.\n", wdelay);
printf_verbose("Reader duration : %lu loops.\n", rduration);
- printf_verbose("thread %-6s, thread id : %lx, tid %lu\n",
- "main", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread %-6s, tid %lu\n",
+ "main", urcu_get_thread_id());
tid_reader = malloc(sizeof(*tid_reader) * nr_readers);
tid_writer = malloc(sizeof(*tid_writer) * nr_writers);
#include <urcu/arch.h>
#include <urcu/tls-compat.h>
#include "cpuset.h"
-
-#ifdef __linux__
-#include <syscall.h>
-#endif
+#include "thread-id.h"
/* hardcoded number of CPUs */
#define NR_CPUS 16384
-#if defined(_syscall0)
-_syscall0(pid_t, gettid)
-#elif defined(__NR_gettid)
-static inline pid_t gettid(void)
-{
- return syscall(__NR_gettid);
-}
-#else
-#warning "use pid as tid"
-static inline pid_t gettid(void)
-{
- return getpid();
-}
-#endif
-
#ifndef DYNAMIC_LINK_TEST
#define _LGPL_SOURCE
#else
unsigned long long *count = _count;
struct test_array *local_ptr;
- printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
- "reader", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
set_affinity();
rcu_unregister_thread();
*count = URCU_TLS(nr_reads);
- printf_verbose("thread_end %s, thread id : %lx, tid %lu\n",
- "reader", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_end %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
return ((void*)1);
}
struct test_array *new, *old = NULL;
int ret;
- printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
- "writer", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
set_affinity();
rcu_defer_unregister_thread();
- printf_verbose("thread_end %s, thread id : %lx, tid %lu\n",
- "writer", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_end %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
tot_nr_writes[wtidx] = URCU_TLS(nr_writes);
return ((void*)2);
}
duration, nr_readers, nr_writers);
printf_verbose("Writer delay : %lu loops.\n", wdelay);
printf_verbose("Reader duration : %lu loops.\n", rduration);
- printf_verbose("thread %-6s, thread id : %lx, tid %lu\n",
- "main", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread %-6s, tid %lu\n",
+ "main", urcu_get_thread_id());
tid_reader = malloc(sizeof(*tid_reader) * nr_readers);
tid_writer = malloc(sizeof(*tid_writer) * nr_writers);
#include <urcu/arch.h>
#include <urcu/tls-compat.h>
#include "cpuset.h"
-
-#ifdef __linux__
-#include <syscall.h>
-#endif
+#include "thread-id.h"
/* hardcoded number of CPUs */
#define NR_CPUS 16384
-#if defined(_syscall0)
-_syscall0(pid_t, gettid)
-#elif defined(__NR_gettid)
-static inline pid_t gettid(void)
-{
- return syscall(__NR_gettid);
-}
-#else
-#warning "use pid as tid"
-static inline pid_t gettid(void)
-{
- return getpid();
-}
-#endif
-
#ifndef DYNAMIC_LINK_TEST
#define _LGPL_SOURCE
#else
unsigned long long *count = _count;
struct test_array *local_ptr;
- printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
- "reader", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
set_affinity();
rcu_unregister_thread();
*count = URCU_TLS(nr_reads);
- printf_verbose("thread_end %s, thread id : %lx, tid %lu\n",
- "reader", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_end %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
return ((void*)1);
}
struct test_array *new, *old;
#endif
- printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
- "writer", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
set_affinity();
loop_sleep(wdelay);
}
- printf_verbose("thread_end %s, thread id : %lx, tid %lu\n",
- "writer", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_end %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
tot_nr_writes[wtidx] = URCU_TLS(nr_writes);
return ((void*)2);
}
duration, nr_readers, nr_writers);
printf_verbose("Writer delay : %lu loops.\n", wdelay);
printf_verbose("Reader duration : %lu loops.\n", rduration);
- printf_verbose("thread %-6s, thread id : %lx, tid %lu\n",
- "main", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread %-6s, tid %lu\n",
+ "main", urcu_get_thread_id());
tid_reader = malloc(sizeof(*tid_reader) * nr_readers);
tid_writer = malloc(sizeof(*tid_writer) * nr_writers);
void *thr_count(void *arg)
{
- printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
- "counter", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "counter", urcu_get_thread_id());
rcu_register_thread();
write_pool_offset, write_pool_size);
printf_verbose("Number of hash chains: %lu.\n",
nr_hash_chains);
- printf_verbose("thread %-6s, thread id : %lx, tid %lu\n",
- "main", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread %-6s, tid %lu\n",
+ "main", urcu_get_thread_id());
tid_reader = malloc(sizeof(*tid_reader) * nr_readers);
if (!tid_reader) {
#include <urcu/tls-compat.h>
#include "cpuset.h"
-
-#ifdef __linux__
-#include <syscall.h>
-#endif
+#include "thread-id.h"
#define DEFAULT_HASH_SIZE 32
#define DEFAULT_MIN_ALLOC_SIZE 1
*/
#define TEST_HASH_SEED 0x42UL
-/* Make this big enough to include the POWER5+ L3 cacheline size of 256B */
-#define CACHE_LINE_SIZE 4096
-
/* hardcoded number of CPUs */
#define NR_CPUS 16384
#define poison_free(ptr) free(ptr)
#endif
-
-
-#if defined(_syscall0)
-_syscall0(pid_t, gettid)
-#elif defined(__NR_gettid)
-static inline pid_t gettid(void)
-{
- return syscall(__NR_gettid);
-}
-#else
-#warning "use pid as tid"
-static inline pid_t gettid(void)
-{
- return getpid();
-}
-#endif
-
#ifndef DYNAMIC_LINK_TEST
#define _LGPL_SOURCE
#else
struct lfht_test_node *node;
struct cds_lfht_iter iter;
- printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
- "reader", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
+
+ URCU_TLS(rand_lookup) = urcu_get_thread_id() ^ time(NULL);
set_affinity();
rcu_unregister_thread();
*count = URCU_TLS(nr_reads);
- printf_verbose("thread_end %s, thread id : %lx, tid %lu\n",
- "reader", (unsigned long) pthread_self(),
- (unsigned long) gettid());
- printf_verbose("readid : %lx, lookupfail %lu, lookupok %lu\n",
- pthread_self(), URCU_TLS(lookup_fail),
+ printf_verbose("thread_end %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
+ printf_verbose("read tid : %lx, lookupfail %lu, lookupok %lu\n",
+ urcu_get_thread_id(),
+ URCU_TLS(lookup_fail),
URCU_TLS(lookup_ok));
return ((void*)1);
struct wr_count *count = _count;
int ret;
- printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
- "writer", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
+
+ URCU_TLS(rand_lookup) = urcu_get_thread_id() ^ time(NULL);
set_affinity();
rcu_unregister_thread();
- printf_verbose("thread_end %s, thread id : %lx, tid %lu\n",
- "writer", (unsigned long) pthread_self(),
- (unsigned long) gettid());
- printf_verbose("info id %lx: nr_add %lu, nr_addexist %lu, nr_del %lu, "
- "nr_delnoent %lu\n", (unsigned long) pthread_self(), URCU_TLS(nr_add),
- URCU_TLS(nr_addexist), URCU_TLS(nr_del),
+ printf_verbose("thread_end %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
+ printf_verbose("info tid %lu: nr_add %lu, nr_addexist %lu, nr_del %lu, "
+ "nr_delnoent %lu\n", urcu_get_thread_id(),
+ URCU_TLS(nr_add),
+ URCU_TLS(nr_addexist),
+ URCU_TLS(nr_del),
URCU_TLS(nr_delnoent));
count->update_ops = URCU_TLS(nr_writes);
count->add = URCU_TLS(nr_add);
printf("Starting rw test\n");
+ URCU_TLS(rand_lookup) = urcu_get_thread_id() ^ time(NULL);
+
if ((add_unique || add_replace) && init_populate * 10 > init_pool_size) {
printf("WARNING: required to populate %lu nodes (-k), but random "
"pool is quite small (%lu values) and we are in add_unique (-u) or add_replace (-s) mode. Try with a "
{
unsigned long long *count = _count;
- printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
- "reader", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
+
+ URCU_TLS(rand_lookup) = urcu_get_thread_id() ^ time(NULL);
set_affinity();
rcu_unregister_thread();
*count = URCU_TLS(nr_reads);
- printf_verbose("thread_end %s, thread id : %lx, tid %lu\n",
- "reader", (unsigned long) pthread_self(),
- (unsigned long) gettid());
- printf_verbose("readid : %lx, lookupfail %lu, lookupok %lu\n",
- pthread_self(), URCU_TLS(lookup_fail),
+ printf_verbose("thread_end %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
+ printf_verbose("read tid : %lu, lookupfail %lu, lookupok %lu\n",
+ urcu_get_thread_id(), URCU_TLS(lookup_fail),
URCU_TLS(lookup_ok));
return ((void*)1);
int ret;
int loc_add_unique;
- printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
- "writer", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
+
+ URCU_TLS(rand_lookup) = urcu_get_thread_id() ^ time(NULL);
set_affinity();
rcu_unregister_thread();
- printf_verbose("thread_end %s, thread id : %lx, tid %lu\n",
- "writer", (unsigned long) pthread_self(),
- (unsigned long) gettid());
- printf_verbose("info id %lx: nr_add %lu, nr_addexist %lu, nr_del %lu, "
- "nr_delnoent %lu\n", (unsigned long) pthread_self(), URCU_TLS(nr_add),
- URCU_TLS(nr_addexist), URCU_TLS(nr_del),
+ printf_verbose("thread_end %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
+ printf_verbose("info tid %lu: nr_add %lu, nr_addexist %lu, nr_del %lu, "
+ "nr_delnoent %lu\n", urcu_get_thread_id(),
+ URCU_TLS(nr_add),
+ URCU_TLS(nr_addexist),
+ URCU_TLS(nr_del),
URCU_TLS(nr_delnoent));
count->update_ops = URCU_TLS(nr_writes);
count->add = URCU_TLS(nr_add);
printf("Starting uniqueness test.\n");
+ URCU_TLS(rand_lookup) = urcu_get_thread_id() ^ time(NULL);
+
if (!init_populate)
return 0;
#include <urcu/arch.h>
#include <urcu/tls-compat.h>
#include "cpuset.h"
-
-#ifdef __linux__
-#include <syscall.h>
-#endif
+#include "thread-id.h"
/* hardcoded number of CPUs */
#define NR_CPUS 16384
-#if defined(_syscall0)
-_syscall0(pid_t, gettid)
-#elif defined(__NR_gettid)
-static inline pid_t gettid(void)
-{
- return syscall(__NR_gettid);
-}
-#else
-#warning "use pid as tid"
-static inline pid_t gettid(void)
-{
- return getpid();
-}
-#endif
-
#ifndef DYNAMIC_LINK_TEST
#define _LGPL_SOURCE
#endif
{
unsigned long long *count = _count;
- printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
- "enqueuer", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "enqueuer", urcu_get_thread_id());
set_affinity();
count[0] = URCU_TLS(nr_enqueues);
count[1] = URCU_TLS(nr_successful_enqueues);
- printf_verbose("enqueuer thread_end, thread id : %lx, tid %lu, "
- "enqueues %llu successful_enqueues %llu\n",
- pthread_self(),
- (unsigned long) gettid(),
- URCU_TLS(nr_enqueues), URCU_TLS(nr_successful_enqueues));
+ printf_verbose("enqueuer thread_end, tid %lu, "
+ "enqueues %llu successful_enqueues %llu\n",
+ urcu_get_thread_id(),
+ URCU_TLS(nr_enqueues),
+ URCU_TLS(nr_successful_enqueues));
return ((void*)1);
}
{
unsigned long long *count = _count;
- printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
- "dequeuer", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "dequeuer", urcu_get_thread_id());
set_affinity();
}
rcu_unregister_thread();
- printf_verbose("dequeuer thread_end, thread id : %lx, tid %lu, "
- "dequeues %llu, successful_dequeues %llu\n",
- pthread_self(),
- (unsigned long) gettid(),
- URCU_TLS(nr_dequeues), URCU_TLS(nr_successful_dequeues));
+ printf_verbose("dequeuer thread_end, tid %lu, "
+ "dequeues %llu, successful_dequeues %llu\n",
+ urcu_get_thread_id(),
+ URCU_TLS(nr_dequeues),
+ URCU_TLS(nr_successful_dequeues));
count[0] = URCU_TLS(nr_dequeues);
count[1] = URCU_TLS(nr_successful_dequeues);
return ((void*)2);
duration, nr_enqueuers, nr_dequeuers);
printf_verbose("Writer delay : %lu loops.\n", rduration);
printf_verbose("Reader duration : %lu loops.\n", wdelay);
- printf_verbose("thread %-6s, thread id : %lx, tid %lu\n",
- "main", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread %-6s, tid %lu\n",
+ "main", urcu_get_thread_id());
tid_enqueuer = malloc(sizeof(*tid_enqueuer) * nr_enqueuers);
tid_dequeuer = malloc(sizeof(*tid_dequeuer) * nr_dequeuers);
#include <urcu/arch.h>
#include <urcu/tls-compat.h>
#include "cpuset.h"
-
-#ifdef __linux__
-#include <syscall.h>
-#endif
+#include "thread-id.h"
/* hardcoded number of CPUs */
#define NR_CPUS 16384
-#if defined(_syscall0)
-_syscall0(pid_t, gettid)
-#elif defined(__NR_gettid)
-static inline pid_t gettid(void)
-{
- return syscall(__NR_gettid);
-}
-#else
-#warning "use pid as tid"
-static inline pid_t gettid(void)
-{
- return getpid();
-}
-#endif
-
#ifndef DYNAMIC_LINK_TEST
#define _LGPL_SOURCE
#endif
{
unsigned long long *count = _count;
- printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
- "enqueuer", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "enqueuer", urcu_get_thread_id());
set_affinity();
count[0] = URCU_TLS(nr_enqueues);
count[1] = URCU_TLS(nr_successful_enqueues);
- printf_verbose("enqueuer thread_end, thread id : %lx, tid %lu, "
- "enqueues %llu successful_enqueues %llu\n",
- pthread_self(),
- (unsigned long) gettid(),
- URCU_TLS(nr_enqueues), URCU_TLS(nr_successful_enqueues));
+ printf_verbose("enqueuer thread_end, tid %lu, "
+ "enqueues %llu successful_enqueues %llu\n",
+ urcu_get_thread_id(),
+ URCU_TLS(nr_enqueues),
+ URCU_TLS(nr_successful_enqueues));
return ((void*)1);
}
unsigned long long *count = _count;
unsigned int counter = 0;
- printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
- "dequeuer", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "dequeuer", urcu_get_thread_id());
set_affinity();
rcu_unregister_thread();
- printf_verbose("dequeuer thread_end, thread id : %lx, tid %lu, "
- "dequeues %llu, successful_dequeues %llu\n",
- pthread_self(),
- (unsigned long) gettid(),
- URCU_TLS(nr_dequeues), URCU_TLS(nr_successful_dequeues));
+ printf_verbose("dequeuer thread_end, tid %lu, "
+ "dequeues %llu, successful_dequeues %llu\n",
+ urcu_get_thread_id(),
+ URCU_TLS(nr_dequeues),
+ URCU_TLS(nr_successful_dequeues));
count[0] = URCU_TLS(nr_dequeues);
count[1] = URCU_TLS(nr_successful_dequeues);
return ((void*)2);
printf_verbose("External sync: none.\n");
printf_verbose("Writer delay : %lu loops.\n", rduration);
printf_verbose("Reader duration : %lu loops.\n", wdelay);
- printf_verbose("thread %-6s, thread id : %lx, tid %lu\n",
- "main", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread %-6s, tid %lu\n",
+ "main", urcu_get_thread_id());
tid_enqueuer = malloc(sizeof(*tid_enqueuer) * nr_enqueuers);
tid_dequeuer = malloc(sizeof(*tid_dequeuer) * nr_dequeuers);
#include <urcu/arch.h>
#include <urcu/tls-compat.h>
#include "cpuset.h"
-
-#ifdef __linux__
-#include <syscall.h>
-#endif
+#include "thread-id.h"
/* hardcoded number of CPUs */
#define NR_CPUS 16384
-#if defined(_syscall0)
-_syscall0(pid_t, gettid)
-#elif defined(__NR_gettid)
-static inline pid_t gettid(void)
-{
- return syscall(__NR_gettid);
-}
-#else
-#warning "use pid as tid"
-static inline pid_t gettid(void)
-{
- return getpid();
-}
-#endif
-
#ifndef DYNAMIC_LINK_TEST
#define _LGPL_SOURCE
#endif
{
unsigned long long *count = _count;
- printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
- "enqueuer", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "enqueuer", urcu_get_thread_id());
set_affinity();
count[0] = URCU_TLS(nr_enqueues);
count[1] = URCU_TLS(nr_successful_enqueues);
- printf_verbose("enqueuer thread_end, thread id : %lx, tid %lu, "
- "enqueues %llu successful_enqueues %llu\n",
- pthread_self(),
- (unsigned long) gettid(),
- URCU_TLS(nr_enqueues), URCU_TLS(nr_successful_enqueues));
+ printf_verbose("enqueuer thread_end, tid %lu, "
+ "enqueues %llu successful_enqueues %llu\n",
+ urcu_get_thread_id(),
+ URCU_TLS(nr_enqueues),
+ URCU_TLS(nr_successful_enqueues));
return ((void*)1);
}
{
unsigned long long *count = _count;
- printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
- "dequeuer", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "dequeuer", urcu_get_thread_id());
set_affinity();
rcu_unregister_thread();
- printf_verbose("dequeuer thread_end, thread id : %lx, tid %lu, "
- "dequeues %llu, successful_dequeues %llu\n",
- pthread_self(),
- (unsigned long) gettid(),
- URCU_TLS(nr_dequeues), URCU_TLS(nr_successful_dequeues));
+ printf_verbose("dequeuer thread_end, tid %lu, "
+ "dequeues %llu, successful_dequeues %llu\n",
+ urcu_get_thread_id(),
+ URCU_TLS(nr_dequeues),
+ URCU_TLS(nr_successful_dequeues));
count[0] = URCU_TLS(nr_dequeues);
count[1] = URCU_TLS(nr_successful_dequeues);
return ((void*)2);
duration, nr_enqueuers, nr_dequeuers);
printf_verbose("Writer delay : %lu loops.\n", rduration);
printf_verbose("Reader duration : %lu loops.\n", wdelay);
- printf_verbose("thread %-6s, thread id : %lx, tid %lu\n",
- "main", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread %-6s, tid %lu\n",
+ "main", urcu_get_thread_id());
tid_enqueuer = malloc(sizeof(*tid_enqueuer) * nr_enqueuers);
tid_dequeuer = malloc(sizeof(*tid_dequeuer) * nr_dequeuers);
#include <urcu/arch.h>
#include <urcu/tls-compat.h>
#include "cpuset.h"
-
-#ifdef __linux__
-#include <syscall.h>
-#endif
+#include "thread-id.h"
/* hardcoded number of CPUs */
#define NR_CPUS 16384
-#if defined(_syscall0)
-_syscall0(pid_t, gettid)
-#elif defined(__NR_gettid)
-static inline pid_t gettid(void)
-{
- return syscall(__NR_gettid);
-}
-#else
-#warning "use pid as tid"
-static inline pid_t gettid(void)
-{
- return getpid();
-}
-#endif
-
#ifndef DYNAMIC_LINK_TEST
#define _LGPL_SOURCE
#else
unsigned long long *count = _count;
int *local_ptr;
- printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
- "reader", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
set_affinity();
rcu_unregister_thread();
*count = URCU_TLS(nr_reads);
- printf_verbose("thread_end %s, thread id : %lx, tid %lu\n",
- "reader", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_end %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
return ((void*)1);
}
unsigned long long *count = _count;
int *new, *old;
- printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
- "writer", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
set_affinity();
loop_sleep(wdelay);
}
- printf_verbose("thread_end %s, thread id : %lx, tid %lu\n",
- "writer", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_end %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
*count = URCU_TLS(nr_writes);
return ((void*)2);
}
duration, nr_readers, nr_writers);
printf_verbose("Writer delay : %lu loops.\n", wdelay);
printf_verbose("Reader duration : %lu loops.\n", rduration);
- printf_verbose("thread %-6s, thread id : %lx, tid %lu\n",
- "main", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread %-6s, tid %lu\n",
+ "main", urcu_get_thread_id());
tid_reader = malloc(sizeof(*tid_reader) * nr_readers);
tid_writer = malloc(sizeof(*tid_writer) * nr_writers);
#include <urcu/arch.h>
#include <urcu/tls-compat.h>
#include "cpuset.h"
-
-#ifdef __linux__
-#include <syscall.h>
-#endif
+#include "thread-id.h"
/* hardcoded number of CPUs */
#define NR_CPUS 16384
-#if defined(_syscall0)
-_syscall0(pid_t, gettid)
-#elif defined(__NR_gettid)
-static inline pid_t gettid(void)
-{
- return syscall(__NR_gettid);
-}
-#else
-#warning "use pid as tid"
-static inline pid_t gettid(void)
-{
- return getpid();
-}
-#endif
-
#define _LGPL_SOURCE
#include <urcu-qsbr.h>
unsigned long long *count = _count;
struct test_array *local_ptr;
- printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
- "reader", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
set_affinity();
rcu_unregister_thread();
*count = URCU_TLS(nr_reads);
- printf_verbose("thread_end %s, thread id : %lx, tid %lu\n",
- "reader", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_end %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
return ((void*)1);
}
struct test_array *new, *old;
#endif
- printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
- "writer", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
set_affinity();
loop_sleep(wdelay);
}
- printf_verbose("thread_end %s, thread id : %lx, tid %lu\n",
- "writer", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_end %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
tot_nr_writes[wtidx] = URCU_TLS(nr_writes);
return ((void*)2);
}
duration, nr_readers, nr_writers);
printf_verbose("Writer delay : %lu loops.\n", wdelay);
printf_verbose("Reader duration : %lu loops.\n", rduration);
- printf_verbose("thread %-6s, thread id : %lx, tid %lu\n",
- "main", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread %-6s, tid %lu\n",
+ "main", urcu_get_thread_id());
tid_reader = malloc(sizeof(*tid_reader) * nr_readers);
tid_writer = malloc(sizeof(*tid_writer) * nr_writers);
#include <errno.h>
#include <urcu/arch.h>
-
-#ifdef __linux__
-#include <syscall.h>
-#endif
-
-#if defined(_syscall0)
-_syscall0(pid_t, gettid)
-#elif defined(__NR_gettid)
-static inline pid_t gettid(void)
-{
- return syscall(__NR_gettid);
-}
-#else
-#warning "use pid as tid"
-static inline pid_t gettid(void)
-{
- return getpid();
-}
-#endif
+#include "thread-id.h"
#define _LGPL_SOURCE
#include <urcu-qsbr.h>
struct test_array *local_ptr;
cycles_t time1, time2;
- printf("thread_begin %s, thread id : %lx, tid %lu\n",
- "reader", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf("thread_begin %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
sleep(2);
rcu_register_thread();
reader_time[(unsigned long)arg] = time2 - time1;
sleep(2);
- printf("thread_end %s, thread id : %lx, tid %lu\n",
- "reader", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf("thread_end %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
return ((void*)1);
}
struct test_array *new, *old;
cycles_t time1, time2;
- printf("thread_begin %s, thread id : %lx, tid %lu\n",
- "writer", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf("thread_begin %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
sleep(2);
for (i = 0; i < OUTER_WRITE_LOOP; i++) {
}
}
- printf("thread_end %s, thread id : %lx, tid %lu\n",
- "writer", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf("thread_end %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
return ((void*)2);
}
tid_reader = malloc(sizeof(*tid_reader) * num_read);
tid_writer = malloc(sizeof(*tid_writer) * num_write);
- printf("thread %-6s, thread id : %lx, tid %lu\n",
- "main", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf("thread %-6s, tid %lu\n",
+ "main", urcu_get_thread_id());
for (i = 0; i < NR_READ; i++) {
err = pthread_create(&tid_reader[i], NULL, thr_reader,
#include <errno.h>
#include <urcu/arch.h>
-#ifdef __linux__
-#include <syscall.h>
-#endif
-
-#if defined(_syscall0)
-_syscall0(pid_t, gettid)
-#elif defined(__NR_gettid)
-static inline pid_t gettid(void)
-{
- return syscall(__NR_gettid);
-}
-#else
-#warning "use pid as tid"
-static inline pid_t gettid(void)
-{
- return getpid();
-}
-#endif
+#include "thread-id.h"
#define _LGPL_SOURCE
#include <urcu.h>
struct test_array *local_ptr;
cycles_t time1, time2;
- printf("thread_begin %s, thread id : %lx, tid %lu\n",
- "reader", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf("thread_begin %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
sleep(2);
rcu_register_thread();
reader_time[(unsigned long)arg] = time2 - time1;
sleep(2);
- printf("thread_end %s, thread id : %lx, tid %lu\n",
- "reader", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf("thread_end %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
return ((void*)1);
}
struct test_array *new, *old;
cycles_t time1, time2;
- printf("thread_begin %s, thread id : %lx, tid %lu\n",
- "writer", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf("thread_begin %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
sleep(2);
for (i = 0; i < OUTER_WRITE_LOOP; i++) {
}
}
- printf("thread_end %s, thread id : %lx, tid %lu\n",
- "writer", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf("thread_end %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
return ((void*)2);
}
tid_reader = malloc(sizeof(*tid_reader) * num_read);
tid_writer = malloc(sizeof(*tid_writer) * num_write);
- printf("thread %-6s, thread id : %lx, tid %lu\n",
- "main", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf("thread %-6s, tid %lu\n",
+ "main", urcu_get_thread_id());
for (i = 0; i < NR_READ; i++) {
err = pthread_create(&tid_reader[i], NULL, thr_reader,
#include <urcu/tls-compat.h>
#include <urcu/uatomic.h>
#include "cpuset.h"
-
-#ifdef __linux__
-#include <syscall.h>
-#endif
+#include "thread-id.h"
/* hardcoded number of CPUs */
#define NR_CPUS 16384
-#if defined(_syscall0)
-_syscall0(pid_t, gettid)
-#elif defined(__NR_gettid)
-static inline pid_t gettid(void)
-{
- return syscall(__NR_gettid);
-}
-#else
-#warning "use pid as tid"
-static inline pid_t gettid(void)
-{
- return getpid();
-}
-#endif
-
#ifndef DYNAMIC_LINK_TEST
#define _LGPL_SOURCE
#endif
unsigned long long *count = _count;
bool was_nonempty;
- printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
- "enqueuer", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "enqueuer", urcu_get_thread_id());
set_affinity();
count[0] = URCU_TLS(nr_enqueues);
count[1] = URCU_TLS(nr_successful_enqueues);
count[2] = URCU_TLS(nr_empty_dest_enqueues);
- printf_verbose("enqueuer thread_end, thread id : %lx, tid %lu, "
- "enqueues %llu successful_enqueues %llu, "
- "empty_dest_enqueues %llu\n",
- pthread_self(),
- (unsigned long) gettid(),
- URCU_TLS(nr_enqueues),
- URCU_TLS(nr_successful_enqueues),
- URCU_TLS(nr_empty_dest_enqueues));
+ printf_verbose("enqueuer thread_end, tid %lu, "
+ "enqueues %llu successful_enqueues %llu, "
+ "empty_dest_enqueues %llu\n",
+ urcu_get_thread_id(),
+ URCU_TLS(nr_enqueues),
+ URCU_TLS(nr_successful_enqueues),
+ URCU_TLS(nr_empty_dest_enqueues));
return ((void*)1);
}
unsigned long long *count = _count;
unsigned int counter = 0;
- printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
- "dequeuer", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "dequeuer", urcu_get_thread_id());
set_affinity();
loop_sleep(rduration);
}
- printf_verbose("dequeuer thread_end, thread id : %lx, tid %lu, "
- "dequeues %llu, successful_dequeues %llu, "
- "nr_splice %llu\n",
- pthread_self(),
- (unsigned long) gettid(),
- URCU_TLS(nr_dequeues), URCU_TLS(nr_successful_dequeues),
- URCU_TLS(nr_splice));
+ printf_verbose("dequeuer thread_end, tid %lu, "
+ "dequeues %llu, successful_dequeues %llu, "
+ "nr_splice %llu\n",
+ urcu_get_thread_id(),
+ URCU_TLS(nr_dequeues), URCU_TLS(nr_successful_dequeues),
+ URCU_TLS(nr_splice));
count[0] = URCU_TLS(nr_dequeues);
count[1] = URCU_TLS(nr_successful_dequeues);
count[2] = URCU_TLS(nr_splice);
printf_verbose("Wait for dequeuers to empty queue.\n");
printf_verbose("Writer delay : %lu loops.\n", rduration);
printf_verbose("Reader duration : %lu loops.\n", wdelay);
- printf_verbose("thread %-6s, thread id : %lx, tid %lu\n",
- "main", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread %-6s, tid %lu\n",
+ "main", urcu_get_thread_id());
tid_enqueuer = malloc(sizeof(*tid_enqueuer) * nr_enqueuers);
tid_dequeuer = malloc(sizeof(*tid_dequeuer) * nr_dequeuers);
#include <urcu/arch.h>
#include <urcu/tls-compat.h>
#include "cpuset.h"
-
-#ifdef __linux__
-#include <syscall.h>
-#endif
+#include "thread-id.h"
/* hardcoded number of CPUs */
#define NR_CPUS 16384
-#if defined(_syscall0)
-_syscall0(pid_t, gettid)
-#elif defined(__NR_gettid)
-static inline pid_t gettid(void)
-{
- return syscall(__NR_gettid);
-}
-#else
-#warning "use pid as tid"
-static inline pid_t gettid(void)
-{
- return getpid();
-}
-#endif
-
#ifndef DYNAMIC_LINK_TEST
#define _LGPL_SOURCE
#endif
{
unsigned long long *count = _count;
- printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
- "enqueuer", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "enqueuer", urcu_get_thread_id());
set_affinity();
count[0] = URCU_TLS(nr_enqueues);
count[1] = URCU_TLS(nr_successful_enqueues);
- printf_verbose("enqueuer thread_end, thread id : %lx, tid %lu, "
- "enqueues %llu successful_enqueues %llu\n",
- pthread_self(),
- (unsigned long) gettid(),
- URCU_TLS(nr_enqueues), URCU_TLS(nr_successful_enqueues));
+ printf_verbose("enqueuer thread_end, tid %lu, "
+ "enqueues %llu successful_enqueues %llu\n",
+ urcu_get_thread_id(),
+ URCU_TLS(nr_enqueues),
+ URCU_TLS(nr_successful_enqueues));
return ((void*)1);
}
{
unsigned long long *count = _count;
- printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
- "dequeuer", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "dequeuer", urcu_get_thread_id());
set_affinity();
loop_sleep(rduration);
}
- printf_verbose("dequeuer thread_end, thread id : %lx, tid %lu, "
- "dequeues %llu, successful_dequeues %llu\n",
- pthread_self(),
- (unsigned long) gettid(),
- URCU_TLS(nr_dequeues), URCU_TLS(nr_successful_dequeues));
+ printf_verbose("dequeuer thread_end, tid %lu, "
+ "dequeues %llu, successful_dequeues %llu\n",
+ urcu_get_thread_id(),
+ URCU_TLS(nr_dequeues),
+ URCU_TLS(nr_successful_dequeues));
count[0] = URCU_TLS(nr_dequeues);
count[1] = URCU_TLS(nr_successful_dequeues);
return ((void*)2);
duration, nr_enqueuers, nr_dequeuers);
printf_verbose("Writer delay : %lu loops.\n", rduration);
printf_verbose("Reader duration : %lu loops.\n", wdelay);
- printf_verbose("thread %-6s, thread id : %lx, tid %lu\n",
- "main", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread %-6s, tid %lu\n",
+ "main", urcu_get_thread_id());
tid_enqueuer = malloc(sizeof(*tid_enqueuer) * nr_enqueuers);
tid_dequeuer = malloc(sizeof(*tid_dequeuer) * nr_dequeuers);
#include <urcu/tls-compat.h>
#include <urcu/uatomic.h>
#include "cpuset.h"
-
-#ifdef __linux__
-#include <syscall.h>
-#endif
+#include "thread-id.h"
/* hardcoded number of CPUs */
#define NR_CPUS 16384
-#if defined(_syscall0)
-_syscall0(pid_t, gettid)
-#elif defined(__NR_gettid)
-static inline pid_t gettid(void)
-{
- return syscall(__NR_gettid);
-}
-#else
-#warning "use pid as tid"
-static inline pid_t gettid(void)
-{
- return getpid();
-}
-#endif
-
#ifndef DYNAMIC_LINK_TEST
#define _LGPL_SOURCE
#endif
unsigned long long *count = _count;
bool was_nonempty;
- printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
- "enqueuer", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "enqueuer", urcu_get_thread_id());
set_affinity();
count[0] = URCU_TLS(nr_enqueues);
count[1] = URCU_TLS(nr_successful_enqueues);
count[2] = URCU_TLS(nr_empty_dest_enqueues);
- printf_verbose("enqueuer thread_end, thread id : %lx, tid %lu, "
- "enqueues %llu successful_enqueues %llu, "
- "empty_dest_enqueues %llu\n",
- pthread_self(),
- (unsigned long) gettid(),
- URCU_TLS(nr_enqueues),
- URCU_TLS(nr_successful_enqueues),
- URCU_TLS(nr_empty_dest_enqueues));
+ printf_verbose("enqueuer thread_end, tid %lu, "
+ "enqueues %llu successful_enqueues %llu, "
+ "empty_dest_enqueues %llu\n",
+ urcu_get_thread_id(),
+ URCU_TLS(nr_enqueues),
+ URCU_TLS(nr_successful_enqueues),
+ URCU_TLS(nr_empty_dest_enqueues));
return ((void*)1);
}
unsigned long long *count = _count;
unsigned int counter = 0;
- printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
- "dequeuer", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "dequeuer", urcu_get_thread_id());
set_affinity();
loop_sleep(rduration);
}
- printf_verbose("dequeuer thread_end, thread id : %lx, tid %lu, "
- "dequeues %llu, successful_dequeues %llu "
- "pop_all %llu pop_last %llu\n",
- pthread_self(),
- (unsigned long) gettid(),
- URCU_TLS(nr_dequeues), URCU_TLS(nr_successful_dequeues),
- URCU_TLS(nr_pop_all),
- URCU_TLS(nr_pop_last));
+ printf_verbose("dequeuer thread_end, tid %lu, "
+ "dequeues %llu, successful_dequeues %llu "
+ "pop_all %llu pop_last %llu\n",
+ urcu_get_thread_id(),
+ URCU_TLS(nr_dequeues), URCU_TLS(nr_successful_dequeues),
+ URCU_TLS(nr_pop_all),
+ URCU_TLS(nr_pop_last));
count[0] = URCU_TLS(nr_dequeues);
count[1] = URCU_TLS(nr_successful_dequeues);
count[2] = URCU_TLS(nr_pop_all);
printf_verbose("Wait for dequeuers to empty stack.\n");
printf_verbose("Writer delay : %lu loops.\n", rduration);
printf_verbose("Reader duration : %lu loops.\n", wdelay);
- printf_verbose("thread %-6s, thread id : %lx, tid %lu\n",
- "main", (unsigned long) pthread_self(),
- (unsigned long) gettid());
+ printf_verbose("thread %-6s, tid %lu\n",
+ "main", urcu_get_thread_id());
tid_enqueuer = malloc(sizeof(*tid_enqueuer) * nr_enqueuers);
tid_dequeuer = malloc(sizeof(*tid_dequeuer) * nr_dequeuers);
--- /dev/null
+#ifndef _TEST_THREAD_ID_H
+#define _TEST_THREAD_ID_H
+
+/*
+ * thread-id.h
+ *
+ * Userspace RCU library - thread ID
+ *
+ * Copyright 2013 - Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+
+#ifdef __linux__
+# include <syscall.h>
+
+# if defined(_syscall0)
+_syscall0(pid_t, gettid)
+# elif defined(__NR_gettid)
+static inline pid_t gettid(void)
+{
+ return syscall(__NR_gettid);
+}
+# endif
+
+static inline
+unsigned long urcu_get_thread_id(void)
+{
+ return (unsigned long) gettid();
+}
+#elif defined(__FreeBSD__)
+# include <pthread_np.h>
+
+static inline
+unsigned long urcu_get_thread_id(void)
+{
+ return (unsigned long) pthread_getthreadid_np();
+}
+#else
+# warning "use pid as thread ID"
+static inline
+unsigned long urcu_get_thread_id(void)
+{
+ return (unsigned long) getpid();
+}
+#endif
+
+#endif /* _TEST_THREAD_ID_H */
void rcu_exit(void)
{
- struct sigaction act;
- int ret;
-
- ret = sigaction(SIGRCU, NULL, &act);
- if (ret)
- urcu_die(errno);
- assert(act.sa_sigaction == sigrcu_handler);
- assert(cds_list_empty(®istry));
+ /*
+ * Don't unregister the SIGRCU signal handler anymore, because
+ * call_rcu threads could still be using it shortly before the
+ * application exits.
+ * Assertion disabled because call_rcu threads are now rcu
+ * readers, and left running at exit.
+ * assert(cds_list_empty(®istry));
+ */
}
#endif /* #ifdef RCU_SIGNAL */
*
* Author: Jan Blunck <jblunck@suse.de>
*
- * Copyright (C) 2010 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ * Copyright (C) 2010-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 Lesser General Public License version 2.1 as
#include <stddef.h>
-struct cds_hlist_head
-{
+struct cds_hlist_head {
struct cds_hlist_node *next;
};
-struct cds_hlist_node
-{
- struct cds_hlist_node *next;
- struct cds_hlist_node *prev;
+struct cds_hlist_node {
+ struct cds_hlist_node *next, *prev;
};
-/* Initialize a new list head. */
-static inline void CDS_INIT_HLIST_HEAD(struct cds_hlist_head *ptr)
+/* Initialize a new list head. */
+static inline
+void CDS_INIT_HLIST_HEAD(struct cds_hlist_head *ptr)
{
ptr->next = NULL;
}
-/* Get typed element from list at a given position. */
-#define cds_hlist_entry(ptr, type, member) \
+#define CDS_HLIST_HEAD(name) \
+ struct cds_hlist_head name = { NULL }
+
+#define CDS_HLIST_HEAD_INIT(name) \
+ { .next = NULL }
+
+/* Get typed element from list at a given position. */
+#define cds_hlist_entry(ptr, type, member) \
((type *) ((char *) (ptr) - (unsigned long) (&((type *) 0)->member)))
/* Get first entry from a list. Assumes the hlist is not empty. */
#define cds_hlist_first_entry(ptr, type, member) \
cds_list_entry((ptr)->next, type, member)
-static inline int cds_hlist_empty(struct cds_hlist_head *head)
+static inline
+int cds_hlist_empty(struct cds_hlist_head *head)
{
return !head->next;
}
-/* Add new element at the head of the list. */
-static inline void cds_hlist_add_head (struct cds_hlist_node *newp,
- struct cds_hlist_head *head)
+/* Add new element at the head of the list. */
+static inline
+void cds_hlist_add_head(struct cds_hlist_node *newp,
+ struct cds_hlist_head *head)
{
if (head->next)
head->next->prev = newp;
-
newp->next = head->next;
- newp->prev = (struct cds_hlist_node *)head;
+ newp->prev = (struct cds_hlist_node *) head;
head->next = newp;
}
-/* Remove element from list. */
-static inline void cds_hlist_del (struct cds_hlist_node *elem)
+/* Remove element from list. */
+static inline
+void cds_hlist_del(struct cds_hlist_node *elem)
{
if (elem->next)
elem->next->prev = elem->prev;
-
elem->prev->next = elem->next;
}
-#define cds_hlist_for_each_entry(entry, pos, head, member) \
- for (pos = (head)->next, \
- entry = cds_hlist_entry(pos, __typeof__(*entry), member); \
- pos != NULL; \
- pos = pos->next, \
- entry = cds_hlist_entry(pos, __typeof__(*entry), member))
-
-#define cds_hlist_for_each_entry_safe(entry, pos, p, head, member) \
- for (pos = (head)->next, \
- entry = cds_hlist_entry(pos, __typeof__(*entry), member); \
- (pos != NULL) && ({ p = pos->next; 1;}); \
- pos = p, \
- entry = cds_hlist_entry(pos, __typeof__(*entry), member))
+#define cds_hlist_for_each(pos, head) \
+ for (pos = (head)->next; pos != NULL; pos = pos->next)
+
+#define cds_hlist_for_each_safe(pos, p, head) \
+ for (pos = (head)->next; \
+ (pos != NULL) && (p = pos->next, 1); \
+ pos = p)
+
+/*
+ * cds_hlist_for_each_entry and cds_hlist_for_each_entry_safe take
+ * respectively 4 and 5 arguments, while the Linux kernel APIs take 3,
+ * and 4. We implement cds_hlist_for_each_entry_2() and
+ * cds_hlist_for_each_entry_safe_2() to follow the Linux kernel APIs.
+ */
+#define cds_hlist_for_each_entry(entry, pos, head, member) \
+ for (pos = (head)->next, \
+ entry = cds_hlist_entry(pos, __typeof__(*entry), member); \
+ pos != NULL; \
+ pos = pos->next, \
+ entry = cds_hlist_entry(pos, __typeof__(*entry), member))
+
+#define cds_hlist_for_each_entry_safe(entry, pos, p, head, member) \
+ for (pos = (head)->next, \
+ entry = cds_hlist_entry(pos, __typeof__(*entry), member); \
+ (pos != NULL) && (p = pos->next, 1); \
+ pos = p, \
+ entry = cds_hlist_entry(pos, __typeof__(*entry), member))
+
+#define cds_hlist_for_each_entry_2(entry, head, member) \
+ for (entry = cds_hlist_entry((head)->next, __typeof__(*entry), member); \
+ &entry->member != NULL; \
+ entry = cds_hlist_entry(entry->member.next, __typeof__(*entry), member))
+
+#define cds_hlist_for_each_entry_safe_2(entry, e, head, member) \
+ for (entry = cds_hlist_entry((head)->next, __typeof__(*entry), member); \
+ (&entry->member != NULL) && (e = cds_hlist_entry(entry->member.next, \
+ __typeof__(*entry), member), 1); \
+ entry = e)
#endif /* _KCOMPAT_HLIST_H */
#ifndef _CDS_LIST_H
#define _CDS_LIST_H 1
-/* The definitions of this file are adopted from those which can be
- found in the Linux kernel headers to enable people familiar with
- the latter find their way in these sources as well. */
-
+/*
+ * The definitions of this file are adopted from those which can be
+ * found in the Linux kernel headers to enable people familiar with the
+ * latter find their way in these sources as well.
+ */
-/* Basic type for the double-link list. */
-struct cds_list_head
-{
- struct cds_list_head *next;
- struct cds_list_head *prev;
+/* Basic type for the double-link list. */
+struct cds_list_head {
+ struct cds_list_head *next, *prev;
};
-
-/* Define a variable with the head and tail of the list. */
+/* Define a variable with the head and tail of the list. */
#define CDS_LIST_HEAD(name) \
- struct cds_list_head name = { &(name), &(name) }
+ struct cds_list_head name = { &(name), &(name) }
-/* Initialize a new list head. */
+/* Initialize a new list head. */
#define CDS_INIT_LIST_HEAD(ptr) \
- (ptr)->next = (ptr)->prev = (ptr)
+ (ptr)->next = (ptr)->prev = (ptr)
#define CDS_LIST_HEAD_INIT(name) { .prev = &(name), .next = &(name) }
-/* Add new element at the head of the list. */
-static inline void
-cds_list_add (struct cds_list_head *newp, struct cds_list_head *head)
+/* Add new element at the head of the list. */
+static inline
+void cds_list_add(struct cds_list_head *newp, struct cds_list_head *head)
{
- head->next->prev = newp;
- newp->next = head->next;
- newp->prev = head;
- head->next = newp;
+ head->next->prev = newp;
+ newp->next = head->next;
+ newp->prev = head;
+ head->next = newp;
}
-
-/* Add new element at the tail of the list. */
-static inline void
-cds_list_add_tail (struct cds_list_head *newp, struct cds_list_head *head)
+/* Add new element at the tail of the list. */
+static inline
+void cds_list_add_tail(struct cds_list_head *newp, struct cds_list_head *head)
{
- head->prev->next = newp;
- newp->next = head;
- newp->prev = head->prev;
- head->prev = newp;
+ head->prev->next = newp;
+ newp->next = head;
+ newp->prev = head->prev;
+ head->prev = newp;
}
-
-/* Remove element from list. */
-static inline void
-__cds_list_del (struct cds_list_head *prev, struct cds_list_head *next)
+/* Remove element from list. */
+static inline
+void __cds_list_del(struct cds_list_head *prev, struct cds_list_head *next)
{
- next->prev = prev;
- prev->next = next;
+ next->prev = prev;
+ prev->next = next;
}
-/* Remove element from list. */
-static inline void
-cds_list_del (struct cds_list_head *elem)
+/* Remove element from list. */
+static inline
+void cds_list_del(struct cds_list_head *elem)
{
- __cds_list_del (elem->prev, elem->next);
+ __cds_list_del(elem->prev, elem->next);
}
/* Remove element from list, initializing the element's list pointers. */
-static inline void
-cds_list_del_init (struct cds_list_head *elem)
+static inline
+void cds_list_del_init(struct cds_list_head *elem)
{
cds_list_del(elem);
CDS_INIT_LIST_HEAD(elem);
}
-/* delete from list, add to another list as head */
-static inline void
-cds_list_move (struct cds_list_head *elem, struct cds_list_head *head)
+/* Delete from list, add to another list as head. */
+static inline
+void cds_list_move(struct cds_list_head *elem, struct cds_list_head *head)
{
- __cds_list_del (elem->prev, elem->next);
- cds_list_add (elem, head);
+ __cds_list_del(elem->prev, elem->next);
+ cds_list_add(elem, head);
}
-/* replace an old entry.
- */
-static inline void
-cds_list_replace(struct cds_list_head *old, struct cds_list_head *_new)
+/* Replace an old entry. */
+static inline
+void cds_list_replace(struct cds_list_head *old, struct cds_list_head *_new)
{
_new->next = old->next;
_new->prev = old->prev;
_new->next->prev = _new;
}
-/* Join two lists. */
-static inline void
-cds_list_splice (struct cds_list_head *add, struct cds_list_head *head)
+/* Join two lists. */
+static inline
+void cds_list_splice(struct cds_list_head *add, struct cds_list_head *head)
{
- /* Do nothing if the list which gets added is empty. */
- if (add != add->next)
- {
- add->next->prev = head;
- add->prev->next = head->next;
- head->next->prev = add->prev;
- head->next = add->next;
- }
+ /* Do nothing if the list which gets added is empty. */
+ if (add != add->next) {
+ add->next->prev = head;
+ add->prev->next = head->next;
+ head->next->prev = add->prev;
+ head->next = add->next;
+ }
}
-/* Get typed element from list at a given position. */
+/* Get typed element from list at a given position. */
#define cds_list_entry(ptr, type, member) \
- ((type *) ((char *) (ptr) - (unsigned long) (&((type *) 0)->member)))
+ ((type *) ((char *) (ptr) - (unsigned long) (&((type *) 0)->member)))
/* Get first entry from a list. */
#define cds_list_first_entry(ptr, type, member) \
cds_list_entry((ptr)->next, type, member)
-
-/* Iterate forward over the elements of the list. */
+/* Iterate forward over the elements of the list. */
#define cds_list_for_each(pos, head) \
- for (pos = (head)->next; pos != (head); pos = pos->next)
+ for (pos = (head)->next; pos != (head); pos = pos->next)
-/* Iterate forward over the elements list. The list elements can be
- removed from the list while doing this. */
+/*
+ * Iterate forward over the elements list. The list elements can be
+ * removed from the list while doing this.
+ */
#define cds_list_for_each_safe(pos, p, head) \
- for (pos = (head)->next, p = pos->next; \
- pos != (head); \
- pos = p, p = pos->next)
+ for (pos = (head)->next, p = pos->next; \
+ pos != (head); \
+ pos = p, p = pos->next)
-/* Iterate backward over the elements of the list. */
+/* Iterate backward over the elements of the list. */
#define cds_list_for_each_prev(pos, head) \
- for (pos = (head)->prev; pos != (head); pos = pos->prev)
+ for (pos = (head)->prev; pos != (head); pos = pos->prev)
-/* Iterate backwards over the elements list. The list elements can be
- removed from the list while doing this. */
+/*
+ * Iterate backwards over the elements list. The list elements can be
+ * removed from the list while doing this.
+ */
#define cds_list_for_each_prev_safe(pos, p, head) \
- for (pos = (head)->prev, p = pos->prev; \
- pos != (head); \
- pos = p, p = pos->prev)
+ for (pos = (head)->prev, p = pos->prev; \
+ pos != (head); \
+ pos = p, p = pos->prev)
-#define cds_list_for_each_entry(pos, head, member) \
+#define cds_list_for_each_entry(pos, head, member) \
for (pos = cds_list_entry((head)->next, __typeof__(*pos), member); \
- &pos->member != (head); \
- pos = cds_list_entry(pos->member.next, __typeof__(*pos), member))
+ &pos->member != (head); \
+ pos = cds_list_entry(pos->member.next, __typeof__(*pos), member))
-#define cds_list_for_each_entry_reverse(pos, head, member) \
+#define cds_list_for_each_entry_reverse(pos, head, member) \
for (pos = cds_list_entry((head)->prev, __typeof__(*pos), member); \
- &pos->member != (head); \
- pos = cds_list_entry(pos->member.prev, __typeof__(*pos), member))
+ &pos->member != (head); \
+ pos = cds_list_entry(pos->member.prev, __typeof__(*pos), member))
-#define cds_list_for_each_entry_safe(pos, p, head, member) \
+#define cds_list_for_each_entry_safe(pos, p, head, member) \
for (pos = cds_list_entry((head)->next, __typeof__(*pos), member), \
- p = cds_list_entry(pos->member.next, __typeof__(*pos), member); \
- &pos->member != (head); \
- pos = p, p = cds_list_entry(pos->member.next, __typeof__(*pos), member))
+ p = cds_list_entry(pos->member.next, __typeof__(*pos), member); \
+ &pos->member != (head); \
+ pos = p, p = cds_list_entry(pos->member.next, __typeof__(*pos), member))
-static inline int cds_list_empty(struct cds_list_head *head)
+static inline
+int cds_list_empty(struct cds_list_head *head)
{
return head == head->next;
}
-static inline void cds_list_replace_init(struct cds_list_head *old,
- struct cds_list_head *_new)
+static inline
+void cds_list_replace_init(struct cds_list_head *old,
+ struct cds_list_head *_new)
{
struct cds_list_head *head = old->next;
+
cds_list_del(old);
cds_list_add_tail(_new, head);
CDS_INIT_LIST_HEAD(old);
#include <urcu/arch.h>
#include <urcu-pointer.h>
-/* Add new element at the head of the list.
- */
-static inline void cds_hlist_add_head_rcu(struct cds_hlist_node *newp,
- struct cds_hlist_head *head)
+/* Add new element at the head of the list. */
+static inline
+void cds_hlist_add_head_rcu(struct cds_hlist_node *newp,
+ struct cds_hlist_head *head)
{
newp->next = head->next;
newp->prev = (struct cds_hlist_node *)head;
- cmm_smp_wmb();
if (head->next)
head->next->prev = newp;
- head->next = newp;
+ rcu_assign_pointer(head->next, newp);
}
/* Remove element from list. */
-static inline void cds_hlist_del_rcu(struct cds_hlist_node *elem)
+static inline
+void cds_hlist_del_rcu(struct cds_hlist_node *elem)
{
if (elem->next)
elem->next->prev = elem->prev;
- elem->prev->next = elem->next;
+ CMM_STORE_SHARED(elem->prev->next, elem->next);
}
/*
* Get first element from a RCU hlist. Assumes the hlist is not empty.
* This must be done while rcu_read_lock() is held.
*/
-#define cds_hlist_first_rcu(ptr, type) \
+#define cds_hlist_first_rcu(ptr, type) \
rcu_dereference((ptr)->next)
/*
* Get first entry from a RCU hlist. Assumes the hlist is not empty.
* This must be done while rcu_read_lock() is held.
*/
-#define cds_hlist_first_entry_rcu(ptr, type, member) \
+#define cds_hlist_first_entry_rcu(ptr, type, member) \
cds_hlist_entry(rcu_dereference((ptr)->next), type, member)
/*
- * Iterate through nodes of the list.
+ * Iterate through elements of the list.
* This must be done while rcu_read_lock() is held.
*/
-
-#define cds_hlist_for_each_rcu(pos, head) \
- for (pos = rcu_dereference((head)->next); \
- pos != NULL; \
- pos = rcu_dereference((pos)->next))
+#define cds_hlist_for_each_rcu(pos, head) \
+ for (pos = rcu_dereference((head)->next); pos != NULL; \
+ pos = rcu_dereference(pos->next))
/*
- * Iterate through elements of the list.
- * This must be done while rcu_read_lock() is held.
+ * cds_hlist_for_each_entry_rcu takes 4 arguments, while the Linux
+ * kernel API only takes 3.
+ * We implement cds_hlist_for_each_entry_rcu_2() to follow the Linux
+ * kernel APIs.
*/
+#define cds_hlist_for_each_entry_rcu(entry, pos, head, member) \
+ for (pos = rcu_dereference((head)->next), \
+ entry = cds_hlist_entry(pos, __typeof__(*entry), member); \
+ pos != NULL; \
+ pos = rcu_dereference(pos->next), \
+ entry = cds_hlist_entry(pos, __typeof__(*entry), member))
-#define cds_hlist_for_each_entry_rcu(entry, pos, head, member) \
- for (pos = rcu_dereference((head)->next), \
- entry = cds_hlist_entry(pos, __typeof__(*entry), member); \
- pos != NULL; \
- pos = rcu_dereference(pos->next), \
- entry = cds_hlist_entry(pos, __typeof__(*entry), member))
+#define cds_hlist_for_each_entry_rcu_2(entry, head, member) \
+ for (entry = cds_hlist_entry(rcu_dereference((head)->next), \
+ __typeof__(*entry), member); \
+ &entry->member != NULL; \
+ entry = cds_hlist_entry(rcu_dereference(entry->member.next), \
+ __typeof__(*entry), member))
#endif /* _URCU_RCUHLIST_H */
#include <urcu/arch.h>
#include <urcu-pointer.h>
-/* Add new element at the head of the list.
- */
-static inline void cds_list_add_rcu(struct cds_list_head *newp, struct cds_list_head *head)
+/* Add new element at the head of the list. */
+static inline
+void cds_list_add_rcu(struct cds_list_head *newp, struct cds_list_head *head)
{
struct cds_list_head *first = head->next;
newp->next = first;
newp->prev = head;
+ head->next->prev = newp;
rcu_assign_pointer(head->next, newp);
- first->prev = newp;
}
-/* replace an old entry atomically.
+/* Add new element at the tail of the list. */
+static inline
+void cds_list_add_tail_rcu(struct cds_list_head *newp,
+ struct cds_list_head *head)
+{
+ newp->next = head;
+ newp->prev = head->prev;
+ rcu_assign_pointer(head->prev->next, newp);
+ head->prev = newp;
+}
+
+/*
+ * Replace an old entry atomically with respect to concurrent RCU
+ * traversal. Mutual exclusion against concurrent updates is required
+ * though.
*/
-static inline void cds_list_replace_rcu(struct cds_list_head *old, struct cds_list_head *_new)
+static inline
+void cds_list_replace_rcu(struct cds_list_head *old, struct cds_list_head *_new)
{
_new->next = old->next;
_new->prev = old->prev;
}
/* Remove element from list. */
-static inline void cds_list_del_rcu(struct cds_list_head *elem)
+static inline
+void cds_list_del_rcu(struct cds_list_head *elem)
{
elem->next->prev = elem->prev;
CMM_STORE_SHARED(elem->prev->next, elem->next);
/* Iterate forward over the elements of the list. */
#define cds_list_for_each_rcu(pos, head) \
- for (pos = rcu_dereference((head)->next); pos != (head); \
- pos = rcu_dereference(pos->next))
+ for (pos = rcu_dereference((head)->next); pos != (head); \
+ pos = rcu_dereference(pos->next))
-/* Iterate through elements of the list.
- */
-#define cds_list_for_each_entry_rcu(pos, head, member) \
- for (pos = cds_list_entry(rcu_dereference((head)->next), __typeof__(*pos), member); \
- &pos->member != (head); \
- pos = cds_list_entry(rcu_dereference(pos->member.next), __typeof__(*pos), member))
+/* Iterate through elements of the list. */
+#define cds_list_for_each_entry_rcu(pos, head, member) \
+ for (pos = cds_list_entry(rcu_dereference((head)->next), __typeof__(*pos), member); \
+ &pos->member != (head); \
+ pos = cds_list_entry(rcu_dereference(pos->member.next), __typeof__(*pos), member))
#endif /* _URCU_RCULIST_H */