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