test_urcu_fork: test many fork, with 3 children deep
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Thu, 17 Apr 2014 12:32:22 +0000 (08:32 -0400)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Thu, 17 Apr 2014 13:02:18 +0000 (09:02 -0400)
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
tests/regression/test_urcu_fork.c

index ce0c9cafd92c5fe86f6b2edd6ccb3598b4556a06..06786b0cc3285b988e225b1bb74c0f0522c76d36 100644 (file)
 #endif
 #include <urcu.h>
 
+/* We generate children 3 levels deep */
+#define FORK_DEPTH     3
+/* Each generation spawns 10 children */
+#define NR_FORK                10
+
+static int fork_generation;
+
 struct test_node {
        int somedata;
        struct rcu_head head;
@@ -80,68 +87,99 @@ static void test_rcu(void)
        rcu_unregister_thread();
 }
 
-int main(int argc, char **argv)
+/*
+ * Return 0 if child, > 0 if parent, < 0 on error.
+ */
+static int do_fork(const char *execname)
 {
        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());
+               execname, (int) getpid());
 
        call_rcu_before_fork();
        pid = fork();
-
        if (pid == 0) {
                /* child */
+               fork_generation++;
+
                call_rcu_after_fork_child();
                fprintf(stderr, "%s child pid: %d, after fork\n",
-                       argv[0], (int) getpid());
+                       execname, (int) getpid());
                test_rcu();
                fprintf(stderr, "%s child pid: %d, after rcu test\n",
-                       argv[0], (int) getpid());
+                       execname, (int) getpid());
+               if (fork_generation >= FORK_DEPTH)
+                       exit(EXIT_SUCCESS);
+               return 0;
        } 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());
+                       execname, (int) getpid());
                test_rcu();
                fprintf(stderr, "%s parent pid: %d, after rcu test\n",
-                       argv[0], (int) getpid());
+                       execname, (int) getpid());
                for (;;) {
                        pid = wait(&status);
+                       if (pid < 0) {
+                               perror("wait");
+                               return -1;
+                       }
                        if (WIFEXITED(status)) {
                                fprintf(stderr, "child %u exited normally with status %u\n",
                                        pid, WEXITSTATUS(status));
+                               if (WEXITSTATUS(status))
+                                       return -1;
                                break;
                        } else if (WIFSIGNALED(status)) {
                                fprintf(stderr, "child %u was terminated by signal %u\n",
                                        pid, WTERMSIG(status));
-                               break;
+                               return -1;
                        } else {
                                continue;
                        }
                }
+               return 1;
        } else {
                perror("fork");
+               return -1;
+       }
+}
+
+int main(int argc, char **argv)
+{
+       unsigned int i;
+
+#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
+
+restart:
+       for (i = 0; i < NR_FORK; i++) {
+               int ret;
+
+               test_rcu();
+               synchronize_rcu();
+               ret = do_fork(argv[0]);
+               if (ret == 0)           /* child */
+                       goto restart;
+               else if (ret < 0)
+                       goto error;
+               /* else parent, continue. */
+       }
        exit(EXIT_SUCCESS);
+
+error:
+       exit(EXIT_FAILURE);
 }
This page took 0.036306 seconds and 4 git commands to generate.