1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2019 Linaro Limited. All rights reserved.
4 * Copyright (c) Linux Test Project, 2019-2024
5 * Author: Sumit Garg <sumit.garg@linaro.org>
6 */
7
8 /*\
9 * Basic test for rt_tgsigqueueinfo(2) syscall. It sends the signal and data
10 * to the single thread specified by the combination of tgid, a thread group
11 * ID, and tid, a thread in that thread group.
12 *
13 * Also this implement 3 tests differing on the basis of signal sender:
14 *
15 * - Sender and receiver is the same thread.
16 * - Sender is parent of the thread.
17 * - Sender is different thread.
18 */
19
20 #define _GNU_SOURCE
21
22 #include <err.h>
23 #include <pthread.h>
24 #include "tst_safe_pthread.h"
25 #include "tst_test.h"
26 #include "lapi/syscalls.h"
27
28 static char sigval_send[] = "rt_tgsigqueueinfo data";
29 static volatile int signum_rcv;
30 static char *sigval_rcv;
31
sigusr1_handler(int signum,siginfo_t * uinfo,void * p LTP_ATTRIBUTE_UNUSED)32 static void sigusr1_handler(int signum, siginfo_t *uinfo,
33 void *p LTP_ATTRIBUTE_UNUSED)
34 {
35 signum_rcv = signum;
36 sigval_rcv = uinfo->si_ptr;
37 }
38
send_rcv_func(void * arg)39 void *send_rcv_func(void *arg)
40 {
41 siginfo_t uinfo;
42
43 signum_rcv = 0;
44 sigval_rcv = NULL;
45
46 uinfo.si_errno = 0;
47 uinfo.si_code = SI_QUEUE;
48 uinfo.si_ptr = sigval_send;
49
50 TEST(tst_syscall(__NR_rt_tgsigqueueinfo, getpid(),
51 syscall(__NR_gettid), SIGUSR1, &uinfo));
52 if (TST_RET)
53 tst_brk(TFAIL | TTERRNO, "rt_tgsigqueueinfo failed");
54
55 while (!signum_rcv)
56 usleep(1000);
57
58 if ((signum_rcv == SIGUSR1) && (sigval_rcv == sigval_send))
59 tst_res(TPASS, "Test signal to self succeeded");
60 else
61 tst_res(TFAIL, "Failed to deliver signal/data to self thread");
62
63 return arg;
64 }
65
verify_signal_self(void)66 static void verify_signal_self(void)
67 {
68 pthread_t pt;
69
70 SAFE_PTHREAD_CREATE(&pt, NULL, send_rcv_func, NULL);
71
72 SAFE_PTHREAD_JOIN(pt, NULL);
73 }
74
receiver_func(void * arg)75 void *receiver_func(void *arg)
76 {
77 pid_t *tid = arg;
78
79 *tid = syscall(__NR_gettid);
80
81 signum_rcv = 0;
82 sigval_rcv = NULL;
83
84 TST_CHECKPOINT_WAKE(0);
85
86 while (!signum_rcv)
87 usleep(1000);
88
89 if ((signum_rcv == SIGUSR1) && (sigval_rcv == sigval_send))
90 tst_res(TPASS, "Test signal to different thread succeeded");
91 else
92 tst_res(TFAIL,
93 "Failed to deliver signal/data to different thread");
94
95 return NULL;
96 }
97
verify_signal_parent_thread(void)98 static void verify_signal_parent_thread(void)
99 {
100 pid_t tid = -1;
101 pthread_t pt;
102 siginfo_t uinfo;
103
104 SAFE_PTHREAD_CREATE(&pt, NULL, receiver_func, &tid);
105
106 TST_CHECKPOINT_WAIT(0);
107
108 uinfo.si_errno = 0;
109 uinfo.si_code = SI_QUEUE;
110 uinfo.si_ptr = sigval_send;
111
112 TEST(tst_syscall(__NR_rt_tgsigqueueinfo, getpid(),
113 tid, SIGUSR1, &uinfo));
114 if (TST_RET)
115 tst_brk(TFAIL | TTERRNO, "rt_tgsigqueueinfo failed");
116
117 SAFE_PTHREAD_JOIN(pt, NULL);
118 }
119
sender_func(void * arg)120 void *sender_func(void *arg)
121 {
122 pid_t *tid = arg;
123 siginfo_t uinfo;
124
125 uinfo.si_errno = 0;
126 uinfo.si_code = SI_QUEUE;
127 uinfo.si_ptr = sigval_send;
128
129 TEST(tst_syscall(__NR_rt_tgsigqueueinfo, getpid(),
130 *tid, SIGUSR1, &uinfo));
131 if (TST_RET)
132 tst_brk(TFAIL | TTERRNO, "rt_tgsigqueueinfo failed");
133
134 return NULL;
135 }
136
verify_signal_inter_thread(void)137 static void verify_signal_inter_thread(void)
138 {
139 pid_t tid = -1;
140 pthread_t pt1, pt2;
141
142 SAFE_PTHREAD_CREATE(&pt1, NULL, receiver_func, &tid);
143
144 TST_CHECKPOINT_WAIT(0);
145
146 SAFE_PTHREAD_CREATE(&pt2, NULL, sender_func, &tid);
147
148 SAFE_PTHREAD_JOIN(pt2, NULL);
149
150 SAFE_PTHREAD_JOIN(pt1, NULL);
151 }
152
153 static struct tcase {
154 void (*tfunc)(void);
155 } tcases[] = {
156 {&verify_signal_self},
157 {&verify_signal_parent_thread},
158 {&verify_signal_inter_thread},
159 };
160
run(unsigned int i)161 static void run(unsigned int i)
162 {
163 tcases[i].tfunc();
164 }
165
setup(void)166 static void setup(void)
167 {
168 struct sigaction sigusr1 = {
169 .sa_flags = SA_SIGINFO,
170 .sa_sigaction = sigusr1_handler,
171 };
172
173 SAFE_SIGACTION(SIGUSR1, &sigusr1, NULL);
174 }
175
176 static struct tst_test test = {
177 .tcnt = ARRAY_SIZE(tcases),
178 .needs_checkpoints = 1,
179 .setup = setup,
180 .test = run,
181 };
182