Merge branch 'master' into urcu/rcuja-range
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Wed, 26 Jun 2013 21:36:11 +0000 (17:36 -0400)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Wed, 26 Jun 2013 21:36:11 +0000 (17:36 -0400)
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
114 files changed:
.gitignore
configure.ac
doc/examples/Makefile.am
doc/examples/Makefile.examples.template [new file with mode: 0644]
doc/examples/dist-files/Makefile [new file with mode: 0644]
doc/examples/hlist/Makefile [new file with mode: 0644]
doc/examples/hlist/Makefile.cds_hlist_add_head_rcu [new file with mode: 0644]
doc/examples/hlist/Makefile.cds_hlist_del_rcu [new file with mode: 0644]
doc/examples/hlist/Makefile.cds_hlist_for_each_entry_rcu [new file with mode: 0644]
doc/examples/hlist/Makefile.cds_hlist_for_each_rcu [new file with mode: 0644]
doc/examples/hlist/cds_hlist_add_head_rcu.c [new file with mode: 0644]
doc/examples/hlist/cds_hlist_del_rcu.c [new file with mode: 0644]
doc/examples/hlist/cds_hlist_for_each_entry_rcu.c [new file with mode: 0644]
doc/examples/hlist/cds_hlist_for_each_rcu.c [new file with mode: 0644]
doc/examples/lfstack/Makefile [new file with mode: 0644]
doc/examples/lfstack/Makefile.cds_lfs_pop_all_blocking [new file with mode: 0644]
doc/examples/lfstack/Makefile.cds_lfs_pop_blocking [new file with mode: 0644]
doc/examples/lfstack/Makefile.cds_lfs_push [new file with mode: 0644]
doc/examples/lfstack/cds_lfs_pop_all_blocking.c [new file with mode: 0644]
doc/examples/lfstack/cds_lfs_pop_blocking.c [new file with mode: 0644]
doc/examples/lfstack/cds_lfs_push.c [new file with mode: 0644]
doc/examples/list/Makefile [new file with mode: 0644]
doc/examples/list/Makefile.cds_list_add_rcu [new file with mode: 0644]
doc/examples/list/Makefile.cds_list_add_tail_rcu [new file with mode: 0644]
doc/examples/list/Makefile.cds_list_del_rcu [new file with mode: 0644]
doc/examples/list/Makefile.cds_list_for_each_entry_rcu [new file with mode: 0644]
doc/examples/list/Makefile.cds_list_for_each_rcu [new file with mode: 0644]
doc/examples/list/Makefile.cds_list_replace_rcu [new file with mode: 0644]
doc/examples/list/cds_list_add_rcu.c [new file with mode: 0644]
doc/examples/list/cds_list_add_tail_rcu.c [new file with mode: 0644]
doc/examples/list/cds_list_del_rcu.c [new file with mode: 0644]
doc/examples/list/cds_list_for_each_entry_rcu.c [new file with mode: 0644]
doc/examples/list/cds_list_for_each_rcu.c [new file with mode: 0644]
doc/examples/list/cds_list_replace_rcu.c [new file with mode: 0644]
doc/examples/qsbr-minimal/Makefile [deleted file]
doc/examples/qsbr-minimal/qsbr-minimal.c [deleted file]
doc/examples/rculfhash/Makefile [new file with mode: 0644]
doc/examples/rculfhash/Makefile.cds_lfht_add [new file with mode: 0644]
doc/examples/rculfhash/Makefile.cds_lfht_add_replace [new file with mode: 0644]
doc/examples/rculfhash/Makefile.cds_lfht_add_unique [new file with mode: 0644]
doc/examples/rculfhash/Makefile.cds_lfht_del [new file with mode: 0644]
doc/examples/rculfhash/Makefile.cds_lfht_destroy [new file with mode: 0644]
doc/examples/rculfhash/Makefile.cds_lfht_for_each_entry_duplicate [new file with mode: 0644]
doc/examples/rculfhash/Makefile.cds_lfht_lookup [new file with mode: 0644]
doc/examples/rculfhash/cds_lfht_add.c [new file with mode: 0644]
doc/examples/rculfhash/cds_lfht_add_replace.c [new file with mode: 0644]
doc/examples/rculfhash/cds_lfht_add_unique.c [new file with mode: 0644]
doc/examples/rculfhash/cds_lfht_del.c [new file with mode: 0644]
doc/examples/rculfhash/cds_lfht_destroy.c [new file with mode: 0644]
doc/examples/rculfhash/cds_lfht_for_each_entry_duplicate.c [new file with mode: 0644]
doc/examples/rculfhash/cds_lfht_lookup.c [new file with mode: 0644]
doc/examples/rculfhash/jhash.h [new file with mode: 0644]
doc/examples/rculfqueue/Makefile [new file with mode: 0644]
doc/examples/rculfqueue/Makefile.cds_lfq_dequeue [new file with mode: 0644]
doc/examples/rculfqueue/Makefile.cds_lfq_enqueue [new file with mode: 0644]
doc/examples/rculfqueue/cds_lfq_dequeue.c [new file with mode: 0644]
doc/examples/rculfqueue/cds_lfq_enqueue.c [new file with mode: 0644]
doc/examples/urcu-flavors/Makefile [new file with mode: 0644]
doc/examples/urcu-flavors/Makefile.bp [new file with mode: 0644]
doc/examples/urcu-flavors/Makefile.mb [new file with mode: 0644]
doc/examples/urcu-flavors/Makefile.membarrier [new file with mode: 0644]
doc/examples/urcu-flavors/Makefile.qsbr [new file with mode: 0644]
doc/examples/urcu-flavors/Makefile.signal [new file with mode: 0644]
doc/examples/urcu-flavors/bp.c [new file with mode: 0644]
doc/examples/urcu-flavors/mb.c [new file with mode: 0644]
doc/examples/urcu-flavors/membarrier.c [new file with mode: 0644]
doc/examples/urcu-flavors/qsbr.c [new file with mode: 0644]
doc/examples/urcu-flavors/signal.c [new file with mode: 0644]
doc/examples/wfcqueue/Makefile [new file with mode: 0644]
doc/examples/wfcqueue/Makefile.cds_wfcq_dequeue [new file with mode: 0644]
doc/examples/wfcqueue/Makefile.cds_wfcq_enqueue [new file with mode: 0644]
doc/examples/wfcqueue/Makefile.cds_wfcq_splice [new file with mode: 0644]
doc/examples/wfcqueue/cds_wfcq_dequeue.c [new file with mode: 0644]
doc/examples/wfcqueue/cds_wfcq_enqueue.c [new file with mode: 0644]
doc/examples/wfcqueue/cds_wfcq_splice.c [new file with mode: 0644]
doc/examples/wfstack/Makefile [new file with mode: 0644]
doc/examples/wfstack/Makefile.cds_wfs_pop [new file with mode: 0644]
doc/examples/wfstack/Makefile.cds_wfs_pop_all_blocking [new file with mode: 0644]
doc/examples/wfstack/Makefile.cds_wfs_push [new file with mode: 0644]
doc/examples/wfstack/cds_wfs_pop.c [new file with mode: 0644]
doc/examples/wfstack/cds_wfs_pop_all_blocking.c [new file with mode: 0644]
doc/examples/wfstack/cds_wfs_push.c [new file with mode: 0644]
tests/Makefile.am
tests/test_looplen.c
tests/test_mutex.c
tests/test_perthreadlock.c
tests/test_perthreadlock_timing.c
tests/test_rwlock.c
tests/test_rwlock_timing.c
tests/test_urcu.c
tests/test_urcu_assign.c
tests/test_urcu_bp.c
tests/test_urcu_defer.c
tests/test_urcu_gc.c
tests/test_urcu_hash.c
tests/test_urcu_hash.h
tests/test_urcu_hash_rw.c
tests/test_urcu_hash_unique.c
tests/test_urcu_lfq.c
tests/test_urcu_lfs.c
tests/test_urcu_lfs_rcu.c
tests/test_urcu_qsbr.c
tests/test_urcu_qsbr_gc.c
tests/test_urcu_qsbr_timing.c
tests/test_urcu_timing.c
tests/test_urcu_wfcq.c
tests/test_urcu_wfq.c
tests/test_urcu_wfs.c
tests/thread-id.h [new file with mode: 0644]
urcu.c
urcu/hlist.h
urcu/list.h
urcu/rcuhlist.h
urcu/rculist.h

