linux/tools/testing/selftests/bpf/prog_tests/send_signal.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#include <test_progs.h>
   3#include <sys/time.h>
   4#include <sys/resource.h>
   5#include "test_send_signal_kern.skel.h"
   6
   7int sigusr1_received = 0;
   8
   9static void sigusr1_handler(int signum)
  10{
  11        sigusr1_received++;
  12}
  13
  14static void test_send_signal_common(struct perf_event_attr *attr,
  15                                    bool signal_thread)
  16{
  17        struct test_send_signal_kern *skel;
  18        int pipe_c2p[2], pipe_p2c[2];
  19        int err = -1, pmu_fd = -1;
  20        char buf[256];
  21        pid_t pid;
  22
  23        if (!ASSERT_OK(pipe(pipe_c2p), "pipe_c2p"))
  24                return;
  25
  26        if (!ASSERT_OK(pipe(pipe_p2c), "pipe_p2c")) {
  27                close(pipe_c2p[0]);
  28                close(pipe_c2p[1]);
  29                return;
  30        }
  31
  32        pid = fork();
  33        if (!ASSERT_GE(pid, 0, "fork")) {
  34                close(pipe_c2p[0]);
  35                close(pipe_c2p[1]);
  36                close(pipe_p2c[0]);
  37                close(pipe_p2c[1]);
  38                return;
  39        }
  40
  41        if (pid == 0) {
  42                int old_prio;
  43
  44                /* install signal handler and notify parent */
  45                signal(SIGUSR1, sigusr1_handler);
  46
  47                close(pipe_c2p[0]); /* close read */
  48                close(pipe_p2c[1]); /* close write */
  49
  50                /* boost with a high priority so we got a higher chance
  51                 * that if an interrupt happens, the underlying task
  52                 * is this process.
  53                 */
  54                errno = 0;
  55                old_prio = getpriority(PRIO_PROCESS, 0);
  56                ASSERT_OK(errno, "getpriority");
  57                ASSERT_OK(setpriority(PRIO_PROCESS, 0, -20), "setpriority");
  58
  59                /* notify parent signal handler is installed */
  60                ASSERT_EQ(write(pipe_c2p[1], buf, 1), 1, "pipe_write");
  61
  62                /* make sure parent enabled bpf program to send_signal */
  63                ASSERT_EQ(read(pipe_p2c[0], buf, 1), 1, "pipe_read");
  64
  65                /* wait a little for signal handler */
  66                sleep(1);
  67
  68                buf[0] = sigusr1_received ? '2' : '0';
  69                ASSERT_EQ(write(pipe_c2p[1], buf, 1), 1, "pipe_write");
  70
  71                /* wait for parent notification and exit */
  72                ASSERT_EQ(read(pipe_p2c[0], buf, 1), 1, "pipe_read");
  73
  74                /* restore the old priority */
  75                ASSERT_OK(setpriority(PRIO_PROCESS, 0, old_prio), "setpriority");
  76
  77                close(pipe_c2p[1]);
  78                close(pipe_p2c[0]);
  79                exit(0);
  80        }
  81
  82        close(pipe_c2p[1]); /* close write */
  83        close(pipe_p2c[0]); /* close read */
  84
  85        skel = test_send_signal_kern__open_and_load();
  86        if (!ASSERT_OK_PTR(skel, "skel_open_and_load"))
  87                goto skel_open_load_failure;
  88
  89        if (!attr) {
  90                err = test_send_signal_kern__attach(skel);
  91                if (!ASSERT_OK(err, "skel_attach")) {
  92                        err = -1;
  93                        goto destroy_skel;
  94                }
  95        } else {
  96                pmu_fd = syscall(__NR_perf_event_open, attr, pid, -1,
  97                                 -1 /* group id */, 0 /* flags */);
  98                if (!ASSERT_GE(pmu_fd, 0, "perf_event_open")) {
  99                        err = -1;
 100                        goto destroy_skel;
 101                }
 102
 103                skel->links.send_signal_perf =
 104                        bpf_program__attach_perf_event(skel->progs.send_signal_perf, pmu_fd);
 105                if (!ASSERT_OK_PTR(skel->links.send_signal_perf, "attach_perf_event"))
 106                        goto disable_pmu;
 107        }
 108
 109        /* wait until child signal handler installed */
 110        ASSERT_EQ(read(pipe_c2p[0], buf, 1), 1, "pipe_read");
 111
 112        /* trigger the bpf send_signal */
 113        skel->bss->pid = pid;
 114        skel->bss->sig = SIGUSR1;
 115        skel->bss->signal_thread = signal_thread;
 116
 117        /* notify child that bpf program can send_signal now */
 118        ASSERT_EQ(write(pipe_p2c[1], buf, 1), 1, "pipe_write");
 119
 120        /* wait for result */
 121        err = read(pipe_c2p[0], buf, 1);
 122        if (!ASSERT_GE(err, 0, "reading pipe"))
 123                goto disable_pmu;
 124        if (!ASSERT_GT(err, 0, "reading pipe error: size 0")) {
 125                err = -1;
 126                goto disable_pmu;
 127        }
 128
 129        ASSERT_EQ(buf[0], '2', "incorrect result");
 130
 131        /* notify child safe to exit */
 132        ASSERT_EQ(write(pipe_p2c[1], buf, 1), 1, "pipe_write");
 133
 134disable_pmu:
 135        close(pmu_fd);
 136destroy_skel:
 137        test_send_signal_kern__destroy(skel);
 138skel_open_load_failure:
 139        close(pipe_c2p[0]);
 140        close(pipe_p2c[1]);
 141        wait(NULL);
 142}
 143
 144static void test_send_signal_tracepoint(bool signal_thread)
 145{
 146        test_send_signal_common(NULL, signal_thread);
 147}
 148
 149static void test_send_signal_perf(bool signal_thread)
 150{
 151        struct perf_event_attr attr = {
 152                .sample_period = 1,
 153                .type = PERF_TYPE_SOFTWARE,
 154                .config = PERF_COUNT_SW_CPU_CLOCK,
 155        };
 156
 157        test_send_signal_common(&attr, signal_thread);
 158}
 159
 160static void test_send_signal_nmi(bool signal_thread)
 161{
 162        struct perf_event_attr attr = {
 163                .sample_period = 1,
 164                .type = PERF_TYPE_HARDWARE,
 165                .config = PERF_COUNT_HW_CPU_CYCLES,
 166        };
 167        int pmu_fd;
 168
 169        /* Some setups (e.g. virtual machines) might run with hardware
 170         * perf events disabled. If this is the case, skip this test.
 171         */
 172        pmu_fd = syscall(__NR_perf_event_open, &attr, 0 /* pid */,
 173                         -1 /* cpu */, -1 /* group_fd */, 0 /* flags */);
 174        if (pmu_fd == -1) {
 175                if (errno == ENOENT) {
 176                        printf("%s:SKIP:no PERF_COUNT_HW_CPU_CYCLES\n",
 177                               __func__);
 178                        test__skip();
 179                        return;
 180                }
 181                /* Let the test fail with a more informative message */
 182        } else {
 183                close(pmu_fd);
 184        }
 185
 186        test_send_signal_common(&attr, signal_thread);
 187}
 188
 189void test_send_signal(void)
 190{
 191        if (test__start_subtest("send_signal_tracepoint"))
 192                test_send_signal_tracepoint(false);
 193        if (test__start_subtest("send_signal_perf"))
 194                test_send_signal_perf(false);
 195        if (test__start_subtest("send_signal_nmi"))
 196                test_send_signal_nmi(false);
 197        if (test__start_subtest("send_signal_tracepoint_thread"))
 198                test_send_signal_tracepoint(true);
 199        if (test__start_subtest("send_signal_perf_thread"))
 200                test_send_signal_perf(true);
 201        if (test__start_subtest("send_signal_nmi_thread"))
 202                test_send_signal_nmi(true);
 203}
 204