147 lines · c
1// SPDX-License-Identifier: GPL-2.02#define _GNU_SOURCE3 4#include <errno.h>5#include <fcntl.h>6#include <linux/perf_event.h>7#include <stddef.h>8#include <sched.h>9#include <signal.h>10#include <stdlib.h>11#include <string.h>12#include <sys/ioctl.h>13#include <sys/mman.h>14#include <sys/syscall.h>15#include <sys/wait.h>16#include <unistd.h>17 18#include "../kselftest_harness.h"19 20#define __maybe_unused __attribute__((__unused__))21 22static int sigio_count;23 24static void handle_sigio(int signum __maybe_unused,25 siginfo_t *oh __maybe_unused,26 void *uc __maybe_unused)27{28 ++sigio_count;29}30 31static void do_child(void)32{33 raise(SIGSTOP);34 35 for (int i = 0; i < 20; ++i)36 sleep(1);37 38 raise(SIGSTOP);39 40 exit(0);41}42 43TEST(watermark_signal)44{45 struct perf_event_attr attr;46 struct perf_event_mmap_page *p = NULL;47 struct sigaction previous_sigio, sigio = { 0 };48 pid_t child = -1;49 int child_status;50 int fd = -1;51 long page_size = sysconf(_SC_PAGE_SIZE);52 53 sigio.sa_sigaction = handle_sigio;54 EXPECT_EQ(sigaction(SIGIO, &sigio, &previous_sigio), 0);55 56 memset(&attr, 0, sizeof(attr));57 attr.size = sizeof(attr);58 attr.type = PERF_TYPE_SOFTWARE;59 attr.config = PERF_COUNT_SW_DUMMY;60 attr.sample_period = 1;61 attr.disabled = 1;62 attr.watermark = 1;63 attr.context_switch = 1;64 attr.wakeup_watermark = 1;65 66 child = fork();67 EXPECT_GE(child, 0);68 if (child == 0)69 do_child();70 else if (child < 0) {71 perror("fork()");72 goto cleanup;73 }74 75 if (waitpid(child, &child_status, WSTOPPED) != child ||76 !(WIFSTOPPED(child_status) && WSTOPSIG(child_status) == SIGSTOP)) {77 fprintf(stderr,78 "failed to sycnhronize with child errno=%d status=%x\n",79 errno,80 child_status);81 goto cleanup;82 }83 84 fd = syscall(__NR_perf_event_open, &attr, child, -1, -1,85 PERF_FLAG_FD_CLOEXEC);86 if (fd < 0) {87 fprintf(stderr, "failed opening event %llx\n", attr.config);88 goto cleanup;89 }90 91 if (fcntl(fd, F_SETFL, FASYNC)) {92 perror("F_SETFL FASYNC");93 goto cleanup;94 }95 96 if (fcntl(fd, F_SETOWN, getpid())) {97 perror("F_SETOWN getpid()");98 goto cleanup;99 }100 101 if (fcntl(fd, F_SETSIG, SIGIO)) {102 perror("F_SETSIG SIGIO");103 goto cleanup;104 }105 106 p = mmap(NULL, 2 * page_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);107 if (p == NULL) {108 perror("mmap");109 goto cleanup;110 }111 112 if (ioctl(fd, PERF_EVENT_IOC_ENABLE, 0)) {113 perror("PERF_EVENT_IOC_ENABLE");114 goto cleanup;115 }116 117 if (kill(child, SIGCONT) < 0) {118 perror("SIGCONT");119 goto cleanup;120 }121 122 if (waitpid(child, &child_status, WSTOPPED) != -1 || errno != EINTR)123 fprintf(stderr,124 "expected SIGIO to terminate wait errno=%d status=%x\n%d",125 errno,126 child_status,127 sigio_count);128 129 EXPECT_GE(sigio_count, 1);130 131cleanup:132 if (p != NULL)133 munmap(p, 2 * page_size);134 135 if (fd >= 0)136 close(fd);137 138 if (child > 0) {139 kill(child, SIGKILL);140 waitpid(child, NULL, 0);141 }142 143 sigaction(SIGIO, &previous_sigio, NULL);144}145 146TEST_HARNESS_MAIN147