From 390f0a26eb268ad42603a106866bacf6fb4a0649 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Mon, 17 Dec 2012 23:43:14 -0500 Subject: [PATCH] test: fork handling Signed-off-by: Mathieu Desnoyers --- tests/Makefile.am | 4 +- tests/test_urcu_fork.c | 147 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 tests/test_urcu_fork.c diff --git a/tests/Makefile.am b/tests/Makefile.am index f8b4c67..0e15a4c 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -20,7 +20,8 @@ noinst_PROGRAMS = test_urcu test_urcu_dynamic_link test_urcu_timing \ test_urcu_wfcq_dynlink \ test_urcu_lfq_dynlink test_urcu_lfs_dynlink test_urcu_hash \ test_urcu_lfs_rcu_dynlink \ - test_urcu_multiflavor test_urcu_multiflavor_dynlink + test_urcu_multiflavor test_urcu_multiflavor_dynlink \ + test_urcu_fork noinst_HEADERS = rcutorture.h test_urcu_multiflavor.h if COMPAT_ARCH @@ -85,6 +86,7 @@ test_urcu_signal_timing_CFLAGS= -DRCU_SIGNAL $(AM_CFLAGS) test_urcu_signal_yield_SOURCES = test_urcu.c $(URCU_SIGNAL) test_urcu_signal_yield_CFLAGS = -DRCU_SIGNAL -DDEBUG_YIELD $(AM_CFLAGS) +test_urcu_fork_SOURCES = test_urcu_fork.c $(URCU) test_rwlock_timing_SOURCES = test_rwlock_timing.c $(URCU_SIGNAL) diff --git a/tests/test_urcu_fork.c b/tests/test_urcu_fork.c new file mode 100644 index 0000000..6e454b5 --- /dev/null +++ b/tests/test_urcu_fork.c @@ -0,0 +1,147 @@ +/* + * test_urcu_fork.c + * + * Userspace RCU library - test program (fork) + * + * Copyright February 2012 - Mathieu Desnoyers + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#define _GNU_SOURCE +#include "../config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifndef DYNAMIC_LINK_TEST +#define _LGPL_SOURCE +#else +#define rcu_debug_yield_read() +#endif +#include + +struct test_node { + int somedata; + struct rcu_head head; +}; + +static void cb(struct rcu_head *head) +{ + struct test_node *node; + + fprintf(stderr, "rcu callback invoked in pid: %d\n", + (int) getpid()); + node = caa_container_of(head, struct test_node, head); + free(node); +} + +static void test_rcu(void) +{ + struct test_node *node; + + rcu_register_thread(); + + synchronize_rcu(); + + rcu_read_lock(); + rcu_read_unlock(); + + node = malloc(sizeof(*node)); + assert(node); + + call_rcu(&node->head, cb); + + synchronize_rcu(); + + rcu_unregister_thread(); +} + +int main(int argc, char **argv) +{ + pid_t pid; + int ret; + +#if 0 + /* pthread_atfork does not work with malloc/free in callbacks */ + ret = pthread_atfork(call_rcu_before_fork, + call_rcu_after_fork_parent, + call_rcu_after_fork_child); + if (ret) { + errno = ret; + perror("pthread_atfork"); + exit(EXIT_FAILURE); + } +#endif + + test_rcu(); + + synchronize_rcu(); + + fprintf(stderr, "%s parent pid: %d, before fork\n", + argv[0], (int) getpid()); + + call_rcu_before_fork(); + pid = fork(); + + if (pid == 0) { + /* child */ + call_rcu_after_fork_child(); + fprintf(stderr, "%s child pid: %d, after fork\n", + argv[0], (int) getpid()); + test_rcu(); + fprintf(stderr, "%s child pid: %d, after rcu test\n", + argv[0], (int) getpid()); + } else if (pid > 0) { + int status; + + /* parent */ + call_rcu_after_fork_parent(); + fprintf(stderr, "%s parent pid: %d, after fork\n", + argv[0], (int) getpid()); + test_rcu(); + fprintf(stderr, "%s parent pid: %d, after rcu test\n", + argv[0], (int) getpid()); + for (;;) { + pid = wait(&status); + if (WIFEXITED(status)) { + fprintf(stderr, "child %u exited normally with status %u\n", + pid, WEXITSTATUS(status)); + break; + } else if (WIFSIGNALED(status)) { + fprintf(stderr, "child %u was terminated by signal %u\n", + pid, WTERMSIG(status)); + break; + } else { + continue; + } + } + } else { + perror("fork"); + exit(EXIT_FAILURE); + } + exit(EXIT_SUCCESS); +} -- 2.34.1