index 4ac34897e0459e46ce0118f49d502fba089a3738..00dbc40dd8d4941ce6a3c6d694db2f0646c97fdd 100644 (file)
@@ -1,24 +1,15 @@
-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
@@ -70,7 +61,58 @@ tests/test_urcu_wfq
 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
index bb95f1c2fc370c2b3f47cf5f1429c95c01e1a5aa..017cdf1b9c623c025442cdc7efe68420dddfaf74 100644 (file)
@@ -162,6 +162,7 @@ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
 
 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], 
index 4583b5bdf1884605603ac1f66d56c2c6f0212d36..16477b5428860d699051d8f9de22c2887ad3a47d 100644 (file)
-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
diff --git a/doc/examples/Makefile.examples.template b/doc/examples/Makefile.examples.template
new file mode 100644 (file)
index 0000000..badecff
--- /dev/null
@@ -0,0 +1,29 @@
+# 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)
diff --git a/doc/examples/dist-files/Makefile b/doc/examples/dist-files/Makefile
new file mode 100644 (file)
index 0000000..cb380b7
--- /dev/null
@@ -0,0 +1,33 @@
+# 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
diff --git a/doc/examples/hlist/Makefile b/doc/examples/hlist/Makefile
new file mode 100644 (file)
index 0000000..d705dac
--- /dev/null
@@ -0,0 +1,25 @@
+# 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
diff --git a/doc/examples/hlist/Makefile.cds_hlist_add_head_rcu b/doc/examples/hlist/Makefile.cds_hlist_add_head_rcu
new file mode 100644 (file)
index 0000000..f1bf7d7
--- /dev/null
@@ -0,0 +1,21 @@
+# 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
diff --git a/doc/examples/hlist/Makefile.cds_hlist_del_rcu b/doc/examples/hlist/Makefile.cds_hlist_del_rcu
new file mode 100644 (file)
index 0000000..642b04d
--- /dev/null
@@ -0,0 +1,21 @@
+# 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
diff --git a/doc/examples/hlist/Makefile.cds_hlist_for_each_entry_rcu b/doc/examples/hlist/Makefile.cds_hlist_for_each_entry_rcu
new file mode 100644 (file)
index 0000000..035ecbf
--- /dev/null
@@ -0,0 +1,21 @@
+# 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
diff --git a/doc/examples/hlist/Makefile.cds_hlist_for_each_rcu b/doc/examples/hlist/Makefile.cds_hlist_for_each_rcu
new file mode 100644 (file)
index 0000000..23d0a0c
--- /dev/null
@@ -0,0 +1,21 @@
+# 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
diff --git a/doc/examples/hlist/cds_hlist_add_head_rcu.c b/doc/examples/hlist/cds_hlist_add_head_rcu.c
new file mode 100644 (file)
index 0000000..12161d1
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * 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;
+}
diff --git a/doc/examples/hlist/cds_hlist_del_rcu.c b/doc/examples/hlist/cds_hlist_del_rcu.c
new file mode 100644 (file)
index 0000000..1995b21
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * 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;
+}
diff --git a/doc/examples/hlist/cds_hlist_for_each_entry_rcu.c b/doc/examples/hlist/cds_hlist_for_each_entry_rcu.c
new file mode 100644 (file)
index 0000000..f6b744a
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * 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;
+}
diff --git a/doc/examples/hlist/cds_hlist_for_each_rcu.c b/doc/examples/hlist/cds_hlist_for_each_rcu.c
new file mode 100644 (file)
index 0000000..47baa0e
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * 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;
+}
diff --git a/doc/examples/lfstack/Makefile b/doc/examples/lfstack/Makefile
new file mode 100644 (file)
index 0000000..e8d1d13
--- /dev/null
@@ -0,0 +1,23 @@
+# 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
diff --git a/doc/examples/lfstack/Makefile.cds_lfs_pop_all_blocking b/doc/examples/lfstack/Makefile.cds_lfs_pop_all_blocking
new file mode 100644 (file)
index 0000000..9ee48d5
--- /dev/null
@@ -0,0 +1,21 @@
+# 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
diff --git a/doc/examples/lfstack/Makefile.cds_lfs_pop_blocking b/doc/examples/lfstack/Makefile.cds_lfs_pop_blocking
new file mode 100644 (file)
index 0000000..da43458
--- /dev/null
@@ -0,0 +1,21 @@
+# 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
diff --git a/doc/examples/lfstack/Makefile.cds_lfs_push b/doc/examples/lfstack/Makefile.cds_lfs_push
new file mode 100644 (file)
index 0000000..a2078c4
--- /dev/null
@@ -0,0 +1,21 @@
+# 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
diff --git a/doc/examples/lfstack/cds_lfs_pop_all_blocking.c b/doc/examples/lfstack/cds_lfs_pop_all_blocking.c
new file mode 100644 (file)
index 0000000..c2199d3
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * 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;
+}
diff --git a/doc/examples/lfstack/cds_lfs_pop_blocking.c b/doc/examples/lfstack/cds_lfs_pop_blocking.c
new file mode 100644 (file)
index 0000000..07b2169
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * 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;
+}
diff --git a/doc/examples/lfstack/cds_lfs_push.c b/doc/examples/lfstack/cds_lfs_push.c
new file mode 100644 (file)
index 0000000..e70ce15
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * 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;
+}
diff --git a/doc/examples/list/Makefile b/doc/examples/list/Makefile
new file mode 100644 (file)
index 0000000..a0e7672
--- /dev/null
@@ -0,0 +1,29 @@
+# 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
diff --git a/doc/examples/list/Makefile.cds_list_add_rcu b/doc/examples/list/Makefile.cds_list_add_rcu
new file mode 100644 (file)
index 0000000..faf2c94
--- /dev/null
@@ -0,0 +1,21 @@
+# 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
diff --git a/doc/examples/list/Makefile.cds_list_add_tail_rcu b/doc/examples/list/Makefile.cds_list_add_tail_rcu
new file mode 100644 (file)
index 0000000..3031024
--- /dev/null
@@ -0,0 +1,21 @@
+# 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
diff --git a/doc/examples/list/Makefile.cds_list_del_rcu b/doc/examples/list/Makefile.cds_list_del_rcu
new file mode 100644 (file)
index 0000000..74cef2b
--- /dev/null
@@ -0,0 +1,21 @@
+# 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
diff --git a/doc/examples/list/Makefile.cds_list_for_each_entry_rcu b/doc/examples/list/Makefile.cds_list_for_each_entry_rcu
new file mode 100644 (file)
index 0000000..911301e
--- /dev/null
@@ -0,0 +1,21 @@
+# 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
diff --git a/doc/examples/list/Makefile.cds_list_for_each_rcu b/doc/examples/list/Makefile.cds_list_for_each_rcu
new file mode 100644 (file)
index 0000000..2f2f02f
--- /dev/null
@@ -0,0 +1,21 @@
+# 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
diff --git a/doc/examples/list/Makefile.cds_list_replace_rcu b/doc/examples/list/Makefile.cds_list_replace_rcu
new file mode 100644 (file)
index 0000000..5e130b3
--- /dev/null
@@ -0,0 +1,21 @@
+# 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
diff --git a/doc/examples/list/cds_list_add_rcu.c b/doc/examples/list/cds_list_add_rcu.c
new file mode 100644 (file)
index 0000000..ad1d909
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * 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;
+}
diff --git a/doc/examples/list/cds_list_add_tail_rcu.c b/doc/examples/list/cds_list_add_tail_rcu.c
new file mode 100644 (file)
index 0000000..53784c9
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * 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;
+}
diff --git a/doc/examples/list/cds_list_del_rcu.c b/doc/examples/list/cds_list_del_rcu.c
new file mode 100644 (file)
index 0000000..c355101
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * 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;
+}
diff --git a/doc/examples/list/cds_list_for_each_entry_rcu.c b/doc/examples/list/cds_list_for_each_entry_rcu.c
new file mode 100644 (file)
index 0000000..777542b
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * 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;
+}
diff --git a/doc/examples/list/cds_list_for_each_rcu.c b/doc/examples/list/cds_list_for_each_rcu.c
new file mode 100644 (file)
index 0000000..86cc4ab
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * 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;
+}
diff --git a/doc/examples/list/cds_list_replace_rcu.c b/doc/examples/list/cds_list_replace_rcu.c
new file mode 100644 (file)
index 0000000..4ccc1df
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * 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;
+}
diff --git a/doc/examples/qsbr-minimal/Makefile b/doc/examples/qsbr-minimal/Makefile
deleted file mode 100644 (file)
index 53f1380..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-# 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
diff --git a/doc/examples/qsbr-minimal/qsbr-minimal.c b/doc/examples/qsbr-minimal/qsbr-minimal.c
deleted file mode 100644 (file)
index cc7278d..0000000
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * 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;
-}
diff --git a/doc/examples/rculfhash/Makefile b/doc/examples/rculfhash/Makefile
new file mode 100644 (file)
index 0000000..b0dd948
--- /dev/null
@@ -0,0 +1,31 @@
+# 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
diff --git a/doc/examples/rculfhash/Makefile.cds_lfht_add b/doc/examples/rculfhash/Makefile.cds_lfht_add
new file mode 100644 (file)
index 0000000..9fab2b6
--- /dev/null
@@ -0,0 +1,22 @@
+# 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
diff --git a/doc/examples/rculfhash/Makefile.cds_lfht_add_replace b/doc/examples/rculfhash/Makefile.cds_lfht_add_replace
new file mode 100644 (file)
index 0000000..dcd253a
--- /dev/null
@@ -0,0 +1,22 @@
+# 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
diff --git a/doc/examples/rculfhash/Makefile.cds_lfht_add_unique b/doc/examples/rculfhash/Makefile.cds_lfht_add_unique
new file mode 100644 (file)
index 0000000..c74c61e
--- /dev/null
@@ -0,0 +1,22 @@
+# 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
diff --git a/doc/examples/rculfhash/Makefile.cds_lfht_del b/doc/examples/rculfhash/Makefile.cds_lfht_del
new file mode 100644 (file)
index 0000000..6377490
--- /dev/null
@@ -0,0 +1,22 @@
+# 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
diff --git a/doc/examples/rculfhash/Makefile.cds_lfht_destroy b/doc/examples/rculfhash/Makefile.cds_lfht_destroy
new file mode 100644 (file)
index 0000000..d797893
--- /dev/null
@@ -0,0 +1,22 @@
+# 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
diff --git a/doc/examples/rculfhash/Makefile.cds_lfht_for_each_entry_duplicate b/doc/examples/rculfhash/Makefile.cds_lfht_for_each_entry_duplicate
new file mode 100644 (file)
index 0000000..7020b14
--- /dev/null
@@ -0,0 +1,22 @@
+# 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
diff --git a/doc/examples/rculfhash/Makefile.cds_lfht_lookup b/doc/examples/rculfhash/Makefile.cds_lfht_lookup
new file mode 100644 (file)
index 0000000..79eb6c4
--- /dev/null
@@ -0,0 +1,22 @@
+# 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
diff --git a/doc/examples/rculfhash/cds_lfht_add.c b/doc/examples/rculfhash/cds_lfht_add.c
new file mode 100644 (file)
index 0000000..8932e7a
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * 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;
+}
diff --git a/doc/examples/rculfhash/cds_lfht_add_replace.c b/doc/examples/rculfhash/cds_lfht_add_replace.c
new file mode 100644 (file)
index 0000000..62de40c
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * 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;
+}
diff --git a/doc/examples/rculfhash/cds_lfht_add_unique.c b/doc/examples/rculfhash/cds_lfht_add_unique.c
new file mode 100644 (file)
index 0000000..f1a7631
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * 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;
+}
diff --git a/doc/examples/rculfhash/cds_lfht_del.c b/doc/examples/rculfhash/cds_lfht_del.c
new file mode 100644 (file)
index 0000000..4bcf15c
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * 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;
+}
diff --git a/doc/examples/rculfhash/cds_lfht_destroy.c b/doc/examples/rculfhash/cds_lfht_destroy.c
new file mode 100644 (file)
index 0000000..d82d81c
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * 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;
+}
diff --git a/doc/examples/rculfhash/cds_lfht_for_each_entry_duplicate.c b/doc/examples/rculfhash/cds_lfht_for_each_entry_duplicate.c
new file mode 100644 (file)
index 0000000..e57509d
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * 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;
+}
diff --git a/doc/examples/rculfhash/cds_lfht_lookup.c b/doc/examples/rculfhash/cds_lfht_lookup.c
new file mode 100644 (file)
index 0000000..e76827b
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * 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;
+}
diff --git a/doc/examples/rculfhash/jhash.h b/doc/examples/rculfhash/jhash.h
new file mode 100644 (file)
index 0000000..673989d
--- /dev/null
@@ -0,0 +1,256 @@
+#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 */
diff --git a/doc/examples/rculfqueue/Makefile b/doc/examples/rculfqueue/Makefile
new file mode 100644 (file)
index 0000000..5538709
--- /dev/null
@@ -0,0 +1,21 @@
+# 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
diff --git a/doc/examples/rculfqueue/Makefile.cds_lfq_dequeue b/doc/examples/rculfqueue/Makefile.cds_lfq_dequeue
new file mode 100644 (file)
index 0000000..c083873
--- /dev/null
@@ -0,0 +1,21 @@
+# 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
diff --git a/doc/examples/rculfqueue/Makefile.cds_lfq_enqueue b/doc/examples/rculfqueue/Makefile.cds_lfq_enqueue
new file mode 100644 (file)
index 0000000..b8f1ff5
--- /dev/null
@@ -0,0 +1,21 @@
+# 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
diff --git a/doc/examples/rculfqueue/cds_lfq_dequeue.c b/doc/examples/rculfqueue/cds_lfq_dequeue.c
new file mode 100644 (file)
index 0000000..d1375c8
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * 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;
+}
diff --git a/doc/examples/rculfqueue/cds_lfq_enqueue.c b/doc/examples/rculfqueue/cds_lfq_enqueue.c
new file mode 100644 (file)
index 0000000..a8c6f86
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * 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;
+}
diff --git a/doc/examples/urcu-flavors/Makefile b/doc/examples/urcu-flavors/Makefile
new file mode 100644 (file)
index 0000000..f4cc0b1
--- /dev/null
@@ -0,0 +1,27 @@
+# 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
diff --git a/doc/examples/urcu-flavors/Makefile.bp b/doc/examples/urcu-flavors/Makefile.bp
new file mode 100644 (file)
index 0000000..5170f02
--- /dev/null
@@ -0,0 +1,21 @@
+# 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
diff --git a/doc/examples/urcu-flavors/Makefile.mb b/doc/examples/urcu-flavors/Makefile.mb
new file mode 100644 (file)
index 0000000..7a4e2f9
--- /dev/null
@@ -0,0 +1,21 @@
+# 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
diff --git a/doc/examples/urcu-flavors/Makefile.membarrier b/doc/examples/urcu-flavors/Makefile.membarrier
new file mode 100644 (file)
index 0000000..977078e
--- /dev/null
@@ -0,0 +1,21 @@
+# 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
diff --git a/doc/examples/urcu-flavors/Makefile.qsbr b/doc/examples/urcu-flavors/Makefile.qsbr
new file mode 100644 (file)
index 0000000..dc28ddd
--- /dev/null
@@ -0,0 +1,21 @@
+# 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
diff --git a/doc/examples/urcu-flavors/Makefile.signal b/doc/examples/urcu-flavors/Makefile.signal
new file mode 100644 (file)
index 0000000..6e2c0db
--- /dev/null
@@ -0,0 +1,21 @@
+# 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
diff --git a/doc/examples/urcu-flavors/bp.c b/doc/examples/urcu-flavors/bp.c
new file mode 100644 (file)
index 0000000..64978fc
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * 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;
+}
diff --git a/doc/examples/urcu-flavors/mb.c b/doc/examples/urcu-flavors/mb.c
new file mode 100644 (file)
index 0000000..62ad54b
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * 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;
+}
diff --git a/doc/examples/urcu-flavors/membarrier.c b/doc/examples/urcu-flavors/membarrier.c
new file mode 100644 (file)
index 0000000..21f4579
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * 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;
+}
diff --git a/doc/examples/urcu-flavors/qsbr.c b/doc/examples/urcu-flavors/qsbr.c
new file mode 100644 (file)
index 0000000..1dbd546
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * 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;
+}
diff --git a/doc/examples/urcu-flavors/signal.c b/doc/examples/urcu-flavors/signal.c
new file mode 100644 (file)
index 0000000..136c380
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * 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;
+}
diff --git a/doc/examples/wfcqueue/Makefile b/doc/examples/wfcqueue/Makefile
new file mode 100644 (file)
index 0000000..98b9def
--- /dev/null
@@ -0,0 +1,23 @@
+# 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
diff --git a/doc/examples/wfcqueue/Makefile.cds_wfcq_dequeue b/doc/examples/wfcqueue/Makefile.cds_wfcq_dequeue
new file mode 100644 (file)
index 0000000..4f80a71
--- /dev/null
@@ -0,0 +1,21 @@
+# 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
diff --git a/doc/examples/wfcqueue/Makefile.cds_wfcq_enqueue b/doc/examples/wfcqueue/Makefile.cds_wfcq_enqueue
new file mode 100644 (file)
index 0000000..aef5105
--- /dev/null
@@ -0,0 +1,21 @@
+# 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
diff --git a/doc/examples/wfcqueue/Makefile.cds_wfcq_splice b/doc/examples/wfcqueue/Makefile.cds_wfcq_splice
new file mode 100644 (file)
index 0000000..76b9f0a
--- /dev/null
@@ -0,0 +1,21 @@
+# 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
diff --git a/doc/examples/wfcqueue/cds_wfcq_dequeue.c b/doc/examples/wfcqueue/cds_wfcq_dequeue.c
new file mode 100644 (file)
index 0000000..c278351
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * 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;
+}
diff --git a/doc/examples/wfcqueue/cds_wfcq_enqueue.c b/doc/examples/wfcqueue/cds_wfcq_enqueue.c
new file mode 100644 (file)
index 0000000..377f017
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * 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;
+}
diff --git a/doc/examples/wfcqueue/cds_wfcq_splice.c b/doc/examples/wfcqueue/cds_wfcq_splice.c
new file mode 100644 (file)
index 0000000..bb2e512
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * 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;
+}
diff --git a/doc/examples/wfstack/Makefile b/doc/examples/wfstack/Makefile
new file mode 100644 (file)
index 0000000..b8be3f5
--- /dev/null
@@ -0,0 +1,23 @@
+# 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
diff --git a/doc/examples/wfstack/Makefile.cds_wfs_pop b/doc/examples/wfstack/Makefile.cds_wfs_pop
new file mode 100644 (file)
index 0000000..24df951
--- /dev/null
@@ -0,0 +1,21 @@
+# 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
diff --git a/doc/examples/wfstack/Makefile.cds_wfs_pop_all_blocking b/doc/examples/wfstack/Makefile.cds_wfs_pop_all_blocking
new file mode 100644 (file)
index 0000000..452fd9c
--- /dev/null
@@ -0,0 +1,21 @@
+# 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
diff --git a/doc/examples/wfstack/Makefile.cds_wfs_push b/doc/examples/wfstack/Makefile.cds_wfs_push
new file mode 100644 (file)
index 0000000..43f96c1
--- /dev/null
@@ -0,0 +1,21 @@
+# 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
diff --git a/doc/examples/wfstack/cds_wfs_pop.c b/doc/examples/wfstack/cds_wfs_pop.c
new file mode 100644 (file)
index 0000000..4cdec0a
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * 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;
+}
diff --git a/doc/examples/wfstack/cds_wfs_pop_all_blocking.c b/doc/examples/wfstack/cds_wfs_pop_all_blocking.c
new file mode 100644 (file)
index 0000000..766f07f
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * 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;
+}
diff --git a/doc/examples/wfstack/cds_wfs_push.c b/doc/examples/wfstack/cds_wfs_push.c
new file mode 100644 (file)
index 0000000..a4727a9
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * 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;
+}
index 1521ecb6fb02f85ded7a8dd2cc9b113df608ac0d..f4c84d2b272782906bb86ec5c3f0c3c0d7abd012 100644 (file)
@@ -23,7 +23,7 @@ noinst_PROGRAMS = test_urcu test_urcu_dynamic_link test_urcu_timing \
        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
