0001
0002 #include <test_progs.h>
0003 #include <sys/time.h>
0004 #include <sys/resource.h>
0005 #include "test_send_signal_kern.skel.h"
0006
0007 static int sigusr1_received;
0008
0009 static void sigusr1_handler(int signum)
0010 {
0011 sigusr1_received = 1;
0012 }
0013
0014 static void test_send_signal_common(struct perf_event_attr *attr,
0015 bool signal_thread)
0016 {
0017 struct test_send_signal_kern *skel;
0018 int pipe_c2p[2], pipe_p2c[2];
0019 int err = -1, pmu_fd = -1;
0020 char buf[256];
0021 pid_t pid;
0022
0023 if (!ASSERT_OK(pipe(pipe_c2p), "pipe_c2p"))
0024 return;
0025
0026 if (!ASSERT_OK(pipe(pipe_p2c), "pipe_p2c")) {
0027 close(pipe_c2p[0]);
0028 close(pipe_c2p[1]);
0029 return;
0030 }
0031
0032 pid = fork();
0033 if (!ASSERT_GE(pid, 0, "fork")) {
0034 close(pipe_c2p[0]);
0035 close(pipe_c2p[1]);
0036 close(pipe_p2c[0]);
0037 close(pipe_p2c[1]);
0038 return;
0039 }
0040
0041 if (pid == 0) {
0042 int old_prio;
0043 volatile int j = 0;
0044
0045
0046 ASSERT_NEQ(signal(SIGUSR1, sigusr1_handler), SIG_ERR, "signal");
0047
0048 close(pipe_c2p[0]);
0049 close(pipe_p2c[1]);
0050
0051
0052
0053
0054
0055 errno = 0;
0056 old_prio = getpriority(PRIO_PROCESS, 0);
0057 ASSERT_OK(errno, "getpriority");
0058 ASSERT_OK(setpriority(PRIO_PROCESS, 0, -20), "setpriority");
0059
0060
0061 ASSERT_EQ(write(pipe_c2p[1], buf, 1), 1, "pipe_write");
0062
0063
0064 ASSERT_EQ(read(pipe_p2c[0], buf, 1), 1, "pipe_read");
0065
0066
0067 for (int i = 0; i < 1000000000 && !sigusr1_received; i++)
0068 j /= i + j + 1;
0069
0070 buf[0] = sigusr1_received ? '2' : '0';
0071 ASSERT_EQ(sigusr1_received, 1, "sigusr1_received");
0072 ASSERT_EQ(write(pipe_c2p[1], buf, 1), 1, "pipe_write");
0073
0074
0075 ASSERT_EQ(read(pipe_p2c[0], buf, 1), 1, "pipe_read");
0076
0077
0078 ASSERT_OK(setpriority(PRIO_PROCESS, 0, old_prio), "setpriority");
0079
0080 close(pipe_c2p[1]);
0081 close(pipe_p2c[0]);
0082 exit(0);
0083 }
0084
0085 close(pipe_c2p[1]);
0086 close(pipe_p2c[0]);
0087
0088 skel = test_send_signal_kern__open_and_load();
0089 if (!ASSERT_OK_PTR(skel, "skel_open_and_load"))
0090 goto skel_open_load_failure;
0091
0092 if (!attr) {
0093 err = test_send_signal_kern__attach(skel);
0094 if (!ASSERT_OK(err, "skel_attach")) {
0095 err = -1;
0096 goto destroy_skel;
0097 }
0098 } else {
0099 pmu_fd = syscall(__NR_perf_event_open, attr, pid, -1 ,
0100 -1 , 0 );
0101 if (!ASSERT_GE(pmu_fd, 0, "perf_event_open")) {
0102 err = -1;
0103 goto destroy_skel;
0104 }
0105
0106 skel->links.send_signal_perf =
0107 bpf_program__attach_perf_event(skel->progs.send_signal_perf, pmu_fd);
0108 if (!ASSERT_OK_PTR(skel->links.send_signal_perf, "attach_perf_event"))
0109 goto disable_pmu;
0110 }
0111
0112
0113 ASSERT_EQ(read(pipe_c2p[0], buf, 1), 1, "pipe_read");
0114
0115
0116 skel->bss->signal_thread = signal_thread;
0117 skel->bss->sig = SIGUSR1;
0118 skel->bss->pid = pid;
0119
0120
0121 ASSERT_EQ(write(pipe_p2c[1], buf, 1), 1, "pipe_write");
0122
0123
0124 err = read(pipe_c2p[0], buf, 1);
0125 if (!ASSERT_GE(err, 0, "reading pipe"))
0126 goto disable_pmu;
0127 if (!ASSERT_GT(err, 0, "reading pipe error: size 0")) {
0128 err = -1;
0129 goto disable_pmu;
0130 }
0131
0132 ASSERT_EQ(buf[0], '2', "incorrect result");
0133
0134
0135 ASSERT_EQ(write(pipe_p2c[1], buf, 1), 1, "pipe_write");
0136
0137 disable_pmu:
0138 close(pmu_fd);
0139 destroy_skel:
0140 test_send_signal_kern__destroy(skel);
0141 skel_open_load_failure:
0142 close(pipe_c2p[0]);
0143 close(pipe_p2c[1]);
0144 wait(NULL);
0145 }
0146
0147 static void test_send_signal_tracepoint(bool signal_thread)
0148 {
0149 test_send_signal_common(NULL, signal_thread);
0150 }
0151
0152 static void test_send_signal_perf(bool signal_thread)
0153 {
0154 struct perf_event_attr attr = {
0155 .sample_period = 1,
0156 .type = PERF_TYPE_SOFTWARE,
0157 .config = PERF_COUNT_SW_CPU_CLOCK,
0158 };
0159
0160 test_send_signal_common(&attr, signal_thread);
0161 }
0162
0163 static void test_send_signal_nmi(bool signal_thread)
0164 {
0165 struct perf_event_attr attr = {
0166 .sample_period = 1,
0167 .type = PERF_TYPE_HARDWARE,
0168 .config = PERF_COUNT_HW_CPU_CYCLES,
0169 };
0170 int pmu_fd;
0171
0172
0173
0174
0175 pmu_fd = syscall(__NR_perf_event_open, &attr, 0 ,
0176 -1 , -1 , 0 );
0177 if (pmu_fd == -1) {
0178 if (errno == ENOENT) {
0179 printf("%s:SKIP:no PERF_COUNT_HW_CPU_CYCLES\n",
0180 __func__);
0181 test__skip();
0182 return;
0183 }
0184
0185 } else {
0186 close(pmu_fd);
0187 }
0188
0189 test_send_signal_common(&attr, signal_thread);
0190 }
0191
0192 void test_send_signal(void)
0193 {
0194 if (test__start_subtest("send_signal_tracepoint"))
0195 test_send_signal_tracepoint(false);
0196 if (test__start_subtest("send_signal_perf"))
0197 test_send_signal_perf(false);
0198 if (test__start_subtest("send_signal_nmi"))
0199 test_send_signal_nmi(false);
0200 if (test__start_subtest("send_signal_tracepoint_thread"))
0201 test_send_signal_tracepoint(true);
0202 if (test__start_subtest("send_signal_perf_thread"))
0203 test_send_signal_perf(true);
0204 if (test__start_subtest("send_signal_nmi_thread"))
0205 test_send_signal_nmi(true);
0206 }