This will set compiler flag --coverage so code coverage may be inspected using gcov. In order to successfully profile processes which are killed or interrupted as well, add a signal handler for those cases which calls exit(). This is relevant for test cases invoking nft monitor. Signed-off-by: Phil Sutter --- Changes since v3: - Avoid illegal exit() call in signal handler by use of signalfd() Changes since v2: - Include profiling option value in configure's final status report - Fix build for --enable-profiling - Add copyright statement to new source file Changes since v1: - Add src/profiling.c and include/profiling.h to keep conditionally built code separate --- .gitignore | 5 +++++ Makefile.am | 21 +++++++++++++++++++ configure.ac | 10 ++++++++- include/profiling.h | 12 +++++++++++ src/mnl.c | 9 +++++++- src/profiling.c | 51 +++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 106 insertions(+), 2 deletions(-) create mode 100644 include/profiling.h create mode 100644 src/profiling.c diff --git a/.gitignore b/.gitignore index 719829b65d212..8673393fac397 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,11 @@ nftversion.h # cscope files /cscope.* +# gcov-related +*.gcda +*.gcno +*.gcov + # Generated by tests *.payload.got tests/build/tests.log diff --git a/Makefile.am b/Makefile.am index bff746b53a0b4..efc11e44e0b59 100644 --- a/Makefile.am +++ b/Makefile.am @@ -96,6 +96,7 @@ noinst_HEADERS = \ include/owner.h \ include/parser.h \ include/payload.h \ + include/profiling.h \ include/proto.h \ include/rt.h \ include/rule.h \ @@ -163,6 +164,10 @@ AM_CFLAGS = \ AM_YFLAGS = -d -Wno-yacc +if BUILD_PROFILING +AM_CFLAGS += --coverage +endif + ############################################################################### BUILT_SOURCES += src/parser_bison.h @@ -264,6 +269,10 @@ src_libnftables_la_SOURCES += \ $(NULL) endif +if BUILD_PROFILING +src_libnftables_la_SOURCES += src/profiling.c +endif + src_libnftables_la_LDFLAGS = \ -version-info "${libnftables_LIBVERSION}" \ -Wl,--version-script="$(srcdir)/src//libnftables.map" \ @@ -453,3 +462,15 @@ TESTS = tests/build/run-tests.sh \ tests/py/nft-test.py \ tests/shell/run-tests.sh endif + +all_c_sources = $(filter %.c,$(src_libnftables_la_SOURCES)) $(src_nft_SOURCES) +if BUILD_MINIGMP +all_c_sources += $(src_libminigmp_la_SOURCES) +endif +if BUILD_AFL +all_c_sources += $(tools_nft_afl_SOURCES) +endif +CLEANFILES += src/libparser_la-parser_bison.gcno +CLEANFILES += src/libparser_la-scanner.gcno +CLEANFILES += $(all_c_sources:.c=.gcno) +CLEANFILES += $(src_nft_SOURCES:.c=.gcda) diff --git a/configure.ac b/configure.ac index 022608627908a..0d3ee2ac89f69 100644 --- a/configure.ac +++ b/configure.ac @@ -156,6 +156,13 @@ AC_ARG_ENABLE([distcheck], [enable_distcheck=yes], []) AM_CONDITIONAL([BUILD_DISTCHECK], [test "x$enable_distcheck" = "xyes"]) +AC_ARG_ENABLE([profiling], + AS_HELP_STRING([--enable-profiling], [build for use of gcov/gprof]), + [enable_profiling="$enableval"], [enable_profiling="no"]) +AM_CONDITIONAL([BUILD_PROFILING], [test "x$enable_profiling" = xyes]) +AM_COND_IF([BUILD_PROFILING], + [AC_DEFINE([BUILD_PROFILING], [1], [Define for profiling])]) + AC_CONFIG_FILES([ \ Makefile \ libnftables.pc \ @@ -170,7 +177,8 @@ echo " use mini-gmp: ${with_mini_gmp} enable man page: ${enable_man_doc} libxtables support: ${with_xtables} - json output support: ${with_json}" + json output support: ${with_json} + collect profiling data: ${enable_profiling}" if test "x$unitdir" != "x"; then AC_SUBST([unitdir]) diff --git a/include/profiling.h b/include/profiling.h new file mode 100644 index 0000000000000..78abd31d4315d --- /dev/null +++ b/include/profiling.h @@ -0,0 +1,12 @@ +#ifndef NFTABLES_PROFILING_H +#define NFTABLES_PROFILING_H + +#ifdef BUILD_PROFILING +int get_signalfd(void); +void check_signalfd(int fd); +#else +static inline int get_signalfd(void) { return -1; } +static inline void check_signalfd(int fd) { /* empty */ } +#endif + +#endif /* NFTABLES_PROFILING_H */ diff --git a/src/mnl.c b/src/mnl.c index eee0a33ceaeb4..3f3ef82a25cb5 100644 --- a/src/mnl.c +++ b/src/mnl.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -2390,6 +2391,7 @@ int mnl_nft_event_listener(struct mnl_socket *nf_sock, unsigned int debug_mask, unsigned int bufsiz = NFTABLES_NLEVENT_BUFSIZ; int fd = mnl_socket_get_fd(nf_sock); char buf[NFT_NLMSG_MAXSIZE]; + int sigfd = get_signalfd(); fd_set readfds; int ret; @@ -2401,11 +2403,16 @@ int mnl_nft_event_listener(struct mnl_socket *nf_sock, unsigned int debug_mask, while (1) { FD_ZERO(&readfds); FD_SET(fd, &readfds); + if (sigfd != -1) + FD_SET(sigfd, &readfds); - ret = select(fd + 1, &readfds, NULL, NULL, NULL); + ret = select(max(fd, sigfd) + 1, &readfds, NULL, NULL, NULL); if (ret < 0) return -1; + if (FD_ISSET(sigfd, &readfds)) + check_signalfd(sigfd); + if (FD_ISSET(fd, &readfds)) { ret = mnl_socket_recvfrom(nf_sock, buf, sizeof(buf)); if (ret < 0) { diff --git a/src/profiling.c b/src/profiling.c new file mode 100644 index 0000000000000..34d91cc1746ec --- /dev/null +++ b/src/profiling.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) Red Hat GmbH. Author: Phil Sutter + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (or any + * later) as published by the Free Software Foundation. + */ + +#include +#include + +#include +#include +#include + +int get_signalfd(void) +{ + sigset_t mask; + int fd; + + sigemptyset(&mask); + sigaddset(&mask, SIGTERM); + sigaddset(&mask, SIGINT); + + fd = signalfd(-1, &mask, 0); + if (fd < 0) { + perror("signalfd()"); + return fd; + } + if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) { + perror("sigprocmask()"); + close(fd); + return -1; + } + return fd; +} + +void check_signalfd(int fd) +{ + struct signalfd_siginfo info; + + if (read(fd, &info, sizeof(info)) < (signed)sizeof(info)) + return; + + switch (info.ssi_signo) { + case SIGTERM: + exit(143); + case SIGINT: + exit(130); + } +} -- 2.51.0