1/* Smoke test for the tgkill system call.
2 Copyright (C) 2019-2024 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. */
27static volatile sig_atomic_t signals_delivered;
28
29/* Expected TID of the thread receiving the signal. */
30static pid_t expected_signal_tid;
31
32static void
33sigusr1_handler (int signo)
34{
35 TEST_COMPARE (expected_signal_tid, gettid ());
36 ++signals_delivered;
37}
38
39struct 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. */
49static void
50subprocess_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. */
64static void
65subprocess (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
84static void *
85threadfunc (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 (callback: 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 (callback: subprocess_no_tid_match,
99 closure: &(struct pid_and_tid)
100 {
101 .pid = getpid (),
102 .tid = gettid (),
103 });
104
105 support_isolate_in_subprocess (callback: subprocess_no_tid_match,
106 closure: &(struct pid_and_tid)
107 {
108 .pid = getpid (),
109 .tid = getpid (),
110 });
111
112 return NULL;
113}
114
115static int
116do_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 (thr: xpthread_create (NULL, thread_func: threadfunc, NULL));
127
128 TEST_VERIFY (signal (SIGUSR1, SIG_DFL) == sigusr1_handler);
129 return 0;
130}
131
132#include <support/test-driver.c>
133

source code of glibc/sysdeps/unix/sysv/linux/tst-tgkill.c