1  /* Smoke test for the tgkill system call.
       2     Copyright (C) 2019-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <errno.h>
      20  #include <signal.h>
      21  #include <support/check.h>
      22  #include <support/namespace.h>
      23  #include <support/xthread.h>
      24  #include <unistd.h>
      25  
      26  /* Number of times sigusr1_handler has been invoked.  */
      27  static volatile sig_atomic_t signals_delivered;
      28  
      29  /* Expected TID of the thread receiving the signal.  */
      30  static pid_t expected_signal_tid;
      31  
      32  static void
      33  sigusr1_handler (int signo)
      34  {
      35    TEST_COMPARE (expected_signal_tid, gettid ());
      36    ++signals_delivered;
      37  }
      38  
      39  struct pid_and_tid
      40  {
      41    pid_t pid;
      42    pid_t tid;
      43  };
      44  
      45  /* Send signals from the subprocess which are not expected to be
      46     delivered.  There is no handler for SIGUSR2, so delivery will
      47     result in a test failure.  CLOSURE must point to a valid PID/TID
      48     combination that is still running.  */
      49  static void
      50  subprocess_no_tid_match (void *closure)
      51  {
      52    struct pid_and_tid *ids = closure;
      53    TEST_COMPARE (tgkill (ids->pid, gettid (), SIGUSR2), -1);
      54    TEST_COMPARE (errno, ESRCH);
      55  
      56    TEST_COMPARE (tgkill (getpid (), ids->tid, SIGUSR2), -1);
      57    TEST_COMPARE (errno, ESRCH);
      58  
      59    TEST_COMPARE (tgkill (getppid (), gettid (), SIGUSR2), -1);
      60    TEST_COMPARE (errno, ESRCH);
      61  }
      62  
      63  /* Called from threadfunc below.  */
      64  static void
      65  subprocess (void *closure)
      66  {
      67    int original_tid = expected_signal_tid;
      68  
      69    /* Do not expect that the following signals are delivered to the
      70       subprocess.  The parent process retains the original
      71       expected_signal_tid value.  */
      72    expected_signal_tid = 0;
      73    TEST_COMPARE (tgkill (getpid (), original_tid, SIGUSR1), -1);
      74    TEST_COMPARE (errno, ESRCH);
      75    TEST_COMPARE (tgkill (getppid (), gettid (), SIGUSR1), -1);
      76    TEST_COMPARE (errno, ESRCH);
      77    TEST_COMPARE (expected_signal_tid, 0);
      78  
      79    /* This call has the correct PID/TID combination and is therefore
      80       expected to succeed.  */
      81    TEST_COMPARE (tgkill (getppid (), original_tid, SIGUSR1), 0);
      82  }
      83  
      84  static void *
      85  threadfunc (void *closure)
      86  {
      87    TEST_VERIFY (gettid () != getpid ());
      88    expected_signal_tid = gettid ();
      89    TEST_COMPARE (tgkill (getpid (), gettid (), SIGUSR1), 0);
      90    TEST_COMPARE (signals_delivered, 1);
      91    signals_delivered = 0;
      92  
      93    support_isolate_in_subprocess (subprocess, NULL);
      94  
      95    /* Check that exactly one signal arrived from the subprocess.  */
      96    TEST_COMPARE (signals_delivered, 1);
      97  
      98    support_isolate_in_subprocess (subprocess_no_tid_match,
      99                                   &(struct pid_and_tid)
     100                                   {
     101                                     .pid = getpid (),
     102                                     .tid = gettid (),
     103                                   });
     104  
     105    support_isolate_in_subprocess (subprocess_no_tid_match,
     106                                   &(struct pid_and_tid)
     107                                   {
     108                                     .pid = getpid (),
     109                                     .tid = getpid (),
     110                                   });
     111  
     112    return NULL;
     113  }
     114  
     115  static int
     116  do_test (void)
     117  {
     118    TEST_VERIFY_EXIT (signal (SIGUSR1, sigusr1_handler) != SIG_ERR);
     119  
     120    expected_signal_tid = gettid ();
     121    TEST_COMPARE (gettid (), getpid ());
     122    TEST_COMPARE (tgkill (getpid (), gettid (), SIGUSR1), 0);
     123    TEST_COMPARE (signals_delivered, 1);
     124    signals_delivered = 0;
     125  
     126    xpthread_join (xpthread_create (NULL, threadfunc, NULL));
     127  
     128    TEST_VERIFY (signal (SIGUSR1, SIG_DFL) == sigusr1_handler);
     129    return 0;
     130  }
     131  
     132  #include <support/test-driver.c>