index e1bd2ea25a037238cba132ba61d2879b1fd36f24..16674e76ac442343b77ea27d1994a5920cd6c9e7 100644 (file)
 
 #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
index e5fbf1a22b26e453112777cb3027ff94f278a6f0..83adfdbcb75a7fd0d8159728adc46447db835794 100644 (file)
 #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
@@ -189,9 +171,8 @@ void *thr_reader(void *data)
 {
        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();
 
@@ -211,9 +192,8 @@ void *thr_reader(void *data)
        }
 
        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);
 
 }
@@ -222,9 +202,8 @@ void *thr_writer(void *data)
 {
        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();
 
@@ -247,9 +226,8 @@ void *thr_writer(void *data)
                        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);
 }
@@ -356,9 +334,8 @@ int main(int argc, char **argv)
                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);
index 59c1ae6038e7fb9721a6adfaba19ed548a0aa19a..be6e59d557c9be527a0eeb1b671f4e4cf8dbdd48 100644 (file)
 #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
@@ -193,9 +175,8 @@ void *thr_reader(void *data)
 {
        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();
 
@@ -215,9 +196,8 @@ void *thr_reader(void *data)
        }
 
        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);
 
 }
@@ -227,9 +207,8 @@ void *thr_writer(void *data)
        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();
 
