(root)/
strace-6.5/
tests/
looping_threads.c
       1  /*
       2   * Check tracing of looping threads.
       3   *
       4   * Copyright (c) 2009-2019 The strace developers.
       5   * All rights reserved.
       6   *
       7   * SPDX-License-Identifier: GPL-2.0-or-later
       8   */
       9  
      10  #include "tests.h"
      11  #include <assert.h>
      12  #include <errno.h>
      13  #include <pthread.h>
      14  #include <signal.h>
      15  #include <stdio.h>
      16  #include <stdlib.h>
      17  #include <unistd.h>
      18  #include <sys/wait.h>
      19  
      20  static void *
      21  thread(void *arg)
      22  {
      23  	for (;;)
      24  		getuid();
      25  	return arg;
      26  }
      27  
      28  int
      29  main(int ac, const char *av[])
      30  {
      31  	assert(ac == 3);
      32  
      33  	int timeout = atoi(av[1]);
      34  	assert(timeout > 0);
      35  
      36  	int num_threads = atoi(av[2]);
      37  	assert(num_threads > 0);
      38  
      39  	/*
      40  	 * Unblock all signals.
      41  	 */
      42  	static sigset_t mask;
      43  	if (sigprocmask(SIG_SETMASK, &mask, NULL))
      44  		perror_msg_and_fail("sigprocmask");
      45  
      46  	/*
      47  	 * Reset SIGALRM and SIGHUP signal handlers.
      48  	 */
      49  	static const struct sigaction sa_def = { .sa_handler = SIG_DFL };
      50  	if (sigaction(SIGHUP, &sa_def, NULL))
      51  		perror_msg_and_fail("sigaction SIGHUP");
      52  	if (sigaction(SIGALRM, &sa_def, NULL))
      53  		perror_msg_and_fail("sigaction SIGALRM");
      54  
      55  	/*
      56  	 * Create a new process group.
      57  	 */
      58  	if (setpgid(0, 0))
      59  		perror_msg_and_fail("setpgid");
      60  
      61  	/*
      62  	 * Set an alarm clock.
      63  	 */
      64  	alarm(timeout);
      65  
      66  	/*
      67  	 * When the main process terminates, the process group becomes orphaned.
      68  	 * If any member of the orphaned process group is stopped, then
      69  	 * a SIGHUP signal followed by a SIGCONT signal is sent to each process
      70  	 * in the orphaned process group.
      71  	 * Create a process in a stopped state to activate this behaviour.
      72  	 */
      73  	const pid_t stopped = fork();
      74  	if (stopped < 0)
      75  		perror_msg_and_fail("fork");
      76  	if (!stopped) {
      77  		raise(SIGSTOP);
      78  		_exit(0);
      79  	}
      80  
      81  	/*
      82  	 * Wait for the process to stop.
      83  	 */
      84  	int status;
      85  	if (waitpid(stopped, &status, WUNTRACED) != stopped)
      86  		perror_msg_and_fail("waitpid WUNTRACED");
      87  	if (!WIFSTOPPED(status) || WSTOPSIG(status) != SIGSTOP)
      88                  error_msg_and_fail("waitpid WUNTRACED: "
      89  				   "unexpected wait status %d", status);
      90  	/*
      91  	 * Create all threads in a subprocess, this guarantees that
      92  	 * their tracer will not be their parent.
      93  	 */
      94  	pid_t pid = fork();
      95  	if (pid < 0)
      96  		perror_msg_and_fail("fork");
      97  	if (!pid) {
      98  		for (int i = 0; i < num_threads; i++) {
      99  			pthread_t t;
     100  			if ((errno = pthread_create(&t, NULL, thread, NULL))) {
     101  				if (EAGAIN == errno)
     102  					break;
     103  				perror_msg_and_fail("pthread_create #%d", i);
     104  			}
     105  		}
     106  
     107  		/* This terminates all threads created above.  */
     108  		_exit(0);
     109  	}
     110  
     111  	if (waitpid(pid, &status, 0) != pid)
     112  		perror_msg_and_fail("waitpid");
     113  	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
     114                  error_msg_and_fail("waitpid: unexpected wait status %d",
     115  				   status);
     116  
     117  	/*
     118  	 * Make the process group orphaned.
     119  	 */
     120  	return 0;
     121  }