116f0efc3SYonghong Song // SPDX-License-Identifier: GPL-2.0
216f0efc3SYonghong Song #include <test_progs.h>
3ab8b7f0cSYonghong Song #include "test_send_signal_kern.skel.h"
416f0efc3SYonghong Song 
5256eab48SAndrii Nakryiko int sigusr1_received = 0;
616f0efc3SYonghong Song 
716f0efc3SYonghong Song static void sigusr1_handler(int signum)
816f0efc3SYonghong Song {
916f0efc3SYonghong Song 	sigusr1_received++;
1016f0efc3SYonghong Song }
1116f0efc3SYonghong Song 
1286ccc384SStanislav Fomichev static void test_send_signal_common(struct perf_event_attr *attr,
13*6f6cc426SYonghong Song 				    bool signal_thread)
1416f0efc3SYonghong Song {
15ab8b7f0cSYonghong Song 	struct test_send_signal_kern *skel;
1616f0efc3SYonghong Song 	int pipe_c2p[2], pipe_p2c[2];
17ab8b7f0cSYonghong Song 	int err = -1, pmu_fd = -1;
1816f0efc3SYonghong Song 	char buf[256];
1916f0efc3SYonghong Song 	pid_t pid;
2016f0efc3SYonghong Song 
21*6f6cc426SYonghong Song 	if (!ASSERT_OK(pipe(pipe_c2p), "pipe_c2p"))
2286ccc384SStanislav Fomichev 		return;
2316f0efc3SYonghong Song 
24*6f6cc426SYonghong Song 	if (!ASSERT_OK(pipe(pipe_p2c), "pipe_p2c")) {
2516f0efc3SYonghong Song 		close(pipe_c2p[0]);
2616f0efc3SYonghong Song 		close(pipe_c2p[1]);
2786ccc384SStanislav Fomichev 		return;
2816f0efc3SYonghong Song 	}
2916f0efc3SYonghong Song 
3016f0efc3SYonghong Song 	pid = fork();
31*6f6cc426SYonghong Song 	if (!ASSERT_GE(pid, 0, "fork")) {
3216f0efc3SYonghong Song 		close(pipe_c2p[0]);
3316f0efc3SYonghong Song 		close(pipe_c2p[1]);
3416f0efc3SYonghong Song 		close(pipe_p2c[0]);
3516f0efc3SYonghong Song 		close(pipe_p2c[1]);
3686ccc384SStanislav Fomichev 		return;
3716f0efc3SYonghong Song 	}
3816f0efc3SYonghong Song 
3916f0efc3SYonghong Song 	if (pid == 0) {
4016f0efc3SYonghong Song 		/* install signal handler and notify parent */
4116f0efc3SYonghong Song 		signal(SIGUSR1, sigusr1_handler);
4216f0efc3SYonghong Song 
4316f0efc3SYonghong Song 		close(pipe_c2p[0]); /* close read */
4416f0efc3SYonghong Song 		close(pipe_p2c[1]); /* close write */
4516f0efc3SYonghong Song 
4616f0efc3SYonghong Song 		/* notify parent signal handler is installed */
47*6f6cc426SYonghong Song 		ASSERT_EQ(write(pipe_c2p[1], buf, 1), 1, "pipe_write");
4816f0efc3SYonghong Song 
4916f0efc3SYonghong Song 		/* make sure parent enabled bpf program to send_signal */
50*6f6cc426SYonghong Song 		ASSERT_EQ(read(pipe_p2c[0], buf, 1), 1, "pipe_read");
5116f0efc3SYonghong Song 
5216f0efc3SYonghong Song 		/* wait a little for signal handler */
5316f0efc3SYonghong Song 		sleep(1);
5416f0efc3SYonghong Song 
55929e54a9SJianlin Lv 		buf[0] = sigusr1_received ? '2' : '0';
56*6f6cc426SYonghong Song 		ASSERT_EQ(write(pipe_c2p[1], buf, 1), 1, "pipe_write");
5716f0efc3SYonghong Song 
5816f0efc3SYonghong Song 		/* wait for parent notification and exit */
59*6f6cc426SYonghong Song 		ASSERT_EQ(read(pipe_p2c[0], buf, 1), 1, "pipe_read");
6016f0efc3SYonghong Song 
6116f0efc3SYonghong Song 		close(pipe_c2p[1]);
6216f0efc3SYonghong Song 		close(pipe_p2c[0]);
6316f0efc3SYonghong Song 		exit(0);
6416f0efc3SYonghong Song 	}
6516f0efc3SYonghong Song 
6616f0efc3SYonghong Song 	close(pipe_c2p[1]); /* close write */
6716f0efc3SYonghong Song 	close(pipe_p2c[0]); /* close read */
6816f0efc3SYonghong Song 
69ab8b7f0cSYonghong Song 	skel = test_send_signal_kern__open_and_load();
70*6f6cc426SYonghong Song 	if (!ASSERT_OK_PTR(skel, "skel_open_and_load"))
71ab8b7f0cSYonghong Song 		goto skel_open_load_failure;
7216f0efc3SYonghong Song 
73ab8b7f0cSYonghong Song 	if (!attr) {
74ab8b7f0cSYonghong Song 		err = test_send_signal_kern__attach(skel);
75*6f6cc426SYonghong Song 		if (!ASSERT_OK(err, "skel_attach")) {
76ab8b7f0cSYonghong Song 			err = -1;
77ab8b7f0cSYonghong Song 			goto destroy_skel;
78ab8b7f0cSYonghong Song 		}
79ab8b7f0cSYonghong Song 	} else {
8016f0efc3SYonghong Song 		pmu_fd = syscall(__NR_perf_event_open, attr, pid, -1,
8116f0efc3SYonghong Song 				 -1 /* group id */, 0 /* flags */);
82*6f6cc426SYonghong Song 		if (!ASSERT_GE(pmu_fd, 0, "perf_event_open")) {
8316f0efc3SYonghong Song 			err = -1;
84ab8b7f0cSYonghong Song 			goto destroy_skel;
8516f0efc3SYonghong Song 		}
8616f0efc3SYonghong Song 
87ab8b7f0cSYonghong Song 		skel->links.send_signal_perf =
88ab8b7f0cSYonghong Song 			bpf_program__attach_perf_event(skel->progs.send_signal_perf, pmu_fd);
89bad2e478SAndrii Nakryiko 		if (!ASSERT_OK_PTR(skel->links.send_signal_perf, "attach_perf_event"))
9016f0efc3SYonghong Song 			goto disable_pmu;
91ab8b7f0cSYonghong Song 	}
9216f0efc3SYonghong Song 
9316f0efc3SYonghong Song 	/* wait until child signal handler installed */
94*6f6cc426SYonghong Song 	ASSERT_EQ(read(pipe_c2p[0], buf, 1), 1, "pipe_read");
9516f0efc3SYonghong Song 
9616f0efc3SYonghong Song 	/* trigger the bpf send_signal */
97ab8b7f0cSYonghong Song 	skel->bss->pid = pid;
98ab8b7f0cSYonghong Song 	skel->bss->sig = SIGUSR1;
99ab8b7f0cSYonghong Song 	skel->bss->signal_thread = signal_thread;
10016f0efc3SYonghong Song 
10116f0efc3SYonghong Song 	/* notify child that bpf program can send_signal now */
102*6f6cc426SYonghong Song 	ASSERT_EQ(write(pipe_p2c[1], buf, 1), 1, "pipe_write");
10316f0efc3SYonghong Song 
10416f0efc3SYonghong Song 	/* wait for result */
10516f0efc3SYonghong Song 	err = read(pipe_c2p[0], buf, 1);
106*6f6cc426SYonghong Song 	if (!ASSERT_GE(err, 0, "reading pipe"))
10716f0efc3SYonghong Song 		goto disable_pmu;
108*6f6cc426SYonghong Song 	if (!ASSERT_GT(err, 0, "reading pipe error: size 0")) {
10916f0efc3SYonghong Song 		err = -1;
11016f0efc3SYonghong Song 		goto disable_pmu;
11116f0efc3SYonghong Song 	}
11216f0efc3SYonghong Song 
113*6f6cc426SYonghong Song 	ASSERT_EQ(buf[0], '2', "incorrect result");
11416f0efc3SYonghong Song 
11516f0efc3SYonghong Song 	/* notify child safe to exit */
116*6f6cc426SYonghong Song 	ASSERT_EQ(write(pipe_p2c[1], buf, 1), 1, "pipe_write");
11716f0efc3SYonghong Song 
11816f0efc3SYonghong Song disable_pmu:
11916f0efc3SYonghong Song 	close(pmu_fd);
120ab8b7f0cSYonghong Song destroy_skel:
121ab8b7f0cSYonghong Song 	test_send_signal_kern__destroy(skel);
122ab8b7f0cSYonghong Song skel_open_load_failure:
12316f0efc3SYonghong Song 	close(pipe_c2p[0]);
12416f0efc3SYonghong Song 	close(pipe_p2c[1]);
12516f0efc3SYonghong Song 	wait(NULL);
12616f0efc3SYonghong Song }
12716f0efc3SYonghong Song 
128ab8b7f0cSYonghong Song static void test_send_signal_tracepoint(bool signal_thread)
12916f0efc3SYonghong Song {
130*6f6cc426SYonghong Song 	test_send_signal_common(NULL, signal_thread);
13116f0efc3SYonghong Song }
13216f0efc3SYonghong Song 
133ab8b7f0cSYonghong Song static void test_send_signal_perf(bool signal_thread)
1344e59afbbSIlya Leoshkevich {
1354e59afbbSIlya Leoshkevich 	struct perf_event_attr attr = {
1364e59afbbSIlya Leoshkevich 		.sample_period = 1,
1374e59afbbSIlya Leoshkevich 		.type = PERF_TYPE_SOFTWARE,
1384e59afbbSIlya Leoshkevich 		.config = PERF_COUNT_SW_CPU_CLOCK,
1394e59afbbSIlya Leoshkevich 	};
1404e59afbbSIlya Leoshkevich 
141*6f6cc426SYonghong Song 	test_send_signal_common(&attr, signal_thread);
1424e59afbbSIlya Leoshkevich }
1434e59afbbSIlya Leoshkevich 
144ab8b7f0cSYonghong Song static void test_send_signal_nmi(bool signal_thread)
14516f0efc3SYonghong Song {
14616f0efc3SYonghong Song 	struct perf_event_attr attr = {
14735697c12SYonghong Song 		.sample_period = 1,
14816f0efc3SYonghong Song 		.type = PERF_TYPE_HARDWARE,
14916f0efc3SYonghong Song 		.config = PERF_COUNT_HW_CPU_CYCLES,
15016f0efc3SYonghong Song 	};
1514e59afbbSIlya Leoshkevich 	int pmu_fd;
15216f0efc3SYonghong Song 
1534e59afbbSIlya Leoshkevich 	/* Some setups (e.g. virtual machines) might run with hardware
1544e59afbbSIlya Leoshkevich 	 * perf events disabled. If this is the case, skip this test.
1554e59afbbSIlya Leoshkevich 	 */
1564e59afbbSIlya Leoshkevich 	pmu_fd = syscall(__NR_perf_event_open, &attr, 0 /* pid */,
1574e59afbbSIlya Leoshkevich 			 -1 /* cpu */, -1 /* group_fd */, 0 /* flags */);
1584e59afbbSIlya Leoshkevich 	if (pmu_fd == -1) {
1594e59afbbSIlya Leoshkevich 		if (errno == ENOENT) {
16066bd2ec1SStanislav Fomichev 			printf("%s:SKIP:no PERF_COUNT_HW_CPU_CYCLES\n",
1614e59afbbSIlya Leoshkevich 			       __func__);
162cd9c21d7SStanislav Fomichev 			test__skip();
16386ccc384SStanislav Fomichev 			return;
1644e59afbbSIlya Leoshkevich 		}
1654e59afbbSIlya Leoshkevich 		/* Let the test fail with a more informative message */
1664e59afbbSIlya Leoshkevich 	} else {
1674e59afbbSIlya Leoshkevich 		close(pmu_fd);
1684e59afbbSIlya Leoshkevich 	}
1694e59afbbSIlya Leoshkevich 
170*6f6cc426SYonghong Song 	test_send_signal_common(&attr, signal_thread);
17116f0efc3SYonghong Song }
17216f0efc3SYonghong Song 
17316f0efc3SYonghong Song void test_send_signal(void)
17416f0efc3SYonghong Song {
175b207edfeSAndrii Nakryiko 	if (test__start_subtest("send_signal_tracepoint"))
176ab8b7f0cSYonghong Song 		test_send_signal_tracepoint(false);
177b207edfeSAndrii Nakryiko 	if (test__start_subtest("send_signal_perf"))
178ab8b7f0cSYonghong Song 		test_send_signal_perf(false);
179b207edfeSAndrii Nakryiko 	if (test__start_subtest("send_signal_nmi"))
180ab8b7f0cSYonghong Song 		test_send_signal_nmi(false);
181ab8b7f0cSYonghong Song 	if (test__start_subtest("send_signal_tracepoint_thread"))
182ab8b7f0cSYonghong Song 		test_send_signal_tracepoint(true);
183ab8b7f0cSYonghong Song 	if (test__start_subtest("send_signal_perf_thread"))
184ab8b7f0cSYonghong Song 		test_send_signal_perf(true);
185ab8b7f0cSYonghong Song 	if (test__start_subtest("send_signal_nmi_thread"))
186ab8b7f0cSYonghong Song 		test_send_signal_nmi(true);
18716f0efc3SYonghong Song }
188