1 // SPDX-License-Identifier: GPL-2.0
3 * Test for perf events with SIGTRAP across all threads.
5 * Copyright (C) 2021, Google LLC.
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
26 #include <linux/hw_breakpoint.h>
27 #include <linux/perf_event.h>
30 #include <sys/ioctl.h>
31 #include <sys/syscall.h>
34 #include "../kselftest_harness.h"
38 /* Data shared between test body, threads, and signal handler. */
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. */
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)
49 static struct perf_event_attr
make_event_attr(bool enabled
, volatile void *addr
,
52 struct perf_event_attr attr
= {
53 .type
= PERF_TYPE_BREAKPOINT
,
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 */
71 static void sigtrap_handler(int signum
, siginfo_t
*info
, void *ucontext
)
73 if (info
->si_code
!= TRAP_PERF
) {
74 fprintf(stderr
, "%s: unexpected si_code %d\n", __func__
, info
->si_code
);
79 * The data in siginfo_t we're interested in should all be the same
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
);
87 static void *test_thread(void *arg
)
89 pthread_barrier_t
*barrier
= (pthread_barrier_t
*)arg
;
90 pid_t tid
= syscall(__NR_gettid
);
94 pthread_barrier_wait(barrier
);
96 __atomic_fetch_add(&ctx
.tids_want_signal
, tid
, __ATOMIC_RELAXED
);
97 iter
= ctx
.iterate_on
; /* read */
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 */
104 while (ctx
.iterate_on
);
110 FIXTURE(sigtrap_threads
)
112 struct sigaction oldact
;
113 pthread_t threads
[NUM_THREADS
];
114 pthread_barrier_t barrier
;
118 FIXTURE_SETUP(sigtrap_threads
)
120 struct perf_event_attr attr
= make_event_attr(false, &ctx
.iterate_on
, 0);
121 struct sigaction action
= {};
124 memset(&ctx
, 0, sizeof(ctx
));
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);
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);
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);
142 FIXTURE_TEARDOWN(sigtrap_threads
)
144 pthread_barrier_destroy(&self
->barrier
);
146 sigaction(SIGTRAP
, &self
->oldact
, NULL
);
149 static void run_test_threads(struct __test_metadata
*_metadata
,
150 FIXTURE_DATA(sigtrap_threads
) *self
)
154 pthread_barrier_wait(&self
->barrier
);
155 for (i
= 0; i
< NUM_THREADS
; i
++)
156 ASSERT_EQ(pthread_join(self
->threads
[i
], NULL
), 0);
159 TEST_F(sigtrap_threads
, remain_disabled
)
161 run_test_threads(_metadata
, self
);
162 EXPECT_EQ(ctx
.signal_count
, 0);
163 EXPECT_NE(ctx
.tids_want_signal
, 0);
166 TEST_F(sigtrap_threads
, enable_event
)
168 EXPECT_EQ(ioctl(self
->fd
, PERF_EVENT_IOC_ENABLE
, 0), 0);
169 run_test_threads(_metadata
, self
);
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));
177 /* Check enabled for parent. */
179 EXPECT_EQ(ctx
.signal_count
, NUM_THREADS
+ 1);
182 /* Test that modification propagates to all inherited events. */
183 TEST_F(sigtrap_threads
, modify_and_enable_event
)
185 struct perf_event_attr new_attr
= make_event_attr(true, &ctx
.iterate_on
, 42);
187 EXPECT_EQ(ioctl(self
->fd
, PERF_EVENT_IOC_MODIFY_ATTRIBUTES
, &new_attr
), 0);
188 run_test_threads(_metadata
, self
);
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));
196 /* Check enabled for parent. */
198 EXPECT_EQ(ctx
.signal_count
, NUM_THREADS
+ 1);
201 /* Stress test event + signal handling. */
202 TEST_F(sigtrap_threads
, signal_stress
)
204 ctx
.iterate_on
= 3000;
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);
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));
217 TEST_F(sigtrap_threads
, signal_stress_with_disable
)
219 const int target_count
= NUM_THREADS
* 3000;
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);
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);
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));