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. */ |
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 (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 | |
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 (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 | |