* Paul E. McKenney ([email protected]) wrote: > Adds call_rcu(), with RCU threads to invoke the callbacks. By default, > there will be one such RCU thread per process, created the first time > that call_rcu() is invoked. On systems supporting sched_getcpu(), it > is possible to create one RCU thread per CPU by calling > create_all_cpu_call_rcu_data().
Thanks for sending this! Here is some input: > > Signed-off-by: Paul E. McKenney <[email protected]> > > diff --git a/Makefile.am b/Makefile.am > index 79a7152..64bb299 100644 > --- a/Makefile.am > +++ b/Makefile.am > @@ -29,8 +29,8 @@ COMPAT+=compat_futex.c > endif > > lib_LTLIBRARIES = liburcu.la liburcu-qsbr.la liburcu-mb.la liburcu-signal.la > \ > - liburcu-bp.la liburcu-defer.la libwfqueue.la libwfstack.la \ > - librculfqueue.la librculfstack.la > + liburcu-bp.la liburcu-defer.la liburcu-call.la \ > + libwfqueue.la libwfstack.la librculfqueue.la librculfstack.la > > liburcu_la_SOURCES = urcu.c urcu-pointer.c $(COMPAT) > > @@ -44,6 +44,7 @@ liburcu_signal_la_CFLAGS = -DRCU_SIGNAL > > liburcu_bp_la_SOURCES = urcu-bp.c urcu-pointer.c $(COMPAT) > > +liburcu_call_la_SOURCES = urcu-call-rcu.c $(COMPAT) > liburcu_defer_la_SOURCES = urcu-defer.c $(COMPAT) > > libwfqueue_la_SOURCES = wfqueue.c $(COMPAT) > diff --git a/configure.ac b/configure.ac > index 89bdb6c..083ed95 100644 > --- a/configure.ac > +++ b/configure.ac > @@ -34,7 +34,7 @@ AC_TYPE_SIZE_T > # Checks for library functions. > AC_FUNC_MALLOC > AC_FUNC_MMAP > -AC_CHECK_FUNCS([bzero gettimeofday munmap strtoul]) > +AC_CHECK_FUNCS([bzero gettimeofday munmap sched_getcpu strtoul sysconf]) > > # Find arch type > case $host_cpu in > diff --git a/tests/Makefile.am b/tests/Makefile.am > index a43dd75..3c025a4 100644 > --- a/tests/Makefile.am > +++ b/tests/Makefile.am > @@ -1,5 +1,5 @@ > AM_LDFLAGS=-lpthread > -AM_CFLAGS=-I$(top_srcdir) -I$(top_builddir) > +AM_CFLAGS=-I$(top_srcdir) -I$(top_builddir) -g > > noinst_PROGRAMS = test_urcu test_urcu_dynamic_link test_urcu_timing \ > test_urcu_signal test_urcu_signal_dynamic_link test_urcu_signal_timing \ > @@ -28,20 +28,21 @@ if COMPAT_FUTEX > COMPAT+=$(top_srcdir)/compat_futex.c > endif > > -URCU=$(top_srcdir)/urcu.c $(top_srcdir)/urcu-pointer.c $(COMPAT) > -URCU_QSBR=$(top_srcdir)/urcu-qsbr.c $(top_srcdir)/urcu-pointer.c $(COMPAT) > +URCU=$(top_srcdir)/urcu.c $(top_srcdir)/urcu-pointer.c > $(top_srcdir)/urcu-call-rcu.c $(top_srcdir)/wfqueue.c $(COMPAT) > +URCU_QSBR=$(top_srcdir)/urcu-qsbr.c $(top_srcdir)/urcu-pointer.c > $(top_srcdir)/urcu-call-rcu.c $(top_srcdir)/wfqueue.c $(COMPAT) > # URCU_MB uses urcu.c but -DRCU_MB must be defined > -URCU_MB=$(top_srcdir)/urcu.c $(top_srcdir)/urcu-pointer.c $(COMPAT) > +URCU_MB=$(top_srcdir)/urcu.c $(top_srcdir)/urcu-pointer.c > $(top_srcdir)/urcu-call-rcu.c $(top_srcdir)/wfqueue.c $(COMPAT) > # URCU_SIGNAL uses urcu.c but -DRCU_SIGNAL must be defined > -URCU_SIGNAL=$(top_srcdir)/urcu.c $(top_srcdir)/urcu-pointer.c $(COMPAT) > -URCU_BP=$(top_srcdir)/urcu-bp.c $(top_srcdir)/urcu-pointer.c $(COMPAT) > -URCU_DEFER=$(top_srcdir)/urcu.c $(top_srcdir)/urcu-defer.c > $(top_srcdir)/urcu-pointer.c $(COMPAT) > +URCU_SIGNAL=$(top_srcdir)/urcu.c $(top_srcdir)/urcu-pointer.c > $(top_srcdir)/urcu-call-rcu.c $(top_srcdir)/wfqueue.c $(COMPAT) > +URCU_BP=$(top_srcdir)/urcu-bp.c $(top_srcdir)/urcu-pointer.c > $(top_srcdir)/urcu-call-rcu.c $(top_srcdir)/wfqueue.c $(COMPAT) > +URCU_DEFER=$(top_srcdir)/urcu.c $(top_srcdir)/urcu-defer.c > $(top_srcdir)/urcu-pointer.c $(top_srcdir)/urcu-call-rcu.c > $(top_srcdir)/wfqueue.c $(COMPAT) > > URCU_LIB=$(top_builddir)/liburcu.la > URCU_QSBR_LIB=$(top_builddir)/liburcu-qsbr.la > URCU_MB_LIB=$(top_builddir)/liburcu-mb.la > URCU_SIGNAL_LIB=$(top_builddir)/liburcu-signal.la > URCU_BP_LIB=$(top_builddir)/liburcu-bp.la > +URCU_CALL_LIB=$(top_builddir)/liburcu-call.la > WFQUEUE_LIB=$(top_builddir)/libwfqueue.la > WFSTACK_LIB=$(top_builddir)/libwfstack.la > RCULFQUEUE_LIB=$(top_builddir)/librculfqueue.la > @@ -95,23 +96,23 @@ test_perthreadlock_SOURCES = test_perthreadlock.c > $(URCU_SIGNAL) > > rcutorture_urcu_SOURCES = urcutorture.c > rcutorture_urcu_CFLAGS = -DTORTURE_URCU $(AM_CFLAGS) > -rcutorture_urcu_LDADD = $(URCU) > +rcutorture_urcu_LDADD = $(URCU) $(URCU_CALL_LIB) $(WFQUEUE_LIB) > > rcutorture_urcu_mb_SOURCES = urcutorture.c > rcutorture_urcu_mb_CFLAGS = -DTORTURE_URCU_MB $(AM_CFLAGS) > -rcutorture_urcu_mb_LDADD = $(URCU_MB_LIB) > +rcutorture_urcu_mb_LDADD = $(URCU_MB_LIB) $(URCU_CALL_LIB) $(WFQUEUE_LIB) > > rcutorture_qsbr_SOURCES = urcutorture.c > rcutorture_qsbr_CFLAGS = -DTORTURE_QSBR $(AM_CFLAGS) > -rcutorture_qsbr_LDADD = $(URCU_QSBR_LIB) > +rcutorture_qsbr_LDADD = $(URCU_QSBR_LIB) $(URCU_CALL_LIB) $(WFQUEUE_LIB) > > rcutorture_urcu_signal_SOURCES = urcutorture.c > rcutorture_urcu_signal_CFLAGS = -DTORTURE_URCU_SIGNAL $(AM_CFLAGS) > -rcutorture_urcu_signal_LDADD = $(URCU_SIGNAL_LIB) > +rcutorture_urcu_signal_LDADD = $(URCU_SIGNAL_LIB) $(URCU_CALL_LIB) > $(WFQUEUE_LIB) > > rcutorture_urcu_bp_SOURCES = urcutorture.c > rcutorture_urcu_bp_CFLAGS = -DTORTURE_URCU_BP $(AM_CFLAGS) > -rcutorture_urcu_bp_LDADD = $(URCU_BP_LIB) > +rcutorture_urcu_bp_LDADD = $(URCU_BP_LIB) $(URCU_CALL_LIB) $(WFQUEUE_LIB) > > test_mutex_SOURCES = test_mutex.c $(URCU) > > diff --git a/tests/rcutorture.h b/tests/rcutorture.h > index 181547a..1970d33 100644 > --- a/tests/rcutorture.h > +++ b/tests/rcutorture.h > @@ -65,6 +65,8 @@ > * Test variables. > */ > > +#include "../urcu-call-rcu.h" > + > DEFINE_PER_THREAD(long long, n_reads_pt); > DEFINE_PER_THREAD(long long, n_updates_pt); > > @@ -296,10 +298,30 @@ void *rcu_read_stress_test(void *arg) > return (NULL); > } > > +static pthread_mutex_t call_rcu_test_mutex = PTHREAD_MUTEX_INITIALIZER; > +static pthread_cond_t call_rcu_test_cond = PTHREAD_COND_INITIALIZER; > + > +void rcu_update_stress_test_rcu(struct rcu_head *head) > +{ > + if (pthread_mutex_lock(&call_rcu_test_mutex) != 0) { > + perror("pthread_mutex_lock"); > + exit(-1); > + } > + if (pthread_cond_signal(&call_rcu_test_cond) != 0) { > + perror("pthread_cond_signal"); > + exit(-1); > + } > + if (pthread_mutex_unlock(&call_rcu_test_mutex) != 0) { > + perror("pthread_mutex_unlock"); > + exit(-1); > + } > +} > + > void *rcu_update_stress_test(void *arg) > { > int i; > struct rcu_stress *p; > + struct rcu_head rh; > > while (goflag == GOFLAG_INIT) > poll(NULL, 0, 1); > @@ -317,7 +339,24 @@ void *rcu_update_stress_test(void *arg) > for (i = 0; i < RCU_STRESS_PIPE_LEN; i++) > if (i != rcu_stress_idx) > rcu_stress_array[i].pipe_count++; > - synchronize_rcu(); > + if (n_updates & 0x1) > + synchronize_rcu(); > + else { > + if (pthread_mutex_lock(&call_rcu_test_mutex) != 0) { > + perror("pthread_mutex_lock"); > + exit(-1); > + } > + call_rcu(&rh, rcu_update_stress_test_rcu); Testing more than one queue entry would be good. > + if (pthread_cond_wait(&call_rcu_test_cond, > + &call_rcu_test_mutex) != 0) { > + perror("pthread_cond_wait"); > + exit(-1); > + } > + if (pthread_mutex_unlock(&call_rcu_test_mutex) != 0) { > + perror("pthread_mutex_unlock"); > + exit(-1); > + } > + } > n_updates++; > } > return NULL; > diff --git a/urcu-call-rcu.c b/urcu-call-rcu.c > new file mode 100644 > index 0000000..245fd33 > --- /dev/null > +++ b/urcu-call-rcu.c > @@ -0,0 +1,397 @@ > +/* > + * urcu-call-rcu.c > + * > + * Userspace RCU library - batch memory reclamation with kernel API > + * > + * Copyright (c) 2010 Paul E. McKenney <[email protected]> > + * > + * 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 <stdio.h> > +#include <pthread.h> > +#include <signal.h> > +#include <assert.h> > +#include <stdlib.h> > +#include <string.h> > +#include <errno.h> > +#include <poll.h> > +#include <sys/time.h> > +#include <syscall.h> > +#include <unistd.h> > + > +#include "config.h" > +#include "urcu/wfqueue.h" > +#include "urcu-call-rcu.h" > +#include "urcu-pointer.h" > + > +/* Data structure that identifies a call_rcu thread. */ > + > +struct call_rcu_data { > + struct wfq_queue cbs; > + unsigned long qlen; We should probably create a RCU_DEBUG function that tests for large values. [ more later, after lunch :) ] -- Mathieu Desnoyers Operating System Efficiency R&D Consultant EfficiOS Inc. http://www.efficios.com _______________________________________________ ltt-dev mailing list [email protected] http://lists.casi.polymtl.ca/cgi-bin/mailman/listinfo/ltt-dev
