]> granicus.if.org Git - strace/commitdiff
tests: check tracing of looping threads
authorDmitry V. Levin <ldv@altlinux.org>
Wed, 4 Jul 2018 02:11:27 +0000 (02:11 +0000)
committerDmitry V. Levin <ldv@altlinux.org>
Wed, 6 Mar 2019 23:20:39 +0000 (23:20 +0000)
* test/many_looping_threads.c: Remove.
* test/.gitignore: Remove many_looping_threads.
* test/Makefile (PROGS): Likewise.
(many_looping_threads): Remove.
* tests/looping_threads.c: New file.
* tests/looping_threads.test: New test.
* tests/.gitignore: Add looping_threads.
* tests/Makefile.am (check_PROGRAMS): Likewise.
(looping_threads_LDADD): New variable.
(MISC_TESTS, XFAIL_TESTS): Add looping_threads.test.

test/.gitignore
test/Makefile
test/many_looping_threads.c [deleted file]
tests/.gitignore
tests/Makefile.am
tests/looping_threads.c [new file with mode: 0644]
tests/looping_threads.test [new file with mode: 0755]

index 34d37bf3904c1f3ca33d73a20b97378e64b99d63..db976548bbb6ce00920488839bc876736d4be9bf 100644 (file)
@@ -1,7 +1,6 @@
 childthread
 clone
 leaderkill
-many_looping_threads
 mmap_offset_decode
 mtd
 seccomp
index ad727fcbf58a2645b5e21d560eb503f5546c640b..caf4549b100a94d1899428930adebeecda63f317 100644 (file)
@@ -3,8 +3,7 @@ CFLAGS += -Wall
 PROGS = \
     sig skodic clone leaderkill childthread \
     sigkill_rain wait_must_be_interruptible threaded_execve \
-    mtd ubi seccomp sfd mmap_offset_decode x32_lseek x32_mmap \
-    many_looping_threads
+    mtd ubi seccomp sfd mmap_offset_decode x32_lseek x32_mmap
 
 all: $(PROGS)
 
@@ -12,8 +11,6 @@ leaderkill: LDFLAGS += -pthread
 
 childthread: LDFLAGS += -pthread
 
-many_looping_threads: LDFLAGS += -pthread
-
 clean distclean:
        rm -f *.o core $(PROGS) *.gdb
 
diff --git a/test/many_looping_threads.c b/test/many_looping_threads.c
deleted file mode 100644 (file)
index 918bd9d..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-// This testcase, when run with large number of threads
-// under stace -f, may never finish because strace does not
-// ensure any fairness in thread scheduling:
-// it restarts threads as they stop. If daughter threads crowd out
-// the "mother" and _they_ get continually restarted by strace,
-// the end of spawning loop will never be reached.
-//
-// Also, it is a testcase which triggers the
-// "strace: Exit of unknown pid 32457 seen"
-// message when on testcase exit, strace sees deaths of newly-attached
-// threads _before_ their first syscall stop.
-//
-#include <stdio.h>
-#include <pthread.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <signal.h>
-#include <stdlib.h>
-
-static int thd_no;
-
-static void *sub_thd(void *c)
-{
-       dprintf(1, "sub-thread %d created\n", ++thd_no);
-       for (;;)
-               getuid();
-       return NULL;
-}
-
-int main(int argc, char *argv[])
-{
-       int i;
-       pthread_t *thd;
-       int num_threads = 1;
-
-       if (argv[1])
-               num_threads = atoi(argv[1]);
-
-       thd = malloc(num_threads * sizeof(thd[0]));
-       dprintf(1, "test start, num_threads:%d...\n", num_threads);
-
-       for (i = 0; i < num_threads; i++) {
-               pthread_create(&thd[i], NULL, sub_thd, NULL);
-               dprintf(1, "after pthread_create\n");
-       }
-
-       /* Exit. This kills all threads */
-       return 0;
-}
index b481a82f39b8c181f20e5af07cf31610d2bdef44..e70388feaebac565859fc172cc4d233ed7d89989 100644 (file)
@@ -224,6 +224,7 @@ list_sigaction_signum
 llseek
 localtime
 lookup_dcookie
+looping_threads
 lseek
 lstat
 lstat64
index 667a4bddc520b0d9e24010c58200b38cf663cf5d..a71fb3d264817660721f60101e58ff8315a12d44 100644 (file)
@@ -110,6 +110,7 @@ check_PROGRAMS = $(PURE_EXECUTABLES) \
        ksysent \
        list_sigaction_signum \
        localtime \
+       looping_threads \
        mmsg-silent \
        mmsg_name-v \
        msg_control-v \
@@ -174,6 +175,7 @@ fstat64_CPPFLAGS = $(AM_CPPFLAGS) -D_FILE_OFFSET_BITS=64
 fstatat64_CPPFLAGS = $(AM_CPPFLAGS) -D_FILE_OFFSET_BITS=64
 ftruncate64_CPPFLAGS = $(AM_CPPFLAGS) -D_FILE_OFFSET_BITS=64
 localtime_LDADD = $(clock_LIBS) $(LDADD)
+looping_threads_LDADD = -lpthread $(LDADD)
 lstat64_CPPFLAGS = $(AM_CPPFLAGS) -D_FILE_OFFSET_BITS=64
 mmap64_CPPFLAGS = $(AM_CPPFLAGS) -D_FILE_OFFSET_BITS=64
 mmap64_Xabbrev_CPPFLAGS = $(AM_CPPFLAGS) -D_FILE_OFFSET_BITS=64
@@ -310,6 +312,7 @@ MISC_TESTS = \
        kill_child.test \
        ksysent.test \
        localtime.test \
+       looping_threads.test \
        opipe.test \
        options-syntax.test \
        pc.test \
