116f0efc3SYonghong Song // SPDX-License-Identifier: GPL-2.0 216f0efc3SYonghong Song #include <test_progs.h> 3ab8b7f0cSYonghong Song #include "test_send_signal_kern.skel.h" 416f0efc3SYonghong Song 516f0efc3SYonghong Song static volatile int sigusr1_received = 0; 616f0efc3SYonghong Song 716f0efc3SYonghong Song static void sigusr1_handler(int signum) 816f0efc3SYonghong Song { 916f0efc3SYonghong Song sigusr1_received++; 1016f0efc3SYonghong Song } 1116f0efc3SYonghong Song 1286ccc384SStanislav Fomichev static void test_send_signal_common(struct perf_event_attr *attr, 13ab8b7f0cSYonghong Song bool signal_thread, 1416f0efc3SYonghong Song const char *test_name) 1516f0efc3SYonghong Song { 16ab8b7f0cSYonghong Song struct test_send_signal_kern *skel; 1716f0efc3SYonghong Song int pipe_c2p[2], pipe_p2c[2]; 18ab8b7f0cSYonghong Song int err = -1, pmu_fd = -1; 19ab8b7f0cSYonghong Song __u32 duration = 0; 2016f0efc3SYonghong Song char buf[256]; 2116f0efc3SYonghong Song pid_t pid; 2216f0efc3SYonghong Song 2316f0efc3SYonghong Song if (CHECK(pipe(pipe_c2p), test_name, 2416f0efc3SYonghong Song "pipe pipe_c2p error: %s\n", strerror(errno))) 2586ccc384SStanislav Fomichev return; 2616f0efc3SYonghong Song 2716f0efc3SYonghong Song if (CHECK(pipe(pipe_p2c), test_name, 2816f0efc3SYonghong Song "pipe pipe_p2c error: %s\n", strerror(errno))) { 2916f0efc3SYonghong Song close(pipe_c2p[0]); 3016f0efc3SYonghong Song close(pipe_c2p[1]); 3186ccc384SStanislav Fomichev return; 3216f0efc3SYonghong Song } 3316f0efc3SYonghong Song 3416f0efc3SYonghong Song pid = fork(); 3516f0efc3SYonghong Song if (CHECK(pid < 0, test_name, "fork error: %s\n", strerror(errno))) { 3616f0efc3SYonghong Song close(pipe_c2p[0]); 3716f0efc3SYonghong Song close(pipe_c2p[1]); 3816f0efc3SYonghong Song close(pipe_p2c[0]); 3916f0efc3SYonghong Song close(pipe_p2c[1]); 4086ccc384SStanislav Fomichev return; 4116f0efc3SYonghong Song } 4216f0efc3SYonghong Song 4316f0efc3SYonghong Song if (pid == 0) { 4416f0efc3SYonghong Song /* install signal handler and notify parent */ 4516f0efc3SYonghong Song signal(SIGUSR1, sigusr1_handler); 4616f0efc3SYonghong Song 4716f0efc3SYonghong Song close(pipe_c2p[0]); /* close read */ 4816f0efc3SYonghong Song close(pipe_p2c[1]); /* close write */ 4916f0efc3SYonghong Song 5016f0efc3SYonghong Song /* notify parent signal handler is installed */ 51929e54a9SJianlin Lv CHECK(write(pipe_c2p[1], buf, 1) != 1, "pipe_write", "err %d\n", -errno); 5216f0efc3SYonghong Song 5316f0efc3SYonghong Song /* make sure parent enabled bpf program to send_signal */ 54929e54a9SJianlin Lv CHECK(read(pipe_p2c[0], buf, 1) != 1, "pipe_read", "err %d\n", -errno); 5516f0efc3SYonghong Song 5616f0efc3SYonghong Song /* wait a little for signal handler */ 5716f0efc3SYonghong Song sleep(1); 5816f0efc3SYonghong Song 59929e54a9SJianlin Lv buf[0] = sigusr1_received ? '2' : '0'; 60929e54a9SJianlin Lv CHECK(write(pipe_c2p[1], buf, 1) != 1, "pipe_write", "err %d\n", -errno); 6116f0efc3SYonghong Song 6216f0efc3SYonghong Song /* wait for parent notification and exit */ 63929e54a9SJianlin Lv CHECK(read(pipe_p2c[0], buf, 1) != 1, "pipe_read", "err %d\n", -errno); 6416f0efc3SYonghong Song 6516f0efc3SYonghong Song close(pipe_c2p[1]); 6616f0efc3SYonghong Song close(pipe_p2c[0]); 6716f0efc3SYonghong Song exit(0); 6816f0efc3SYonghong Song } 6916f0efc3SYonghong Song 7016f0efc3SYonghong Song close(pipe_c2p[1]); /* close write */ 7116f0efc3SYonghong Song close(pipe_p2c[0]); /* close read */ 7216f0efc3SYonghong Song 73ab8b7f0cSYonghong Song skel = test_send_signal_kern__open_and_load(); 74ab8b7f0cSYonghong Song if (CHECK(!skel, "skel_open_and_load", "skeleton open_and_load failed\n")) 75ab8b7f0cSYonghong Song goto skel_open_load_failure; 7616f0efc3SYonghong Song 77ab8b7f0cSYonghong Song if (!attr) { 78ab8b7f0cSYonghong Song err = test_send_signal_kern__attach(skel); 79ab8b7f0cSYonghong Song if (CHECK(err, "skel_attach", "skeleton attach failed\n")) { 80ab8b7f0cSYonghong Song err = -1; 81ab8b7f0cSYonghong Song goto destroy_skel; 82ab8b7f0cSYonghong Song } 83ab8b7f0cSYonghong Song } else { 8416f0efc3SYonghong Song pmu_fd = syscall(__NR_perf_event_open, attr, pid, -1, 8516f0efc3SYonghong Song -1 /* group id */, 0 /* flags */); 8616f0efc3SYonghong Song if (CHECK(pmu_fd < 0, test_name, "perf_event_open error: %s\n", 8716f0efc3SYonghong Song strerror(errno))) { 8816f0efc3SYonghong Song err = -1; 89ab8b7f0cSYonghong Song goto destroy_skel; 9016f0efc3SYonghong Song } 9116f0efc3SYonghong Song 92ab8b7f0cSYonghong Song skel->links.send_signal_perf = 93ab8b7f0cSYonghong Song bpf_program__attach_perf_event(skel->progs.send_signal_perf, pmu_fd); 94ab8b7f0cSYonghong Song if (CHECK(IS_ERR(skel->links.send_signal_perf), "attach_perf_event", 95ab8b7f0cSYonghong Song "err %ld\n", PTR_ERR(skel->links.send_signal_perf))) 9616f0efc3SYonghong Song goto disable_pmu; 97ab8b7f0cSYonghong Song } 9816f0efc3SYonghong Song 9916f0efc3SYonghong Song /* wait until child signal handler installed */ 100929e54a9SJianlin Lv CHECK(read(pipe_c2p[0], buf, 1) != 1, "pipe_read", "err %d\n", -errno); 10116f0efc3SYonghong Song 10216f0efc3SYonghong Song /* trigger the bpf send_signal */ 103ab8b7f0cSYonghong Song skel->bss->pid = pid; 104ab8b7f0cSYonghong Song skel->bss->sig = SIGUSR1; 105ab8b7f0cSYonghong Song skel->bss->signal_thread = signal_thread; 10616f0efc3SYonghong Song 10716f0efc3SYonghong Song /* notify child that bpf program can send_signal now */ 108929e54a9SJianlin Lv CHECK(write(pipe_p2c[1], buf, 1) != 1, "pipe_write", "err %d\n", -errno); 10916f0efc3SYonghong Song 11016f0efc3SYonghong Song /* wait for result */ 11116f0efc3SYonghong Song err = read(pipe_c2p[0], buf, 1); 11216f0efc3SYonghong Song if (CHECK(err < 0, test_name, "reading pipe error: %s\n", strerror(errno))) 11316f0efc3SYonghong Song goto disable_pmu; 11416f0efc3SYonghong Song if (CHECK(err == 0, test_name, "reading pipe error: size 0\n")) { 11516f0efc3SYonghong Song err = -1; 11616f0efc3SYonghong Song goto disable_pmu; 11716f0efc3SYonghong Song } 11816f0efc3SYonghong Song 11986ccc384SStanislav Fomichev CHECK(buf[0] != '2', test_name, "incorrect result\n"); 12016f0efc3SYonghong Song 12116f0efc3SYonghong Song /* notify child safe to exit */ 122929e54a9SJianlin Lv CHECK(write(pipe_p2c[1], buf, 1) != 1, "pipe_write", "err %d\n", -errno); 12316f0efc3SYonghong Song 12416f0efc3SYonghong Song disable_pmu: 12516f0efc3SYonghong Song close(pmu_fd); 126ab8b7f0cSYonghong Song destroy_skel: 127ab8b7f0cSYonghong Song test_send_signal_kern__destroy(skel); 128ab8b7f0cSYonghong Song skel_open_load_failure: 12916f0efc3SYonghong Song close(pipe_c2p[0]); 13016f0efc3SYonghong Song close(pipe_p2c[1]); 13116f0efc3SYonghong Song wait(NULL); 13216f0efc3SYonghong Song } 13316f0efc3SYonghong Song 134ab8b7f0cSYonghong Song static void test_send_signal_tracepoint(bool signal_thread) 13516f0efc3SYonghong Song { 136ab8b7f0cSYonghong Song test_send_signal_common(NULL, signal_thread, "tracepoint"); 13716f0efc3SYonghong Song } 13816f0efc3SYonghong Song 139ab8b7f0cSYonghong Song static void test_send_signal_perf(bool signal_thread) 1404e59afbbSIlya Leoshkevich { 1414e59afbbSIlya Leoshkevich struct perf_event_attr attr = { 1424e59afbbSIlya Leoshkevich .sample_period = 1, 1434e59afbbSIlya Leoshkevich .type = PERF_TYPE_SOFTWARE, 1444e59afbbSIlya Leoshkevich .config = PERF_COUNT_SW_CPU_CLOCK, 1454e59afbbSIlya Leoshkevich }; 1464e59afbbSIlya Leoshkevich 147ab8b7f0cSYonghong Song test_send_signal_common(&attr, signal_thread, "perf_sw_event"); 1484e59afbbSIlya Leoshkevich } 1494e59afbbSIlya Leoshkevich 150ab8b7f0cSYonghong Song static void test_send_signal_nmi(bool signal_thread) 15116f0efc3SYonghong Song { 15216f0efc3SYonghong Song struct perf_event_attr attr = { 15335697c12SYonghong Song .sample_period = 1, 15416f0efc3SYonghong Song .type = PERF_TYPE_HARDWARE, 15516f0efc3SYonghong Song .config = PERF_COUNT_HW_CPU_CYCLES, 15616f0efc3SYonghong Song }; 1574e59afbbSIlya Leoshkevich int pmu_fd; 15816f0efc3SYonghong Song 1594e59afbbSIlya Leoshkevich /* Some setups (e.g. virtual machines) might run with hardware 1604e59afbbSIlya Leoshkevich * perf events disabled. If this is the case, skip this test. 1614e59afbbSIlya Leoshkevich */ 1624e59afbbSIlya Leoshkevich pmu_fd = syscall(__NR_perf_event_open, &attr, 0 /* pid */, 1634e59afbbSIlya Leoshkevich -1 /* cpu */, -1 /* group_fd */, 0 /* flags */); 1644e59afbbSIlya Leoshkevich if (pmu_fd == -1) { 1654e59afbbSIlya Leoshkevich if (errno == ENOENT) { 16666bd2ec1SStanislav Fomichev printf("%s:SKIP:no PERF_COUNT_HW_CPU_CYCLES\n", 1674e59afbbSIlya Leoshkevich __func__); 168cd9c21d7SStanislav Fomichev test__skip(); 16986ccc384SStanislav Fomichev return; 1704e59afbbSIlya Leoshkevich } 1714e59afbbSIlya Leoshkevich /* Let the test fail with a more informative message */ 1724e59afbbSIlya Leoshkevich } else { 1734e59afbbSIlya Leoshkevich close(pmu_fd); 1744e59afbbSIlya Leoshkevich } 1754e59afbbSIlya Leoshkevich 176ab8b7f0cSYonghong Song test_send_signal_common(&attr, signal_thread, "perf_hw_event"); 17716f0efc3SYonghong Song } 17816f0efc3SYonghong Song 17916f0efc3SYonghong Song void test_send_signal(void) 18016f0efc3SYonghong Song { 181b207edfeSAndrii Nakryiko if (test__start_subtest("send_signal_tracepoint")) 182ab8b7f0cSYonghong Song test_send_signal_tracepoint(false); 183b207edfeSAndrii Nakryiko if (test__start_subtest("send_signal_perf")) 184ab8b7f0cSYonghong Song test_send_signal_perf(false); 185b207edfeSAndrii Nakryiko if (test__start_subtest("send_signal_nmi")) 186ab8b7f0cSYonghong Song test_send_signal_nmi(false); 187ab8b7f0cSYonghong Song if (test__start_subtest("send_signal_tracepoint_thread")) 188ab8b7f0cSYonghong Song test_send_signal_tracepoint(true); 189ab8b7f0cSYonghong Song if (test__start_subtest("send_signal_perf_thread")) 190ab8b7f0cSYonghong Song test_send_signal_perf(true); 191ab8b7f0cSYonghong Song if (test__start_subtest("send_signal_nmi_thread")) 192ab8b7f0cSYonghong Song test_send_signal_nmi(true); 19316f0efc3SYonghong Song } 194