From a782ef357067962f60580478067f4023facab6a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= Date: Sat, 30 Mar 2024 13:47:10 +0100 Subject: linux: move libnl code into separate file Move all the code using libnl functionality into a separate file to ease modifications. No functional change. --- Makefile.am | 5 ++ configure.ac | 1 + linux/LibNl.c | 123 ++++++++++++++++++++++++++++++++++++++++++++++ linux/LibNl.h | 18 +++++++ linux/LinuxProcessTable.c | 119 +++----------------------------------------- 5 files changed, 153 insertions(+), 113 deletions(-) create mode 100644 linux/LibNl.c create mode 100644 linux/LibNl.h diff --git a/Makefile.am b/Makefile.am index 0d95e370..ca2f90ba 100644 --- a/Makefile.am +++ b/Makefile.am @@ -214,6 +214,11 @@ linux_platform_sources = \ zfs/ZfsArcMeter.c \ zfs/ZfsCompressedArcMeter.c +if HAVE_DELAYACCT +linux_platform_headers += linux/LibNl.h +linux_platform_sources += linux/LibNl.c +endif + if HTOP_LINUX AM_LDFLAGS += -rdynamic myhtopplatheaders = $(linux_platform_headers) diff --git a/configure.ac b/configure.ac index 8c9e484a..b3137dec 100644 --- a/configure.ac +++ b/configure.ac @@ -692,6 +692,7 @@ case "$enable_delayacct" in AC_MSG_ERROR([bad value '$enable_delayacct' for --enable-delayacct]) ;; esac +AM_CONDITIONAL([HAVE_DELAYACCT], [test "$enable_delayacct" = yes]) AC_ARG_ENABLE([sensors], diff --git a/linux/LibNl.c b/linux/LibNl.c new file mode 100644 index 00000000..e61b14f6 --- /dev/null +++ b/linux/LibNl.c @@ -0,0 +1,123 @@ +/* +htop - linux/LibNl.c +(C) 2024 htop dev team +Released under the GNU GPLv2+, see the COPYING file +in the source distribution for its full text. +*/ + +#include "config.h" // IWYU pragma: keep + +#ifndef HAVE_DELAYACCT +#error Compiling this file requires HAVE_DELAYACCT +#endif + +#include "linux/LibNl.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +static void initNetlinkSocket(LinuxProcessTable* this) { + this->netlink_socket = nl_socket_alloc(); + if (this->netlink_socket == NULL) { + return; + } + if (nl_connect(this->netlink_socket, NETLINK_GENERIC) < 0) { + return; + } + this->netlink_family = genl_ctrl_resolve(this->netlink_socket, TASKSTATS_GENL_NAME); +} + +void LibNl_destroyNetlinkSocket(LinuxProcessTable* this) { + if (!this->netlink_socket) + return; + + nl_close(this->netlink_socket); + nl_socket_free(this->netlink_socket); + this->netlink_socket = NULL; +} + +static int handleNetlinkMsg(struct nl_msg* nlmsg, void* linuxProcess) { + struct nlmsghdr* nlhdr; + struct nlattr* nlattrs[TASKSTATS_TYPE_MAX + 1]; + const struct nlattr* nlattr; + struct taskstats stats; + int rem; + LinuxProcess* lp = (LinuxProcess*) linuxProcess; + + nlhdr = nlmsg_hdr(nlmsg); + + if (genlmsg_parse(nlhdr, 0, nlattrs, TASKSTATS_TYPE_MAX, NULL) < 0) { + return NL_SKIP; + } + + if ((nlattr = nlattrs[TASKSTATS_TYPE_AGGR_PID]) || (nlattr = nlattrs[TASKSTATS_TYPE_NULL])) { + memcpy(&stats, nla_data(nla_next(nla_data(nlattr), &rem)), sizeof(stats)); + assert(Process_getPid(&lp->super) == (pid_t)stats.ac_pid); + + // The xxx_delay_total values wrap around on overflow. + // (Linux Kernel "Documentation/accounting/taskstats-struct.rst") + unsigned long long int timeDelta = stats.ac_etime * 1000 - lp->delay_read_time; + #define DELTAPERC(x, y) (timeDelta ? MINIMUM((float)((x) - (y)) / timeDelta * 100.0f, 100.0f) : NAN) + lp->cpu_delay_percent = DELTAPERC(stats.cpu_delay_total, lp->cpu_delay_total); + lp->blkio_delay_percent = DELTAPERC(stats.blkio_delay_total, lp->blkio_delay_total); + lp->swapin_delay_percent = DELTAPERC(stats.swapin_delay_total, lp->swapin_delay_total); + #undef DELTAPERC + + lp->swapin_delay_total = stats.swapin_delay_total; + lp->blkio_delay_total = stats.blkio_delay_total; + lp->cpu_delay_total = stats.cpu_delay_total; + lp->delay_read_time = stats.ac_etime * 1000; + } + return NL_OK; +} + +void LibNl_readDelayAcctData(LinuxProcessTable* this, LinuxProcess* process) { + struct nl_msg* msg; + + if (!this->netlink_socket) { + initNetlinkSocket(this); + if (!this->netlink_socket) { + goto delayacct_failure; + } + } + + if (nl_socket_modify_cb(this->netlink_socket, NL_CB_VALID, NL_CB_CUSTOM, handleNetlinkMsg, process) < 0) { + goto delayacct_failure; + } + + if (! (msg = nlmsg_alloc())) { + goto delayacct_failure; + } + + if (! genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, this->netlink_family, 0, NLM_F_REQUEST, TASKSTATS_CMD_GET, TASKSTATS_VERSION)) { + nlmsg_free(msg); + } + + if (nla_put_u32(msg, TASKSTATS_CMD_ATTR_PID, Process_getPid(&process->super)) < 0) { + nlmsg_free(msg); + } + + if (nl_send_sync(this->netlink_socket, msg) < 0) { + goto delayacct_failure; + } + + if (nl_recvmsgs_default(this->netlink_socket) < 0) { + goto delayacct_failure; + } + + return; + +delayacct_failure: + process->swapin_delay_percent = NAN; + process->blkio_delay_percent = NAN; + process->cpu_delay_percent = NAN; +} diff --git a/linux/LibNl.h b/linux/LibNl.h new file mode 100644 index 00000000..e89c3694 --- /dev/null +++ b/linux/LibNl.h @@ -0,0 +1,18 @@ +#ifndef HEADER_LibNl +#define HEADER_LibNl +/* +htop - linux/LibNl.h +(C) 2024 htop dev team +Released under the GNU GPLv2+, see the COPYING file +in the source distribution for its full text. +*/ + +#include "linux/LinuxProcess.h" +#include "linux/LinuxProcessTable.h" + + +void LibNl_destroyNetlinkSocket(LinuxProcessTable* this); + +void LibNl_readDelayAcctData(LinuxProcessTable* this, LinuxProcess* process); + +#endif /* HEADER_LibNl */ diff --git a/linux/LinuxProcessTable.c b/linux/LinuxProcessTable.c index 428199d2..9a5ffdb4 100644 --- a/linux/LinuxProcessTable.c +++ b/linux/LinuxProcessTable.c @@ -23,18 +23,6 @@ in the source distribution for its full text. #include #include -#ifdef HAVE_DELAYACCT -#include -#include -#include -#include -#include -#include -#include -#include -#include -#endif - #include "Compat.h" #include "Hashtable.h" #include "Machine.h" @@ -55,6 +43,10 @@ in the source distribution for its full text. #include "linux/LinuxProcess.h" #include "linux/Platform.h" // needed for GNU/hurd to get PATH_MAX // IWYU pragma: keep +#ifdef HAVE_DELAYACCT +#include "linux/LibNl.h" +#endif + #if defined(MAJOR_IN_MKDEV) #include #elif defined(MAJOR_IN_SYSMACROS) @@ -187,21 +179,6 @@ static void LinuxProcessTable_initTtyDrivers(LinuxProcessTable* this) { this->ttyDrivers = ttyDrivers; } -#ifdef HAVE_DELAYACCT - -static void LinuxProcessTable_initNetlinkSocket(LinuxProcessTable* this) { - this->netlink_socket = nl_socket_alloc(); - if (this->netlink_socket == NULL) { - return; - } - if (nl_connect(this->netlink_socket, NETLINK_GENERIC) < 0) { - return; - } - this->netlink_family = genl_ctrl_resolve(this->netlink_socket, TASKSTATS_GENL_NAME); -} - -#endif - ProcessTable* ProcessTable_new(Machine* host, Hashtable* pidMatchList) { LinuxProcessTable* this = xCalloc(1, sizeof(LinuxProcessTable)); Object_setClass(this, Class(ProcessTable)); @@ -227,10 +204,7 @@ void ProcessTable_delete(Object* cast) { free(this->ttyDrivers); } #ifdef HAVE_DELAYACCT - if (this->netlink_socket) { - nl_close(this->netlink_socket); - nl_socket_free(this->netlink_socket); - } + LibNl_destroyNetlinkSocket(this); #endif free(this); } @@ -1010,87 +984,6 @@ static void LinuxProcessTable_readCwd(LinuxProcess* process, openat_arg_t procFd free_and_xStrdup(&process->super.procCwd, pathBuffer); } -#ifdef HAVE_DELAYACCT - -static int handleNetlinkMsg(struct nl_msg* nlmsg, void* linuxProcess) { - struct nlmsghdr* nlhdr; - struct nlattr* nlattrs[TASKSTATS_TYPE_MAX + 1]; - const struct nlattr* nlattr; - struct taskstats stats; - int rem; - LinuxProcess* lp = (LinuxProcess*) linuxProcess; - - nlhdr = nlmsg_hdr(nlmsg); - - if (genlmsg_parse(nlhdr, 0, nlattrs, TASKSTATS_TYPE_MAX, NULL) < 0) { - return NL_SKIP; - } - - if ((nlattr = nlattrs[TASKSTATS_TYPE_AGGR_PID]) || (nlattr = nlattrs[TASKSTATS_TYPE_NULL])) { - memcpy(&stats, nla_data(nla_next(nla_data(nlattr), &rem)), sizeof(stats)); - assert(Process_getPid(&lp->super) == (pid_t)stats.ac_pid); - - // The xxx_delay_total values wrap around on overflow. - // (Linux Kernel "Documentation/accounting/taskstats-struct.rst") - unsigned long long int timeDelta = stats.ac_etime * 1000 - lp->delay_read_time; - #define DELTAPERC(x, y) (timeDelta ? MINIMUM((float)((x) - (y)) / timeDelta * 100.0f, 100.0f) : NAN) - lp->cpu_delay_percent = DELTAPERC(stats.cpu_delay_total, lp->cpu_delay_total); - lp->blkio_delay_percent = DELTAPERC(stats.blkio_delay_total, lp->blkio_delay_total); - lp->swapin_delay_percent = DELTAPERC(stats.swapin_delay_total, lp->swapin_delay_total); - #undef DELTAPERC - - lp->swapin_delay_total = stats.swapin_delay_total; - lp->blkio_delay_total = stats.blkio_delay_total; - lp->cpu_delay_total = stats.cpu_delay_total; - lp->delay_read_time = stats.ac_etime * 1000; - } - return NL_OK; -} - -static void LinuxProcessTable_readDelayAcctData(LinuxProcessTable* this, LinuxProcess* process) { - struct nl_msg* msg; - - if (!this->netlink_socket) { - LinuxProcessTable_initNetlinkSocket(this); - if (!this->netlink_socket) { - goto delayacct_failure; - } - } - - if (nl_socket_modify_cb(this->netlink_socket, NL_CB_VALID, NL_CB_CUSTOM, handleNetlinkMsg, process) < 0) { - goto delayacct_failure; - } - - if (! (msg = nlmsg_alloc())) { - goto delayacct_failure; - } - - if (! genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, this->netlink_family, 0, NLM_F_REQUEST, TASKSTATS_CMD_GET, TASKSTATS_VERSION)) { - nlmsg_free(msg); - } - - if (nla_put_u32(msg, TASKSTATS_CMD_ATTR_PID, Process_getPid(&process->super)) < 0) { - nlmsg_free(msg); - } - - if (nl_send_sync(this->netlink_socket, msg) < 0) { - goto delayacct_failure; - } - - if (nl_recvmsgs_default(this->netlink_socket) < 0) { - goto delayacct_failure; - } - - return; - -delayacct_failure: - process->swapin_delay_percent = NAN; - process->blkio_delay_percent = NAN; - process->cpu_delay_percent = NAN; -} - -#endif - static bool LinuxProcessTable_readCmdlineFile(Process* process, openat_arg_t procFd) { char filename[MAX_NAME + 1]; ssize_t amtRead; @@ -1593,7 +1486,7 @@ static bool LinuxProcessTable_recurseProcTree(LinuxProcessTable* this, openat_ar #ifdef HAVE_DELAYACCT if (ss->flags & PROCESS_FLAG_LINUX_DELAYACCT) { - LinuxProcessTable_readDelayAcctData(this, lp); + LibNl_readDelayAcctData(this, lp); } #endif -- cgit v1.2.3