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