| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144 |
- // SPDX-License-Identifier: GPL-2.0
- #define _GNU_SOURCE
- #include <errno.h>
- #include <fcntl.h>
- #include <linux/perf_event.h>
- #include <stddef.h>
- #include <sched.h>
- #include <signal.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/ioctl.h>
- #include <sys/mman.h>
- #include <sys/syscall.h>
- #include <sys/wait.h>
- #include <unistd.h>
- #include "kselftest_harness.h"
- static int sigio_count;
- static void handle_sigio(int signum __maybe_unused,
- siginfo_t *oh __maybe_unused,
- void *uc __maybe_unused)
- {
- ++sigio_count;
- }
- static void do_child(void)
- {
- raise(SIGSTOP);
- for (int i = 0; i < 20; ++i)
- sleep(1);
- raise(SIGSTOP);
- exit(0);
- }
- TEST(watermark_signal)
- {
- struct perf_event_attr attr;
- struct perf_event_mmap_page *p = NULL;
- struct sigaction previous_sigio, sigio = { 0 };
- pid_t child = -1;
- int child_status;
- int fd = -1;
- long page_size = sysconf(_SC_PAGE_SIZE);
- sigio.sa_sigaction = handle_sigio;
- EXPECT_EQ(sigaction(SIGIO, &sigio, &previous_sigio), 0);
- memset(&attr, 0, sizeof(attr));
- attr.size = sizeof(attr);
- attr.type = PERF_TYPE_SOFTWARE;
- attr.config = PERF_COUNT_SW_DUMMY;
- attr.sample_period = 1;
- attr.disabled = 1;
- attr.watermark = 1;
- attr.context_switch = 1;
- attr.wakeup_watermark = 1;
- child = fork();
- EXPECT_GE(child, 0);
- if (child == 0)
- do_child();
- else if (child < 0) {
- perror("fork()");
- goto cleanup;
- }
- if (waitpid(child, &child_status, WSTOPPED) != child ||
- !(WIFSTOPPED(child_status) && WSTOPSIG(child_status) == SIGSTOP)) {
- fprintf(stderr,
- "failed to synchronize with child errno=%d status=%x\n",
- errno,
- child_status);
- goto cleanup;
- }
- fd = syscall(__NR_perf_event_open, &attr, child, -1, -1,
- PERF_FLAG_FD_CLOEXEC);
- if (fd < 0) {
- fprintf(stderr, "failed opening event %llx\n", attr.config);
- goto cleanup;
- }
- if (fcntl(fd, F_SETFL, FASYNC)) {
- perror("F_SETFL FASYNC");
- goto cleanup;
- }
- if (fcntl(fd, F_SETOWN, getpid())) {
- perror("F_SETOWN getpid()");
- goto cleanup;
- }
- if (fcntl(fd, F_SETSIG, SIGIO)) {
- perror("F_SETSIG SIGIO");
- goto cleanup;
- }
- p = mmap(NULL, 2 * page_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
- if (p == NULL) {
- perror("mmap");
- goto cleanup;
- }
- if (ioctl(fd, PERF_EVENT_IOC_ENABLE, 0)) {
- perror("PERF_EVENT_IOC_ENABLE");
- goto cleanup;
- }
- if (kill(child, SIGCONT) < 0) {
- perror("SIGCONT");
- goto cleanup;
- }
- if (waitpid(child, &child_status, WSTOPPED) != -1 || errno != EINTR)
- fprintf(stderr,
- "expected SIGIO to terminate wait errno=%d status=%x\n%d",
- errno,
- child_status,
- sigio_count);
- EXPECT_GE(sigio_count, 1);
- cleanup:
- if (p != NULL)
- munmap(p, 2 * page_size);
- if (fd >= 0)
- close(fd);
- if (child > 0) {
- kill(child, SIGKILL);
- waitpid(child, NULL, 0);
- }
- sigaction(SIGIO, &previous_sigio, NULL);
- }
- TEST_HARNESS_MAIN
|