@@ -256,9 +235,8 @@ void *thr_writer(void *data)
                        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);
 }
@@ -364,8 +342,8 @@ int main(int argc, char **argv)
                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);
index d0cc11c3841df70e08a1718417cc9e9c134d1116..9321f034f1221882c0dfc307033c3fc514d90473 100644 (file)
 
 #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>
 
@@ -90,9 +73,8 @@ void *thr_reader(void *arg)
        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();
@@ -108,9 +90,8 @@ void *thr_reader(void *arg)
        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);
 
 }
@@ -121,9 +102,8 @@ void *thr_writer(void *arg)
        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++) {
@@ -142,9 +122,8 @@ void *thr_writer(void *arg)
                }
        }
 
-       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);
 }
 
@@ -169,9 +148,8 @@ int main(int argc, char **argv)
        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);
 
index aa53b3bad44fdf896854fc6a4dfd56f28e2518c0..287b14eda2aeabcf3e5689d0857e00cee6971b5c 100644 (file)
 #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
@@ -185,9 +167,8 @@ void *thr_reader(void *_count)
 {
        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();
 
@@ -207,9 +188,8 @@ void *thr_reader(void *_count)
        }
 
        *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);
 
 }
@@ -218,9 +198,8 @@ void *thr_writer(void *_count)
 {
        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();
 
@@ -243,9 +222,8 @@ void *thr_writer(void *_count)
                        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);
 }
