Merge branches 'clk-range', 'clk-uniphier', 'clk-apple' and 'clk-qcom' into clk-next
[linux-2.6-microblaze.git] / tools / testing / selftests / perf_events / sigtrap_threads.c
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         };
66         return attr;
67 }
68
69 static void sigtrap_handler(int signum, siginfo_t *info, void *ucontext)
70 {
71         if (info->si_code != TRAP_PERF) {
72                 fprintf(stderr, "%s: unexpected si_code %d\n", __func__, info->si_code);
73                 return;
74         }
75
76         /*
77          * The data in siginfo_t we're interested in should all be the same
78          * across threads.
79          */
80         if (!__atomic_fetch_add(&ctx.signal_count, 1, __ATOMIC_RELAXED))
81                 ctx.first_siginfo = *info;
82         __atomic_fetch_sub(&ctx.tids_want_signal, syscall(__NR_gettid), __ATOMIC_RELAXED);
83 }
84
85 static void *test_thread(void *arg)
86 {
87         pthread_barrier_t *barrier = (pthread_barrier_t *)arg;
88         pid_t tid = syscall(__NR_gettid);
89         int iter;
90         int i;
91
92         pthread_barrier_wait(barrier);
93
94         __atomic_fetch_add(&ctx.tids_want_signal, tid, __ATOMIC_RELAXED);
95         iter = ctx.iterate_on; /* read */
96         for (i = 0; i < iter - 1; i++) {
97                 __atomic_fetch_add(&ctx.tids_want_signal, tid, __ATOMIC_RELAXED);
98                 ctx.iterate_on = iter; /* idempotent write */
99         }
100
101         return NULL;
102 }
103
104 FIXTURE(sigtrap_threads)
105 {
106         struct sigaction oldact;
107         pthread_t threads[NUM_THREADS];
108         pthread_barrier_t barrier;
109         int fd;
110 };
111
112 FIXTURE_SETUP(sigtrap_threads)
113 {
114         struct perf_event_attr attr = make_event_attr(false, &ctx.iterate_on, 0);
115         struct sigaction action = {};
116         int i;
117
118         memset(&ctx, 0, sizeof(ctx));
119
120         /* Initialize sigtrap handler. */
121         action.sa_flags = SA_SIGINFO | SA_NODEFER;
122         action.sa_sigaction = sigtrap_handler;
123         sigemptyset(&action.sa_mask);
124         ASSERT_EQ(sigaction(SIGTRAP, &action, &self->oldact), 0);
125
126         /* Initialize perf event. */
127         self->fd = syscall(__NR_perf_event_open, &attr, 0, -1, -1, PERF_FLAG_FD_CLOEXEC);
128         ASSERT_NE(self->fd, -1);
129
130         /* Spawn threads inheriting perf event. */
131         pthread_barrier_init(&self->barrier, NULL, NUM_THREADS + 1);
132         for (i = 0; i < NUM_THREADS; i++)
133                 ASSERT_EQ(pthread_create(&self->threads[i], NULL, test_thread, &self->barrier), 0);
134 }
135
136 FIXTURE_TEARDOWN(sigtrap_threads)
137 {
138         pthread_barrier_destroy(&self->barrier);
139         close(self->fd);
140         sigaction(SIGTRAP, &self->oldact, NULL);
141 }
142
143 static void run_test_threads(struct __test_metadata *_metadata,
144                              FIXTURE_DATA(sigtrap_threads) *self)
145 {
146         int i;
147
148         pthread_barrier_wait(&self->barrier);
149         for (i = 0; i < NUM_THREADS; i++)
150                 ASSERT_EQ(pthread_join(self->threads[i], NULL), 0);
151 }
152
153 TEST_F(sigtrap_threads, remain_disabled)
154 {
155         run_test_threads(_metadata, self);
156         EXPECT_EQ(ctx.signal_count, 0);
157         EXPECT_NE(ctx.tids_want_signal, 0);
158 }
159
160 TEST_F(sigtrap_threads, enable_event)
161 {
162         EXPECT_EQ(ioctl(self->fd, PERF_EVENT_IOC_ENABLE, 0), 0);
163         run_test_threads(_metadata, self);
164
165         EXPECT_EQ(ctx.signal_count, NUM_THREADS);
166         EXPECT_EQ(ctx.tids_want_signal, 0);
167         EXPECT_EQ(ctx.first_siginfo.si_addr, &ctx.iterate_on);
168         EXPECT_EQ(ctx.first_siginfo.si_perf_type, PERF_TYPE_BREAKPOINT);
169         EXPECT_EQ(ctx.first_siginfo.si_perf_data, TEST_SIG_DATA(&ctx.iterate_on, 0));
170
171         /* Check enabled for parent. */
172         ctx.iterate_on = 0;
173         EXPECT_EQ(ctx.signal_count, NUM_THREADS + 1);
174 }
175
176 /* Test that modification propagates to all inherited events. */
177 TEST_F(sigtrap_threads, modify_and_enable_event)
178 {
179         struct perf_event_attr new_attr = make_event_attr(true, &ctx.iterate_on, 42);
180
181         EXPECT_EQ(ioctl(self->fd, PERF_EVENT_IOC_MODIFY_ATTRIBUTES, &new_attr), 0);
182         run_test_threads(_metadata, self);
183
184         EXPECT_EQ(ctx.signal_count, NUM_THREADS);
185         EXPECT_EQ(ctx.tids_want_signal, 0);
186         EXPECT_EQ(ctx.first_siginfo.si_addr, &ctx.iterate_on);
187         EXPECT_EQ(ctx.first_siginfo.si_perf_type, PERF_TYPE_BREAKPOINT);
188         EXPECT_EQ(ctx.first_siginfo.si_perf_data, TEST_SIG_DATA(&ctx.iterate_on, 42));
189
190         /* Check enabled for parent. */
191         ctx.iterate_on = 0;
192         EXPECT_EQ(ctx.signal_count, NUM_THREADS + 1);
193 }
194
195 /* Stress test event + signal handling. */
196 TEST_F(sigtrap_threads, signal_stress)
197 {
198         ctx.iterate_on = 3000;
199
200         EXPECT_EQ(ioctl(self->fd, PERF_EVENT_IOC_ENABLE, 0), 0);
201         run_test_threads(_metadata, self);
202         EXPECT_EQ(ioctl(self->fd, PERF_EVENT_IOC_DISABLE, 0), 0);
203
204         EXPECT_EQ(ctx.signal_count, NUM_THREADS * ctx.iterate_on);
205         EXPECT_EQ(ctx.tids_want_signal, 0);
206         EXPECT_EQ(ctx.first_siginfo.si_addr, &ctx.iterate_on);
207         EXPECT_EQ(ctx.first_siginfo.si_perf_type, PERF_TYPE_BREAKPOINT);
208         EXPECT_EQ(ctx.first_siginfo.si_perf_data, TEST_SIG_DATA(&ctx.iterate_on, 0));
209 }
210
211 TEST_HARNESS_MAIN