xref: /linux/tools/testing/selftests/perf_events/sigtrap_threads.c (revision b54a2377ec02d52b7bb5dab381e9a45ba0bc617a)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Test for perf events with SIGTRAP across all threads.
4  *
5  * Copyright (C) 2021, Google LLC.
6  */
7 
8 #define _GNU_SOURCE
9 
10 /* We need the latest siginfo from the kernel repo. */
11 #include <sys/types.h>
12 #include <asm/siginfo.h>
13 #define __have_siginfo_t 1
14 #define __have_sigval_t 1
15 #define __have_sigevent_t 1
16 #define __siginfo_t_defined
17 #define __sigval_t_defined
18 #define __sigevent_t_defined
19 #define _BITS_SIGINFO_CONSTS_H 1
20 #define _BITS_SIGEVENT_CONSTS_H 1
21 
22 #include <stdbool.h>
23 #include <stddef.h>
24 #include <stdint.h>
25 #include <stdio.h>
26 #include <linux/hw_breakpoint.h>
27 #include <linux/perf_event.h>
28 #include <pthread.h>
29 #include <signal.h>
30 #include <sys/ioctl.h>
31 #include <sys/syscall.h>
32 #include <unistd.h>
33 
34 #include "../kselftest_harness.h"
35 
36 #define NUM_THREADS 5
37 
38 /* Data shared between test body, threads, and signal handler. */
39 static struct {
40 	int tids_want_signal;		/* Which threads still want a signal. */
41 	int signal_count;		/* Sanity check number of signals received. */
42 	volatile int iterate_on;	/* Variable to set breakpoint on. */
43 	siginfo_t first_siginfo;	/* First observed siginfo_t. */
44 } ctx;
45 
46 /* Unique value to check si_perf_data is correctly set from perf_event_attr::sig_data. */
47 #define TEST_SIG_DATA(addr, id) (~(unsigned long)(addr) + id)
48 
49 static struct perf_event_attr make_event_attr(bool enabled, volatile void *addr,
50 					      unsigned long id)
51 {
52 	struct perf_event_attr attr = {
53 		.type		= PERF_TYPE_BREAKPOINT,
54 		.size		= sizeof(attr),
55 		.sample_period	= 1,
56 		.disabled	= !enabled,
57 		.bp_addr	= (unsigned long)addr,
58 		.bp_type	= HW_BREAKPOINT_RW,
59 		.bp_len		= HW_BREAKPOINT_LEN_1,
60 		.inherit	= 1, /* Children inherit events ... */
61 		.inherit_thread = 1, /* ... but only cloned with CLONE_THREAD. */
62 		.remove_on_exec = 1, /* Required by sigtrap. */
63 		.sigtrap	= 1, /* Request synchronous SIGTRAP on event. */
64 		.sig_data	= TEST_SIG_DATA(addr, id),
65 		.exclude_kernel = 1, /* To allow */
66 		.exclude_hv     = 1, /* running as !root */
67 	};
68 	return attr;
69 }
70 
71 static void sigtrap_handler(int signum, siginfo_t *info, void *ucontext)
72 {
73 	if (info->si_code != TRAP_PERF) {
74 		fprintf(stderr, "%s: unexpected si_code %d\n", __func__, info->si_code);
75 		return;
76 	}
77 
78 	/*
79 	 * The data in siginfo_t we're interested in should all be the same
80 	 * across threads.
81 	 */
82 	if (!__atomic_fetch_add(&ctx.signal_count, 1, __ATOMIC_RELAXED))
83 		ctx.first_siginfo = *info;
84 	__atomic_fetch_sub(&ctx.tids_want_signal, syscall(__NR_gettid), __ATOMIC_RELAXED);
85 }
86 
87 static void *test_thread(void *arg)
88 {
89 	pthread_barrier_t *barrier = (pthread_barrier_t *)arg;
90 	pid_t tid = syscall(__NR_gettid);
91 	int iter;
92 	int i;
93 
94 	pthread_barrier_wait(barrier);
95 
96 	__atomic_fetch_add(&ctx.tids_want_signal, tid, __ATOMIC_RELAXED);
97 	iter = ctx.iterate_on; /* read */
98 	if (iter >= 0) {
99 		for (i = 0; i < iter - 1; i++) {
100 			__atomic_fetch_add(&ctx.tids_want_signal, tid, __ATOMIC_RELAXED);
101 			ctx.iterate_on = iter; /* idempotent write */
102 		}
103 	} else {
104 		while (ctx.iterate_on);
105 	}
106 
107 	return NULL;
108 }
109 
110 FIXTURE(sigtrap_threads)
111 {
112 	struct sigaction oldact;
113 	pthread_t threads[NUM_THREADS];
114 	pthread_barrier_t barrier;
115 	int fd;
116 };
117 
118 FIXTURE_SETUP(sigtrap_threads)
119 {
120 	struct perf_event_attr attr = make_event_attr(false, &ctx.iterate_on, 0);
121 	struct sigaction action = {};
122 	int i;
123 
124 	memset(&ctx, 0, sizeof(ctx));
125 
126 	/* Initialize sigtrap handler. */
127 	action.sa_flags = SA_SIGINFO | SA_NODEFER;
128 	action.sa_sigaction = sigtrap_handler;
129 	sigemptyset(&action.sa_mask);
130 	ASSERT_EQ(sigaction(SIGTRAP, &action, &self->oldact), 0);
131 
132 	/* Initialize perf event. */
133 	self->fd = syscall(__NR_perf_event_open, &attr, 0, -1, -1, PERF_FLAG_FD_CLOEXEC);
134 	ASSERT_NE(self->fd, -1);
135 
136 	/* Spawn threads inheriting perf event. */
137 	pthread_barrier_init(&self->barrier, NULL, NUM_THREADS + 1);
138 	for (i = 0; i < NUM_THREADS; i++)
139 		ASSERT_EQ(pthread_create(&self->threads[i], NULL, test_thread, &self->barrier), 0);
140 }
141 
142 FIXTURE_TEARDOWN(sigtrap_threads)
143 {
144 	pthread_barrier_destroy(&self->barrier);
145 	close(self->fd);
146 	sigaction(SIGTRAP, &self->oldact, NULL);
147 }
148 
149 static void run_test_threads(struct __test_metadata *_metadata,
150 			     FIXTURE_DATA(sigtrap_threads) *self)
151 {
152 	int i;
153 
154 	pthread_barrier_wait(&self->barrier);
155 	for (i = 0; i < NUM_THREADS; i++)
156 		ASSERT_EQ(pthread_join(self->threads[i], NULL), 0);
157 }
158 
159 TEST_F(sigtrap_threads, remain_disabled)
160 {
161 	run_test_threads(_metadata, self);
162 	EXPECT_EQ(ctx.signal_count, 0);
163 	EXPECT_NE(ctx.tids_want_signal, 0);
164 }
165 
166 TEST_F(sigtrap_threads, enable_event)
167 {
168 	EXPECT_EQ(ioctl(self->fd, PERF_EVENT_IOC_ENABLE, 0), 0);
169 	run_test_threads(_metadata, self);
170 
171 	EXPECT_EQ(ctx.signal_count, NUM_THREADS);
172 	EXPECT_EQ(ctx.tids_want_signal, 0);
173 	EXPECT_EQ(ctx.first_siginfo.si_addr, &ctx.iterate_on);
174 	EXPECT_EQ(ctx.first_siginfo.si_perf_type, PERF_TYPE_BREAKPOINT);
175 	EXPECT_EQ(ctx.first_siginfo.si_perf_data, TEST_SIG_DATA(&ctx.iterate_on, 0));
176 
177 	/* Check enabled for parent. */
178 	ctx.iterate_on = 0;
179 	EXPECT_EQ(ctx.signal_count, NUM_THREADS + 1);
180 }
181 
182 /* Test that modification propagates to all inherited events. */
183 TEST_F(sigtrap_threads, modify_and_enable_event)
184 {
185 	struct perf_event_attr new_attr = make_event_attr(true, &ctx.iterate_on, 42);
186 
187 	EXPECT_EQ(ioctl(self->fd, PERF_EVENT_IOC_MODIFY_ATTRIBUTES, &new_attr), 0);
188 	run_test_threads(_metadata, self);
189 
190 	EXPECT_EQ(ctx.signal_count, NUM_THREADS);
191 	EXPECT_EQ(ctx.tids_want_signal, 0);
192 	EXPECT_EQ(ctx.first_siginfo.si_addr, &ctx.iterate_on);
193 	EXPECT_EQ(ctx.first_siginfo.si_perf_type, PERF_TYPE_BREAKPOINT);
194 	EXPECT_EQ(ctx.first_siginfo.si_perf_data, TEST_SIG_DATA(&ctx.iterate_on, 42));
195 
196 	/* Check enabled for parent. */
197 	ctx.iterate_on = 0;
198 	EXPECT_EQ(ctx.signal_count, NUM_THREADS + 1);
199 }
200 
201 /* Stress test event + signal handling. */
202 TEST_F(sigtrap_threads, signal_stress)
203 {
204 	ctx.iterate_on = 3000;
205 
206 	EXPECT_EQ(ioctl(self->fd, PERF_EVENT_IOC_ENABLE, 0), 0);
207 	run_test_threads(_metadata, self);
208 	EXPECT_EQ(ioctl(self->fd, PERF_EVENT_IOC_DISABLE, 0), 0);
209 
210 	EXPECT_EQ(ctx.signal_count, NUM_THREADS * ctx.iterate_on);
211 	EXPECT_EQ(ctx.tids_want_signal, 0);
212 	EXPECT_EQ(ctx.first_siginfo.si_addr, &ctx.iterate_on);
213 	EXPECT_EQ(ctx.first_siginfo.si_perf_type, PERF_TYPE_BREAKPOINT);
214 	EXPECT_EQ(ctx.first_siginfo.si_perf_data, TEST_SIG_DATA(&ctx.iterate_on, 0));
215 }
216 
217 TEST_F(sigtrap_threads, signal_stress_with_disable)
218 {
219 	const int target_count = NUM_THREADS * 3000;
220 	int i;
221 
222 	ctx.iterate_on = -1;
223 
224 	EXPECT_EQ(ioctl(self->fd, PERF_EVENT_IOC_ENABLE, 0), 0);
225 	pthread_barrier_wait(&self->barrier);
226 	while (__atomic_load_n(&ctx.signal_count, __ATOMIC_RELAXED) < target_count) {
227 		EXPECT_EQ(ioctl(self->fd, PERF_EVENT_IOC_DISABLE, 0), 0);
228 		EXPECT_EQ(ioctl(self->fd, PERF_EVENT_IOC_ENABLE, 0), 0);
229 	}
230 	ctx.iterate_on = 0;
231 	for (i = 0; i < NUM_THREADS; i++)
232 		ASSERT_EQ(pthread_join(self->threads[i], NULL), 0);
233 	EXPECT_EQ(ioctl(self->fd, PERF_EVENT_IOC_DISABLE, 0), 0);
234 
235 	EXPECT_EQ(ctx.first_siginfo.si_addr, &ctx.iterate_on);
236 	EXPECT_EQ(ctx.first_siginfo.si_perf_type, PERF_TYPE_BREAKPOINT);
237 	EXPECT_EQ(ctx.first_siginfo.si_perf_data, TEST_SIG_DATA(&ctx.iterate_on, 0));
238 }
239 
240 TEST_HARNESS_MAIN
241