@@ -352,9 +330,8 @@ int main(int argc, char **argv)
                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);
index bc7737002596a5856f278b5fcd1898292d069c83..3ff7ee42eb6d455063c3f766c35b221370356612 100644 (file)
 
 #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>
 
@@ -86,9 +69,8 @@ void *thr_reader(void *arg)
        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();
@@ -104,9 +86,8 @@ void *thr_reader(void *arg)
        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);
 
 }
@@ -116,9 +97,8 @@ void *thr_writer(void *arg)
        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++) {
@@ -133,9 +113,8 @@ void *thr_writer(void *arg)
                }
        }
 
-       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);
 }
 
@@ -160,9 +139,8 @@ int main(int argc, char **argv)
        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,
index f77a2b5de264077a558e46c08cce5de8e82f0f8e..3017e812aa4687bfb5eae21178ff2d45434aee47 100644 (file)
 #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
@@ -180,9 +162,8 @@ void *thr_reader(void *_count)
        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();
 
@@ -216,9 +197,8 @@ void *thr_reader(void *_count)
        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);
 
 }
@@ -228,9 +208,8 @@ void *thr_writer(void *_count)
        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();
 
@@ -257,9 +236,8 @@ void *thr_writer(void *_count)
                        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);
 }
@@ -365,9 +343,8 @@ int main(int argc, char **argv)
                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);
