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