1 /* Smoke test for the tgkill system call.
2    Copyright (C) 2019-2022 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
sigusr1_handler(int signo)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
subprocess_no_tid_match(void * closure)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
subprocess(void * closure)65 subprocess (void *closure)
66 {
67   int original_tid = expected_signal_tid;
68 
69   /* Do not expect that the folloing 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 suceed.  */
81   TEST_COMPARE (tgkill (getppid (), original_tid, SIGUSR1), 0);
82 }
83 
84 static void *
threadfunc(void * closure)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
do_test(void)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>
133