index 62cb5f4d201b76846f1b08db5b8bf4fd7352d952..67253da34dc6023d80e500924d41427898900405 100644 (file)
 #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
@@ -217,9 +199,8 @@ void *thr_reader(void *_count)
        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();
 
@@ -247,9 +228,8 @@ void *thr_reader(void *_count)
        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);
 
 }
@@ -259,9 +239,8 @@ void *thr_writer(void *_count)
        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();
 
@@ -290,9 +269,8 @@ void *thr_writer(void *_count)
                        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);
 }
@@ -398,9 +376,8 @@ int main(int argc, char **argv)
                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);
index b59f16dc08e82fe8b8ed5b719a1c28272700fcda..a0d6f117bdb811f1a356797c6ab6155f0104dc8f 100644 (file)
 #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
@@ -180,9 +162,8 @@ void *thr_reader(void *_count)
        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();
 
@@ -212,9 +193,8 @@ void *thr_reader(void *_count)
        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);
 
 }
@@ -224,9 +204,8 @@ void *thr_writer(void *_count)
        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();
 
@@ -252,9 +231,8 @@ void *thr_writer(void *_count)
                        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);
 }
@@ -360,9 +338,8 @@ int main(int argc, char **argv)
                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);
index 8a6adebb893d955911c42bc76e5860db9fd0035d..395014e72153800c58fe8b80e9faa61d572b4d24 100644 (file)
 #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
