sigtrap_threads.c (6104B)
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. */ 39static 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 49static 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 69static 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 85static 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 104FIXTURE(sigtrap_threads) 105{ 106 struct sigaction oldact; 107 pthread_t threads[NUM_THREADS]; 108 pthread_barrier_t barrier; 109 int fd; 110}; 111 112FIXTURE_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 136FIXTURE_TEARDOWN(sigtrap_threads) 137{ 138 pthread_barrier_destroy(&self->barrier); 139 close(self->fd); 140 sigaction(SIGTRAP, &self->oldact, NULL); 141} 142 143static 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 153TEST_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 160TEST_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. */ 177TEST_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. */ 196TEST_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 211TEST_HARNESS_MAIN