Linux Audio

Check our new training course

Loading...
v6.13.7
  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#include "io_helpers.h"
  7
  8static int sigusr1_received;
  9
 10static void sigusr1_handler(int signum)
 11{
 12	sigusr1_received = 8;
 13}
 14
 15static void sigusr1_siginfo_handler(int s, siginfo_t *i, void *v)
 16{
 17	sigusr1_received = (int)(long long)i->si_value.sival_ptr;
 18}
 19
 20static void test_send_signal_common(struct perf_event_attr *attr,
 21				    bool signal_thread, bool remote)
 
 22{
 23	struct test_send_signal_kern *skel;
 24	struct sigaction sa;
 25	int pipe_c2p[2], pipe_p2c[2];
 26	int err = -1, pmu_fd = -1;
 27	volatile int j = 0;
 28	int retry_count;
 29	char buf[256];
 30	pid_t pid;
 31	int old_prio;
 32
 33	if (!ASSERT_OK(pipe(pipe_c2p), "pipe_c2p"))
 
 34		return;
 35
 36	if (!ASSERT_OK(pipe(pipe_p2c), "pipe_p2c")) {
 
 37		close(pipe_c2p[0]);
 38		close(pipe_c2p[1]);
 39		return;
 40	}
 41
 42	pid = fork();
 43	if (!ASSERT_GE(pid, 0, "fork")) {
 44		close(pipe_c2p[0]);
 45		close(pipe_c2p[1]);
 46		close(pipe_p2c[0]);
 47		close(pipe_p2c[1]);
 48		return;
 49	}
 50
 51	if (pid == 0) {
 52		/* install signal handler and notify parent */
 53		if (remote) {
 54			sa.sa_sigaction = sigusr1_siginfo_handler;
 55			sa.sa_flags = SA_RESTART | SA_SIGINFO;
 56			ASSERT_NEQ(sigaction(SIGUSR1, &sa, NULL), -1, "sigaction");
 57		} else {
 58			ASSERT_NEQ(signal(SIGUSR1, sigusr1_handler), SIG_ERR, "signal");
 59		}
 60
 61		close(pipe_c2p[0]); /* close read */
 62		close(pipe_p2c[1]); /* close write */
 63
 64		/* boost with a high priority so we got a higher chance
 65		 * that if an interrupt happens, the underlying task
 66		 * is this process.
 67		 */
 68		if (!remote) {
 69			errno = 0;
 70			old_prio = getpriority(PRIO_PROCESS, 0);
 71			ASSERT_OK(errno, "getpriority");
 72			ASSERT_OK(setpriority(PRIO_PROCESS, 0, -20), "setpriority");
 73		}
 74
 75		/* notify parent signal handler is installed */
 76		ASSERT_EQ(write(pipe_c2p[1], buf, 1), 1, "pipe_write");
 77
 78		/* make sure parent enabled bpf program to send_signal */
 79		ASSERT_EQ(read(pipe_p2c[0], buf, 1), 1, "pipe_read");
 80
 81		/* wait a little for signal handler */
 82		for (int i = 0; i < 1000000000 && !sigusr1_received; i++) {
 83			j /= i + j + 1;
 84			if (remote)
 85				sleep(1);
 86			else
 87				if (!attr)
 88					/* trigger the nanosleep tracepoint program. */
 89					usleep(1);
 90		}
 91
 92		buf[0] = sigusr1_received;
 93
 94		ASSERT_EQ(sigusr1_received, 8, "sigusr1_received");
 95		ASSERT_EQ(write(pipe_c2p[1], buf, 1), 1, "pipe_write");
 96
 97		/* wait for parent notification and exit */
 98		ASSERT_EQ(read(pipe_p2c[0], buf, 1), 1, "pipe_read");
 99
100		/* restore the old priority */
101		if (!remote)
102			ASSERT_OK(setpriority(PRIO_PROCESS, 0, old_prio), "setpriority");
103
104		close(pipe_c2p[1]);
105		close(pipe_p2c[0]);
106		exit(0);
107	}
108
109	close(pipe_c2p[1]); /* close write */
110	close(pipe_p2c[0]); /* close read */
111
112	skel = test_send_signal_kern__open_and_load();
113	if (!ASSERT_OK_PTR(skel, "skel_open_and_load"))
114		goto skel_open_load_failure;
115
116	/* boost with a high priority so we got a higher chance
117	 * that if an interrupt happens, the underlying task
118	 * is this process.
119	 */
120	if (remote) {
121		errno = 0;
122		old_prio = getpriority(PRIO_PROCESS, 0);
123		ASSERT_OK(errno, "getpriority");
124		ASSERT_OK(setpriority(PRIO_PROCESS, 0, -20), "setpriority");
125	}
126
127	if (!attr) {
128		err = test_send_signal_kern__attach(skel);
129		if (!ASSERT_OK(err, "skel_attach")) {
130			err = -1;
131			goto destroy_skel;
132		}
133	} else {
134		if (!remote)
135			pmu_fd = syscall(__NR_perf_event_open, attr, pid, -1 /* cpu */,
136					 -1 /* group id */, 0 /* flags */);
137		else
138			pmu_fd = syscall(__NR_perf_event_open, attr, getpid(), -1 /* cpu */,
139					 -1 /* group id */, 0 /* flags */);
140		if (!ASSERT_GE(pmu_fd, 0, "perf_event_open")) {
141			err = -1;
142			goto destroy_skel;
143		}
144
145		skel->links.send_signal_perf =
146			bpf_program__attach_perf_event(skel->progs.send_signal_perf, pmu_fd);
147		if (!ASSERT_OK_PTR(skel->links.send_signal_perf, "attach_perf_event"))
 
148			goto disable_pmu;
149	}
150
151	/* wait until child signal handler installed */
152	ASSERT_EQ(read(pipe_c2p[0], buf, 1), 1, "pipe_read");
153
154	/* trigger the bpf send_signal */
155	skel->bss->signal_thread = signal_thread;
156	skel->bss->sig = SIGUSR1;
157	if (!remote) {
158		skel->bss->target_pid = 0;
159		skel->bss->pid = pid;
160	} else {
161		skel->bss->target_pid = pid;
162		skel->bss->pid = getpid();
163	}
164
165	/* notify child that bpf program can send_signal now */
166	ASSERT_EQ(write(pipe_p2c[1], buf, 1), 1, "pipe_write");
167
168	for (retry_count = 0;;) {
169		/* For the remote test, the BPF program is triggered from this
170		 * process but the other process/thread is signaled.
171		 */
172		if (remote) {
173			if (!attr) {
174				for (int i = 0; i < 10; i++)
175					usleep(1);
176			} else {
177				for (int i = 0; i < 100000000; i++)
178					j /= i + 1;
179			}
180		}
181		/* wait for result */
182		err = read_with_timeout(pipe_c2p[0], buf, 1, 100);
183		if (err == -EAGAIN && retry_count++ < 10000)
184			continue;
185		break;
186	}
187	if (!ASSERT_GE(err, 0, "reading pipe"))
188		goto disable_pmu;
189	if (!ASSERT_GT(err, 0, "reading pipe error: size 0")) {
190		err = -1;
191		goto disable_pmu;
192	}
193
194	ASSERT_EQ(buf[0], 8, "incorrect result");
195
196	/* notify child safe to exit */
197	ASSERT_EQ(write(pipe_p2c[1], buf, 1), 1, "pipe_write");
198
199disable_pmu:
200	close(pmu_fd);
201destroy_skel:
202	test_send_signal_kern__destroy(skel);
203	/* restore the old priority */
204	if (remote)
205		ASSERT_OK(setpriority(PRIO_PROCESS, 0, old_prio), "setpriority");
206skel_open_load_failure:
207	close(pipe_c2p[0]);
208	close(pipe_p2c[1]);
209	wait(NULL);
210}
211
212static void test_send_signal_tracepoint(bool signal_thread, bool remote)
213{
214	test_send_signal_common(NULL, signal_thread, remote);
215}
216
217static void test_send_signal_perf(bool signal_thread, bool remote)
218{
219	struct perf_event_attr attr = {
220		.freq = 1,
221		.sample_freq = 1000,
222		.type = PERF_TYPE_SOFTWARE,
223		.config = PERF_COUNT_SW_CPU_CLOCK,
224	};
225
226	test_send_signal_common(&attr, signal_thread, remote);
227}
228
229static void test_send_signal_nmi(bool signal_thread, bool remote)
230{
231	struct perf_event_attr attr = {
232		.freq = 1,
233		.sample_freq = 1000,
234		.type = PERF_TYPE_HARDWARE,
235		.config = PERF_COUNT_HW_CPU_CYCLES,
236	};
237	int pmu_fd;
238
239	/* Some setups (e.g. virtual machines) might run with hardware
240	 * perf events disabled. If this is the case, skip this test.
241	 */
242	pmu_fd = syscall(__NR_perf_event_open, &attr, 0 /* pid */,
243			 -1 /* cpu */, -1 /* group_fd */, 0 /* flags */);
244	if (pmu_fd == -1) {
245		if (errno == ENOENT || errno == EOPNOTSUPP) {
246			printf("%s:SKIP:no PERF_COUNT_HW_CPU_CYCLES\n",
247			       __func__);
248			test__skip();
249			return;
250		}
251		/* Let the test fail with a more informative message */
252	} else {
253		close(pmu_fd);
254	}
255
256	test_send_signal_common(&attr, signal_thread, remote);
257}
258
259void test_send_signal(void)
260{
261	if (test__start_subtest("send_signal_tracepoint"))
262		test_send_signal_tracepoint(false, false);
263	if (test__start_subtest("send_signal_perf"))
264		test_send_signal_perf(false, false);
265	if (test__start_subtest("send_signal_nmi"))
266		test_send_signal_nmi(false, false);
267	if (test__start_subtest("send_signal_tracepoint_thread"))
268		test_send_signal_tracepoint(true, false);
269	if (test__start_subtest("send_signal_perf_thread"))
270		test_send_signal_perf(true, false);
271	if (test__start_subtest("send_signal_nmi_thread"))
272		test_send_signal_nmi(true, false);
273
274	/* Signal remote thread and thread group */
275	if (test__start_subtest("send_signal_tracepoint_remote"))
276		test_send_signal_tracepoint(false, true);
277	if (test__start_subtest("send_signal_perf_remote"))
278		test_send_signal_perf(false, true);
279	if (test__start_subtest("send_signal_nmi_remote"))
280		test_send_signal_nmi(false, true);
281	if (test__start_subtest("send_signal_tracepoint_thread_remote"))
282		test_send_signal_tracepoint(true, true);
283	if (test__start_subtest("send_signal_perf_thread_remote"))
284		test_send_signal_perf(true, true);
285	if (test__start_subtest("send_signal_nmi_thread_remote"))
286		test_send_signal_nmi(true, true);
287}
v5.9
  1// SPDX-License-Identifier: GPL-2.0
  2#include <test_progs.h>
 
 
  3#include "test_send_signal_kern.skel.h"
 
  4
  5static volatile int sigusr1_received = 0;
  6
  7static void sigusr1_handler(int signum)
  8{
  9	sigusr1_received++;
 
 
 
 
 
 10}
 11
 12static void test_send_signal_common(struct perf_event_attr *attr,
 13				    bool signal_thread,
 14				    const char *test_name)
 15{
 16	struct test_send_signal_kern *skel;
 
 17	int pipe_c2p[2], pipe_p2c[2];
 18	int err = -1, pmu_fd = -1;
 19	__u32 duration = 0;
 
 20	char buf[256];
 21	pid_t pid;
 
 22
 23	if (CHECK(pipe(pipe_c2p), test_name,
 24		  "pipe pipe_c2p error: %s\n", strerror(errno)))
 25		return;
 26
 27	if (CHECK(pipe(pipe_p2c), test_name,
 28		  "pipe pipe_p2c error: %s\n", strerror(errno))) {
 29		close(pipe_c2p[0]);
 30		close(pipe_c2p[1]);
 31		return;
 32	}
 33
 34	pid = fork();
 35	if (CHECK(pid < 0, test_name, "fork error: %s\n", strerror(errno))) {
 36		close(pipe_c2p[0]);
 37		close(pipe_c2p[1]);
 38		close(pipe_p2c[0]);
 39		close(pipe_p2c[1]);
 40		return;
 41	}
 42
 43	if (pid == 0) {
 44		/* install signal handler and notify parent */
 45		signal(SIGUSR1, sigusr1_handler);
 
 
 
 
 
 
 46
 47		close(pipe_c2p[0]); /* close read */
 48		close(pipe_p2c[1]); /* close write */
 49
 
 
 
 
 
 
 
 
 
 
 
 50		/* notify parent signal handler is installed */
 51		CHECK(write(pipe_c2p[1], buf, 1) != 1, "pipe_write", "err %d\n", -errno);
 52
 53		/* make sure parent enabled bpf program to send_signal */
 54		CHECK(read(pipe_p2c[0], buf, 1) != 1, "pipe_read", "err %d\n", -errno);
 55
 56		/* wait a little for signal handler */
 57		sleep(1);
 
 
 
 
 
 
 
 
 
 
 58
 59		buf[0] = sigusr1_received ? '2' : '0';
 60		CHECK(write(pipe_c2p[1], buf, 1) != 1, "pipe_write", "err %d\n", -errno);
 61
 62		/* wait for parent notification and exit */
 63		CHECK(read(pipe_p2c[0], buf, 1) != 1, "pipe_read", "err %d\n", -errno);
 
 
 
 
 64
 65		close(pipe_c2p[1]);
 66		close(pipe_p2c[0]);
 67		exit(0);
 68	}
 69
 70	close(pipe_c2p[1]); /* close write */
 71	close(pipe_p2c[0]); /* close read */
 72
 73	skel = test_send_signal_kern__open_and_load();
 74	if (CHECK(!skel, "skel_open_and_load", "skeleton open_and_load failed\n"))
 75		goto skel_open_load_failure;
 76
 
 
 
 
 
 
 
 
 
 
 
 77	if (!attr) {
 78		err = test_send_signal_kern__attach(skel);
 79		if (CHECK(err, "skel_attach", "skeleton attach failed\n")) {
 80			err = -1;
 81			goto destroy_skel;
 82		}
 83	} else {
 84		pmu_fd = syscall(__NR_perf_event_open, attr, pid, -1,
 85				 -1 /* group id */, 0 /* flags */);
 86		if (CHECK(pmu_fd < 0, test_name, "perf_event_open error: %s\n",
 87			strerror(errno))) {
 
 
 
 88			err = -1;
 89			goto destroy_skel;
 90		}
 91
 92		skel->links.send_signal_perf =
 93			bpf_program__attach_perf_event(skel->progs.send_signal_perf, pmu_fd);
 94		if (CHECK(IS_ERR(skel->links.send_signal_perf), "attach_perf_event",
 95			  "err %ld\n", PTR_ERR(skel->links.send_signal_perf)))
 96			goto disable_pmu;
 97	}
 98
 99	/* wait until child signal handler installed */
100	CHECK(read(pipe_c2p[0], buf, 1) != 1, "pipe_read", "err %d\n", -errno);
101
102	/* trigger the bpf send_signal */
103	skel->bss->pid = pid;
104	skel->bss->sig = SIGUSR1;
105	skel->bss->signal_thread = signal_thread;
 
 
 
 
 
 
106
107	/* notify child that bpf program can send_signal now */
108	CHECK(write(pipe_p2c[1], buf, 1) != 1, "pipe_write", "err %d\n", -errno);
109
110	/* wait for result */
111	err = read(pipe_c2p[0], buf, 1);
112	if (CHECK(err < 0, test_name, "reading pipe error: %s\n", strerror(errno)))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113		goto disable_pmu;
114	if (CHECK(err == 0, test_name, "reading pipe error: size 0\n")) {
115		err = -1;
116		goto disable_pmu;
117	}
118
119	CHECK(buf[0] != '2', test_name, "incorrect result\n");
120
121	/* notify child safe to exit */
122	CHECK(write(pipe_p2c[1], buf, 1) != 1, "pipe_write", "err %d\n", -errno);
123
124disable_pmu:
125	close(pmu_fd);
126destroy_skel:
127	test_send_signal_kern__destroy(skel);
 
 
 
128skel_open_load_failure:
129	close(pipe_c2p[0]);
130	close(pipe_p2c[1]);
131	wait(NULL);
132}
133
134static void test_send_signal_tracepoint(bool signal_thread)
135{
136	test_send_signal_common(NULL, signal_thread, "tracepoint");
137}
138
139static void test_send_signal_perf(bool signal_thread)
140{
141	struct perf_event_attr attr = {
142		.sample_period = 1,
 
143		.type = PERF_TYPE_SOFTWARE,
144		.config = PERF_COUNT_SW_CPU_CLOCK,
145	};
146
147	test_send_signal_common(&attr, signal_thread, "perf_sw_event");
148}
149
150static void test_send_signal_nmi(bool signal_thread)
151{
152	struct perf_event_attr attr = {
153		.sample_period = 1,
 
154		.type = PERF_TYPE_HARDWARE,
155		.config = PERF_COUNT_HW_CPU_CYCLES,
156	};
157	int pmu_fd;
158
159	/* Some setups (e.g. virtual machines) might run with hardware
160	 * perf events disabled. If this is the case, skip this test.
161	 */
162	pmu_fd = syscall(__NR_perf_event_open, &attr, 0 /* pid */,
163			 -1 /* cpu */, -1 /* group_fd */, 0 /* flags */);
164	if (pmu_fd == -1) {
165		if (errno == ENOENT) {
166			printf("%s:SKIP:no PERF_COUNT_HW_CPU_CYCLES\n",
167			       __func__);
168			test__skip();
169			return;
170		}
171		/* Let the test fail with a more informative message */
172	} else {
173		close(pmu_fd);
174	}
175
176	test_send_signal_common(&attr, signal_thread, "perf_hw_event");
177}
178
179void test_send_signal(void)
180{
181	if (test__start_subtest("send_signal_tracepoint"))
182		test_send_signal_tracepoint(false);
183	if (test__start_subtest("send_signal_perf"))
184		test_send_signal_perf(false);
185	if (test__start_subtest("send_signal_nmi"))
186		test_send_signal_nmi(false);
187	if (test__start_subtest("send_signal_tracepoint_thread"))
188		test_send_signal_tracepoint(true);
189	if (test__start_subtest("send_signal_perf_thread"))
190		test_send_signal_perf(true);
191	if (test__start_subtest("send_signal_nmi_thread"))
192		test_send_signal_nmi(true);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
193}