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