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.4
  1// SPDX-License-Identifier: GPL-2.0
  2#include <test_progs.h>
 
 
 
 
  3
  4static volatile int sigusr1_received = 0;
  5
  6static void sigusr1_handler(int signum)
  7{
  8	sigusr1_received++;
 
 
 
 
 
  9}
 10
 11static void test_send_signal_common(struct perf_event_attr *attr,
 12				    int prog_type,
 13				    const char *test_name)
 14{
 15	int err = -1, pmu_fd, prog_fd, info_map_fd, status_map_fd;
 16	const char *file = "./test_send_signal_kern.o";
 17	struct bpf_object *obj = NULL;
 18	int pipe_c2p[2], pipe_p2c[2];
 19	__u32 key = 0, duration = 0;
 
 
 20	char buf[256];
 21	pid_t pid;
 22	__u64 val;
 23
 24	if (CHECK(pipe(pipe_c2p), test_name,
 25		  "pipe pipe_c2p error: %s\n", strerror(errno)))
 26		return;
 27
 28	if (CHECK(pipe(pipe_p2c), test_name,
 29		  "pipe pipe_p2c error: %s\n", strerror(errno))) {
 30		close(pipe_c2p[0]);
 31		close(pipe_c2p[1]);
 32		return;
 33	}
 34
 35	pid = fork();
 36	if (CHECK(pid < 0, test_name, "fork error: %s\n", strerror(errno))) {
 37		close(pipe_c2p[0]);
 38		close(pipe_c2p[1]);
 39		close(pipe_p2c[0]);
 40		close(pipe_p2c[1]);
 41		return;
 42	}
 43
 44	if (pid == 0) {
 45		/* install signal handler and notify parent */
 46		signal(SIGUSR1, sigusr1_handler);
 
 
 
 
 
 
 47
 48		close(pipe_c2p[0]); /* close read */
 49		close(pipe_p2c[1]); /* close write */
 50
 
 
 
 
 
 
 
 
 
 
 
 51		/* notify parent signal handler is installed */
 52		write(pipe_c2p[1], buf, 1);
 53
 54		/* make sure parent enabled bpf program to send_signal */
 55		read(pipe_p2c[0], buf, 1);
 56
 57		/* wait a little for signal handler */
 58		sleep(1);
 
 
 
 
 
 
 
 
 
 
 59
 60		if (sigusr1_received)
 61			write(pipe_c2p[1], "2", 1);
 62		else
 63			write(pipe_c2p[1], "0", 1);
 64
 65		/* wait for parent notification and exit */
 66		read(pipe_p2c[0], buf, 1);
 
 
 
 
 67
 68		close(pipe_c2p[1]);
 69		close(pipe_p2c[0]);
 70		exit(0);
 71	}
 72
 73	close(pipe_c2p[1]); /* close write */
 74	close(pipe_p2c[0]); /* close read */
 75
 76	err = bpf_prog_load(file, prog_type, &obj, &prog_fd);
 77	if (CHECK(err < 0, test_name, "bpf_prog_load error: %s\n",
 78		  strerror(errno)))
 79		goto prog_load_failure;
 80
 81	pmu_fd = syscall(__NR_perf_event_open, attr, pid, -1,
 82			 -1 /* group id */, 0 /* flags */);
 83	if (CHECK(pmu_fd < 0, test_name, "perf_event_open error: %s\n",
 84		  strerror(errno))) {
 85		err = -1;
 86		goto close_prog;
 
 
 87	}
 88
 89	err = ioctl(pmu_fd, PERF_EVENT_IOC_ENABLE, 0);
 90	if (CHECK(err < 0, test_name, "ioctl perf_event_ioc_enable error: %s\n",
 91		  strerror(errno)))
 92		goto disable_pmu;
 
 
 
 
 
 
 
 
 
 
 
 
 
 93
 94	err = ioctl(pmu_fd, PERF_EVENT_IOC_SET_BPF, prog_fd);
 95	if (CHECK(err < 0, test_name, "ioctl perf_event_ioc_set_bpf error: %s\n",
 96		  strerror(errno)))
 97		goto disable_pmu;
 98
 99	err = -1;
100	info_map_fd = bpf_object__find_map_fd_by_name(obj, "info_map");
101	if (CHECK(info_map_fd < 0, test_name, "find map %s error\n", "info_map"))
102		goto disable_pmu;
103
104	status_map_fd = bpf_object__find_map_fd_by_name(obj, "status_map");
105	if (CHECK(status_map_fd < 0, test_name, "find map %s error\n", "status_map"))
106		goto disable_pmu;
107
108	/* wait until child signal handler installed */
109	read(pipe_c2p[0], buf, 1);
110
111	/* trigger the bpf send_signal */
112	key = 0;
113	val = (((__u64)(SIGUSR1)) << 32) | pid;
114	bpf_map_update_elem(info_map_fd, &key, &val, 0);
 
 
 
 
 
 
115
116	/* notify child that bpf program can send_signal now */
117	write(pipe_p2c[1], buf, 1);
118
119	/* wait for result */
120	err = read(pipe_c2p[0], buf, 1);
121	if (CHECK(err < 0, test_name, "reading pipe error: %s\n", strerror(errno)))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122		goto disable_pmu;
123	if (CHECK(err == 0, test_name, "reading pipe error: size 0\n")) {
124		err = -1;
125		goto disable_pmu;
126	}
127
128	CHECK(buf[0] != '2', test_name, "incorrect result\n");
129
130	/* notify child safe to exit */
131	write(pipe_p2c[1], buf, 1);
132
133disable_pmu:
134	close(pmu_fd);
135close_prog:
136	bpf_object__close(obj);
137prog_load_failure:
 
 
 
138	close(pipe_c2p[0]);
139	close(pipe_p2c[1]);
140	wait(NULL);
141}
142
143static void test_send_signal_tracepoint(void)
144{
145	const char *id_path = "/sys/kernel/debug/tracing/events/syscalls/sys_enter_nanosleep/id";
146	struct perf_event_attr attr = {
147		.type = PERF_TYPE_TRACEPOINT,
148		.sample_type = PERF_SAMPLE_RAW | PERF_SAMPLE_CALLCHAIN,
149		.sample_period = 1,
150		.wakeup_events = 1,
151	};
152	__u32 duration = 0;
153	int bytes, efd;
154	char buf[256];
155
156	efd = open(id_path, O_RDONLY, 0);
157	if (CHECK(efd < 0, "tracepoint",
158		  "open syscalls/sys_enter_nanosleep/id failure: %s\n",
159		  strerror(errno)))
160		return;
161
162	bytes = read(efd, buf, sizeof(buf));
163	close(efd);
164	if (CHECK(bytes <= 0 || bytes >= sizeof(buf), "tracepoint",
165		  "read syscalls/sys_enter_nanosleep/id failure: %s\n",
166		  strerror(errno)))
167		return;
168
169	attr.config = strtol(buf, NULL, 0);
170
171	test_send_signal_common(&attr, BPF_PROG_TYPE_TRACEPOINT, "tracepoint");
172}
173
174static void test_send_signal_perf(void)
175{
176	struct perf_event_attr attr = {
177		.sample_period = 1,
 
178		.type = PERF_TYPE_SOFTWARE,
179		.config = PERF_COUNT_SW_CPU_CLOCK,
180	};
181
182	test_send_signal_common(&attr, BPF_PROG_TYPE_PERF_EVENT,
183				"perf_sw_event");
184}
185
186static void test_send_signal_nmi(void)
187{
188	struct perf_event_attr attr = {
189		.sample_freq = 50,
190		.freq = 1,
 
191		.type = PERF_TYPE_HARDWARE,
192		.config = PERF_COUNT_HW_CPU_CYCLES,
193	};
194	int pmu_fd;
195
196	/* Some setups (e.g. virtual machines) might run with hardware
197	 * perf events disabled. If this is the case, skip this test.
198	 */
199	pmu_fd = syscall(__NR_perf_event_open, &attr, 0 /* pid */,
200			 -1 /* cpu */, -1 /* group_fd */, 0 /* flags */);
201	if (pmu_fd == -1) {
202		if (errno == ENOENT) {
203			printf("%s:SKIP:no PERF_COUNT_HW_CPU_CYCLES\n",
204			       __func__);
205			test__skip();
206			return;
207		}
208		/* Let the test fail with a more informative message */
209	} else {
210		close(pmu_fd);
211	}
212
213	test_send_signal_common(&attr, BPF_PROG_TYPE_PERF_EVENT,
214				"perf_hw_event");
215}
216
217void test_send_signal(void)
218{
219	if (test__start_subtest("send_signal_tracepoint"))
220		test_send_signal_tracepoint();
221	if (test__start_subtest("send_signal_perf"))
222		test_send_signal_perf();
223	if (test__start_subtest("send_signal_nmi"))
224		test_send_signal_nmi();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
225}