@@ -188,9 +170,8 @@ void *thr_reader(void *_count)
        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();
 
@@ -218,9 +199,8 @@ void *thr_reader(void *_count)
        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);
 
 }
@@ -239,9 +219,8 @@ void *thr_writer(void *data)
        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();
 
@@ -279,9 +258,8 @@ void *thr_writer(void *data)
 
        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);
 }
@@ -387,9 +365,8 @@ int main(int argc, char **argv)
                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);
index da17a212dae00490c1336994dedae7369c2ed999..6e5cc1d90a2dd65eea3a58b362f2ee50b3246802 100644 (file)
 #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
@@ -196,9 +178,8 @@ void *thr_reader(void *_count)
        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();
 
@@ -226,9 +207,8 @@ void *thr_reader(void *_count)
        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);
 
 }
@@ -273,9 +253,8 @@ void *thr_writer(void *data)
        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();
 
@@ -300,9 +279,8 @@ void *thr_writer(void *data)
                        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);
 }
@@ -415,9 +393,8 @@ int main(int argc, char **argv)
                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);
index c4c11924549ba1ab5b3ed7332e65610f8e114106..9416224d8af115491d689ff4328078482591d78c 100644 (file)
@@ -201,9 +201,8 @@ unsigned long test_compare(const void *key1, size_t key1_len,
 
 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();
 
@@ -548,9 +547,8 @@ int main(int argc, char **argv)
                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) {
index 50e720ac1749518aaf3b706b8e9cbd6d6d25454a..cd064e62b76e6821c311fa9e9588330d134f503f 100644 (file)
 
 #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
@@ -55,9 +52,6 @@
  */
 #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
index f30207d000ca039f0c3394b0fefce3bbb41aecb7..8802b9cd0a621d1d07fee0f4e7bfe368f0a287b6 100644 (file)
@@ -65,9 +65,10 @@ void *test_hash_rw_thr_reader(void *_count)
        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();
 
@@ -107,11 +108,11 @@ void *test_hash_rw_thr_reader(void *_count)
        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);
 
@@ -125,9 +126,10 @@ void *test_hash_rw_thr_writer(void *_count)
        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();
 
@@ -211,12 +213,13 @@ void *test_hash_rw_thr_writer(void *_count)
 
        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);
@@ -235,6 +238,8 @@ int test_hash_rw_populate_hash(void)
 
        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 "
index b36d782791a9686ae992fc6cfb3fe52fe7c3a3de..adbbde0db4f0c59ce751feec00cc4276763c57d3 100644 (file)
@@ -63,9 +63,10 @@ void *test_hash_unique_thr_reader(void *_count)
 {
        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();
 
@@ -109,11 +110,10 @@ void *test_hash_unique_thr_reader(void *_count)
        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);
 
@@ -128,9 +128,10 @@ void *test_hash_unique_thr_writer(void *_count)
        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();
 
@@ -223,12 +224,13 @@ void *test_hash_unique_thr_writer(void *_count)
 
        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);
@@ -244,6 +246,8 @@ int test_hash_unique_populate_hash(void)
 
        printf("Starting uniqueness test.\n");
 
+       URCU_TLS(rand_lookup) = urcu_get_thread_id() ^ time(NULL);
+
        if (!init_populate)
                return 0;
 
index 6d0f41a62bedaf2b859815903f0cd303bbdef450..52ca22557c7e6e8a3f52284873ca1b8ffe5295af 100644 (file)
 #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
@@ -163,9 +145,8 @@ void *thr_enqueuer(void *_count)
 {
        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();
 
@@ -198,11 +179,11 @@ fail:
 
        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);
 
 }
@@ -219,9 +200,8 @@ void *thr_dequeuer(void *_count)
 {
        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();
 
@@ -255,11 +235,11 @@ void *thr_dequeuer(void *_count)
        }
 
        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);
@@ -367,9 +347,8 @@ int main(int argc, char **argv)
                       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);
index 9636f5bb0da7a935f3e52092d0b3cbef1278cea8..b2a33712a5aefa488d69bfc746291c72471cd463 100644 (file)
 #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
@@ -175,9 +157,8 @@ static void *thr_enqueuer(void *_count)
 {
        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();
 
@@ -208,11 +189,11 @@ fail:
 
        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);
 
 }
@@ -276,9 +257,8 @@ static void *thr_dequeuer(void *_count)
        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();
 
@@ -314,11 +294,11 @@ static void *thr_dequeuer(void *_count)
 
        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);
@@ -451,9 +431,8 @@ int main(int argc, char **argv)
                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);
index f8e793eb48271c9aaa4a8412cb9b636d17a9ed39..89077dc7bb4a3670a2b72810461ab60280d599ff 100644 (file)
 #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
@@ -166,9 +148,8 @@ void *thr_enqueuer(void *_count)
 {
        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();
 
@@ -200,11 +181,11 @@ fail:
 
        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);
 
 }
@@ -221,9 +202,8 @@ void *thr_dequeuer(void *_count)
 {
        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();
 
@@ -256,11 +236,11 @@ void *thr_dequeuer(void *_count)
 
        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);
@@ -368,9 +348,8 @@ int main(int argc, char **argv)
                       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);
index 1bade60fd53dddc01a2c963c413254673074abbb..2e9e2b2c409a120bb0fee68f9eb6521b175062d5 100644 (file)
 #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
@@ -179,9 +161,8 @@ void *thr_reader(void *_count)
        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();
 
@@ -222,9 +203,8 @@ void *thr_reader(void *_count)
        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);
 
 }
@@ -234,9 +214,8 @@ void *thr_writer(void *_count)
        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();
 
@@ -263,9 +242,8 @@ void *thr_writer(void *_count)
                        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);
 }