@@ -351,7 +354,8 @@ TESTS = $(GEN_TESTS) $(DECODER_TESTS) $(MISC_TESTS) $(STACKTRACE_TESTS)
 XFAIL_TESTS_ =
 XFAIL_TESTS_m32 = $(STACKTRACE_TESTS)
 XFAIL_TESTS_mx32 = $(STACKTRACE_TESTS)
-XFAIL_TESTS = $(XFAIL_TESTS_$(MPERS_NAME)) $(XFAIL_TESTS_$(ARCH))
+XFAIL_TESTS = $(XFAIL_TESTS_$(MPERS_NAME)) $(XFAIL_TESTS_$(ARCH)) \
+             looping_threads.test
 
 TEST_LOG_COMPILER = env
 AM_TEST_LOG_FLAGS = STRACE_ARCH=$(ARCH) STRACE_NATIVE_ARCH=$(NATIVE_ARCH) \
diff --git a/tests/looping_threads.c b/tests/looping_threads.c
new file mode 100644 (file)
index 0000000..2f5e955
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Check tracing of looping threads.
+ *
+ * Copyright (c) 2009-2019 The strace developers.
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "tests.h"
+#include <assert.h>
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+static void *
+thread(void *arg)
+{
+       for (;;)
+               getuid();
+       return arg;
+}
+
+int
+main(int ac, const char *av[])
+{
+       assert(ac == 3);
+
+       int timeout = atoi(av[1]);
+       assert(timeout > 0);
+
+       int num_threads = atoi(av[2]);
+       assert(num_threads > 0);
+
+       /*
+        * Unblock all signals.
+        */
+       static sigset_t mask;
+       if (sigprocmask(SIG_SETMASK, &mask, NULL))
+               perror_msg_and_fail("sigprocmask");
+
+       /*
+        * Reset SIGALRM and SIGHUP signal handlers.
+        */
+       static const struct sigaction sa_def = { .sa_handler = SIG_DFL };
+       if (sigaction(SIGHUP, &sa_def, NULL))
+               perror_msg_and_fail("sigaction SIGHUP");
+       if (sigaction(SIGALRM, &sa_def, NULL))
+               perror_msg_and_fail("sigaction SIGALRM");
+
+       /*
+        * Create a new process group.
+        */
+       if (setpgid(0, 0))
+               perror_msg_and_fail("setpgid");
+
+       /*
+        * Set an alarm clock.
+        */
+       alarm(timeout);
+
+       /*
+        * When the main process terminates, the process group becomes orphaned.
+        * If any member of the orphaned process group is stopped, then
+        * a SIGHUP signal followed by a SIGCONT signal is sent to each process
+        * in the orphaned process group.
+        * Create a process in a stopped state to activate this behaviour.
+        */
+       const pid_t stopped = fork();
+       if (stopped < 0)
+               perror_msg_and_fail("fork");
+       if (!stopped) {
+               raise(SIGSTOP);
+               _exit(0);
+       }
+
+       /*
+        * Wait for the process to stop.
+        */
+       int status;
+       if (waitpid(stopped, &status, WUNTRACED) != stopped)
+               perror_msg_and_fail("waitpid WUNTRACED");
+       if (!WIFSTOPPED(status) || WSTOPSIG(status) != SIGSTOP)
+                error_msg_and_fail("waitpid WUNTRACED: "
+                                  "unexpected wait status %d", status);
+       /*
+        * Create all threads in a subprocess, this guarantees that
+        * their tracer will not be their parent.
+        */
+       pid_t pid = fork();
+       if (pid < 0)
+               perror_msg_and_fail("fork");
+       if (!pid) {
+               for (int i = 0; i < num_threads; i++) {
+                       pthread_t t;
+                       if ((errno = pthread_create(&t, NULL, thread, NULL))) {
+                               if (EAGAIN == errno)
+                                       break;
+                               perror_msg_and_fail("pthread_create #%d", i);
+                       }
+               }
+
+               /* This terminates all threads created above.  */
+               _exit(0);
+       }
+
+       if (waitpid(pid, &status, 0) != pid)
+               perror_msg_and_fail("waitpid");
+       if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
+                error_msg_and_fail("waitpid: unexpected wait status %d",
+                                  status);
+
+       /*
+        * Make the process group orphaned.
+        */
+       return 0;
+}
diff --git a/tests/looping_threads.test b/tests/looping_threads.test
new file mode 100755 (executable)
index 0000000..e8b0bbb
--- /dev/null
@@ -0,0 +1,38 @@
+#!/bin/sh
+#
+# Check tracing of looping threads.
+#
+# Copyright (c) 2009-2019 The strace developers.
+# All rights reserved.
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+. "${srcdir=.}/init.sh"
+. "${srcdir=.}/PTRACE_SEIZE.sh"
+
+run_prog ../orphaned_process_group > /dev/null
+
+run_prog_skip_if_failed date +%s > /dev/null
+s0="$(date +%s)"
+
+check_prog nproc
+inc="$(nproc)"
+[ "$inc" -ge 1 ] || inc=1
+
+timeout_2="$(($TIMEOUT_DURATION/2))"
+timeout_8="$(($TIMEOUT_DURATION/8))"
+nproc=1
+
+run_prog "../$NAME" "$timeout_8" "$nproc"
+
+while :; do
+       run_strace -f -qq -enone -esignal=none "../$NAME" "$timeout_2" "$nproc"
+
+       s1="$(date +%s)"
+       [ "$(($s1-$s0))" -lt "$timeout_8" ] ||
+               break
+
+       nproc="$(($nproc+$inc))"
+done
+
+warn_ "$ME_: nproc=$nproc elapsed=$(($s1-$s0))"