Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.15.
  1// SPDX-License-Identifier: GPL-2.0
  2#include <test_progs.h>
  3#include <sys/time.h>
  4#include <sys/resource.h>
  5#include "test_send_signal_kern.skel.h"
  6
  7int sigusr1_received = 0;
  8
  9static void sigusr1_handler(int signum)
 10{
 11	sigusr1_received++;
 12}
 13
 14static void test_send_signal_common(struct perf_event_attr *attr,
 15				    bool signal_thread,
 16				    const char *test_name)
 17{
 18	struct test_send_signal_kern *skel;
 19	int pipe_c2p[2], pipe_p2c[2];
 20	int err = -1, pmu_fd = -1;
 21	__u32 duration = 0;
 22	char buf[256];
 23	pid_t pid;
 24
 25	if (CHECK(pipe(pipe_c2p), test_name,
 26		  "pipe pipe_c2p error: %s\n", strerror(errno)))
 27		return;
 28
 29	if (CHECK(pipe(pipe_p2c), test_name,
 30		  "pipe pipe_p2c error: %s\n", strerror(errno))) {
 31		close(pipe_c2p[0]);
 32		close(pipe_c2p[1]);
 33		return;
 34	}
 35
 36	pid = fork();
 37	if (CHECK(pid < 0, test_name, "fork error: %s\n", strerror(errno))) {
 38		close(pipe_c2p[0]);
 39		close(pipe_c2p[1]);
 40		close(pipe_p2c[0]);
 41		close(pipe_p2c[1]);
 42		return;
 43	}
 44
 45	if (pid == 0) {
 46		int old_prio;
 47
 48		/* install signal handler and notify parent */
 49		signal(SIGUSR1, sigusr1_handler);
 50
 51		close(pipe_c2p[0]); /* close read */
 52		close(pipe_p2c[1]); /* close write */
 53
 54		/* boost with a high priority so we got a higher chance
 55		 * that if an interrupt happens, the underlying task
 56		 * is this process.
 57		 */
 58		errno = 0;
 59		old_prio = getpriority(PRIO_PROCESS, 0);
 60		ASSERT_OK(errno, "getpriority");
 61		ASSERT_OK(setpriority(PRIO_PROCESS, 0, -20), "setpriority");
 62
 63		/* notify parent signal handler is installed */
 64		CHECK(write(pipe_c2p[1], buf, 1) != 1, "pipe_write", "err %d\n", -errno);
 65
 66		/* make sure parent enabled bpf program to send_signal */
 67		CHECK(read(pipe_p2c[0], buf, 1) != 1, "pipe_read", "err %d\n", -errno);
 68
 69		/* wait a little for signal handler */
 70		sleep(1);
 71
 72		buf[0] = sigusr1_received ? '2' : '0';
 73		CHECK(write(pipe_c2p[1], buf, 1) != 1, "pipe_write", "err %d\n", -errno);
 74
 75		/* wait for parent notification and exit */
 76		CHECK(read(pipe_p2c[0], buf, 1) != 1, "pipe_read", "err %d\n", -errno);
 77
 78		/* restore the old priority */
 79		ASSERT_OK(setpriority(PRIO_PROCESS, 0, old_prio), "setpriority");
 80
 81		close(pipe_c2p[1]);
 82		close(pipe_p2c[0]);
 83		exit(0);
 84	}
 85
 86	close(pipe_c2p[1]); /* close write */
 87	close(pipe_p2c[0]); /* close read */
 88
 89	skel = test_send_signal_kern__open_and_load();
 90	if (CHECK(!skel, "skel_open_and_load", "skeleton open_and_load failed\n"))
 91		goto skel_open_load_failure;
 92
 93	if (!attr) {
 94		err = test_send_signal_kern__attach(skel);
 95		if (CHECK(err, "skel_attach", "skeleton attach failed\n")) {
 96			err = -1;
 97			goto destroy_skel;
 98		}
 99	} else {
100		pmu_fd = syscall(__NR_perf_event_open, attr, pid, -1,
101				 -1 /* group id */, 0 /* flags */);
102		if (CHECK(pmu_fd < 0, test_name, "perf_event_open error: %s\n",
103			strerror(errno))) {
104			err = -1;
105			goto destroy_skel;
106		}
107
108		skel->links.send_signal_perf =
109			bpf_program__attach_perf_event(skel->progs.send_signal_perf, pmu_fd);
110		if (!ASSERT_OK_PTR(skel->links.send_signal_perf, "attach_perf_event"))
111			goto disable_pmu;
112	}
113
114	/* wait until child signal handler installed */
115	CHECK(read(pipe_c2p[0], buf, 1) != 1, "pipe_read", "err %d\n", -errno);
116
117	/* trigger the bpf send_signal */
118	skel->bss->pid = pid;
119	skel->bss->sig = SIGUSR1;
120	skel->bss->signal_thread = signal_thread;
121
122	/* notify child that bpf program can send_signal now */
123	CHECK(write(pipe_p2c[1], buf, 1) != 1, "pipe_write", "err %d\n", -errno);
124
125	/* wait for result */
126	err = read(pipe_c2p[0], buf, 1);
127	if (CHECK(err < 0, test_name, "reading pipe error: %s\n", strerror(errno)))
128		goto disable_pmu;
129	if (CHECK(err == 0, test_name, "reading pipe error: size 0\n")) {
130		err = -1;
131		goto disable_pmu;
132	}
133
134	CHECK(buf[0] != '2', test_name, "incorrect result\n");
135
136	/* notify child safe to exit */
137	CHECK(write(pipe_p2c[1], buf, 1) != 1, "pipe_write", "err %d\n", -errno);
138
139disable_pmu:
140	close(pmu_fd);
141destroy_skel:
142	test_send_signal_kern__destroy(skel);
143skel_open_load_failure:
144	close(pipe_c2p[0]);
145	close(pipe_p2c[1]);
146	wait(NULL);
147}
148
149static void test_send_signal_tracepoint(bool signal_thread)
150{
151	test_send_signal_common(NULL, signal_thread, "tracepoint");
152}
153
154static void test_send_signal_perf(bool signal_thread)
155{
156	struct perf_event_attr attr = {
157		.sample_period = 1,
158		.type = PERF_TYPE_SOFTWARE,
159		.config = PERF_COUNT_SW_CPU_CLOCK,
160	};
161
162	test_send_signal_common(&attr, signal_thread, "perf_sw_event");
163}
164
165static void test_send_signal_nmi(bool signal_thread)
166{
167	struct perf_event_attr attr = {
168		.sample_period = 1,
169		.type = PERF_TYPE_HARDWARE,
170		.config = PERF_COUNT_HW_CPU_CYCLES,
171	};
172	int pmu_fd;
173
174	/* Some setups (e.g. virtual machines) might run with hardware
175	 * perf events disabled. If this is the case, skip this test.
176	 */
177	pmu_fd = syscall(__NR_perf_event_open, &attr, 0 /* pid */,
178			 -1 /* cpu */, -1 /* group_fd */, 0 /* flags */);
179	if (pmu_fd == -1) {
180		if (errno == ENOENT) {
181			printf("%s:SKIP:no PERF_COUNT_HW_CPU_CYCLES\n",
182			       __func__);
183			test__skip();
184			return;
185		}
186		/* Let the test fail with a more informative message */
187	} else {
188		close(pmu_fd);
189	}
190
191	test_send_signal_common(&attr, signal_thread, "perf_hw_event");
192}
193
194void test_send_signal(void)
195{
196	if (test__start_subtest("send_signal_tracepoint"))
197		test_send_signal_tracepoint(false);
198	if (test__start_subtest("send_signal_perf"))
199		test_send_signal_perf(false);
200	if (test__start_subtest("send_signal_nmi"))
201		test_send_signal_nmi(false);
202	if (test__start_subtest("send_signal_tracepoint_thread"))
203		test_send_signal_tracepoint(true);
204	if (test__start_subtest("send_signal_perf_thread"))
205		test_send_signal_perf(true);
206	if (test__start_subtest("send_signal_nmi_thread"))
207		test_send_signal_nmi(true);
208}