@@ -371,9 +349,8 @@ int main(int argc, char **argv)
                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);
index 34d0a1791dff2030000ca3eb48b475092da97fa2..64d2e2431d0447a041e5edc90eb2ab79a73e73fa 100644 (file)
 #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>
 
@@ -192,9 +174,8 @@ void *thr_reader(void *_count)
        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();
 
@@ -225,9 +206,8 @@ void *thr_reader(void *_count)
        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);
 
 }
@@ -272,9 +252,8 @@ void *thr_writer(void *data)
        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();
 
@@ -299,9 +278,8 @@ void *thr_writer(void *data)
                        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);
 }
@@ -415,9 +393,8 @@ int main(int argc, char **argv)
                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);
index b50c95f3f82bdfd3010499291246d084c371c0b0..bb29301da20fd13c57ffc121034d7a34db8184fa 100644 (file)
 #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>
@@ -107,9 +89,8 @@ void *thr_reader(void *arg)
        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();
@@ -133,9 +114,8 @@ void *thr_reader(void *arg)
        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);
 
 }
@@ -146,9 +126,8 @@ void *thr_writer(void *arg)
        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++) {
@@ -175,9 +154,8 @@ void *thr_writer(void *arg)
                }
        }
 
-       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);
 }
 
@@ -202,9 +180,8 @@ int main(int argc, char **argv)
        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,
index 4de8896b77d024abe2d11b43ba5b9414f1bbbef3..4fbdcca8f594f5681696609e75ce110d28e6e7e9 100644 (file)
 #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>
@@ -106,9 +89,8 @@ void *thr_reader(void *arg)
        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();
@@ -131,9 +113,8 @@ void *thr_reader(void *arg)
        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);
 
 }
@@ -144,9 +125,8 @@ void *thr_writer(void *arg)
        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++) {
@@ -173,9 +153,8 @@ void *thr_writer(void *arg)
                }
        }
 
-       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);
 }
 
@@ -200,9 +179,8 @@ int main(int argc, char **argv)
        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,
index a3bd7e556031eef71c19b1be5e811ae5daaebdf6..5a36c76f24e73739cd090438934d708b152b251f 100644 (file)
 #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
@@ -175,9 +157,8 @@ static void *thr_enqueuer(void *_count)
        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();
 
@@ -208,14 +189,13 @@ fail:
        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);
 
 }
@@ -287,9 +267,8 @@ static void *thr_dequeuer(void *_count)
        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();
 
@@ -317,13 +296,12 @@ static void *thr_dequeuer(void *_count)
                        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);
@@ -483,9 +461,8 @@ int main(int argc, char **argv)
                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);
index 0940224ecbae653a00f8e83e16f8c7f17441a326..db00d8c77c36f1d73dfa7cc57ddb4c9ce958d488 100644 (file)
 #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
@@ -162,9 +144,8 @@ void *thr_enqueuer(void *_count)
 {
        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();
 
@@ -191,11 +172,11 @@ fail:
 
        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);
 
 }
@@ -204,9 +185,8 @@ void *thr_dequeuer(void *_count)
 {
        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();
 
@@ -230,11 +210,11 @@ void *thr_dequeuer(void *_count)
                        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);
@@ -339,9 +319,8 @@ int main(int argc, char **argv)
                       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);
index 043d842e73b5a4b93c9b462120add91bae1c5e23..2a031fe25850cc62d3943e77f05a83cd6c1ddd69 100644 (file)
 #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
@@ -177,9 +159,8 @@ static void *thr_enqueuer(void *_count)
        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();
 
@@ -210,14 +191,13 @@ fail:
        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);
 
 }
@@ -272,9 +252,8 @@ static void *thr_dequeuer(void *_count)
        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();
 
@@ -305,14 +284,13 @@ static void *thr_dequeuer(void *_count)
                        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);
@@ -471,9 +449,8 @@ int main(int argc, char **argv)
                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);
diff --git a/tests/thread-id.h b/tests/thread-id.h
new file mode 100644 (file)
index 0000000..9378edc
--- /dev/null
@@ -0,0 +1,55 @@
+#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 */
diff --git a/urcu.c b/urcu.c
index 1d5c06f53c565af243fb45c5e47c1ebb609dff97..759b94bdb9e9550e178caa04904e6048c7810b2c 100644 (file)
--- a/urcu.c
+++ b/urcu.c
@@ -513,14 +513,14 @@ void rcu_init(void)
 
 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(&registry));
+       /*
+        * 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(&registry));
+        */
 }
 
 #endif /* #ifdef RCU_SIGNAL */
index 15e672bc1702135ddfdb20b5676785dbd3cb2f55..d2e2ec38e2304f24e8ad86c18389e7faf3154508 100644 (file)
@@ -9,7 +9,7 @@
  *
  * 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 */
index 1d1c7b5ce2882b6bd0e13b53b096c081dbcb1b44..b4962b445dfbc766ee229923b0af97f0f16beadf 100644 (file)
 #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;
@@ -112,77 +107,82 @@ cds_list_replace(struct cds_list_head *old, struct cds_list_head *_new)
        _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);
index 1dcbdb4eecbc35207ba85c8c47af7a49d82f1f9f..b07c66b65ff1ccd33621f08e054594c375127bd7 100644 (file)
 #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 */
index e67503d9431d5da5d68d8f0a888613b1cebe2395..6759947dba2b78bcdb41b16222afd490922722f9 100644 (file)
 #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;
@@ -52,7 +67,8 @@ static inline void cds_list_replace_rcu(struct cds_list_head *old, struct cds_li
 }
 
 /* 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);
@@ -65,15 +81,14 @@ static inline void cds_list_del_rcu(struct cds_list_head *elem)
 
 /* 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 */
This page took 0.171881 seconds and 4 git commands to generate.