Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Test for perf events with SIGTRAP across all threads.
0004  *
0005  * Copyright (C) 2021, Google LLC.
0006  */
0007 
0008 #define _GNU_SOURCE
0009 
0010 /* We need the latest siginfo from the kernel repo. */
0011 #include <sys/types.h>
0012 #include <asm/siginfo.h>
0013 #define __have_siginfo_t 1
0014 #define __have_sigval_t 1
0015 #define __have_sigevent_t 1
0016 #define __siginfo_t_defined
0017 #define __sigval_t_defined
0018 #define __sigevent_t_defined
0019 #define _BITS_SIGINFO_CONSTS_H 1
0020 #define _BITS_SIGEVENT_CONSTS_H 1
0021 
0022 #include <stdbool.h>
0023 #include <stddef.h>
0024 #include <stdint.h>
0025 #include <stdio.h>
0026 #include <linux/hw_breakpoint.h>
0027 #include <linux/perf_event.h>
0028 #include <pthread.h>
0029 #include <signal.h>
0030 #include <sys/ioctl.h>
0031 #include <sys/syscall.h>
0032 #include <unistd.h>
0033 
0034 #include "../kselftest_harness.h"
0035 
0036 #define NUM_THREADS 5
0037 
0038 /* Data shared between test body, threads, and signal handler. */
0039 static struct {
0040     int tids_want_signal;       /* Which threads still want a signal. */
0041     int signal_count;       /* Sanity check number of signals received. */
0042     volatile int iterate_on;    /* Variable to set breakpoint on. */
0043     siginfo_t first_siginfo;    /* First observed siginfo_t. */
0044 } ctx;
0045 
0046 /* Unique value to check si_perf_data is correctly set from perf_event_attr::sig_data. */
0047 #define TEST_SIG_DATA(addr, id) (~(unsigned long)(addr) + id)
0048 
0049 static struct perf_event_attr make_event_attr(bool enabled, volatile void *addr,
0050                           unsigned long id)
0051 {
0052     struct perf_event_attr attr = {
0053         .type       = PERF_TYPE_BREAKPOINT,
0054         .size       = sizeof(attr),
0055         .sample_period  = 1,
0056         .disabled   = !enabled,
0057         .bp_addr    = (unsigned long)addr,
0058         .bp_type    = HW_BREAKPOINT_RW,
0059         .bp_len     = HW_BREAKPOINT_LEN_1,
0060         .inherit    = 1, /* Children inherit events ... */
0061         .inherit_thread = 1, /* ... but only cloned with CLONE_THREAD. */
0062         .remove_on_exec = 1, /* Required by sigtrap. */
0063         .sigtrap    = 1, /* Request synchronous SIGTRAP on event. */
0064         .sig_data   = TEST_SIG_DATA(addr, id),
0065     };
0066     return attr;
0067 }
0068 
0069 static void sigtrap_handler(int signum, siginfo_t *info, void *ucontext)
0070 {
0071     if (info->si_code != TRAP_PERF) {
0072         fprintf(stderr, "%s: unexpected si_code %d\n", __func__, info->si_code);
0073         return;
0074     }
0075 
0076     /*
0077      * The data in siginfo_t we're interested in should all be the same
0078      * across threads.
0079      */
0080     if (!__atomic_fetch_add(&ctx.signal_count, 1, __ATOMIC_RELAXED))
0081         ctx.first_siginfo = *info;
0082     __atomic_fetch_sub(&ctx.tids_want_signal, syscall(__NR_gettid), __ATOMIC_RELAXED);
0083 }
0084 
0085 static void *test_thread(void *arg)
0086 {
0087     pthread_barrier_t *barrier = (pthread_barrier_t *)arg;
0088     pid_t tid = syscall(__NR_gettid);
0089     int iter;
0090     int i;
0091 
0092     pthread_barrier_wait(barrier);
0093 
0094     __atomic_fetch_add(&ctx.tids_want_signal, tid, __ATOMIC_RELAXED);
0095     iter = ctx.iterate_on; /* read */
0096     for (i = 0; i < iter - 1; i++) {
0097         __atomic_fetch_add(&ctx.tids_want_signal, tid, __ATOMIC_RELAXED);
0098         ctx.iterate_on = iter; /* idempotent write */
0099     }
0100 
0101     return NULL;
0102 }
0103 
0104 FIXTURE(sigtrap_threads)
0105 {
0106     struct sigaction oldact;
0107     pthread_t threads[NUM_THREADS];
0108     pthread_barrier_t barrier;
0109     int fd;
0110 };
0111 
0112 FIXTURE_SETUP(sigtrap_threads)
0113 {
0114     struct perf_event_attr attr = make_event_attr(false, &ctx.iterate_on, 0);
0115     struct sigaction action = {};
0116     int i;
0117 
0118     memset(&ctx, 0, sizeof(ctx));
0119 
0120     /* Initialize sigtrap handler. */
0121     action.sa_flags = SA_SIGINFO | SA_NODEFER;
0122     action.sa_sigaction = sigtrap_handler;
0123     sigemptyset(&action.sa_mask);
0124     ASSERT_EQ(sigaction(SIGTRAP, &action, &self->oldact), 0);
0125 
0126     /* Initialize perf event. */
0127     self->fd = syscall(__NR_perf_event_open, &attr, 0, -1, -1, PERF_FLAG_FD_CLOEXEC);
0128     ASSERT_NE(self->fd, -1);
0129 
0130     /* Spawn threads inheriting perf event. */
0131     pthread_barrier_init(&self->barrier, NULL, NUM_THREADS + 1);
0132     for (i = 0; i < NUM_THREADS; i++)
0133         ASSERT_EQ(pthread_create(&self->threads[i], NULL, test_thread, &self->barrier), 0);
0134 }
0135 
0136 FIXTURE_TEARDOWN(sigtrap_threads)
0137 {
0138     pthread_barrier_destroy(&self->barrier);
0139     close(self->fd);
0140     sigaction(SIGTRAP, &self->oldact, NULL);
0141 }
0142 
0143 static void run_test_threads(struct __test_metadata *_metadata,
0144                  FIXTURE_DATA(sigtrap_threads) *self)
0145 {
0146     int i;
0147 
0148     pthread_barrier_wait(&self->barrier);
0149     for (i = 0; i < NUM_THREADS; i++)
0150         ASSERT_EQ(pthread_join(self->threads[i], NULL), 0);
0151 }
0152 
0153 TEST_F(sigtrap_threads, remain_disabled)
0154 {
0155     run_test_threads(_metadata, self);
0156     EXPECT_EQ(ctx.signal_count, 0);
0157     EXPECT_NE(ctx.tids_want_signal, 0);
0158 }
0159 
0160 TEST_F(sigtrap_threads, enable_event)
0161 {
0162     EXPECT_EQ(ioctl(self->fd, PERF_EVENT_IOC_ENABLE, 0), 0);
0163     run_test_threads(_metadata, self);
0164 
0165     EXPECT_EQ(ctx.signal_count, NUM_THREADS);
0166     EXPECT_EQ(ctx.tids_want_signal, 0);
0167     EXPECT_EQ(ctx.first_siginfo.si_addr, &ctx.iterate_on);
0168     EXPECT_EQ(ctx.first_siginfo.si_perf_type, PERF_TYPE_BREAKPOINT);
0169     EXPECT_EQ(ctx.first_siginfo.si_perf_data, TEST_SIG_DATA(&ctx.iterate_on, 0));
0170 
0171     /* Check enabled for parent. */
0172     ctx.iterate_on = 0;
0173     EXPECT_EQ(ctx.signal_count, NUM_THREADS + 1);
0174 }
0175 
0176 /* Test that modification propagates to all inherited events. */
0177 TEST_F(sigtrap_threads, modify_and_enable_event)
0178 {
0179     struct perf_event_attr new_attr = make_event_attr(true, &ctx.iterate_on, 42);
0180 
0181     EXPECT_EQ(ioctl(self->fd, PERF_EVENT_IOC_MODIFY_ATTRIBUTES, &new_attr), 0);
0182     run_test_threads(_metadata, self);
0183 
0184     EXPECT_EQ(ctx.signal_count, NUM_THREADS);
0185     EXPECT_EQ(ctx.tids_want_signal, 0);
0186     EXPECT_EQ(ctx.first_siginfo.si_addr, &ctx.iterate_on);
0187     EXPECT_EQ(ctx.first_siginfo.si_perf_type, PERF_TYPE_BREAKPOINT);
0188     EXPECT_EQ(ctx.first_siginfo.si_perf_data, TEST_SIG_DATA(&ctx.iterate_on, 42));
0189 
0190     /* Check enabled for parent. */
0191     ctx.iterate_on = 0;
0192     EXPECT_EQ(ctx.signal_count, NUM_THREADS + 1);
0193 }
0194 
0195 /* Stress test event + signal handling. */
0196 TEST_F(sigtrap_threads, signal_stress)
0197 {
0198     ctx.iterate_on = 3000;
0199 
0200     EXPECT_EQ(ioctl(self->fd, PERF_EVENT_IOC_ENABLE, 0), 0);
0201     run_test_threads(_metadata, self);
0202     EXPECT_EQ(ioctl(self->fd, PERF_EVENT_IOC_DISABLE, 0), 0);
0203 
0204     EXPECT_EQ(ctx.signal_count, NUM_THREADS * ctx.iterate_on);
0205     EXPECT_EQ(ctx.tids_want_signal, 0);
0206     EXPECT_EQ(ctx.first_siginfo.si_addr, &ctx.iterate_on);
0207     EXPECT_EQ(ctx.first_siginfo.si_perf_type, PERF_TYPE_BREAKPOINT);
0208     EXPECT_EQ(ctx.first_siginfo.si_perf_data, TEST_SIG_DATA(&ctx.iterate_on, 0));
0209 }
0210 
0211 TEST_HARNESS_MAIN