From: Shunsuke Nakamura <nakamura.shun@xxxxxxxxxxx> Extend the fields of the opts structure to set up overflow handling for sampling events. Also, add processing to set signal handlers in perf_evsel__open_opts. Signed-off-by: Shunsuke Nakamura <nakamura.shun@xxxxxxxxxxx> Signed-off-by: Charlie Jenkins <charlie@xxxxxxxxxxxx> --- tools/lib/perf/Documentation/libperf.txt | 6 ++- tools/lib/perf/Makefile | 1 + tools/lib/perf/evsel.c | 79 ++++++++++++++++++++++++++++++++ tools/lib/perf/include/perf/evsel.h | 6 ++- tools/lib/perf/tests/test-evlist.c | 1 - 5 files changed, 90 insertions(+), 3 deletions(-) diff --git a/tools/lib/perf/Documentation/libperf.txt b/tools/lib/perf/Documentation/libperf.txt index 83827b94617a..bb99534d5855 100644 --- a/tools/lib/perf/Documentation/libperf.txt +++ b/tools/lib/perf/Documentation/libperf.txt @@ -137,8 +137,12 @@ SYNOPSIS size_t sz; unsigned long open_flags; /* perf_event_open flags */ + int fcntl_flags; + unsigned int signal; + int owner_type; /* value for F_SETOWN_EX */ + struct sigaction *sigact; }; - #define perf_evsel_open_opts__last_field open_flags + #define perf_evsel_open_opts__last_field sigact #define LIBPERF_OPTS(TYPE, NAME, ...) diff --git a/tools/lib/perf/Makefile b/tools/lib/perf/Makefile index 3a9b2140aa04..9dade2ad91bd 100644 --- a/tools/lib/perf/Makefile +++ b/tools/lib/perf/Makefile @@ -75,6 +75,7 @@ override CFLAGS += -Werror -Wall override CFLAGS += -fPIC override CFLAGS += $(INCLUDES) override CFLAGS += -fvisibility=hidden +override CFLAGS += -D_GNU_SOURCE all: diff --git a/tools/lib/perf/evsel.c b/tools/lib/perf/evsel.c index 96ecf3e5c8b4..17d3d9a88c23 100644 --- a/tools/lib/perf/evsel.c +++ b/tools/lib/perf/evsel.c @@ -562,6 +562,79 @@ void perf_counts_values__scale(struct perf_counts_values *count, *pscaled = scaled; } +static int perf_evsel__run_fcntl(struct perf_evsel *evsel, + unsigned int cmd, unsigned long arg, + int cpu_map_idx) +{ + int thread; + + for (thread = 0; thread < xyarray__max_y(evsel->fd); thread++) { + int err; + int *fd = FD(evsel, cpu_map_idx, thread); + + if (!fd || *fd < 0) + return -1; + + err = fcntl(*fd, cmd, arg); + if (err) + return err; + } + + return 0; +} + +static int perf_evsel__set_signal_handler(struct perf_evsel *evsel, + struct perf_evsel_open_opts *opts) +{ + unsigned int fcntl_flags; + unsigned int signal; + struct f_owner_ex owner; + struct sigaction *sigact; + int cpu_map_idx; + int err = 0; + + fcntl_flags = OPTS_GET(opts, fcntl_flags, (O_RDWR | O_NONBLOCK | O_ASYNC)); + signal = OPTS_GET(opts, signal, SIGIO); + owner.type = OPTS_GET(opts, owner_type, F_OWNER_PID); + sigact = OPTS_GET(opts, sigact, NULL); + + if (fcntl_flags == 0 && signal == 0 && !owner.type == 0 && sigact == 0) + return err; + + err = sigaction(signal, sigact, NULL); + if (err) + return err; + + switch (owner.type) { + case F_OWNER_PID: + owner.pid = getpid(); + break; + case F_OWNER_TID: + owner.pid = syscall(SYS_gettid); + break; + case F_OWNER_PGRP: + default: + return -1; + } + + for (cpu_map_idx = 0; cpu_map_idx < xyarray__max_x(evsel->fd); cpu_map_idx++) { + err = perf_evsel__run_fcntl(evsel, F_SETFL, fcntl_flags, cpu_map_idx); + if (err) + return err; + + err = perf_evsel__run_fcntl(evsel, F_SETSIG, signal, cpu_map_idx); + if (err) + return err; + + err = perf_evsel__run_fcntl(evsel, F_SETOWN_EX, + (unsigned long)&owner, cpu_map_idx); + if (err) + return err; + } + + return err; +} + int perf_evsel__open_opts(struct perf_evsel *evsel, struct perf_cpu_map *cpus, struct perf_thread_map *threads, struct perf_evsel_open_opts *opts) @@ -576,6 +649,12 @@ int perf_evsel__open_opts(struct perf_evsel *evsel, struct perf_cpu_map *cpus, evsel->open_flags = OPTS_GET(opts, open_flags, 0); err = perf_evsel__open(evsel, cpus, threads); + if (err) + return err; + + err = perf_evsel__set_signal_handler(evsel, opts); + if (err) + return err; return err; } diff --git a/tools/lib/perf/include/perf/evsel.h b/tools/lib/perf/include/perf/evsel.h index 8eb3927f3cd0..344808f23371 100644 --- a/tools/lib/perf/include/perf/evsel.h +++ b/tools/lib/perf/include/perf/evsel.h @@ -31,9 +31,13 @@ struct perf_evsel_open_opts { size_t sz; unsigned long open_flags; /* perf_event_open flags */ + int fcntl_flags; + int signal; + int owner_type; /* value for F_SETOWN_EX */ + struct sigaction *sigact; }; -#define perf_evsel_open_opts__last_field open_flags +#define perf_evsel_open_opts__last_field sigact #define LIBPERF_OPTS(TYPE, NAME, ...) \ struct TYPE NAME = ({ \ diff --git a/tools/lib/perf/tests/test-evlist.c b/tools/lib/perf/tests/test-evlist.c index 10f70cb41ff1..3a833f0349d3 100644 --- a/tools/lib/perf/tests/test-evlist.c +++ b/tools/lib/perf/tests/test-evlist.c @@ -1,5 +1,4 @@ // SPDX-License-Identifier: GPL-2.0 -#define _GNU_SOURCE // needed for sched.h to get sched_[gs]etaffinity and CPU_(ZERO,SET) #include <inttypes.h> #include <sched.h> #include <stdio.h> -- 2.44.0