diff --git a/configure b/configure index 082b6d50cd..6f4873c359 100755 --- a/configure +++ b/configure @@ -5289,11 +5289,11 @@ if test x$ac_prog_cxx_stdcxx = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CXX option to enable C++11 features" >&5 printf %s "checking for $CXX option to enable C++11 features... " >&6; } -if test ${ac_cv_prog_cxx_11+y} +if test ${ac_cv_prog_cxx_cxx11+y} then : printf %s "(cached) " >&6 else $as_nop - ac_cv_prog_cxx_11=no + ac_cv_prog_cxx_cxx11=no ac_save_CXX=$CXX cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -5335,11 +5335,11 @@ if test x$ac_prog_cxx_stdcxx = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CXX option to enable C++98 features" >&5 printf %s "checking for $CXX option to enable C++98 features... " >&6; } -if test ${ac_cv_prog_cxx_98+y} +if test ${ac_cv_prog_cxx_cxx98+y} then : printf %s "(cached) " >&6 else $as_nop - ac_cv_prog_cxx_98=no + ac_cv_prog_cxx_cxx98=no ac_save_CXX=$CXX cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -11560,6 +11560,25 @@ if test "x$ac_cv_header_ncursesw_curses_h" = xyes then : printf "%s\n" "#define HAVE_NCURSESW_CURSES_H 1" >>confdefs.h +fi +ac_fn_c_check_header_compile "$LINENO" "ncursesw/term.h" "ac_cv_header_ncursesw_term_h" "$ac_includes_default" +if test "x$ac_cv_header_ncursesw_term_h" = xyes +then : + printf "%s\n" "#define HAVE_NCURSESW_TERM_H 1" >>confdefs.h + +fi + +ac_fn_c_check_header_compile "$LINENO" "ncurses/term.h" "ac_cv_header_ncurses_term_h" "$ac_includes_default" +if test "x$ac_cv_header_ncurses_term_h" = xyes +then : + printf "%s\n" "#define HAVE_NCURSES_TERM_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "term.h" "ac_cv_header_term_h" "$ac_includes_default" +if test "x$ac_cv_header_term_h" = xyes +then : + printf "%s\n" "#define HAVE_TERM_H 1" >>confdefs.h + fi ac_fn_c_check_header_compile "$LINENO" "linux/perf_event.h" "ac_cv_header_linux_perf_event_h" "$ac_includes_default" diff --git a/configure.ac b/configure.ac index 9b75e56029..45bb67ac4f 100644 --- a/configure.ac +++ b/configure.ac @@ -1865,7 +1865,8 @@ AC_CHECK_HEADERS(fts.h libzfs.h) AC_CHECK_HEADERS(sys/statvfs.h sys/statfs.h sys/mount.h) AC_CHECK_HEADERS(curses.h ncurses.h) AC_CHECK_HEADERS(ncurses/curses.h ncurses/ncurses.h) -AC_CHECK_HEADERS(ncursesw/curses.h) +AC_CHECK_HEADERS(ncursesw/curses.h ncursesw/term.h) +AC_CHECK_HEADERS(ncurses/term.h term.h) AC_CHECK_HEADERS(linux/perf_event.h) dnl Check if we have ... standard way diff --git a/src/include/pcp/config.h.in b/src/include/pcp/config.h.in index 9175aaf9e6..bcb5739195 100644 --- a/src/include/pcp/config.h.in +++ b/src/include/pcp/config.h.in @@ -289,6 +289,15 @@ /* Define to 1 if you have the header file. */ #undef HAVE_NCURSESW_CURSES_H +/* Define to 1 if you have the header file. */ +#undef HAVE_NCURSESW_TERM_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NCURSES_TERM_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_TERM_H + /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_NDIR_H diff --git a/src/pcp/htop/.gitignore b/src/pcp/htop/.gitignore index 5bff251452..83045b795c 100644 --- a/src/pcp/htop/.gitignore +++ b/src/pcp/htop/.gitignore @@ -7,6 +7,7 @@ pcp-htop.5 pcp-htop.5.* pcp/columns pcp/meters +pcp/screens AUTHORS *.h *.c diff --git a/src/pcp/htop/GNUmakefile b/src/pcp/htop/GNUmakefile index 6b7c0c571e..bc7866874e 100644 --- a/src/pcp/htop/GNUmakefile +++ b/src/pcp/htop/GNUmakefile @@ -1,5 +1,5 @@ # -# Copyright (c) 2020-2021 Red Hat. +# Copyright (c) 2020-2023 Red Hat. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the @@ -15,7 +15,7 @@ TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs -COPYRIGHT = "(C) 2004-2019 Hisham Muhammad. (C) 2020-2021 htop dev team." +COPYRIGHT = "(C) 2004-2019 Hisham Muhammad. (C) 2020-2023 htop dev team." CMDTARGET = pcp-htop DISTARGET = $(PCP_BINADM_DIR)/$(CMDTARGET) @@ -47,6 +47,7 @@ TOPCFILES = \ DisplayOptionsPanel.c \ DynamicColumn.c \ DynamicMeter.c \ + DynamicScreen.c \ EnvScreen.c \ FileDescriptorMeter.c \ FunctionBar.c \ @@ -73,13 +74,16 @@ TOPCFILES = \ ProcessList.c \ ProcessLocksScreen.c \ RichString.c \ + Row.c \ Scheduling.c \ ScreenManager.c \ ScreensPanel.c \ + ScreenTabsPanel.c \ Settings.c \ SignalsPanel.c \ SwapMeter.c \ SysArchMeter.c \ + Table.c \ TasksMeter.c \ TraceScreen.c \ UptimeMeter.c \ @@ -88,14 +92,18 @@ TOPCFILES = \ XUtils.c \ SUBCFILES = \ + linux/CGroupUtils.c \ linux/PressureStallMeter.c \ linux/ZramMeter.c \ zfs/ZfsArcMeter.c \ zfs/ZfsCompressedArcMeter.c \ + pcp/InDomTable.c \ + pcp/Instance.c \ + pcp/Metric.c \ pcp/PCPDynamicColumn.c \ pcp/PCPDynamicMeter.c \ + pcp/PCPDynamicScreen.c \ pcp/PCPMachine.c \ - pcp/PCPMetric.c \ pcp/PCPProcess.c \ pcp/PCPProcessList.c \ pcp/Platform.c \ @@ -120,6 +128,7 @@ TOPHFILES = \ DisplayOptionsPanel.h \ DynamicColumn.h \ DynamicMeter.h \ + DynamicScreen.h \ EnvScreen.h \ FileDescriptorMeter.h \ FunctionBar.h \ @@ -148,14 +157,19 @@ TOPHFILES = \ ProcessList.h \ ProcessLocksScreen.h \ ProvideCurses.h \ + ProvideTerm.h \ RichString.h \ + Row.h \ + RowField.h \ Scheduling.h \ ScreenManager.h \ ScreensPanel.h \ + ScreenTabsPanel.h \ Settings.h \ SignalsPanel.h \ SwapMeter.h \ SysArchMeter.h \ + Table.h \ TasksMeter.h \ TraceScreen.h \ UptimeMeter.h \ @@ -164,16 +178,20 @@ TOPHFILES = \ XUtils.h \ SUBHFILES = \ + linux/CGroupUtils.h \ linux/PressureStallMeter.h \ linux/ZramMeter.h \ linux/ZramStats.h \ zfs/ZfsArcMeter.h \ zfs/ZfsArcStats.h \ zfs/ZfsCompressedArcMeter.h \ + pcp/InDomTable.h \ + pcp/Instance.h \ + pcp/Metric.h \ pcp/PCPDynamicColumn.h \ pcp/PCPDynamicMeter.h \ + pcp/PCPDynamicScreen.h \ pcp/PCPMachine.h \ - pcp/PCPMetric.h \ pcp/PCPProcess.h \ pcp/PCPProcessList.h \ pcp/Platform.h \ @@ -182,10 +200,13 @@ SUBHFILES = \ DOCFILES = AUTHORS pcp-htop.5.in COLUMNS = container delayacct fdcount guest memory sched swap tcp udp wchan METERS = entropy freespace ipc locks memcache mysql postfix redis tcp +SCREENS = cgroups cgroupsio cgroupsmem devices filesystems \ + biosnoop execsnoop exitsnoop opensnoop CFGMETERS = $(patsubst %,pcp/meters/%,$(METERS)) CFGCOLUMNS = $(patsubst %,pcp/columns/%,$(COLUMNS)) +CFGSCREENS = $(patsubst %,pcp/screens/%,$(SCREENS)) -CFGXFILES = $(CFGMETERS) $(CFGCOLUMNS) +CFGXFILES = $(CFGMETERS) $(CFGCOLUMNS) $(CFGSCREENS) TOPXFILES = $(TOPCFILES) $(TOPHFILES) $(DOCFILES) SUBXFILES = $(SUBCFILES) $(SUBHFILES) CFILES = $(TOPCFILES) $(SUBCFILES) @@ -208,15 +229,20 @@ install: default $(INSTALL) -m 755 -d $(PCP_SYSCONF_DIR)/htop $(INSTALL) -m 755 -d $(PCP_SYSCONF_DIR)/htop/meters $(INSTALL) -m 755 -d $(PCP_SYSCONF_DIR)/htop/columns + $(INSTALL) -m 755 -d $(PCP_SYSCONF_DIR)/htop/screens $(INSTALL) -m 755 -d $(PCP_SHARE_DIR)/htop $(INSTALL) -m 755 -d $(PCP_SHARE_DIR)/htop/meters @for m in $(METERS); do \ $(INSTALL) -m 644 pcp/meters/$$m $(PCP_SHARE_DIR)/htop/meters/$$m; \ done - $(INSTALL) -m 755 -d $(PCP_SHARE_DIR)/htop/meters + $(INSTALL) -m 755 -d $(PCP_SHARE_DIR)/htop/columns @for c in $(COLUMNS); do \ $(INSTALL) -m 644 pcp/columns/$$c $(PCP_SHARE_DIR)/htop/columns/$$c; \ done + $(INSTALL) -m 755 -d $(PCP_SHARE_DIR)/htop/screens + @for c in $(SCREENS); do \ + $(INSTALL) -m 644 pcp/screens/$$c $(PCP_SHARE_DIR)/htop/screens/$$c; \ + done else build-me: install: @@ -234,7 +260,7 @@ $(SUBXFILES): $(LN_S) -f $(TOPDIR)/../vendor/github.com/htop-dev/htop/$@ $@ $(CFGXFILES): - mkdir -p pcp/columns pcp/meters + mkdir -p pcp/columns pcp/meters pcp/screens $(LN_S) -f $(TOPDIR)/../../vendor/github.com/htop-dev/htop/$@ $@ $(DISTLINKS): $(CMDTARGET) diff --git a/vendor/github.com/htop-dev/htop/.github/workflows/ci.yml b/vendor/github.com/htop-dev/htop/.github/workflows/ci.yml index 8e4ea06528..509e012020 100644 --- a/vendor/github.com/htop-dev/htop/.github/workflows/ci.yml +++ b/vendor/github.com/htop-dev/htop/.github/workflows/ci.yml @@ -31,16 +31,16 @@ jobs: build-ubuntu-latest-minimal-clang: runs-on: ubuntu-latest env: - CC: clang-15 + CC: clang-16 steps: - uses: actions/checkout@v3 - name: install clang repo run: | wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key 2>/dev/null | sudo apt-key add - - sudo add-apt-repository 'deb http://apt.llvm.org/focal/ llvm-toolchain-focal-15 main' -y + sudo add-apt-repository 'deb http://apt.llvm.org/focal/ llvm-toolchain-focal-16 main' -y sudo apt-get update -q - name: Install Dependencies - run: sudo apt-get install --no-install-recommends clang-15 libncursesw5-dev + run: sudo apt-get install --no-install-recommends clang-16 libncursesw5-dev - name: Bootstrap run: ./autogen.sh - name: Configure @@ -72,16 +72,16 @@ jobs: build-ubuntu-latest-full-featured-clang: runs-on: ubuntu-latest env: - CC: clang-15 + CC: clang-16 steps: - uses: actions/checkout@v3 - name: install clang repo run: | wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key 2>/dev/null | sudo apt-key add - - sudo add-apt-repository 'deb http://apt.llvm.org/focal/ llvm-toolchain-focal-15 main' -y + sudo add-apt-repository 'deb http://apt.llvm.org/focal/ llvm-toolchain-focal-16 main' -y sudo apt-get update -q - name: Install Dependencies - run: sudo apt-get install --no-install-recommends clang-15 libncursesw5-dev libhwloc-dev libnl-3-dev libnl-genl-3-dev libsensors4-dev libcap-dev + run: sudo apt-get install --no-install-recommends clang-16 libncursesw5-dev libhwloc-dev libnl-3-dev libnl-genl-3-dev libsensors4-dev libcap-dev - name: Bootstrap run: ./autogen.sh - name: Configure @@ -127,22 +127,22 @@ jobs: build-ubuntu-latest-clang-analyzer: runs-on: ubuntu-latest env: - CC: clang-15 + CC: clang-16 steps: - uses: actions/checkout@v3 - name: install clang repo run: | wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key 2>/dev/null | sudo apt-key add - - sudo add-apt-repository 'deb http://apt.llvm.org/focal/ llvm-toolchain-focal-15 main' -y + sudo add-apt-repository 'deb http://apt.llvm.org/focal/ llvm-toolchain-focal-16 main' -y sudo apt-get update -q - name: Install Dependencies - run: sudo apt-get install --no-install-recommends clang-15 clang-tools-15 libncursesw5-dev libnl-3-dev libnl-genl-3-dev libsensors4-dev libcap-dev + run: sudo apt-get install --no-install-recommends clang-16 clang-tools-16 libncursesw5-dev libnl-3-dev libnl-genl-3-dev libsensors4-dev libcap-dev - name: Bootstrap run: ./autogen.sh - name: Configure - run: scan-build-15 -analyze-headers --status-bugs ./configure --enable-debug --enable-werror --enable-openvz --enable-vserver --enable-ancient-vserver --enable-unicode --enable-delayacct --enable-sensors --enable-capabilities + run: scan-build-16 -analyze-headers --status-bugs ./configure --enable-debug --enable-werror --enable-openvz --enable-vserver --enable-ancient-vserver --enable-unicode --enable-delayacct --enable-sensors --enable-capabilities - name: Build - run: scan-build-15 -analyze-headers --status-bugs make -j"$(nproc)" + run: scan-build-16 -analyze-headers --status-bugs make -j"$(nproc)" build-macos-latest-clang: runs-on: macOS-latest diff --git a/vendor/github.com/htop-dev/htop/Action.c b/vendor/github.com/htop-dev/htop/Action.c index d6b2a1cea0..e00383c76e 100644 --- a/vendor/github.com/htop-dev/htop/Action.c +++ b/vendor/github.com/htop-dev/htop/Action.c @@ -43,7 +43,7 @@ in the source distribution for its full text. #endif -Object* Action_pickFromVector(State* st, Panel* list, int x, bool followProcess) { +Object* Action_pickFromVector(State* st, Panel* list, int x, bool follow) { MainPanel* mainPanel = st->mainPanel; Header* header = st->header; Machine* host = st->host; @@ -56,22 +56,22 @@ Object* Action_pickFromVector(State* st, Panel* list, int x, bool followProcess) Panel* panelFocus; int ch; bool unfollow = false; - int pid = followProcess ? MainPanel_selectedPid(mainPanel) : -1; - if (followProcess && host->pl->following == -1) { - host->pl->following = pid; + int row = follow ? MainPanel_selectedRow(mainPanel) : -1; + if (follow && host->activeTable->following == -1) { + host->activeTable->following = row; unfollow = true; } ScreenManager_run(scr, &panelFocus, &ch, NULL); if (unfollow) { - host->pl->following = -1; + host->activeTable->following = -1; } ScreenManager_delete(scr); Panel_move((Panel*)mainPanel, 0, y); Panel_resize((Panel*)mainPanel, COLS, LINES - y - 1); if (panelFocus == list && ch == 13) { - if (followProcess) { - const Process* selected = (const Process*)Panel_getSelected((Panel*)mainPanel); - if (selected && selected->pid == pid) + if (follow) { + const Row* selected = (const Row*)Panel_getSelected((Panel*)mainPanel); + if (selected && selected->id == row) return Panel_getSelected(list); beep(); @@ -99,7 +99,7 @@ static void Action_runSetup(State* st) { static bool changePriority(MainPanel* panel, int delta) { bool anyTagged; - bool ok = MainPanel_foreachProcess(panel, Process_changePriorityBy, (Arg) { .i = delta }, &anyTagged); + bool ok = MainPanel_foreachRow(panel, Process_rowChangePriorityBy, (Arg) { .i = delta }, &anyTagged); if (!ok) beep(); return anyTagged; @@ -121,36 +121,36 @@ bool Action_setUserOnly(const char* userName, uid_t* userId) { return false; } -static void tagAllChildren(Panel* panel, Process* parent) { +static void tagAllChildren(Panel* panel, Row* parent) { parent->tag = true; - pid_t ppid = parent->pid; + int parent_id = parent->id; for (int i = 0; i < Panel_size(panel); i++) { - Process* p = (Process*) Panel_get(panel, i); - if (!p->tag && Process_isChildOf(p, ppid)) { - tagAllChildren(panel, p); + Row* row = (Row*) Panel_get(panel, i); + if (!row->tag && Row_isChildOf(row, parent_id)) { + tagAllChildren(panel, row); } } } static bool expandCollapse(Panel* panel) { - Process* p = (Process*) Panel_getSelected(panel); - if (!p) + Row* row = (Row*) Panel_getSelected(panel); + if (!row) return false; - p->showChildren = !p->showChildren; + row->showChildren = !row->showChildren; return true; } static bool collapseIntoParent(Panel* panel) { - const Process* p = (Process*) Panel_getSelected(panel); - if (!p) + const Row* r = (Row*) Panel_getSelected(panel); + if (!r) return false; - pid_t ppid = Process_getParentPid(p); + int parent_id = Row_getGroupOrParent(r); for (int i = 0; i < Panel_size(panel); i++) { - Process* q = (Process*) Panel_get(panel, i); - if (q->pid == ppid) { - q->showChildren = false; + Row* row = (Row*) Panel_get(panel, i); + if (row->id == parent_id) { + row->showChildren = false; Panel_setSelected(panel, i); return true; } @@ -159,23 +159,34 @@ static bool collapseIntoParent(Panel* panel) { } Htop_Reaction Action_setSortKey(Settings* settings, ProcessField sortKey) { - ScreenSettings_setSortKey(settings->ss, sortKey); + ScreenSettings_setSortKey(settings->ss, (RowField) sortKey); return HTOP_REFRESH | HTOP_SAVE_SETTINGS | HTOP_UPDATE_PANELHDR | HTOP_KEEP_FOLLOWING; } // ---------------------------------------- +static bool Action_writeableProcess(State* st) { + const Settings* settings = st->host->settings; + bool readonly = Settings_isReadonly() || settings->ss->dynamic; + return !readonly; +} + +static bool Action_readableProcess(State* st) { + const Settings* settings = st->host->settings; + return !settings->ss->dynamic; +} + static Htop_Reaction actionSetSortColumn(State* st) { Htop_Reaction reaction = HTOP_OK; Panel* sortPanel = Panel_new(0, 0, 0, 0, Class(ListItem), true, FunctionBar_newEnterEsc("Sort ", "Cancel ")); Panel_setHeader(sortPanel, "Sort by"); Machine* host = st->host; Settings* settings = host->settings; - const ProcessField* fields = settings->ss->fields; + const RowField* fields = settings->ss->fields; Hashtable* dynamicColumns = settings->dynamicColumns; for (int i = 0; fields[i]; i++) { char* name = NULL; - if (fields[i] >= LAST_PROCESSFIELD) { + if (fields[i] >= ROW_DYNAMIC_FIELDS) { DynamicColumn* column = Hashtable_get(dynamicColumns, fields[i]); if (!column) continue; @@ -195,7 +206,7 @@ static Htop_Reaction actionSetSortColumn(State* st) { } Object_delete(sortPanel); - host->pl->needsSort = true; + host->activeTable->needsSort = true; return reaction | HTOP_REFRESH | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR; } @@ -262,9 +273,9 @@ static Htop_Reaction actionToggleTreeView(State* st) { ss->treeView = !ss->treeView; if (!ss->allBranchesCollapsed) - ProcessList_expandTree(host->pl); + Table_expandTree(host->activeTable); - host->pl->needsSort = true; + host->activeTable->needsSort = true; return HTOP_REFRESH | HTOP_SAVE_SETTINGS | HTOP_KEEP_FOLLOWING | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR; } @@ -282,9 +293,9 @@ static Htop_Reaction actionExpandOrCollapseAllBranches(State* st) { } ss->allBranchesCollapsed = !ss->allBranchesCollapsed; if (ss->allBranchesCollapsed) - ProcessList_collapseAllBranches(host->pl); + Table_collapseAllBranches(host->activeTable); else - ProcessList_expandTree(host->pl); + Table_expandTree(host->activeTable); return HTOP_REFRESH | HTOP_SAVE_SETTINGS; } @@ -292,7 +303,7 @@ static Htop_Reaction actionIncFilter(State* st) { Machine* host = st->host; IncSet* inc = (st->mainPanel)->inc; IncSet_activate(inc, INC_FILTER, (Panel*)st->mainPanel); - host->pl->incFilter = IncSet_filter(inc); + host->activeTable->incFilter = IncSet_filter(inc); return HTOP_REFRESH | HTOP_KEEP_FOLLOWING; } @@ -303,7 +314,7 @@ static Htop_Reaction actionIncSearch(State* st) { } static Htop_Reaction actionHigherPriority(State* st) { - if (Settings_isReadonly()) + if (!Action_writeableProcess(st)) return HTOP_OK; bool changed = changePriority(st->mainPanel, -1); @@ -311,7 +322,7 @@ static Htop_Reaction actionHigherPriority(State* st) { } static Htop_Reaction actionLowerPriority(State* st) { - if (Settings_isReadonly()) + if (!Action_writeableProcess(st)) return HTOP_OK; bool changed = changePriority(st->mainPanel, 1); @@ -321,7 +332,7 @@ static Htop_Reaction actionLowerPriority(State* st) { static Htop_Reaction actionInvertSortOrder(State* st) { Machine* host = st->host; ScreenSettings_invertSortOrder(host->settings->ss); - host->pl->needsSort = true; + host->activeTable->needsSort = true; return HTOP_REFRESH | HTOP_SAVE_SETTINGS | HTOP_KEEP_FOLLOWING | HTOP_UPDATE_PANELHDR; } @@ -345,14 +356,28 @@ static Htop_Reaction actionExpandCollapseOrSortColumn(State* st) { return st->host->settings->ss->treeView ? actionExpandOrCollapse(st) : actionSetSortColumn(st); } +static inline void setActiveScreen(Settings* settings, State* st, unsigned int ssIdx) { + assert(settings->ssIndex == ssIdx); + Machine* host = st->host; + + settings->ss = settings->screens[ssIdx]; + if (!settings->ss->table) + settings->ss->table = host->processTable; + host->activeTable = settings->ss->table; + + // set correct functionBar - readonly if requested, and/or with non-process screens + bool readonly = Settings_isReadonly() || (host->activeTable != host->processTable); + MainPanel_setFunctionBar(st->mainPanel, readonly); +} + static Htop_Reaction actionNextScreen(State* st) { Settings* settings = st->host->settings; settings->ssIndex++; if (settings->ssIndex == settings->nScreens) { settings->ssIndex = 0; } - settings->ss = settings->screens[settings->ssIndex]; - return HTOP_UPDATE_PANELHDR | HTOP_REFRESH; + setActiveScreen(settings, st, settings->ssIndex); + return HTOP_UPDATE_PANELHDR | HTOP_REFRESH | HTOP_REDRAW_BAR; } static Htop_Reaction actionPrevScreen(State* st) { @@ -362,22 +387,23 @@ static Htop_Reaction actionPrevScreen(State* st) { } else { settings->ssIndex--; } - settings->ss = settings->screens[settings->ssIndex]; - return HTOP_UPDATE_PANELHDR | HTOP_REFRESH; + setActiveScreen(settings, st, settings->ssIndex); + return HTOP_UPDATE_PANELHDR | HTOP_REFRESH | HTOP_REDRAW_BAR; } -Htop_Reaction Action_setScreenTab(Settings* settings, int x) { +Htop_Reaction Action_setScreenTab(State* st, int x) { + Settings* settings = st->host->settings; int s = 2; for (unsigned int i = 0; i < settings->nScreens; i++) { if (x < s) { return 0; } - const char* name = settings->screens[i]->name; - int len = strlen(name); + const char* tab = settings->screens[i]->heading; + int len = strlen(tab); if (x <= s + len + 1) { settings->ssIndex = i; - settings->ss = settings->screens[i]; - return HTOP_UPDATE_PANELHDR | HTOP_REFRESH; + setActiveScreen(settings, st, i); + return HTOP_UPDATE_PANELHDR | HTOP_REFRESH | HTOP_REDRAW_BAR; } s += len + 3; } @@ -389,7 +415,7 @@ static Htop_Reaction actionQuit(ATTR_UNUSED State* st) { } static Htop_Reaction actionSetAffinity(State* st) { - if (Settings_isReadonly()) + if (!Action_writeableProcess(st)) return HTOP_OK; Machine* host = st->host; @@ -397,11 +423,11 @@ static Htop_Reaction actionSetAffinity(State* st) { return HTOP_OK; #if (defined(HAVE_LIBHWLOC) || defined(HAVE_AFFINITY)) - const Process* p = (const Process*) Panel_getSelected((Panel*)st->mainPanel); - if (!p) + const Row* row = (const Row*) Panel_getSelected((Panel*)st->mainPanel); + if (!row) return HTOP_OK; - Affinity* affinity1 = Affinity_get(p, host); + Affinity* affinity1 = Affinity_rowGet(row, host); if (!affinity1) return HTOP_OK; @@ -412,7 +438,7 @@ static Htop_Reaction actionSetAffinity(State* st) { const void* set = Action_pickFromVector(st, affinityPanel, width, true); if (set) { Affinity* affinity2 = AffinityPanel_getAffinity(affinityPanel, host); - bool ok = MainPanel_foreachProcess(st->mainPanel, Affinity_set, (Arg) { .v = affinity2 }, NULL); + bool ok = MainPanel_foreachRow(st->mainPanel, Affinity_rowSet, (Arg) { .v = affinity2 }, NULL); if (!ok) beep(); Affinity_delete(affinity2); @@ -422,12 +448,11 @@ static Htop_Reaction actionSetAffinity(State* st) { #else return HTOP_OK; #endif - } #ifdef SCHEDULER_SUPPORT static Htop_Reaction actionSetSchedPolicy(State* st) { - if (Settings_isReadonly()) + if (!Action_writeableProcess(st)) return HTOP_KEEP_FOLLOWING; static int preSelectedPolicy = SCHEDULINGPANEL_INITSELECTEDPOLICY; @@ -459,7 +484,7 @@ static Htop_Reaction actionSetSchedPolicy(State* st) { SchedulingArg v = { .policy = preSelectedPolicy, .priority = preSelectedPriority }; - bool ok = MainPanel_foreachProcess(st->mainPanel, Scheduling_setPolicy, (Arg) { .v = &v }, NULL); + bool ok = MainPanel_foreachRow(st->mainPanel, Scheduling_rowSetPolicy, (Arg) { .v = &v }, NULL); if (!ok) beep(); } @@ -471,7 +496,7 @@ static Htop_Reaction actionSetSchedPolicy(State* st) { #endif /* SCHEDULER_SUPPORT */ static Htop_Reaction actionKill(State* st) { - if (Settings_isReadonly()) + if (!Action_writeableProcess(st)) return HTOP_OK; static int preSelectedSignal = SIGNALSPANEL_INITSELECTEDSIGNAL; @@ -483,7 +508,7 @@ static Htop_Reaction actionKill(State* st) { Panel_setHeader((Panel*)st->mainPanel, "Sending..."); Panel_draw((Panel*)st->mainPanel, false, true, true, State_hideFunctionBar(st)); refresh(); - MainPanel_foreachProcess(st->mainPanel, Process_sendSignal, (Arg) { .i = sgn->key }, NULL); + MainPanel_foreachRow(st->mainPanel, Process_rowSendSignal, (Arg) { .i = sgn->key }, NULL); napms(500); } Panel_delete((Object*)signalsPanel); @@ -511,7 +536,7 @@ static Htop_Reaction actionFilterByUser(State* st) { } Htop_Reaction Action_follow(State* st) { - st->host->pl->following = MainPanel_selectedPid(st->mainPanel); + st->host->activeTable->following = MainPanel_selectedRow(st->mainPanel); Panel_setSelectionColor((Panel*)st->mainPanel, PANEL_SELECTION_FOLLOW); return HTOP_KEEP_FOLLOWING; } @@ -522,13 +547,15 @@ static Htop_Reaction actionSetup(State* st) { } static Htop_Reaction actionLsof(State* st) { - if (Settings_isReadonly()) + if (!Action_writeableProcess(st)) return HTOP_OK; const Process* p = (Process*) Panel_getSelected((Panel*)st->mainPanel); if (!p) return HTOP_OK; + assert(Object_isA((const Object*) p, (const ObjectClass*) &Process_class)); + OpenFilesScreen* ofs = OpenFilesScreen_new(p); InfoScreen_run((InfoScreen*)ofs); OpenFilesScreen_delete((Object*)ofs); @@ -538,9 +565,15 @@ static Htop_Reaction actionLsof(State* st) { } static Htop_Reaction actionShowLocks(State* st) { + if (!Action_readableProcess(st)) + return HTOP_OK; + const Process* p = (Process*) Panel_getSelected((Panel*)st->mainPanel); if (!p) return HTOP_OK; + + assert(Object_isA((const Object*) p, (const ObjectClass*) &Process_class)); + ProcessLocksScreen* pls = ProcessLocksScreen_new(p); InfoScreen_run((InfoScreen*)pls); ProcessLocksScreen_delete((Object*)pls); @@ -550,13 +583,15 @@ static Htop_Reaction actionShowLocks(State* st) { } static Htop_Reaction actionStrace(State* st) { - if (Settings_isReadonly()) + if (!Action_writeableProcess(st)) return HTOP_OK; const Process* p = (Process*) Panel_getSelected((Panel*)st->mainPanel); if (!p) return HTOP_OK; + assert(Object_isA((const Object*) p, (const ObjectClass*) &Process_class)); + TraceScreen* ts = TraceScreen_new(p); bool ok = TraceScreen_forkTracer(ts); if (ok) { @@ -569,11 +604,11 @@ static Htop_Reaction actionStrace(State* st) { } static Htop_Reaction actionTag(State* st) { - Process* p = (Process*) Panel_getSelected((Panel*)st->mainPanel); - if (!p) + Row* r = (Row*) Panel_getSelected((Panel*)st->mainPanel); + if (!r) return HTOP_OK; - Process_toggleTag(p); + Row_toggleTag(r); Panel_onKey((Panel*)st->mainPanel, KEY_DOWN); return HTOP_OK; } @@ -606,6 +641,7 @@ static const struct { { .key = " u: ", .roInactive = false, .info = "show processes of a single user" }, { .key = " H: ", .roInactive = false, .info = "hide/show user process threads" }, { .key = " K: ", .roInactive = false, .info = "hide/show kernel threads" }, + { .key = " O: ", .roInactive = false, .info = "hide/show processes in containers" }, { .key = " F: ", .roInactive = false, .info = "cursor follows process" }, { .key = " + - *: ", .roInactive = false, .info = "expand/collapse tree/toggle all" }, { .key = "N P M T: ", .roInactive = false, .info = "sort by PID, CPU%, MEM% or TIME" }, @@ -763,9 +799,9 @@ static Htop_Reaction actionHelp(State* st) { for (item = 0; helpRight[item].key; item++) { attrset((helpRight[item].roInactive && readonly) ? CRT_colors[HELP_SHADOW] : CRT_colors[HELP_BOLD]); - mvaddstr(line + item, 41, helpRight[item].key); + mvaddstr(line + item, 43, helpRight[item].key); attrset((helpRight[item].roInactive && readonly) ? CRT_colors[HELP_SHADOW] : CRT_colors[DEFAULT_COLOR]); - mvaddstr(line + item, 50, helpRight[item].info); + mvaddstr(line + item, 52, helpRight[item].info); } line += MAXIMUM(leftHelpItems, item); line++; @@ -782,26 +818,31 @@ static Htop_Reaction actionHelp(State* st) { static Htop_Reaction actionUntagAll(State* st) { for (int i = 0; i < Panel_size((Panel*)st->mainPanel); i++) { - Process* p = (Process*) Panel_get((Panel*)st->mainPanel, i); - p->tag = false; + Row* row = (Row*) Panel_get((Panel*)st->mainPanel, i); + row->tag = false; } return HTOP_REFRESH; } static Htop_Reaction actionTagAllChildren(State* st) { - Process* p = (Process*) Panel_getSelected((Panel*)st->mainPanel); - if (!p) + Row* row = (Row*) Panel_getSelected((Panel*)st->mainPanel); + if (!row) return HTOP_OK; - tagAllChildren((Panel*)st->mainPanel, p); + tagAllChildren((Panel*)st->mainPanel, row); return HTOP_OK; } static Htop_Reaction actionShowEnvScreen(State* st) { + if (!Action_readableProcess(st)) + return HTOP_OK; + Process* p = (Process*) Panel_getSelected((Panel*)st->mainPanel); if (!p) return HTOP_OK; + assert(Object_isA((const Object*) p, (const ObjectClass*) &Process_class)); + EnvScreen* es = EnvScreen_new(p); InfoScreen_run((InfoScreen*)es); EnvScreen_delete((Object*)es); @@ -811,10 +852,15 @@ static Htop_Reaction actionShowEnvScreen(State* st) { } static Htop_Reaction actionShowCommandScreen(State* st) { + if (!Action_readableProcess(st)) + return HTOP_OK; + Process* p = (Process*) Panel_getSelected((Panel*)st->mainPanel); if (!p) return HTOP_OK; + assert(Object_isA((const Object*) p, (const ObjectClass*) &Process_class)); + CommandScreen* cmdScr = CommandScreen_new(p); InfoScreen_run((InfoScreen*)cmdScr); CommandScreen_delete((Object*)cmdScr); diff --git a/vendor/github.com/htop-dev/htop/Action.h b/vendor/github.com/htop-dev/htop/Action.h index 3540e93e3e..d285e1b884 100644 --- a/vendor/github.com/htop-dev/htop/Action.h +++ b/vendor/github.com/htop-dev/htop/Action.h @@ -57,7 +57,7 @@ bool Action_setUserOnly(const char* userName, uid_t* userId); Htop_Reaction Action_setSortKey(Settings* settings, ProcessField sortKey); -Htop_Reaction Action_setScreenTab(Settings* settings, int x); +Htop_Reaction Action_setScreenTab(State* st, int x); Htop_Reaction Action_follow(State* st); diff --git a/vendor/github.com/htop-dev/htop/Affinity.c b/vendor/github.com/htop-dev/htop/Affinity.c index f7c597bfc1..546975d5d3 100644 --- a/vendor/github.com/htop-dev/htop/Affinity.c +++ b/vendor/github.com/htop-dev/htop/Affinity.c @@ -12,6 +12,7 @@ in the source distribution for its full text. #include +#include "Process.h" #include "XUtils.h" #if defined(HAVE_LIBHWLOC) @@ -49,12 +50,11 @@ void Affinity_add(Affinity* this, unsigned int id) { this->used++; } - #if defined(HAVE_LIBHWLOC) -Affinity* Affinity_get(const Process* proc, Machine* host) { +static Affinity* Affinity_get(const Process* p, Machine* host) { hwloc_cpuset_t cpuset = hwloc_bitmap_alloc(); - bool ok = (hwloc_get_proc_cpubind(host->topology, proc->pid, cpuset, HTOP_HWLOC_CPUBIND_FLAG) == 0); + bool ok = (hwloc_get_proc_cpubind(host->topology, Process_getPid(p), cpuset, HTOP_HWLOC_CPUBIND_FLAG) == 0); Affinity* affinity = NULL; if (ok) { affinity = Affinity_new(host); @@ -73,22 +73,22 @@ Affinity* Affinity_get(const Process* proc, Machine* host) { return affinity; } -bool Affinity_set(Process* proc, Arg arg) { +static bool Affinity_set(Process* p, Arg arg) { Affinity* this = arg.v; hwloc_cpuset_t cpuset = hwloc_bitmap_alloc(); for (unsigned int i = 0; i < this->used; i++) { hwloc_bitmap_set(cpuset, this->cpus[i]); } - bool ok = (hwloc_set_proc_cpubind(this->host->topology, proc->pid, cpuset, HTOP_HWLOC_CPUBIND_FLAG) == 0); + bool ok = (hwloc_set_proc_cpubind(this->host->topology, Process_getPid(p), cpuset, HTOP_HWLOC_CPUBIND_FLAG) == 0); hwloc_bitmap_free(cpuset); return ok; } #elif defined(HAVE_AFFINITY) -Affinity* Affinity_get(const Process* proc, Machine* host) { +static Affinity* Affinity_get(const Process* p, Machine* host) { cpu_set_t cpuset; - bool ok = (sched_getaffinity(proc->pid, sizeof(cpu_set_t), &cpuset) == 0); + bool ok = (sched_getaffinity(Process_getPid(p), sizeof(cpu_set_t), &cpuset) == 0); if (!ok) return NULL; @@ -101,15 +101,31 @@ Affinity* Affinity_get(const Process* proc, Machine* host) { return affinity; } -bool Affinity_set(Process* proc, Arg arg) { +static bool Affinity_set(Process* p, Arg arg) { Affinity* this = arg.v; cpu_set_t cpuset; CPU_ZERO(&cpuset); for (unsigned int i = 0; i < this->used; i++) { CPU_SET(this->cpus[i], &cpuset); } - bool ok = (sched_setaffinity(proc->pid, sizeof(unsigned long), &cpuset) == 0); + bool ok = (sched_setaffinity(Process_getPid(p), sizeof(unsigned long), &cpuset) == 0); return ok; } #endif + +#if defined(HAVE_LIBHWLOC) || defined(HAVE_AFFINITY) + +bool Affinity_rowSet(Row* row, Arg arg) { + Process* p = (Process*) row; + assert(Object_isA((const Object*) p, (const ObjectClass*) &Process_class)); + return Affinity_set(p, arg); +} + +Affinity* Affinity_rowGet(const Row* row, Machine* host) { + const Process* p = (const Process*) row; + assert(Object_isA((const Object*) p, (const ObjectClass*) &Process_class)); + return Affinity_get(p, host); +} + +#endif /* HAVE_LIBHWLOC || HAVE_AFFINITY */ diff --git a/vendor/github.com/htop-dev/htop/Affinity.h b/vendor/github.com/htop-dev/htop/Affinity.h index 58d9bd733d..341b0c04ff 100644 --- a/vendor/github.com/htop-dev/htop/Affinity.h +++ b/vendor/github.com/htop-dev/htop/Affinity.h @@ -16,7 +16,7 @@ in the source distribution for its full text. #include #include "Object.h" -#include "Process.h" +#include "Row.h" #endif @@ -40,9 +40,9 @@ void Affinity_add(Affinity* this, unsigned int id); #if defined(HAVE_LIBHWLOC) || defined(HAVE_AFFINITY) -Affinity* Affinity_get(const Process* proc, Machine* host); +Affinity* Affinity_rowGet(const Row* row, Machine* host); -bool Affinity_set(Process* proc, Arg arg); +bool Affinity_rowSet(Row* row, Arg arg); #endif /* HAVE_LIBHWLOC || HAVE_AFFINITY */ diff --git a/vendor/github.com/htop-dev/htop/AvailableColumnsPanel.c b/vendor/github.com/htop-dev/htop/AvailableColumnsPanel.c index b8c09c74c0..a590bac29b 100644 --- a/vendor/github.com/htop-dev/htop/AvailableColumnsPanel.c +++ b/vendor/github.com/htop-dev/htop/AvailableColumnsPanel.c @@ -18,6 +18,7 @@ in the source distribution for its full text. #include "Hashtable.h" #include "ListItem.h" #include "Object.h" +#include "Platform.h" #include "Process.h" #include "ProvideCurses.h" #include "XUtils.h" @@ -34,8 +35,8 @@ static void AvailableColumnsPanel_delete(Object* object) { static void AvailableColumnsPanel_insert(AvailableColumnsPanel* this, int at, int key) { const char* name; - if (key >= LAST_PROCESSFIELD) - name = DynamicColumn_init(key); + if (key >= ROW_DYNAMIC_FIELDS) + name = DynamicColumn_name(key); else name = Process_fields[key].name; Panel_insert(this->columns, at, (Object*) ListItem_new(name, key)); @@ -81,42 +82,61 @@ const PanelClass AvailableColumnsPanel_class = { static void AvailableColumnsPanel_addDynamicColumn(ht_key_t key, void* value, void* data) { const DynamicColumn* column = (const DynamicColumn*) value; - Panel* super = (Panel*) data; - const char* title = column->caption ? column->caption : column->heading; - if (!title) - title = column->name; // fallback to the only mandatory field + if (column->table) /* DynamicScreen, handled differently */ + return; + AvailableColumnsPanel* this = (AvailableColumnsPanel*) data; + const char* title = column->heading ? column->heading : column->name; + const char* text = column->description ? column->description : column->caption; char description[256]; - xSnprintf(description, sizeof(description), "%s - %s", title, column->description); - Panel_add(super, (Object*) ListItem_new(description, key)); + if (text) + xSnprintf(description, sizeof(description), "%s - %s", title, text); + else + xSnprintf(description, sizeof(description), "%s", title); + Panel_add(&this->super, (Object*) ListItem_new(description, key)); } // Handle DynamicColumns entries in the AvailableColumnsPanel -static void AvailableColumnsPanel_addDynamicColumns(Panel* super, Hashtable* dynamicColumns) { +static void AvailableColumnsPanel_addDynamicColumns(AvailableColumnsPanel* this, Hashtable* dynamicColumns) { assert(dynamicColumns); - Hashtable_foreach(dynamicColumns, AvailableColumnsPanel_addDynamicColumn, super); + Hashtable_foreach(dynamicColumns, AvailableColumnsPanel_addDynamicColumn, this); } // Handle remaining Platform Meter entries in the AvailableColumnsPanel -static void AvailableColumnsPanel_addPlatformColumn(Panel* super) { +static void AvailableColumnsPanel_addPlatformColumns(AvailableColumnsPanel* this) { for (int i = 1; i < LAST_PROCESSFIELD; i++) { if (i != COMM && Process_fields[i].description) { char description[256]; xSnprintf(description, sizeof(description), "%s - %s", Process_fields[i].name, Process_fields[i].description); - Panel_add(super, (Object*) ListItem_new(description, i)); + Panel_add(&this->super, (Object*) ListItem_new(description, i)); } } } +// Handle DynamicColumns entries associated with DynamicScreens +static void AvailableColumnsPanel_addDynamicScreens(AvailableColumnsPanel* this, const char* screen) { + Platform_addDynamicScreenAvailableColumns(&this->super, screen); +} + +void AvailableColumnsPanel_fill(AvailableColumnsPanel* this, const char* dynamicScreen, Hashtable* dynamicColumns) { + Panel* super = (Panel*) this; + Panel_prune(super); + if (dynamicScreen) { + AvailableColumnsPanel_addDynamicScreens(this, dynamicScreen); + } else { + AvailableColumnsPanel_addPlatformColumns(this); + AvailableColumnsPanel_addDynamicColumns(this, dynamicColumns); + } +} + AvailableColumnsPanel* AvailableColumnsPanel_new(Panel* columns, Hashtable* dynamicColumns) { AvailableColumnsPanel* this = AllocThis(AvailableColumnsPanel); Panel* super = (Panel*) this; FunctionBar* fuBar = FunctionBar_new(AvailableColumnsFunctions, NULL, NULL); Panel_init(super, 1, 1, 1, 1, Class(ListItem), true, fuBar); - Panel_setHeader(super, "Available Columns"); - AvailableColumnsPanel_addPlatformColumn(super); - AvailableColumnsPanel_addDynamicColumns(super, dynamicColumns); this->columns = columns; + AvailableColumnsPanel_fill(this, NULL, dynamicColumns); + return this; } diff --git a/vendor/github.com/htop-dev/htop/AvailableColumnsPanel.h b/vendor/github.com/htop-dev/htop/AvailableColumnsPanel.h index aca59060df..3d233be09e 100644 --- a/vendor/github.com/htop-dev/htop/AvailableColumnsPanel.h +++ b/vendor/github.com/htop-dev/htop/AvailableColumnsPanel.h @@ -9,6 +9,7 @@ in the source distribution for its full text. #include "Hashtable.h" #include "Panel.h" +#include "Settings.h" typedef struct AvailableColumnsPanel_ { @@ -20,4 +21,6 @@ extern const PanelClass AvailableColumnsPanel_class; AvailableColumnsPanel* AvailableColumnsPanel_new(Panel* columns, Hashtable* dynamicColumns); +void AvailableColumnsPanel_fill(AvailableColumnsPanel* this, const char* dynamicScreen, Hashtable* dynamicColumns); + #endif diff --git a/vendor/github.com/htop-dev/htop/BatteryMeter.c b/vendor/github.com/htop-dev/htop/BatteryMeter.c index 33d17b7343..24b2e6825f 100644 --- a/vendor/github.com/htop-dev/htop/BatteryMeter.c +++ b/vendor/github.com/htop-dev/htop/BatteryMeter.c @@ -12,6 +12,7 @@ This meter written by Ian P. Hands (iphands@gmail.com, ihands@redhat.com). #include #include "CRT.h" +#include "Macros.h" #include "Object.h" #include "Platform.h" #include "XUtils.h" @@ -27,7 +28,7 @@ static void BatteryMeter_updateValues(Meter* this) { Platform_getBattery(&percent, &isOnAC); - if (isnan(percent)) { + if (!isNonnegative(percent)) { this->values[0] = NAN; xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "N/A"); return; diff --git a/vendor/github.com/htop-dev/htop/CPUMeter.c b/vendor/github.com/htop-dev/htop/CPUMeter.c index a946aa7d72..c12bb72c67 100644 --- a/vendor/github.com/htop-dev/htop/CPUMeter.c +++ b/vendor/github.com/htop-dev/htop/CPUMeter.c @@ -9,11 +9,11 @@ in the source distribution for its full text. #include "CPUMeter.h" -#include #include #include #include "CRT.h" +#include "Macros.h" #include "Object.h" #include "Platform.h" #include "ProcessList.h" @@ -71,7 +71,7 @@ static void CPUMeter_updateValues(Meter* this) { } double percent = Platform_setCPUValues(this, cpu); - if (isnan(percent)) { + if (!isNonnegative(percent)) { xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "offline"); return; } @@ -86,17 +86,17 @@ static void CPUMeter_updateValues(Meter* this) { if (settings->showCPUFrequency) { double cpuFrequency = this->values[CPU_METER_FREQUENCY]; - if (isnan(cpuFrequency)) { - xSnprintf(cpuFrequencyBuffer, sizeof(cpuFrequencyBuffer), "N/A"); - } else { + if (isNonnegative(cpuFrequency)) { xSnprintf(cpuFrequencyBuffer, sizeof(cpuFrequencyBuffer), "%4uMHz", (unsigned)cpuFrequency); + } else { + xSnprintf(cpuFrequencyBuffer, sizeof(cpuFrequencyBuffer), "N/A"); } } #ifdef BUILD_WITH_CPU_TEMP if (settings->showCPUTemperature) { double cpuTemperature = this->values[CPU_METER_TEMPERATURE]; - if (isnan(cpuTemperature)) + if (isNaN(cpuTemperature)) xSnprintf(cpuTemperatureBuffer, sizeof(cpuTemperatureBuffer), "N/A"); else if (settings->degreeFahrenheit) xSnprintf(cpuTemperatureBuffer, sizeof(cpuTemperatureBuffer), "%3d%sF", (int)(cpuTemperature * 9 / 5 + 32), CRT_degreeSign); @@ -146,12 +146,12 @@ static void CPUMeter_display(const Object* cast, RichString* out) { len = xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_SOFTIRQ]); RichString_appendAscii(out, CRT_colors[METER_TEXT], "si:"); RichString_appendnAscii(out, CRT_colors[CPU_SOFTIRQ], buffer, len); - if (!isnan(this->values[CPU_METER_STEAL])) { + if (isNonnegative(this->values[CPU_METER_STEAL])) { len = xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_STEAL]); RichString_appendAscii(out, CRT_colors[METER_TEXT], "st:"); RichString_appendnAscii(out, CRT_colors[CPU_STEAL], buffer, len); } - if (!isnan(this->values[CPU_METER_GUEST])) { + if (isNonnegative(this->values[CPU_METER_GUEST])) { len = xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_GUEST]); RichString_appendAscii(out, CRT_colors[METER_TEXT], "gu:"); RichString_appendnAscii(out, CRT_colors[CPU_GUEST], buffer, len); @@ -166,7 +166,7 @@ static void CPUMeter_display(const Object* cast, RichString* out) { len = xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_NICE]); RichString_appendAscii(out, CRT_colors[METER_TEXT], "low:"); RichString_appendnAscii(out, CRT_colors[CPU_NICE_TEXT], buffer, len); - if (!isnan(this->values[CPU_METER_IRQ])) { + if (isNonnegative(this->values[CPU_METER_IRQ])) { len = xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_IRQ]); RichString_appendAscii(out, CRT_colors[METER_TEXT], "vir:"); RichString_appendnAscii(out, CRT_colors[CPU_GUEST], buffer, len); @@ -176,10 +176,10 @@ static void CPUMeter_display(const Object* cast, RichString* out) { if (settings->showCPUFrequency) { char cpuFrequencyBuffer[10]; double cpuFrequency = this->values[CPU_METER_FREQUENCY]; - if (isnan(cpuFrequency)) { - len = xSnprintf(cpuFrequencyBuffer, sizeof(cpuFrequencyBuffer), "N/A "); - } else { + if (isNonnegative(cpuFrequency)) { len = xSnprintf(cpuFrequencyBuffer, sizeof(cpuFrequencyBuffer), "%4uMHz ", (unsigned)cpuFrequency); + } else { + len = xSnprintf(cpuFrequencyBuffer, sizeof(cpuFrequencyBuffer), "N/A "); } RichString_appendAscii(out, CRT_colors[METER_TEXT], "freq: "); RichString_appendnWide(out, CRT_colors[METER_VALUE], cpuFrequencyBuffer, len); @@ -189,7 +189,7 @@ static void CPUMeter_display(const Object* cast, RichString* out) { if (settings->showCPUTemperature) { char cpuTemperatureBuffer[10]; double cpuTemperature = this->values[CPU_METER_TEMPERATURE]; - if (isnan(cpuTemperature)) { + if (isNaN(cpuTemperature)) { len = xSnprintf(cpuTemperatureBuffer, sizeof(cpuTemperatureBuffer), "N/A"); } else if (settings->degreeFahrenheit) { len = xSnprintf(cpuTemperatureBuffer, sizeof(cpuTemperatureBuffer), "%5.1f%sF", cpuTemperature * 9 / 5 + 32, CRT_degreeSign); diff --git a/vendor/github.com/htop-dev/htop/CRT.c b/vendor/github.com/htop-dev/htop/CRT.c index a82fc8c1b4..05acc92ac7 100644 --- a/vendor/github.com/htop-dev/htop/CRT.c +++ b/vendor/github.com/htop-dev/htop/CRT.c @@ -21,6 +21,7 @@ in the source distribution for its full text. #include "CommandLine.h" #include "ProvideCurses.h" +#include "ProvideTerm.h" #include "XUtils.h" #if !defined(NDEBUG) && defined(HAVE_MEMFD_CREATE) @@ -215,7 +216,7 @@ static int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = { [ZFS_OTHER] = ColorPair(Magenta, Black), [ZFS_COMPRESSED] = A_BOLD | ColorPair(Blue, Black), [ZFS_RATIO] = ColorPair(Magenta, Black), - [ZRAM_COMPRESSED] = ColorPair(Blue, Black), + [ZRAM_COMPRESSED] = A_BOLD | ColorPair(Blue, Black), [ZRAM_UNCOMPRESSED] = ColorPair(Yellow, Black), [DYNAMIC_GRAY] = ColorPairGrayBlack, [DYNAMIC_DARKGRAY] = A_BOLD | ColorPairGrayBlack, @@ -793,6 +794,8 @@ static int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = { [COLORSCHEME_BROKENGRAY] = { 0 } // dynamically generated. }; +static bool CRT_retainScreenOnExit = false; + int CRT_scrollHAmount = 5; int CRT_scrollWheelVAmount = 10; @@ -951,8 +954,19 @@ void CRT_setMouse(bool enabled) { } #endif -void CRT_init(const Settings* settings, bool allowUnicode) { +void CRT_init(const Settings* settings, bool allowUnicode, bool retainScreenOnExit) { initscr(); + + if (retainScreenOnExit) { + CRT_retainScreenOnExit = true; + refresh(); + tputs(exit_ca_mode, 0, putchar); + tputs(clear_screen, 0, putchar); + fflush(stdout); + enter_ca_mode = 0; + exit_ca_mode = 0; + } + redirectStderr(); noecho(); CRT_crashSettings = settings; @@ -1056,6 +1070,10 @@ void CRT_done(void) { attroff(resetColor); refresh(); + if (CRT_retainScreenOnExit) { + mvcur(-1, -1, LINES - 1, 0); + } + curs_set(1); endwin(); diff --git a/vendor/github.com/htop-dev/htop/CRT.h b/vendor/github.com/htop-dev/htop/CRT.h index ae78c9c508..f5fd945270 100644 --- a/vendor/github.com/htop-dev/htop/CRT.h +++ b/vendor/github.com/htop-dev/htop/CRT.h @@ -197,7 +197,7 @@ void CRT_setMouse(bool enabled); #define CRT_setMouse(enabled) #endif -void CRT_init(const Settings* settings, bool allowUnicode); +void CRT_init(const Settings* settings, bool allowUnicode, bool retainScreenOnExit); void CRT_done(void); diff --git a/vendor/github.com/htop-dev/htop/CategoriesPanel.c b/vendor/github.com/htop-dev/htop/CategoriesPanel.c index ba7ee50307..31c7da0546 100644 --- a/vendor/github.com/htop-dev/htop/CategoriesPanel.c +++ b/vendor/github.com/htop-dev/htop/CategoriesPanel.c @@ -25,6 +25,7 @@ in the source distribution for its full text. #include "Object.h" #include "ProvideCurses.h" #include "ScreensPanel.h" +#include "ScreenTabsPanel.h" #include "Vector.h" #include "XUtils.h" @@ -72,11 +73,21 @@ static void CategoriesPanel_makeColorsPage(CategoriesPanel* this) { ScreenManager_add(this->scr, colors, -1); } +#if defined(HTOP_PCP) /* all platforms supporting dynamic screens */ +static void CategoriesPanel_makeScreenTabsPage(CategoriesPanel* this) { + Settings* settings = this->host->settings; + Panel* screenTabs = (Panel*) ScreenTabsPanel_new(settings); + Panel* screenNames = (Panel*) ((ScreenTabsPanel*)screenTabs)->names; + ScreenManager_add(this->scr, screenTabs, 20); + ScreenManager_add(this->scr, screenNames, -1); +} +#endif + static void CategoriesPanel_makeScreensPage(CategoriesPanel* this) { Settings* settings = this->host->settings; Panel* screens = (Panel*) ScreensPanel_new(settings); Panel* columns = (Panel*) ((ScreensPanel*)screens)->columns; - Panel* availableColumns = (Panel*) AvailableColumnsPanel_new(columns, settings->dynamicColumns); + Panel* availableColumns = (Panel*) ((ScreensPanel*)screens)->availableColumns; ScreenManager_add(this->scr, screens, 20); ScreenManager_add(this->scr, columns, 20); ScreenManager_add(this->scr, availableColumns, -1); @@ -94,10 +105,13 @@ typedef struct CategoriesPanelPage_ { CategoriesPanel_makePageFunc ctor; } CategoriesPanelPage; -static const CategoriesPanelPage categoriesPanelPages[] = { +static CategoriesPanelPage categoriesPanelPages[] = { { .name = "Display options", .ctor = CategoriesPanel_makeDisplayOptionsPage }, { .name = "Header layout", .ctor = CategoriesPanel_makeHeaderOptionsPage }, { .name = "Meters", .ctor = CategoriesPanel_makeMetersPage }, +#if defined(HTOP_PCP) /* all platforms supporting dynamic screens */ + { .name = "Screen tabs", .ctor = CategoriesPanel_makeScreenTabsPage }, +#endif { .name = "Screens", .ctor = CategoriesPanel_makeScreensPage }, { .name = "Colors", .ctor = CategoriesPanel_makeColorsPage }, }; diff --git a/vendor/github.com/htop-dev/htop/ColumnsPanel.c b/vendor/github.com/htop-dev/htop/ColumnsPanel.c index d53fff258c..e3445a0008 100644 --- a/vendor/github.com/htop-dev/htop/ColumnsPanel.c +++ b/vendor/github.com/htop-dev/htop/ColumnsPanel.c @@ -128,9 +128,8 @@ static void ColumnsPanel_add(Panel* super, unsigned int key, Hashtable* columns) if (!column) { name = NULL; } else { - name = column->caption ? column->caption : column->heading; - if (!name) - name = column->name; /* name is a mandatory field */ + /* heading preferred here but name is always available */ + name = column->heading ? column->heading : column->name; } } if (name == NULL) @@ -141,7 +140,7 @@ static void ColumnsPanel_add(Panel* super, unsigned int key, Hashtable* columns) void ColumnsPanel_fill(ColumnsPanel* this, ScreenSettings* ss, Hashtable* columns) { Panel* super = (Panel*) this; Panel_prune(super); - for (const ProcessField* fields = ss->fields; *fields; fields++) + for (const RowField* fields = ss->fields; *fields; fields++) ColumnsPanel_add(super, *fields, columns); this->ss = ss; } diff --git a/vendor/github.com/htop-dev/htop/CommandLine.c b/vendor/github.com/htop-dev/htop/CommandLine.c index 8095fa8f8c..2cd905161d 100644 --- a/vendor/github.com/htop-dev/htop/CommandLine.c +++ b/vendor/github.com/htop-dev/htop/CommandLine.c @@ -25,6 +25,7 @@ in the source distribution for its full text. #include "CRT.h" #include "DynamicColumn.h" #include "DynamicMeter.h" +#include "DynamicScreen.h" #include "Hashtable.h" #include "Header.h" #include "IncSet.h" @@ -57,7 +58,8 @@ static void printHelpFlag(const char* name) { #ifdef HAVE_GETMOUSE printf("-M --no-mouse Disable the mouse\n"); #endif - printf("-p --pid=PID[,PID,PID...] Show only the given PIDs\n" + printf("-n --max-iterations=NUMBER Exit htop after NUMBER iterations/frame updates\n" + "-p --pid=PID[,PID,PID...] Show only the given PIDs\n" " --readonly Disable all system and process changing features\n" "-s --sort-key=COLUMN Sort by COLUMN in list view (try --sort-key=help for a list)\n" "-t --tree Show the tree view (can be combined with -s)\n" @@ -78,6 +80,7 @@ typedef struct CommandLineSettings_ { uid_t userId; int sortKey; int delay; + int iterationsRemaining; bool useColors; #ifdef HAVE_GETMOUSE bool enableMouse; @@ -97,6 +100,7 @@ static CommandLineStatus parseArguments(int argc, char** argv, CommandLineSettin .userId = (uid_t)-1, // -1 is guaranteed to be an invalid uid_t (see setreuid(2)) .sortKey = 0, .delay = -1, + .iterationsRemaining = -1, .useColors = true, #ifdef HAVE_GETMOUSE .enableMouse = true, @@ -113,6 +117,7 @@ static CommandLineStatus parseArguments(int argc, char** argv, CommandLineSettin {"help", no_argument, 0, 'h'}, {"version", no_argument, 0, 'V'}, {"delay", required_argument, 0, 'd'}, + {"max-iterations", required_argument, 0, 'n'}, {"sort-key", required_argument, 0, 's'}, {"user", optional_argument, 0, 'u'}, {"no-color", no_argument, 0, 'C'}, @@ -130,7 +135,7 @@ static CommandLineStatus parseArguments(int argc, char** argv, CommandLineSettin int opt, opti = 0; /* Parse arguments */ - while ((opt = getopt_long(argc, argv, "hVMCs:td:u::Up:F:H::", long_opts, &opti))) { + while ((opt = getopt_long(argc, argv, "hVMCs:td:n:u::Up:F:H::", long_opts, &opti))) { if (opt == EOF) break; switch (opt) { @@ -176,6 +181,17 @@ static CommandLineStatus parseArguments(int argc, char** argv, CommandLineSettin return STATUS_ERROR_EXIT; } break; + case 'n': + if (sscanf(optarg, "%16d", &flags->iterationsRemaining) == 1) { + if (flags->iterationsRemaining <= 0) { + fprintf(stderr, "Error: maximum iteration count must be positive.\n"); + return STATUS_ERROR_EXIT; + } + } else { + fprintf(stderr, "Error: invalid maximum iteration count \"%s\".\n", optarg); + return STATUS_ERROR_EXIT; + } + break; case 'u': { const char* username = optarg; @@ -288,11 +304,11 @@ static void CommandLine_delay(Machine* host, unsigned long millisec) { } static void setCommFilter(State* state, char** commFilter) { - ProcessList* pl = state->host->pl; + Table* table = state->host->activeTable; IncSet* inc = state->mainPanel->inc; IncSet_setFilter(inc, *commFilter); - pl->incFilter = IncSet_filter(inc); + table->incFilter = IncSet_filter(inc); free(*commFilter); *commFilter = NULL; @@ -319,20 +335,15 @@ int CommandLine_run(int argc, char** argv) { if (!Platform_init()) return 1; - Process_setupColumnWidths(); - UsersTable* ut = UsersTable_new(); Hashtable* dm = DynamicMeters_new(); Hashtable* dc = DynamicColumns_new(); - if (!dc) - dc = Hashtable_new(0, true); + Hashtable* ds = DynamicScreens_new(); Machine* host = Machine_new(ut, flags.userId); ProcessList* pl = ProcessList_new(host, flags.pidMatchList); - Settings* settings = Settings_new(host->activeCPUs, dm, dc); - - host->settings = settings; - Machine_addList(host, pl); + Settings* settings = Settings_new(host->activeCPUs, dm, dc, ds); + Machine_populateTablesFromSettings(host, settings, &pl->super); Header* header = Header_new(host, 2); Header_populateFromSettings(header); @@ -360,10 +371,11 @@ int CommandLine_run(int argc, char** argv) { ScreenSettings_setSortKey(settings->ss, flags.sortKey); } - CRT_init(settings, flags.allowUnicode); + host->iterationsRemaining = flags.iterationsRemaining; + CRT_init(settings, flags.allowUnicode, flags.iterationsRemaining != -1); MainPanel* panel = MainPanel_new(); - ProcessList_setPanel(pl, (Panel*) panel); + Machine_setTablesPanel(host, (Panel*) panel); MainPanel_updateLabels(panel, settings->ss->treeView, flags.commFilter); @@ -384,13 +396,13 @@ int CommandLine_run(int argc, char** argv) { ScreenManager_add(scr, (Panel*) panel, -1); Machine_scan(host); - ProcessList_scan(pl); + Machine_scanTables(host); CommandLine_delay(host, 75); Machine_scan(host); - ProcessList_scan(pl); + Machine_scanTables(host); if (settings->ss->allBranchesCollapsed) - ProcessList_collapseAllBranches(pl); + Table_collapseAllBranches(&pl->super); ScreenManager_run(scr, NULL, NULL, NULL); @@ -405,7 +417,6 @@ int CommandLine_run(int argc, char** argv) { } Header_delete(header); - ProcessList_delete(pl); Machine_delete(host); ScreenManager_delete(scr); @@ -422,6 +433,7 @@ int CommandLine_run(int argc, char** argv) { Settings_delete(settings); DynamicColumns_delete(dc); DynamicMeters_delete(dm); + DynamicScreens_delete(ds); return 0; } diff --git a/vendor/github.com/htop-dev/htop/CommandScreen.c b/vendor/github.com/htop-dev/htop/CommandScreen.c index 6a87d13750..ecd823bdf1 100644 --- a/vendor/github.com/htop-dev/htop/CommandScreen.c +++ b/vendor/github.com/htop-dev/htop/CommandScreen.c @@ -46,7 +46,7 @@ static void CommandScreen_scan(InfoScreen* this) { } static void CommandScreen_draw(InfoScreen* this) { - InfoScreen_drawTitled(this, "Command of process %d - %s", this->process->pid, Process_getCommand(this->process)); + InfoScreen_drawTitled(this, "Command of process %d - %s", Process_getPid(this->process), Process_getCommand(this->process)); } const InfoScreenClass CommandScreen_class = { diff --git a/vendor/github.com/htop-dev/htop/DisplayOptionsPanel.c b/vendor/github.com/htop-dev/htop/DisplayOptionsPanel.c index f9fa9b12b3..e74409fc22 100644 --- a/vendor/github.com/htop-dev/htop/DisplayOptionsPanel.c +++ b/vendor/github.com/htop-dev/htop/DisplayOptionsPanel.c @@ -104,7 +104,7 @@ DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager* #define TABMSG "For current screen tab: \0" char tabheader[sizeof(TABMSG) + SCREEN_NAME_LEN + 1] = TABMSG; - strncat(tabheader, settings->ss->name, SCREEN_NAME_LEN); + strncat(tabheader, settings->ss->heading, SCREEN_NAME_LEN); Panel_add(super, (Object*) TextItem_new(tabheader)); #undef TABMSG diff --git a/vendor/github.com/htop-dev/htop/DynamicColumn.c b/vendor/github.com/htop-dev/htop/DynamicColumn.c index bd038df4e5..7c0ed3ad11 100644 --- a/vendor/github.com/htop-dev/htop/DynamicColumn.c +++ b/vendor/github.com/htop-dev/htop/DynamicColumn.c @@ -19,7 +19,10 @@ in the source distribution for its full text. Hashtable* DynamicColumns_new(void) { - return Platform_dynamicColumns(); + Hashtable* dynamics = Platform_dynamicColumns(); + if (!dynamics) + dynamics = Hashtable_new(0, true); + return dynamics; } void DynamicColumns_delete(Hashtable* dynamics) { @@ -29,8 +32,14 @@ void DynamicColumns_delete(Hashtable* dynamics) { } } -const char* DynamicColumn_init(unsigned int key) { - return Platform_dynamicColumnInit(key); +const char* DynamicColumn_name(unsigned int key) { + return Platform_dynamicColumnName(key); +} + +void DynamicColumn_done(DynamicColumn* this) { + free(this->heading); + free(this->caption); + free(this->description); } typedef struct { diff --git a/vendor/github.com/htop-dev/htop/DynamicColumn.h b/vendor/github.com/htop-dev/htop/DynamicColumn.h index 4760e6ea5d..3b0336a9bb 100644 --- a/vendor/github.com/htop-dev/htop/DynamicColumn.h +++ b/vendor/github.com/htop-dev/htop/DynamicColumn.h @@ -1,29 +1,40 @@ #ifndef HEADER_DynamicColumn #define HEADER_DynamicColumn +/* +htop - DynamicColumn.h +(C) 2023 htop dev team +Released under the GNU GPLv2+, see the COPYING file +in the source distribution for its full text. +*/ #include #include "Hashtable.h" #include "Process.h" #include "RichString.h" +#include "Table.h" -#define DYNAMIC_MAX_COLUMN_WIDTH 28 +#define DYNAMIC_MAX_COLUMN_WIDTH 64 #define DYNAMIC_DEFAULT_COLUMN_WIDTH -5 typedef struct DynamicColumn_ { - char name[32]; /* unique, internal-only name */ - char* heading; /* displayed in main screen */ - char* caption; /* displayed in setup menu (short name) */ - char* description; /* displayed in setup menu (detail) */ - int width; /* display width +/- for value alignment */ + char name[32]; /* unique, internal-only name */ + char* heading; /* displayed in main screen */ + char* caption; /* displayed in setup menu (short name) */ + char* description; /* displayed in setup menu (detail) */ + int width; /* display width +/- for value alignment */ + bool enabled; /* false == ignore this column (until enabled) */ + Table* table; /* pointer to DynamicScreen or ProcessList */ } DynamicColumn; Hashtable* DynamicColumns_new(void); void DynamicColumns_delete(Hashtable* dynamics); -const char* DynamicColumn_init(unsigned int key); +const char* DynamicColumn_name(unsigned int key); + +void DynamicColumn_done(DynamicColumn* this); const DynamicColumn* DynamicColumn_lookup(Hashtable* dynamics, unsigned int key); diff --git a/vendor/github.com/htop-dev/htop/DynamicScreen.c b/vendor/github.com/htop-dev/htop/DynamicScreen.c new file mode 100644 index 0000000000..35eb4ee69d --- /dev/null +++ b/vendor/github.com/htop-dev/htop/DynamicScreen.c @@ -0,0 +1,65 @@ +/* +htop - DynamicScreen.c +(C) 2022 Sohaib Mohammed +(C) 2022-2023 htop dev team +Released under the GNU GPLv2+, see the COPYING file +in the source distribution for its full text. +*/ + +#include "DynamicScreen.h" + +#include +#include + +#include "Hashtable.h" +#include "Platform.h" +#include "XUtils.h" + + +Hashtable* DynamicScreens_new(void) { + return Platform_dynamicScreens(); +} + +void DynamicScreens_delete(Hashtable* screens) { + if (screens) { + Platform_dynamicScreensDone(screens); + Hashtable_delete(screens); + } +} + +void DynamicScreen_done(DynamicScreen* this) { + free(this->caption); + free(this->fields); + free(this->heading); + free(this->sortKey); + free(this->columnKeys); +} + +typedef struct { + ht_key_t key; + const char* name; + bool found; +} DynamicIterator; + +static void DynamicScreen_compare(ht_key_t key, void* value, void* data) { + const DynamicScreen* screen = (const DynamicScreen*)value; + DynamicIterator* iter = (DynamicIterator*)data; + if (String_eq(iter->name, screen->name)) { + iter->found = true; + iter->key = key; + } +} + +bool DynamicScreen_search(Hashtable* screens, const char* name, ht_key_t* key) { + DynamicIterator iter = { .key = 0, .name = name, .found = false }; + if (screens) + Hashtable_foreach(screens, DynamicScreen_compare, &iter); + if (key) + *key = iter.key; + return iter.found; +} + +const char* DynamicScreen_lookup(Hashtable* screens, ht_key_t key) { + const DynamicScreen* screen = Hashtable_get(screens, key); + return screen ? screen->name : NULL; +} diff --git a/vendor/github.com/htop-dev/htop/DynamicScreen.h b/vendor/github.com/htop-dev/htop/DynamicScreen.h new file mode 100644 index 0000000000..76b3d428b0 --- /dev/null +++ b/vendor/github.com/htop-dev/htop/DynamicScreen.h @@ -0,0 +1,39 @@ +#ifndef HEADER_DynamicScreen +#define HEADER_DynamicScreen +/* +htop - DynamicColumn.h +(C) 2023 htop dev team +Released under the GNU GPLv2+, see the COPYING file +in the source distribution for its full text. +*/ + +#include + +#include "Hashtable.h" +#include "Panel.h" +#include "Settings.h" + + +typedef struct DynamicScreen_ { + char name[32]; /* unique name cannot contain any spaces */ + char* heading; /* user-settable more readable name */ + char* caption; /* explanatory text for screen */ + char* fields; + char* sortKey; + char* columnKeys; + int direction; +} DynamicScreen; + +Hashtable* DynamicScreens_new(void); + +void DynamicScreens_delete(Hashtable* dynamics); + +void DynamicScreen_done(DynamicScreen* this); + +void DynamicScreens_addAvailableColumns(Panel* availableColumns, char* screen); + +const char* DynamicScreen_lookup(Hashtable* screens, unsigned int key); + +bool DynamicScreen_search(Hashtable* screens, const char* name, unsigned int* key); + +#endif diff --git a/vendor/github.com/htop-dev/htop/EnvScreen.c b/vendor/github.com/htop-dev/htop/EnvScreen.c index 0fcee83a20..b27155e67b 100644 --- a/vendor/github.com/htop-dev/htop/EnvScreen.c +++ b/vendor/github.com/htop-dev/htop/EnvScreen.c @@ -24,7 +24,7 @@ void EnvScreen_delete(Object* this) { } static void EnvScreen_draw(InfoScreen* this) { - InfoScreen_drawTitled(this, "Environment of process %d - %s", this->process->pid, Process_getCommand(this->process)); + InfoScreen_drawTitled(this, "Environment of process %d - %s", Process_getPid(this->process), Process_getCommand(this->process)); } static void EnvScreen_scan(InfoScreen* this) { @@ -33,7 +33,7 @@ static void EnvScreen_scan(InfoScreen* this) { Panel_prune(panel); - char* env = Platform_getProcessEnv(this->process->pid); + char* env = Platform_getProcessEnv(Process_getPid(this->process)); if (env) { for (const char* p = env; *p; p = strrchr(p, 0) + 1) InfoScreen_addLine(this, p); diff --git a/vendor/github.com/htop-dev/htop/FileDescriptorMeter.c b/vendor/github.com/htop-dev/htop/FileDescriptorMeter.c index 2d939d66db..92dc99ae33 100644 --- a/vendor/github.com/htop-dev/htop/FileDescriptorMeter.c +++ b/vendor/github.com/htop-dev/htop/FileDescriptorMeter.c @@ -12,6 +12,7 @@ in the source distribution for its full text. #include #include "CRT.h" +#include "Macros.h" #include "Meter.h" #include "Object.h" #include "Platform.h" @@ -19,7 +20,7 @@ in the source distribution for its full text. #include "XUtils.h" -#define FD_EFFECTIVE_UNLIMITED(x) ((x) > (1<<30)) +#define FD_EFFECTIVE_UNLIMITED(x) (!isgreaterequal((double)(1<<30), (x))) static const int FileDescriptorMeter_attributes[] = { FILE_DESCRIPTOR_USED, @@ -67,9 +68,9 @@ static void FileDescriptorMeter_updateValues(Meter* this) { } } - if (isnan(this->values[0])) { + if (!isNonnegative(this->values[0])) { xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "unknown/unknown"); - } else if (isnan(this->values[1]) || FD_EFFECTIVE_UNLIMITED(this->values[1])) { + } else if (FD_EFFECTIVE_UNLIMITED(this->values[1])) { xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "%.0lf/unlimited", this->values[0]); } else { xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "%.0lf/%.0lf", this->values[0], this->values[1]); @@ -81,7 +82,7 @@ static void FileDescriptorMeter_display(const Object* cast, RichString* out) { char buffer[50]; int len; - if (isnan(this->values[0])) { + if (!isNonnegative(this->values[0])) { RichString_appendAscii(out, CRT_colors[METER_TEXT], "unknown"); return; } @@ -91,7 +92,7 @@ static void FileDescriptorMeter_display(const Object* cast, RichString* out) { RichString_appendnAscii(out, CRT_colors[FILE_DESCRIPTOR_USED], buffer, len); RichString_appendAscii(out, CRT_colors[METER_TEXT], " max: "); - if (isnan(this->values[1]) || FD_EFFECTIVE_UNLIMITED(this->values[1])) { + if (FD_EFFECTIVE_UNLIMITED(this->values[1])) { RichString_appendAscii(out, CRT_colors[FILE_DESCRIPTOR_MAX], "unlimited"); } else { len = xSnprintf(buffer, sizeof(buffer), "%.0lf", this->values[1]); diff --git a/vendor/github.com/htop-dev/htop/Machine.c b/vendor/github.com/htop-dev/htop/Machine.c index 63a996ef50..c7b98c9fa2 100644 --- a/vendor/github.com/htop-dev/htop/Machine.c +++ b/vendor/github.com/htop-dev/htop/Machine.c @@ -15,6 +15,7 @@ in the source distribution for its full text. #include "Hashtable.h" #include "Macros.h" #include "Platform.h" +#include "Row.h" #include "XUtils.h" @@ -22,6 +23,11 @@ void Machine_init(Machine* this, UsersTable* usersTable, uid_t userId) { this->usersTable = usersTable; this->userId = userId; + this->htopUserId = getuid(); + + // discover fixed column width limits + Row_setPidColumnWidth(Platform_getMaxPid()); + // always maintain valid realtime timestamps Platform_gettime_realtime(&this->realtime, &this->realtimeMs); @@ -49,12 +55,70 @@ void Machine_done(Machine* this) { if (this->topologyOk) { hwloc_topology_destroy(this->topology); } -#else - (void)this; #endif + Object_delete(this->processTable); + free(this->tables); +} + +static void Machine_addTable(Machine* this, Table* table) { + /* check that this table has not been seen previously */ + for (size_t i = 0; i < this->tableCount; i++) + if (this->tables[i] == table) + return; + + size_t nmemb = this->tableCount + 1; + Table** tables = xReallocArray(this->tables, nmemb, sizeof(Table*)); + tables[nmemb - 1] = table; + this->tables = tables; + this->tableCount++; } -void Machine_addList(Machine* this, struct ProcessList_ *pl) { - // currently only process lists are supported - this->pl = pl; +void Machine_populateTablesFromSettings(Machine* this, Settings* settings, Table* processTable) { + this->settings = settings; + this->processTable = processTable; + + for (size_t i = 0; i < settings->nScreens; i++) { + ScreenSettings* ss = settings->screens[i]; + Table* table = ss->table; + if (!table) + table = ss->table = processTable; + if (i == 0) + this->activeTable = table; + + Machine_addTable(this, table); + } +} + +void Machine_setTablesPanel(Machine* this, Panel* panel) { + for (size_t i = 0; i < this->tableCount; i++) { + Table_setPanel(this->tables[i], panel); + } +} + +void Machine_scanTables(Machine* this) { + // set scan timestamp + static bool firstScanDone = false; + + if (firstScanDone) + Platform_gettime_monotonic(&this->monotonicMs); + else + firstScanDone = true; + + this->maxUserId = 0; + Row_resetFieldWidths(); + + for (size_t i = 0; i < this->tableCount; i++) { + Table* table = this->tables[i]; + + // pre-processing of each row + Table_scanPrepare(table); + + // scan values for this table + Table_scanIterate(table); + + // post-process after scanning + Table_scanCleanup(table); + } + + Row_setUidColumnWidth(this->maxUserId); } diff --git a/vendor/github.com/htop-dev/htop/Machine.h b/vendor/github.com/htop-dev/htop/Machine.h index 4628d686c5..6c60050db0 100644 --- a/vendor/github.com/htop-dev/htop/Machine.h +++ b/vendor/github.com/htop-dev/htop/Machine.h @@ -17,7 +17,9 @@ in the source distribution for its full text. #include #include "Hashtable.h" +#include "Panel.h" #include "Settings.h" +#include "Table.h" #include "UsersTable.h" #include "Vector.h" @@ -37,15 +39,15 @@ in the source distribution for its full text. typedef unsigned long long int memory_t; #define MEMORY_MAX ULLONG_MAX -struct ProcessList_; - typedef struct Machine_ { - Settings* settings; + struct Settings_* settings; struct timeval realtime; /* time of the current sample */ uint64_t realtimeMs; /* current time in milliseconds */ uint64_t monotonicMs; /* same, but from monotonic clock */ + int64_t iterationsRemaining; + #ifdef HAVE_LIBHWLOC hwloc_topology_t topology; bool topologyOk; @@ -66,11 +68,14 @@ typedef struct Machine_ { unsigned int existingCPUs; UsersTable* usersTable; - uid_t userId; - - /* To become an array of lists - processes, cgroups, filesystems,... etc */ - /* for now though, just point back to the one list we have at the moment */ - struct ProcessList_ *pl; + uid_t htopUserId; + uid_t maxUserId; /* recently observed */ + uid_t userId; /* selected row user ID */ + + size_t tableCount; + Table **tables; + Table *activeTable; + Table *processTable; } Machine; @@ -84,8 +89,12 @@ void Machine_done(Machine* this); bool Machine_isCPUonline(const Machine* this, unsigned int id); -void Machine_addList(Machine* this, struct ProcessList_ *pl); +void Machine_populateTablesFromSettings(Machine* this, Settings* settings, Table* processTable); + +void Machine_setTablesPanel(Machine* host, Panel* panel); void Machine_scan(Machine* this); +void Machine_scanTables(Machine* this); + #endif diff --git a/vendor/github.com/htop-dev/htop/Macros.h b/vendor/github.com/htop-dev/htop/Macros.h index 0f95347b75..459102a37f 100644 --- a/vendor/github.com/htop-dev/htop/Macros.h +++ b/vendor/github.com/htop-dev/htop/Macros.h @@ -2,6 +2,8 @@ #define HEADER_Macros #include // IWYU pragma: keep +#include +#include #ifndef MINIMUM #define MINIMUM(a, b) ((a) < (b) ? (a) : (b)) @@ -98,6 +100,24 @@ #define IGNORE_WCASTQUAL_END #endif +/* Cheaper function for checking NaNs. Unlike the standard isnan(), this may + throw an FP exception on a "signaling" NaN. + (ISO/IEC TS 18661-1 and the C23 standard stated that isnan() throws no + exceptions even with a "signaling" NaN) */ +static inline bool isNaN(double x) { + return !isgreaterequal(x, x); +} + +/* Checks if x is nonnegative. Returns false if x is NaN. */ +static inline bool isNonnegative(double x) { + return isgreaterequal(x, 0.0); +} + +/* Checks if x is positive. Returns false if x is NaN. */ +static inline bool isPositive(double x) { + return isgreater(x, 0.0); +} + /* This subtraction is used by Linux / NetBSD / OpenBSD for calculation of CPU usage items. */ static inline unsigned long long saturatingSub(unsigned long long a, unsigned long long b) { return a > b ? a - b : 0; diff --git a/vendor/github.com/htop-dev/htop/MainPanel.c b/vendor/github.com/htop-dev/htop/MainPanel.c index 14bd3bbdf7..7ca7b20158 100644 --- a/vendor/github.com/htop-dev/htop/MainPanel.c +++ b/vendor/github.com/htop-dev/htop/MainPanel.c @@ -14,10 +14,10 @@ in the source distribution for its full text. #include "CRT.h" #include "FunctionBar.h" #include "Platform.h" -#include "Process.h" -#include "ProcessList.h" #include "ProvideCurses.h" +#include "Row.h" #include "Settings.h" +#include "Table.h" #include "XUtils.h" @@ -30,25 +30,25 @@ void MainPanel_updateLabels(MainPanel* this, bool list, bool filter) { FunctionBar_setLabel(bar, KEY_F(4), filter ? "FILTER" : "Filter"); } -static void MainPanel_pidSearch(MainPanel* this, int ch) { +static void MainPanel_idSearch(MainPanel* this, int ch) { Panel* super = (Panel*) this; - pid_t pid = ch - 48 + this->pidSearch; + pid_t id = ch - 48 + this->idSearch; for (int i = 0; i < Panel_size(super); i++) { - const Process* p = (const Process*) Panel_get(super, i); - if (p && p->pid == pid) { + const Row* row = (const Row*) Panel_get(super, i); + if (row && row->id == id) { Panel_setSelected(super, i); break; } } - this->pidSearch = pid * 10; - if (this->pidSearch > 10000000) { - this->pidSearch = 0; + this->idSearch = id * 10; + if (this->idSearch > 10000000) { + this->idSearch = 0; } } static const char* MainPanel_getValue(Panel* this, int i) { - const Process* p = (const Process*) Panel_get(this, i); - return Process_getCommand(p); + Row* row = (Row*) Panel_get(this, i); + return Row_sortKeyString(row); } static HandlerResult MainPanel_eventHandler(Panel* super, int ch) { @@ -77,7 +77,7 @@ static HandlerResult MainPanel_eventHandler(Panel* super, int ch) { if (EVENT_IS_HEADER_CLICK(ch)) { int x = EVENT_HEADER_CLICK_GET_X(ch); int hx = super->scrollH + x + 1; - ProcessField field = ProcessList_keyAt(host->pl, hx); + RowField field = RowField_keyAt(settings, hx); if (ss->treeView && ss->treeViewAlwaysByPID) { ss->treeView = false; ss->direction = 1; @@ -91,12 +91,12 @@ static HandlerResult MainPanel_eventHandler(Panel* super, int ch) { result = HANDLED; } else if (EVENT_IS_SCREEN_TAB_CLICK(ch)) { int x = EVENT_SCREEN_TAB_GET_X(ch); - reaction |= Action_setScreenTab(settings, x); + reaction |= Action_setScreenTab(this->state, x); result = HANDLED; } else if (ch != ERR && this->inc->active) { bool filterChanged = IncSet_handleKey(this->inc, ch, super, MainPanel_getValue, NULL); if (filterChanged) { - host->pl->incFilter = IncSet_filter(this->inc); + host->activeTable->incFilter = IncSet_filter(this->inc); reaction = HTOP_REFRESH | HTOP_REDRAW_BAR; } if (this->inc->found) { @@ -111,17 +111,17 @@ static HandlerResult MainPanel_eventHandler(Panel* super, int ch) { reaction |= (this->keys[ch])(this->state); result = HANDLED; } else if (0 < ch && ch < 255 && isdigit((unsigned char)ch)) { - MainPanel_pidSearch(this, ch); + MainPanel_idSearch(this, ch); } else { if (ch != ERR) { - this->pidSearch = 0; + this->idSearch = 0; } else { reaction |= HTOP_KEEP_FOLLOWING; } } if ((reaction & HTOP_REDRAW_BAR) == HTOP_REDRAW_BAR) { - MainPanel_updateLabels(this, settings->ss->treeView, host->pl->incFilter); + MainPanel_updateLabels(this, settings->ss->treeView, host->activeTable->incFilter); } if ((reaction & HTOP_RESIZE) == HTOP_RESIZE) { result |= RESIZE; @@ -142,35 +142,32 @@ static HandlerResult MainPanel_eventHandler(Panel* super, int ch) { return BREAK_LOOP; } if ((reaction & HTOP_KEEP_FOLLOWING) != HTOP_KEEP_FOLLOWING) { - host->pl->following = -1; + host->activeTable->following = -1; Panel_setSelectionColor(super, PANEL_SELECTION_FOCUS); } return result; } -int MainPanel_selectedPid(MainPanel* this) { - const Process* p = (const Process*) Panel_getSelected((Panel*)this); - if (p) { - return p->pid; - } - return -1; +int MainPanel_selectedRow(MainPanel* this) { + const Row* row = (const Row*) Panel_getSelected((Panel*)this); + return row ? row->id : -1; } -bool MainPanel_foreachProcess(MainPanel* this, MainPanel_ForeachProcessFn fn, Arg arg, bool* wasAnyTagged) { +bool MainPanel_foreachRow(MainPanel* this, MainPanel_foreachRowFn fn, Arg arg, bool* wasAnyTagged) { Panel* super = (Panel*) this; bool ok = true; bool anyTagged = false; for (int i = 0; i < Panel_size(super); i++) { - Process* p = (Process*) Panel_get(super, i); - if (p->tag) { - ok = fn(p, arg) && ok; + Row* row = (Row*) Panel_get(super, i); + if (row->tag) { + ok &= fn(row, arg); anyTagged = true; } } if (!anyTagged) { - Process* p = (Process*) Panel_getSelected(super); - if (p) { - ok &= fn(p, arg); + Row* row = (Row*) Panel_getSelected(super); + if (row) { + ok &= fn(row, arg); } } @@ -196,7 +193,7 @@ static void MainPanel_drawFunctionBar(Panel* super, bool hideFunctionBar) { static void MainPanel_printHeader(Panel* super) { MainPanel* this = (MainPanel*) super; Machine* host = this->state->host; - ProcessList_printHeader(host->pl, &super->header); + Table_printHeader(host->settings, &super->header); } const PanelClass MainPanel_class = { @@ -211,9 +208,12 @@ const PanelClass MainPanel_class = { MainPanel* MainPanel_new(void) { MainPanel* this = AllocThis(MainPanel); - Panel_init((Panel*) this, 1, 1, 1, 1, Class(Process), false, FunctionBar_new(Settings_isReadonly() ? MainFunctions_ro : MainFunctions, NULL, NULL)); + this->processBar = FunctionBar_new(MainFunctions, NULL, NULL); + this->readonlyBar = FunctionBar_new(MainFunctions_ro, NULL, NULL); + FunctionBar* activeBar = Settings_isReadonly() ? this->readonlyBar : this->processBar; + Panel_init((Panel*) this, 1, 1, 1, 1, Class(Row), false, activeBar); this->keys = xCalloc(KEY_MAX, sizeof(Htop_Action)); - this->inc = IncSet_new(MainPanel_getFunctionBar(this)); + this->inc = IncSet_new(activeBar); Action_setBindings(this->keys); Platform_setBindings(this->keys); @@ -225,9 +225,16 @@ void MainPanel_setState(MainPanel* this, State* state) { this->state = state; } +void MainPanel_setFunctionBar(MainPanel* this, bool readonly) { + this->super.defaultBar = readonly ? this->readonlyBar : this->processBar; + this->inc->defaultBar = this->super.defaultBar; +} + void MainPanel_delete(Object* object) { Panel* super = (Panel*) object; MainPanel* this = (MainPanel*) object; + MainPanel_setFunctionBar(this, false); + FunctionBar_delete(this->readonlyBar); Panel_done(super); IncSet_delete(this->inc); free(this->keys); diff --git a/vendor/github.com/htop-dev/htop/MainPanel.h b/vendor/github.com/htop-dev/htop/MainPanel.h index bd22acd0ce..19229d59fe 100644 --- a/vendor/github.com/htop-dev/htop/MainPanel.h +++ b/vendor/github.com/htop-dev/htop/MainPanel.h @@ -17,7 +17,7 @@ in the source distribution for its full text. #include "IncSet.h" #include "Object.h" #include "Panel.h" -#include "Process.h" +#include "Row.h" typedef struct MainPanel_ { @@ -25,19 +25,21 @@ typedef struct MainPanel_ { State* state; IncSet* inc; Htop_Action* keys; - pid_t pidSearch; + FunctionBar* processBar; /* function bar with process-specific actions */ + FunctionBar* readonlyBar; /* function bar without process actions (ro) */ + unsigned int idSearch; } MainPanel; -typedef bool(*MainPanel_ForeachProcessFn)(Process*, Arg); +typedef bool(*MainPanel_foreachRowFn)(Row*, Arg); #define MainPanel_getFunctionBar(this_) (((Panel*)(this_))->defaultBar) // update the Label Keys in the MainPanel bar, list: list / tree mode, filter: filter (inc) active / inactive void MainPanel_updateLabels(MainPanel* this, bool list, bool filter); -int MainPanel_selectedPid(MainPanel* this); +int MainPanel_selectedRow(MainPanel* this); -bool MainPanel_foreachProcess(MainPanel* this, MainPanel_ForeachProcessFn fn, Arg arg, bool* wasAnyTagged); +bool MainPanel_foreachRow(MainPanel* this, MainPanel_foreachRowFn fn, Arg arg, bool* wasAnyTagged); extern const PanelClass MainPanel_class; @@ -45,6 +47,8 @@ MainPanel* MainPanel_new(void); void MainPanel_setState(MainPanel* this, State* state); +void MainPanel_setFunctionBar(MainPanel* this, bool readonly); + void MainPanel_delete(Object* object); #endif diff --git a/vendor/github.com/htop-dev/htop/Makefile.am b/vendor/github.com/htop-dev/htop/Makefile.am index b25d1cb825..90bd30ef16 100644 --- a/vendor/github.com/htop-dev/htop/Makefile.am +++ b/vendor/github.com/htop-dev/htop/Makefile.am @@ -49,6 +49,7 @@ myhtopsources = \ DisplayOptionsPanel.c \ DynamicColumn.c \ DynamicMeter.c \ + DynamicScreen.c \ EnvScreen.c \ FileDescriptorMeter.c \ FunctionBar.c \ @@ -74,14 +75,17 @@ myhtopsources = \ Process.c \ ProcessList.c \ ProcessLocksScreen.c \ + Row.c \ RichString.c \ Scheduling.c \ ScreenManager.c \ ScreensPanel.c \ + ScreenTabsPanel.c \ Settings.c \ SignalsPanel.c \ SwapMeter.c \ SysArchMeter.c \ + Table.c \ TasksMeter.c \ TraceScreen.c \ UptimeMeter.c \ @@ -111,6 +115,7 @@ myhtopheaders = \ DisplayOptionsPanel.h \ DynamicColumn.h \ DynamicMeter.h \ + DynamicScreen.h \ EnvScreen.h \ FileDescriptorMeter.h \ FunctionBar.h \ @@ -139,14 +144,19 @@ myhtopheaders = \ ProcessList.h \ ProcessLocksScreen.h \ ProvideCurses.h \ + ProvideTerm.h \ RichString.h \ + Row.h \ + RowField.h \ Scheduling.h \ ScreenManager.h \ ScreensPanel.h \ + ScreenTabsPanel.h \ Settings.h \ SignalsPanel.h \ SwapMeter.h \ SysArchMeter.h \ + Table.h \ TasksMeter.h \ TraceScreen.h \ UptimeMeter.h \ @@ -402,31 +412,39 @@ endif # -------------------------- pcp_platform_headers = \ + linux/CGroupUtils.h \ linux/PressureStallMeter.h \ linux/ZramMeter.h \ linux/ZramStats.h \ + pcp/Instance.h \ + pcp/InDomTable.h \ + pcp/Metric.h \ + pcp/Platform.h \ + pcp/ProcessField.h \ pcp/PCPDynamicColumn.h \ pcp/PCPDynamicMeter.h \ + pcp/PCPDynamicScreen.h \ pcp/PCPMachine.h \ - pcp/PCPMetric.h \ pcp/PCPProcess.h \ pcp/PCPProcessList.h \ - pcp/Platform.h \ - pcp/ProcessField.h \ zfs/ZfsArcMeter.h \ zfs/ZfsArcStats.h \ zfs/ZfsCompressedArcMeter.h pcp_platform_sources = \ + linux/CGroupUtils.c \ linux/PressureStallMeter.c \ linux/ZramMeter.c \ + pcp/Instance.c \ + pcp/InDomTable.c \ + pcp/Metric.c \ + pcp/Platform.c \ pcp/PCPDynamicColumn.c \ pcp/PCPDynamicMeter.c \ + pcp/PCPDynamicScreen.c \ pcp/PCPMachine.c \ - pcp/PCPMetric.c \ pcp/PCPProcess.c \ pcp/PCPProcessList.c \ - pcp/Platform.c \ zfs/ZfsArcMeter.c \ zfs/ZfsCompressedArcMeter.c diff --git a/vendor/github.com/htop-dev/htop/MemoryMeter.c b/vendor/github.com/htop-dev/htop/MemoryMeter.c index 28c0be277f..c7d99f885f 100644 --- a/vendor/github.com/htop-dev/htop/MemoryMeter.c +++ b/vendor/github.com/htop-dev/htop/MemoryMeter.c @@ -11,6 +11,7 @@ in the source distribution for its full text. #include #include "CRT.h" +#include "Macros.h" #include "Object.h" #include "Platform.h" #include "RichString.h" @@ -42,9 +43,8 @@ static void MemoryMeter_updateValues(Meter* this) { /* we actually want to show "used + compressed" */ double used = this->values[MEMORY_METER_USED]; - if (!isnan(this->values[MEMORY_METER_COMPRESSED])) { + if (isPositive(this->values[MEMORY_METER_COMPRESSED])) used += this->values[MEMORY_METER_COMPRESSED]; - } written = Meter_humanUnit(buffer, used, size); METER_BUFFER_CHECK(buffer, size, written); @@ -71,14 +71,14 @@ static void MemoryMeter_display(const Object* cast, RichString* out) { RichString_appendAscii(out, CRT_colors[MEMORY_BUFFERS_TEXT], buffer); /* shared memory is not supported on all platforms */ - if (!isnan(this->values[MEMORY_METER_SHARED])) { + if (isNonnegative(this->values[MEMORY_METER_SHARED])) { Meter_humanUnit(buffer, this->values[MEMORY_METER_SHARED], sizeof(buffer)); RichString_appendAscii(out, CRT_colors[METER_TEXT], " shared:"); RichString_appendAscii(out, CRT_colors[MEMORY_SHARED], buffer); } /* compressed memory is not supported on all platforms */ - if (!isnan(this->values[MEMORY_METER_COMPRESSED])) { + if (isNonnegative(this->values[MEMORY_METER_COMPRESSED])) { Meter_humanUnit(buffer, this->values[MEMORY_METER_COMPRESSED], sizeof(buffer)); RichString_appendAscii(out, CRT_colors[METER_TEXT], " compressed:"); RichString_appendAscii(out, CRT_colors[MEMORY_COMPRESSED], buffer); @@ -89,7 +89,7 @@ static void MemoryMeter_display(const Object* cast, RichString* out) { RichString_appendAscii(out, CRT_colors[MEMORY_CACHE], buffer); /* available memory is not supported on all platforms */ - if (!isnan(this->values[MEMORY_METER_AVAILABLE])) { + if (isNonnegative(this->values[MEMORY_METER_AVAILABLE])) { Meter_humanUnit(buffer, this->values[MEMORY_METER_AVAILABLE], sizeof(buffer)); RichString_appendAscii(out, CRT_colors[METER_TEXT], " available:"); RichString_appendAscii(out, CRT_colors[METER_VALUE], buffer); diff --git a/vendor/github.com/htop-dev/htop/Meter.c b/vendor/github.com/htop-dev/htop/Meter.c index cf0fe36acb..5e7d3b7067 100644 --- a/vendor/github.com/htop-dev/htop/Meter.c +++ b/vendor/github.com/htop-dev/htop/Meter.c @@ -11,9 +11,9 @@ in the source distribution for its full text. #include #include +#include #include #include -#include #include "CRT.h" #include "Macros.h" @@ -219,24 +219,18 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) { assert(startPos + w <= RichString_sizeVal(bar)); int blockSizes[10]; - int blockSizeSum = 0; // First draw in the bar[] buffer... int offset = 0; for (uint8_t i = 0; i < this->curItems; i++) { double value = this->values[i]; - value = CLAMP(value, 0.0, this->total); - if (value > 0) { + if (isPositive(value)) { + assert(this->total > 0.0); + value = MINIMUM(value, this->total); blockSizes[i] = ceil((value / this->total) * w); } else { blockSizes[i] = 0; } - - if (Meter_comprisedValues(this)) { - blockSizes[i] = MAXIMUM(blockSizes[i] - blockSizeSum, 0); - blockSizeSum += blockSizes[i]; - } - int nextOffset = offset + blockSizes[i]; // (Control against invalid values) nextOffset = CLAMP(nextOffset, 0, w); @@ -330,14 +324,7 @@ static void GraphMeterMode_draw(Meter* this, int x, int y, int w) { for (int i = 0; i < nValues - 1; i++) data->values[i] = data->values[i + 1]; - if (Meter_comprisedValues(this)) { - data->values[nValues - 1] = (this->curItems > 0) ? this->values[this->curItems - 1] : 0.0; - } else { - double value = 0.0; - for (uint8_t i = 0; i < this->curItems; i++) - value += !isnan(this->values[i]) ? this->values[i] : 0; - data->values[nValues - 1] = value; - } + data->values[nValues - 1] = sumPositiveValues(this->values, this->curItems); } int i = nValues - (w * 2), k = 0; diff --git a/vendor/github.com/htop-dev/htop/Meter.h b/vendor/github.com/htop-dev/htop/Meter.h index db93e4c040..89f0570a8f 100644 --- a/vendor/github.com/htop-dev/htop/Meter.h +++ b/vendor/github.com/htop-dev/htop/Meter.h @@ -74,7 +74,6 @@ typedef struct MeterClass_ { const char* const description; /* optional meter description in header setup menu */ const uint8_t maxItems; const bool isMultiColumn; /* whether the meter draws multiple sub-columns (defaults to false) */ - const bool comprisedValues; /* whether latter values comprise previous ones (defaults to false) */ } MeterClass; #define As_Meter(this_) ((const MeterClass*)((this_)->super.klass)) @@ -95,7 +94,6 @@ typedef struct MeterClass_ { #define Meter_name(this_) As_Meter(this_)->name #define Meter_uiName(this_) As_Meter(this_)->uiName #define Meter_isMultiColumn(this_) As_Meter(this_)->isMultiColumn -#define Meter_comprisedValues(this_) As_Meter(this_)->comprisedValues typedef struct GraphData_ { struct timeval time; diff --git a/vendor/github.com/htop-dev/htop/OpenFilesScreen.c b/vendor/github.com/htop-dev/htop/OpenFilesScreen.c index 4256575cde..3077490d21 100644 --- a/vendor/github.com/htop-dev/htop/OpenFilesScreen.c +++ b/vendor/github.com/htop-dev/htop/OpenFilesScreen.c @@ -72,12 +72,12 @@ static const char* getDataForType(const OpenFiles_Data* data, char type) { } OpenFilesScreen* OpenFilesScreen_new(const Process* process) { - OpenFilesScreen* this = xMalloc(sizeof(OpenFilesScreen)); + OpenFilesScreen* this = xCalloc(1, sizeof(OpenFilesScreen)); Object_setClass(this, Class(OpenFilesScreen)); if (Process_isThread(process)) { - this->pid = process->tgid; + this->pid = Process_getThreadGroup(process); } else { - this->pid = process->pid; + this->pid = Process_getPid(process); } return (OpenFilesScreen*) InfoScreen_init(&this->super, process, NULL, LINES - 2, " FD TYPE MODE DEVICE SIZE OFFSET NODE NAME"); } @@ -252,10 +252,8 @@ static void OpenFilesScreen_scan(InfoScreen* this) { OpenFiles_FileData* fdata = pdata->files; while (fdata) { OpenFiles_Data* data = &fdata->data; - size_t lenN = strlen(getDataForType(data, 'n')); - size_t sizeEntry = 5 + 7 + 4 + 10 + 10 + 10 + 10 + lenN + 8 /*spaces*/ + 1 /*null*/; - char entry[sizeEntry]; - xSnprintf(entry, sizeof(entry), "%5.5s %-7.7s %-4.4s %-10.10s %10.10s %10.10s %10.10s %s", + char* entry = NULL; + xAsprintf(&entry, "%5.5s %-7.7s %-4.4s %-10.10s %10.10s %10.10s %10.10s %s", getDataForType(data, 'f'), getDataForType(data, 't'), getDataForType(data, 'a'), @@ -265,6 +263,7 @@ static void OpenFilesScreen_scan(InfoScreen* this) { getDataForType(data, 'i'), getDataForType(data, 'n')); InfoScreen_addLine(this, entry); + free(entry); OpenFiles_Data_clear(data); OpenFiles_FileData* old = fdata; fdata = fdata->next; diff --git a/vendor/github.com/htop-dev/htop/Process.c b/vendor/github.com/htop-dev/htop/Process.c index 43f7f70dd3..6c4fb7adc5 100644 --- a/vendor/github.com/htop-dev/htop/Process.c +++ b/vendor/github.com/htop-dev/htop/Process.c @@ -40,242 +40,15 @@ in the source distribution for its full text. /* Used to identify kernel threads in Comm and Exe columns */ static const char* const kthreadID = "KTHREAD"; -static uid_t Process_getuid = (uid_t)-1; - -int Process_pidDigits = PROCESS_MIN_PID_DIGITS; -int Process_uidDigits = PROCESS_MIN_UID_DIGITS; - -void Process_setupColumnWidths(void) { - int maxPid = Platform_getMaxPid(); - if (maxPid == -1) - return; - - if (maxPid < (int)pow(10, PROCESS_MIN_PID_DIGITS)) { - Process_pidDigits = PROCESS_MIN_PID_DIGITS; - return; - } - - Process_pidDigits = (int)log10(maxPid) + 1; - assert(Process_pidDigits <= PROCESS_MAX_PID_DIGITS); -} - -void Process_setUidColumnWidth(uid_t maxUid) { - if (maxUid < (uid_t)pow(10, PROCESS_MIN_UID_DIGITS)) { - Process_uidDigits = PROCESS_MIN_UID_DIGITS; - return; - } - - Process_uidDigits = (int)log10(maxUid) + 1; - assert(Process_uidDigits <= PROCESS_MAX_UID_DIGITS); -} - -void Process_printBytes(RichString* str, unsigned long long number, bool coloring) { - char buffer[16]; - int len; - - int largeNumberColor = coloring ? CRT_colors[LARGE_NUMBER] : CRT_colors[PROCESS]; - int processMegabytesColor = coloring ? CRT_colors[PROCESS_MEGABYTES] : CRT_colors[PROCESS]; - int processGigabytesColor = coloring ? CRT_colors[PROCESS_GIGABYTES] : CRT_colors[PROCESS]; - int shadowColor = coloring ? CRT_colors[PROCESS_SHADOW] : CRT_colors[PROCESS]; - int processColor = CRT_colors[PROCESS]; - - if (number == ULLONG_MAX) { - //Invalid number - RichString_appendAscii(str, shadowColor, " N/A "); - return; - } - - number /= ONE_K; - - if (number < 1000) { - //Plain number, no markings - len = xSnprintf(buffer, sizeof(buffer), "%5llu ", number); - RichString_appendnAscii(str, processColor, buffer, len); - } else if (number < 100000) { - //2 digit MB, 3 digit KB - len = xSnprintf(buffer, sizeof(buffer), "%2llu", number / 1000); - RichString_appendnAscii(str, processMegabytesColor, buffer, len); - number %= 1000; - len = xSnprintf(buffer, sizeof(buffer), "%03llu ", number); - RichString_appendnAscii(str, processColor, buffer, len); - } else if (number < 1000 * ONE_K) { - //3 digit MB - number /= ONE_K; - len = xSnprintf(buffer, sizeof(buffer), "%4lluM ", number); - RichString_appendnAscii(str, processMegabytesColor, buffer, len); - } else if (number < 10000 * ONE_K) { - //1 digit GB, 3 digit MB - number /= ONE_K; - len = xSnprintf(buffer, sizeof(buffer), "%1llu", number / 1000); - RichString_appendnAscii(str, processGigabytesColor, buffer, len); - number %= 1000; - len = xSnprintf(buffer, sizeof(buffer), "%03lluM ", number); - RichString_appendnAscii(str, processMegabytesColor, buffer, len); - } else if (number < 100000 * ONE_K) { - //2 digit GB, 1 digit MB - number /= 100 * ONE_K; - len = xSnprintf(buffer, sizeof(buffer), "%2llu", number / 10); - RichString_appendnAscii(str, processGigabytesColor, buffer, len); - number %= 10; - len = xSnprintf(buffer, sizeof(buffer), ".%1llu", number); - RichString_appendnAscii(str, processMegabytesColor, buffer, len); - RichString_appendAscii(str, processGigabytesColor, "G "); - } else if (number < 1000 * ONE_M) { - //3 digit GB - number /= ONE_M; - len = xSnprintf(buffer, sizeof(buffer), "%4lluG ", number); - RichString_appendnAscii(str, processGigabytesColor, buffer, len); - } else if (number < 10000ULL * ONE_M) { - //1 digit TB, 3 digit GB - number /= ONE_M; - len = xSnprintf(buffer, sizeof(buffer), "%1llu", number / 1000); - RichString_appendnAscii(str, largeNumberColor, buffer, len); - number %= 1000; - len = xSnprintf(buffer, sizeof(buffer), "%03lluG ", number); - RichString_appendnAscii(str, processGigabytesColor, buffer, len); - } else if (number < 100000 * ONE_M) { - //2 digit TB, 1 digit GB - number /= 100 * ONE_M; - len = xSnprintf(buffer, sizeof(buffer), "%2llu", number / 10); - RichString_appendnAscii(str, largeNumberColor, buffer, len); - number %= 10; - len = xSnprintf(buffer, sizeof(buffer), ".%1llu", number); - RichString_appendnAscii(str, processGigabytesColor, buffer, len); - RichString_appendAscii(str, largeNumberColor, "T "); - } else if (number < 10000ULL * ONE_G) { - //3 digit TB or 1 digit PB, 3 digit TB - number /= ONE_G; - len = xSnprintf(buffer, sizeof(buffer), "%4lluT ", number); - RichString_appendnAscii(str, largeNumberColor, buffer, len); - } else { - //2 digit PB and above - len = xSnprintf(buffer, sizeof(buffer), "%4.1lfP ", (double)number / ONE_T); - RichString_appendnAscii(str, largeNumberColor, buffer, len); - } -} - -void Process_printKBytes(RichString* str, unsigned long long number, bool coloring) { - if (number == ULLONG_MAX) - Process_printBytes(str, ULLONG_MAX, coloring); - else - Process_printBytes(str, number * ONE_K, coloring); -} - -void Process_printCount(RichString* str, unsigned long long number, bool coloring) { - char buffer[13]; - - int largeNumberColor = coloring ? CRT_colors[LARGE_NUMBER] : CRT_colors[PROCESS]; - int processMegabytesColor = coloring ? CRT_colors[PROCESS_MEGABYTES] : CRT_colors[PROCESS]; - int processColor = CRT_colors[PROCESS]; - int processShadowColor = coloring ? CRT_colors[PROCESS_SHADOW] : CRT_colors[PROCESS]; - - if (number == ULLONG_MAX) { - RichString_appendAscii(str, CRT_colors[PROCESS_SHADOW], " N/A "); - } else if (number >= 100000LL * ONE_DECIMAL_T) { - xSnprintf(buffer, sizeof(buffer), "%11llu ", number / ONE_DECIMAL_G); - RichString_appendnAscii(str, largeNumberColor, buffer, 12); - } else if (number >= 100LL * ONE_DECIMAL_T) { - xSnprintf(buffer, sizeof(buffer), "%11llu ", number / ONE_DECIMAL_M); - RichString_appendnAscii(str, largeNumberColor, buffer, 8); - RichString_appendnAscii(str, processMegabytesColor, buffer + 8, 4); - } else if (number >= 10LL * ONE_DECIMAL_G) { - xSnprintf(buffer, sizeof(buffer), "%11llu ", number / ONE_DECIMAL_K); - RichString_appendnAscii(str, largeNumberColor, buffer, 5); - RichString_appendnAscii(str, processMegabytesColor, buffer + 5, 3); - RichString_appendnAscii(str, processColor, buffer + 8, 4); - } else { - xSnprintf(buffer, sizeof(buffer), "%11llu ", number); - RichString_appendnAscii(str, largeNumberColor, buffer, 2); - RichString_appendnAscii(str, processMegabytesColor, buffer + 2, 3); - RichString_appendnAscii(str, processColor, buffer + 5, 3); - RichString_appendnAscii(str, processShadowColor, buffer + 8, 4); - } -} - -void Process_printTime(RichString* str, unsigned long long totalHundredths, bool coloring) { - char buffer[10]; - int len; - - unsigned long long totalSeconds = totalHundredths / 100; - unsigned long long hours = totalSeconds / 3600; - unsigned long long days = totalSeconds / 86400; - int minutes = (totalSeconds / 60) % 60; - int seconds = totalSeconds % 60; - int hundredths = totalHundredths - (totalSeconds * 100); - - int yearColor = coloring ? CRT_colors[LARGE_NUMBER] : CRT_colors[PROCESS]; - int dayColor = coloring ? CRT_colors[PROCESS_GIGABYTES] : CRT_colors[PROCESS]; - int hourColor = coloring ? CRT_colors[PROCESS_MEGABYTES] : CRT_colors[PROCESS]; - int defColor = CRT_colors[PROCESS]; - - if (days >= /* Ignore leapyears */365) { - int years = days / 365; - int daysLeft = days - 365 * years; - - if (years >= 10000000) { - RichString_appendnAscii(str, yearColor, "eternity ", 9); - } else if (years >= 1000) { - len = xSnprintf(buffer, sizeof(buffer), "%7dy ", years); - RichString_appendnAscii(str, yearColor, buffer, len); - } else if (daysLeft >= 100) { - len = xSnprintf(buffer, sizeof(buffer), "%3dy", years); - RichString_appendnAscii(str, yearColor, buffer, len); - len = xSnprintf(buffer, sizeof(buffer), "%3dd ", daysLeft); - RichString_appendnAscii(str, dayColor, buffer, len); - } else if (daysLeft >= 10) { - len = xSnprintf(buffer, sizeof(buffer), "%4dy", years); - RichString_appendnAscii(str, yearColor, buffer, len); - len = xSnprintf(buffer, sizeof(buffer), "%2dd ", daysLeft); - RichString_appendnAscii(str, dayColor, buffer, len); - } else { - len = xSnprintf(buffer, sizeof(buffer), "%5dy", years); - RichString_appendnAscii(str, yearColor, buffer, len); - len = xSnprintf(buffer, sizeof(buffer), "%1dd ", daysLeft); - RichString_appendnAscii(str, dayColor, buffer, len); - } - } else if (days >= 100) { - int hoursLeft = hours - days * 24; - - if (hoursLeft >= 10) { - len = xSnprintf(buffer, sizeof(buffer), "%4llud", days); - RichString_appendnAscii(str, dayColor, buffer, len); - len = xSnprintf(buffer, sizeof(buffer), "%2dh ", hoursLeft); - RichString_appendnAscii(str, hourColor, buffer, len); - } else { - len = xSnprintf(buffer, sizeof(buffer), "%5llud", days); - RichString_appendnAscii(str, dayColor, buffer, len); - len = xSnprintf(buffer, sizeof(buffer), "%1dh ", hoursLeft); - RichString_appendnAscii(str, hourColor, buffer, len); - } - } else if (hours >= 100) { - int minutesLeft = totalSeconds / 60 - hours * 60; - - if (minutesLeft >= 10) { - len = xSnprintf(buffer, sizeof(buffer), "%4lluh", hours); - RichString_appendnAscii(str, hourColor, buffer, len); - len = xSnprintf(buffer, sizeof(buffer), "%2dm ", minutesLeft); - RichString_appendnAscii(str, defColor, buffer, len); - } else { - len = xSnprintf(buffer, sizeof(buffer), "%5lluh", hours); - RichString_appendnAscii(str, hourColor, buffer, len); - len = xSnprintf(buffer, sizeof(buffer), "%1dm ", minutesLeft); - RichString_appendnAscii(str, defColor, buffer, len); - } - } else if (hours > 0) { - len = xSnprintf(buffer, sizeof(buffer), "%2lluh", hours); - RichString_appendnAscii(str, hourColor, buffer, len); - len = xSnprintf(buffer, sizeof(buffer), "%02d:%02d ", minutes, seconds); - RichString_appendnAscii(str, defColor, buffer, len); - } else { - len = xSnprintf(buffer, sizeof(buffer), "%2d:%02d.%02d ", minutes, seconds, hundredths); - RichString_appendnAscii(str, defColor, buffer, len); - } -} - void Process_fillStarttimeBuffer(Process* this) { struct tm date; + time_t now = this->super.host->realtime.tv_sec; (void) localtime_r(&this->starttime_ctime, &date); - strftime(this->starttime_show, sizeof(this->starttime_show) - 1, (this->starttime_ctime > (time(NULL) - 86400)) ? "%R " : "%b%d ", &date); + + strftime(this->starttime_show, + sizeof(this->starttime_show) - 1, + (this->starttime_ctime > now - 86400) ? "%R " : (this->starttime_ctime > now - 364*86400) ? "%b%d " : " %Y ", + &date); } /* @@ -287,7 +60,7 @@ void Process_fillStarttimeBuffer(Process* this) { * * Note: when colorizing a basename with the comm prefix, the entire basename * (not just the comm prefix) is colorized for better readability, and it is - * implicit that only upto (TASK_COMM_LEN - 1) could be comm. + * implicit that only up to (TASK_COMM_LEN - 1) could be comm. */ #define TASK_COMM_LEN 16 @@ -405,9 +178,8 @@ static inline char* stpcpyWithNewlineConversion(char* dstStr, const char* srcStr * Process_writeCommand() for coloring. The merged Command string is also * returned by Process_getCommand() for searching, sorting and filtering. */ -void Process_makeCommandStr(Process* this) { +void Process_makeCommandStr(Process* this, const Settings* settings) { ProcessMergedCommand* mc = &this->mergedCommand; - const Settings* settings = this->host->settings; bool showMergedCommand = settings->showMergedCommand; bool showProgramPath = settings->showProgramPath; @@ -675,7 +447,7 @@ void Process_writeCommand(const Process* this, int attr, int baseAttr, RichStrin int strStart = RichString_size(str); - const Settings* settings = this->host->settings; + const Settings* settings = this->super.host->settings; const bool highlightBaseName = settings->highlightBaseName; const bool highlightSeparator = true; const bool highlightDeleted = settings->highlightDeletedExe; @@ -741,73 +513,6 @@ void Process_writeCommand(const Process* this, int attr, int baseAttr, RichStrin } } -void Process_printRate(RichString* str, double rate, bool coloring) { - char buffer[16]; - - int largeNumberColor = CRT_colors[LARGE_NUMBER]; - int processMegabytesColor = CRT_colors[PROCESS_MEGABYTES]; - int processColor = CRT_colors[PROCESS]; - int shadowColor = CRT_colors[PROCESS_SHADOW]; - - if (!coloring) { - largeNumberColor = CRT_colors[PROCESS]; - processMegabytesColor = CRT_colors[PROCESS]; - } - - if (isnan(rate)) { - RichString_appendAscii(str, shadowColor, " N/A "); - } else if (rate < 0.005) { - int len = snprintf(buffer, sizeof(buffer), "%7.2f B/s ", rate); - RichString_appendnAscii(str, shadowColor, buffer, len); - } else if (rate < ONE_K) { - int len = snprintf(buffer, sizeof(buffer), "%7.2f B/s ", rate); - RichString_appendnAscii(str, processColor, buffer, len); - } else if (rate < ONE_M) { - int len = snprintf(buffer, sizeof(buffer), "%7.2f K/s ", rate / ONE_K); - RichString_appendnAscii(str, processColor, buffer, len); - } else if (rate < ONE_G) { - int len = snprintf(buffer, sizeof(buffer), "%7.2f M/s ", rate / ONE_M); - RichString_appendnAscii(str, processMegabytesColor, buffer, len); - } else if (rate < ONE_T) { - int len = snprintf(buffer, sizeof(buffer), "%7.2f G/s ", rate / ONE_G); - RichString_appendnAscii(str, largeNumberColor, buffer, len); - } else if (rate < ONE_P) { - int len = snprintf(buffer, sizeof(buffer), "%7.2f T/s ", rate / ONE_T); - RichString_appendnAscii(str, largeNumberColor, buffer, len); - } else { - int len = snprintf(buffer, sizeof(buffer), "%7.2f P/s ", rate / ONE_P); - RichString_appendnAscii(str, largeNumberColor, buffer, len); - } -} - -void Process_printLeftAlignedField(RichString* str, int attr, const char* content, unsigned int width) { - int columns = width; - RichString_appendnWideColumns(str, attr, content, strlen(content), &columns); - RichString_appendChr(str, attr, ' ', width + 1 - columns); -} - -void Process_printPercentage(float val, char* buffer, int n, uint8_t width, int* attr) { - if (val >= 0) { - if (val < 0.05F) - *attr = CRT_colors[PROCESS_SHADOW]; - else if (val >= 99.9F) - *attr = CRT_colors[PROCESS_MEGABYTES]; - - int precision = 1; - - // Display "val" as "100" for columns like "MEM%". - if (width == 4 && val > 99.9F) { - precision = 0; - val = 100.0F; - } - - xSnprintf(buffer, n, "%*.*f ", width, precision, val); - } else { - *attr = CRT_colors[PROCESS_SHADOW]; - xSnprintf(buffer, n, "%*.*s ", width, width, "N/A"); - } -} - static inline char processStateChar(ProcessState state) { switch (state) { case UNKNOWN: return '?'; @@ -830,11 +535,19 @@ static inline char processStateChar(ProcessState state) { } } -void Process_writeField(const Process* this, RichString* str, ProcessField field) { +static void Process_rowWriteField(const Row* super, RichString* str, RowField field) { + const Process* this = (const Process*) super; + assert(Object_isA((const Object*) this, (const ObjectClass*) &Process_class)); + Process_writeField(this, str, field); +} + +void Process_writeField(const Process* this, RichString* str, RowField field) { char buffer[256]; size_t n = sizeof(buffer); int attr = CRT_colors[DEFAULT_COLOR]; - const Settings* settings = this->host->settings; + const Row* super = (const Row*) &this->super; + const Machine* host = super->host; + const Settings* settings = host->settings; bool coloring = settings->highlightMegabytes; switch (field) { @@ -845,15 +558,15 @@ void Process_writeField(const Process* this, RichString* str, ProcessField field baseattr = CRT_colors[PROCESS_THREAD_BASENAME]; } const ScreenSettings* ss = settings->ss; - if (!ss->treeView || this->indent == 0) { + if (!ss->treeView || super->indent == 0) { Process_writeCommand(this, attr, baseattr, str); return; } char* buf = buffer; - const bool lastItem = (this->indent < 0); + const bool lastItem = (super->indent < 0); - for (uint32_t indent = (this->indent < 0 ? -this->indent : this->indent); indent > 1; indent >>= 1) { + for (uint32_t indent = (super->indent < 0 ? -super->indent : super->indent); indent > 1; indent >>= 1) { int written, ret; if (indent & 1U) { ret = xSnprintf(buf, n, "%s ", CRT_treeStr[TREE_STR_VERT]); @@ -870,7 +583,7 @@ void Process_writeField(const Process* this, RichString* str, ProcessField field } const char* draw = CRT_treeStr[lastItem ? TREE_STR_BEND : TREE_STR_RTEE]; - xSnprintf(buf, n, "%s%s ", draw, this->showChildren ? CRT_treeStr[TREE_STR_SHUT] : CRT_treeStr[TREE_STR_OPEN] ); + xSnprintf(buf, n, "%s%s ", draw, super->showChildren ? CRT_treeStr[TREE_STR_SHUT] : CRT_treeStr[TREE_STR_OPEN] ); RichString_appendWide(str, CRT_colors[PROCESS_TREE], buffer); Process_writeCommand(this, attr, baseattr, str); return; @@ -885,7 +598,7 @@ void Process_writeField(const Process* this, RichString* str, ProcessField field procComm = Process_isKernelThread(this) ? kthreadID : "N/A"; } - Process_printLeftAlignedField(str, attr, procComm, TASK_COMM_LEN - 1); + Row_printLeftAlignedField(str, attr, procComm, TASK_COMM_LEN - 1); return; } case PROC_EXE: { @@ -904,7 +617,7 @@ void Process_writeField(const Process* this, RichString* str, ProcessField field procExe = Process_isKernelThread(this) ? kthreadID : "N/A"; } - Process_printLeftAlignedField(str, attr, procExe, TASK_COMM_LEN - 1); + Row_printLeftAlignedField(str, attr, procExe, TASK_COMM_LEN - 1); return; } case CWD: { @@ -918,22 +631,22 @@ void Process_writeField(const Process* this, RichString* str, ProcessField field } else { cwd = this->procCwd; } - Process_printLeftAlignedField(str, attr, cwd, 25); + Row_printLeftAlignedField(str, attr, cwd, 25); return; } case ELAPSED: { - const uint64_t rt = this->host->realtimeMs; + const uint64_t rt = host->realtimeMs; const uint64_t st = this->starttime_ctime * 1000; const uint64_t dt = rt < st ? 0 : rt - st; - Process_printTime(str, /* convert to hundreds of a second */ dt / 10, coloring); + Row_printTime(str, /* convert to hundreds of a second */ dt / 10, coloring); return; } - case MAJFLT: Process_printCount(str, this->majflt, coloring); return; - case MINFLT: Process_printCount(str, this->minflt, coloring); return; - case M_RESIDENT: Process_printKBytes(str, this->m_resident, coloring); return; - case M_VIRT: Process_printKBytes(str, this->m_virt, coloring); return; + case MAJFLT: Row_printCount(str, this->majflt, coloring); return; + case MINFLT: Row_printCount(str, this->minflt, coloring); return; + case M_RESIDENT: Row_printKBytes(str, this->m_resident, coloring); return; + case M_VIRT: Row_printKBytes(str, this->m_virt, coloring); return; case NICE: xSnprintf(buffer, n, "%3ld ", this->nice); attr = this->nice < 0 ? CRT_colors[PROCESS_HIGH_PRIORITY] @@ -946,16 +659,16 @@ void Process_writeField(const Process* this, RichString* str, ProcessField field xSnprintf(buffer, n, "%4ld ", this->nlwp); break; - case PERCENT_CPU: Process_printPercentage(this->percent_cpu, buffer, n, Process_fieldWidths[PERCENT_CPU], &attr); break; + case PERCENT_CPU: Row_printPercentage(this->percent_cpu, buffer, n, Row_fieldWidths[PERCENT_CPU], &attr); break; case PERCENT_NORM_CPU: { - float cpuPercentage = this->percent_cpu / this->host->activeCPUs; - Process_printPercentage(cpuPercentage, buffer, n, Process_fieldWidths[PERCENT_CPU], &attr); + float cpuPercentage = this->percent_cpu / host->activeCPUs; + Row_printPercentage(cpuPercentage, buffer, n, Row_fieldWidths[PERCENT_CPU], &attr); break; } - case PERCENT_MEM: Process_printPercentage(this->percent_mem, buffer, n, 4, &attr); break; + case PERCENT_MEM: Row_printPercentage(this->percent_mem, buffer, n, 4, &attr); break; case PGRP: xSnprintf(buffer, n, "%*d ", Process_pidDigits, this->pgrp); break; - case PID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, this->pid); break; - case PPID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, this->ppid); break; + case PID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, Process_getPid(this)); break; + case PPID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, Process_getParent(this)); break; case PRIORITY: if (this->priority <= -100) xSnprintf(buffer, n, " RT "); @@ -1004,12 +717,12 @@ void Process_writeField(const Process* this, RichString* str, ProcessField field } break; case ST_UID: xSnprintf(buffer, n, "%*d ", Process_uidDigits, this->st_uid); break; - case TIME: Process_printTime(str, this->time, coloring); return; + case TIME: Row_printTime(str, this->time, coloring); return; case TGID: - if (this->tgid == this->pid) + if (Process_getThreadGroup(this) == Process_getPid(this)) attr = CRT_colors[PROCESS_SHADOW]; - xSnprintf(buffer, n, "%*d ", Process_pidDigits, this->tgid); + xSnprintf(buffer, n, "%*d ", Process_pidDigits, Process_getThreadGroup(this)); break; case TPGID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, this->tpgid); break; case TTY: @@ -1024,11 +737,11 @@ void Process_writeField(const Process* this, RichString* str, ProcessField field case USER: if (this->elevated_priv) attr = CRT_colors[PROCESS_PRIV]; - else if (Process_getuid != this->st_uid) + else if (host->htopUserId != this->st_uid) attr = CRT_colors[PROCESS_SHADOW]; if (this->user) { - Process_printLeftAlignedField(str, attr, this->user, 10); + Row_printLeftAlignedField(str, attr, this->user, 10); return; } @@ -1044,34 +757,8 @@ void Process_writeField(const Process* this, RichString* str, ProcessField field RichString_appendAscii(str, attr, buffer); } -void Process_display(const Object* cast, RichString* out) { - const Process* this = (const Process*) cast; - const Settings* settings = this->host->settings; - const ProcessField* fields = settings->ss->fields; - for (int i = 0; fields[i]; i++) - As_Process(this)->writeField(this, out, fields[i]); - - if (settings->shadowOtherUsers && this->st_uid != Process_getuid) { - RichString_setAttr(out, CRT_colors[PROCESS_SHADOW]); - } - - if (this->tag == true) { - RichString_setAttr(out, CRT_colors[PROCESS_TAG]); - } - - if (settings->highlightChanges) { - if (Process_isTomb(this)) { - out->highlightAttr = CRT_colors[PROCESS_TOMB]; - } else if (Process_isNew(this)) { - out->highlightAttr = CRT_colors[PROCESS_NEW]; - } - } - - assert(RichString_size(out) > 0); -} - void Process_done(Process* this) { - assert (this != NULL); + assert(this != NULL); free(this->cmdline); free(this->procComm); free(this->procExe); @@ -1084,7 +771,8 @@ void Process_done(Process* this) { * happens on what is displayed - whether comm, full path, basename, etc.. So * this follows Process_writeField(COMM) and Process_writeCommand */ const char* Process_getCommand(const Process* this) { - const Settings* settings = this->host->settings; + const Settings* settings = this->super.host->settings; + if ((Process_isUserlandThread(this) && settings->showThreadNames) || !this->mergedCommand.str) { return this->cmdline; } @@ -1092,75 +780,112 @@ const char* Process_getCommand(const Process* this) { return this->mergedCommand.str; } -const ProcessClass Process_class = { - .super = { - .extends = Class(Object), - .display = Process_display, - .delete = Process_delete, - .compare = Process_compare - }, - .writeField = Process_writeField, -}; +static const char* Process_getSortKey(const Process* this) { + return Process_getCommand(this); +} -void Process_init(Process* this, const Machine* host) { - this->host = host; - this->tag = false; - this->showChildren = true; - this->show = true; - this->updated = false; - this->cmdlineBasenameEnd = -1; - this->st_uid = (uid_t)-1; +const char* Process_rowGetSortKey(Row* super) { + const Process* this = (const Process*) super; + assert(Object_isA((const Object*) this, (const ObjectClass*) &Process_class)); + return Process_getSortKey(this); +} - if (Process_getuid == (uid_t)-1) { - Process_getuid = getuid(); - } +/* Test whether display must highlight this row (if the htop UID matches) */ +static bool Process_isHighlighted(const Process* this) { + const Machine* host = this->super.host; + const Settings* settings = host->settings; + return settings->shadowOtherUsers && this->st_uid != host->htopUserId; } -void Process_toggleTag(Process* this) { - this->tag = !this->tag; +bool Process_rowIsHighlighted(const Row* super) { + const Process* this = (const Process*) super; + assert(Object_isA((const Object*) this, (const ObjectClass*) &Process_class)); + return Process_isHighlighted(this); } -bool Process_isNew(const Process* this) { - assert(this->host); - const Machine* host = this->host; - if (host->monotonicMs >= this->seenStampMs) { - const Settings* settings = host->settings; - return host->monotonicMs - this->seenStampMs <= 1000 * (uint64_t)settings->highlightDelaySecs; - } +/* Test whether display must follow parent process (if this thread is hidden) */ +static bool Process_isVisible(const Process* p, const Settings* settings) { + if (settings->hideUserlandThreads) + return !Process_isThread(p); + return true; +} + +bool Process_rowIsVisible(const Row* super, const Table* table) { + const Process* this = (const Process*) super; + assert(Object_isA((const Object*) this, (const ObjectClass*) &Process_class)); + return Process_isVisible(this, table->host->settings); +} + +/* Test whether display must filter out this process (various mechanisms) */ +static bool Process_matchesFilter(const Process* this, const Table* table) { + const Machine* host = table->host; + if (host->userId != (uid_t) -1 && this->st_uid != host->userId) + return true; + + const char* incFilter = table->incFilter; + if (incFilter && !String_contains_i(Process_getCommand(this), incFilter, true)) + return true; + + const ProcessList* pl = (const ProcessList*) host->activeTable; + assert(Object_isA((const Object*) pl, (const ObjectClass*) &ProcessList_class)); + if (pl->pidMatchList && !Hashtable_get(pl->pidMatchList, Process_getThreadGroup(this))) + return true; + return false; } -bool Process_isTomb(const Process* this) { - return this->tombStampMs > 0; +bool Process_rowMatchesFilter(const Row* super, const Table* table) { + const Process* this = (const Process*) super; + assert(Object_isA((const Object*) this, (const ObjectClass*) &Process_class)); + return Process_matchesFilter(this, table); +} + +void Process_init(Process* this, const Machine* host) { + Row_init(&this->super, host); + + this->cmdlineBasenameEnd = -1; } -bool Process_setPriority(Process* this, int priority) { +static bool Process_setPriority(Process* this, int priority) { if (Settings_isReadonly()) return false; - int old_prio = getpriority(PRIO_PROCESS, this->pid); - int err = setpriority(PRIO_PROCESS, this->pid, priority); + int old_prio = getpriority(PRIO_PROCESS, Process_getPid(this)); + int err = setpriority(PRIO_PROCESS, Process_getPid(this), priority); - if (err == 0 && old_prio != getpriority(PRIO_PROCESS, this->pid)) { + if (err == 0 && old_prio != getpriority(PRIO_PROCESS, Process_getPid(this))) { this->nice = priority; } return (err == 0); } -bool Process_changePriorityBy(Process* this, Arg delta) { +bool Process_rowSetPriority(Row* super, int priority) { + Process* this = (Process*) super; + assert(Object_isA((const Object*) this, (const ObjectClass*) &Process_class)); + return Process_setPriority(this, priority); +} + +bool Process_rowChangePriorityBy(Row* super, Arg delta) { + Process* this = (Process*) super; + assert(Object_isA((const Object*) this, (const ObjectClass*) &Process_class)); return Process_setPriority(this, this->nice + delta.i); } -bool Process_sendSignal(Process* this, Arg sgn) { - return kill(this->pid, sgn.i) == 0; +static bool Process_sendSignal(Process* this, Arg sgn) { + return kill(Process_getPid(this), sgn.i) == 0; +} + +bool Process_rowSendSignal(Row* super, Arg sgn) { + Process* this = (Process*) super; + assert(Object_isA((const Object*) this, (const ObjectClass*) &Process_class)); + return Process_sendSignal(this, sgn); } int Process_compare(const void* v1, const void* v2) { const Process* p1 = (const Process*)v1; const Process* p2 = (const Process*)v2; - const Settings* settings = p1->host->settings; - const ScreenSettings* ss = settings->ss; + const ScreenSettings* ss = p1->super.host->settings->ss; ProcessField key = ScreenSettings_getActiveSortKey(ss); @@ -1168,18 +893,27 @@ int Process_compare(const void* v1, const void* v2) { // Implement tie-breaker (needed to make tree mode more stable) if (!result) - return SPACESHIP_NUMBER(p1->pid, p2->pid); + return SPACESHIP_NUMBER(Process_getPid(p1), Process_getPid(p2)); return (ScreenSettings_getActiveDirection(ss) == 1) ? result : -result; } +int Process_compareByParent(const Row* r1, const Row* r2) { + int result = Row_compareByParent_Base(r1, r2); + + if (result != 0) + return result; + + return Process_compare(r1, r2); +} + int Process_compareByKey_Base(const Process* p1, const Process* p2, ProcessField key) { int r; switch (key) { case PERCENT_CPU: case PERCENT_NORM_CPU: - return SPACESHIP_NUMBER(p1->percent_cpu, p2->percent_cpu); + return compareRealNumbers(p1->percent_cpu, p2->percent_cpu); case PERCENT_MEM: return SPACESHIP_NUMBER(p1->m_resident, p2->m_resident); case COMM: @@ -1198,7 +932,7 @@ int Process_compareByKey_Base(const Process* p1, const Process* p2, ProcessField return SPACESHIP_NULLSTR(p1->procCwd, p2->procCwd); case ELAPSED: r = -SPACESHIP_NUMBER(p1->starttime_ctime, p2->starttime_ctime); - return r != 0 ? r : SPACESHIP_NUMBER(p1->pid, p2->pid); + return r != 0 ? r : SPACESHIP_NUMBER(Process_getPid(p1), Process_getPid(p2)); case MAJFLT: return SPACESHIP_NUMBER(p1->majflt, p2->majflt); case MINFLT: @@ -1214,9 +948,9 @@ int Process_compareByKey_Base(const Process* p1, const Process* p2, ProcessField case PGRP: return SPACESHIP_NUMBER(p1->pgrp, p2->pgrp); case PID: - return SPACESHIP_NUMBER(p1->pid, p2->pid); + return SPACESHIP_NUMBER(Process_getPid(p1), Process_getPid(p2)); case PPID: - return SPACESHIP_NUMBER(p1->ppid, p2->ppid); + return SPACESHIP_NUMBER(Process_getParent(p1), Process_getParent(p2)); case PRIORITY: return SPACESHIP_NUMBER(p1->priority, p2->priority); case PROCESSOR: @@ -1227,7 +961,7 @@ int Process_compareByKey_Base(const Process* p1, const Process* p2, ProcessField return SPACESHIP_NUMBER(p1->session, p2->session); case STARTTIME: r = SPACESHIP_NUMBER(p1->starttime_ctime, p2->starttime_ctime); - return r != 0 ? r : SPACESHIP_NUMBER(p1->pid, p2->pid); + return r != 0 ? r : SPACESHIP_NUMBER(Process_getPid(p1), Process_getPid(p2)); case STATE: return SPACESHIP_NUMBER(p1->state, p2->state); case ST_UID: @@ -1235,7 +969,7 @@ int Process_compareByKey_Base(const Process* p1, const Process* p2, ProcessField case TIME: return SPACESHIP_NUMBER(p1->time, p2->time); case TGID: - return SPACESHIP_NUMBER(p1->tgid, p2->tgid); + return SPACESHIP_NUMBER(Process_getThreadGroup(p1), Process_getThreadGroup(p2)); case TPGID: return SPACESHIP_NUMBER(p1->tpgid, p2->tpgid); case TTY: @@ -1246,7 +980,7 @@ int Process_compareByKey_Base(const Process* p1, const Process* p2, ProcessField default: CRT_debug("Process_compareByKey_Base() called with key %d", key); assert(0 && "Process_compareByKey_Base: default key reached"); /* should never be reached */ - return SPACESHIP_NUMBER(p1->pid, p2->pid); + return SPACESHIP_NUMBER(Process_getPid(p1), Process_getPid(p2)); } } @@ -1324,36 +1058,33 @@ void Process_updateExe(Process* this, const char* exe) { this->mergedCommand.lastUpdate = 0; } -uint8_t Process_fieldWidths[LAST_PROCESSFIELD] = { 0 }; - -void Process_resetFieldWidths(void) { - for (size_t i = 0; i < LAST_PROCESSFIELD; i++) { - if (!Process_fields[i].autoWidth) - continue; - - size_t len = strlen(Process_fields[i].title); - assert(len <= UINT8_MAX); - Process_fieldWidths[i] = (uint8_t)len; - } -} - -void Process_updateFieldWidth(ProcessField key, size_t width) { - if (width > UINT8_MAX) - Process_fieldWidths[key] = UINT8_MAX; - else if (width > Process_fieldWidths[key]) - Process_fieldWidths[key] = (uint8_t)width; -} - void Process_updateCPUFieldWidths(float percentage) { if (percentage < 99.9F) { - Process_updateFieldWidth(PERCENT_CPU, 4); - Process_updateFieldWidth(PERCENT_NORM_CPU, 4); + Row_updateFieldWidth(PERCENT_CPU, 4); + Row_updateFieldWidth(PERCENT_NORM_CPU, 4); return; } // Add additional two characters, one for "." and another for precision. uint8_t width = ceil(log10(percentage + 0.1)) + 2; - Process_updateFieldWidth(PERCENT_CPU, width); - Process_updateFieldWidth(PERCENT_NORM_CPU, width); + Row_updateFieldWidth(PERCENT_CPU, width); + Row_updateFieldWidth(PERCENT_NORM_CPU, width); } + +const ProcessClass Process_class = { + .super = { + .super = { + .extends = Class(Row), + .display = Row_display, + .delete = Process_delete, + .compare = Process_compare + }, + .isHighlighted = Process_rowIsHighlighted, + .isVisible = Process_rowIsVisible, + .matchesFilter = Process_rowMatchesFilter, + .sortKeyString = Process_rowGetSortKey, + .compareByParent = Process_compareByParent, + .writeField = Process_rowWriteField + }, +}; diff --git a/vendor/github.com/htop-dev/htop/Process.h b/vendor/github.com/htop-dev/htop/Process.h index ad89fd452d..92908155aa 100644 --- a/vendor/github.com/htop-dev/htop/Process.h +++ b/vendor/github.com/htop-dev/htop/Process.h @@ -13,8 +13,8 @@ in the source distribution for its full text. #include #include "Object.h" -#include "ProcessField.h" #include "RichString.h" +#include "Row.h" #define PROCESS_FLAG_IO 0x00000001 @@ -23,45 +23,6 @@ in the source distribution for its full text. #define DEFAULT_HIGHLIGHT_SECS 5 -typedef enum ProcessField_ { - NULL_PROCESSFIELD = 0, - PID = 1, - COMM = 2, - STATE = 3, - PPID = 4, - PGRP = 5, - SESSION = 6, - TTY = 7, - TPGID = 8, - MINFLT = 10, - MAJFLT = 12, - PRIORITY = 18, - NICE = 19, - STARTTIME = 21, - PROCESSOR = 38, - M_VIRT = 39, - M_RESIDENT = 40, - ST_UID = 46, - PERCENT_CPU = 47, - PERCENT_MEM = 48, - USER = 49, - TIME = 50, - NLWP = 51, - TGID = 52, - PERCENT_NORM_CPU = 53, - ELAPSED = 54, - SCHEDULERPOLICY = 55, - PROC_COMM = 124, - PROC_EXE = 125, - CWD = 126, - - /* Platform specific fields, defined in ${platform}/ProcessField.h */ - PLATFORM_PROCESS_FIELDS - - /* Do not add new fields after this entry (dynamic entries follow) */ - LAST_PROCESSFIELD -} ProcessField; - /* Core process states (shared by platforms) * NOTE: The enum has an ordering that is important! * See processStateChar in process.c for ProcessSate -> letter mapping */ @@ -83,6 +44,7 @@ typedef enum ProcessState_ { } ProcessState; struct Machine_; +struct Settings_; /* Holds information about regions of the cmdline that should be * highlighted (e.g. program basename, delimiter, comm). */ @@ -106,19 +68,7 @@ typedef struct ProcessMergedCommand_ { typedef struct Process_ { /* Super object for emulated OOP */ - Object super; - - /* Pointer to quasi-global data */ - const struct Machine_* host; - - /* Process identifier */ - pid_t pid; - - /* Parent process identifier */ - pid_t ppid; - - /* Thread group identifier */ - pid_t tgid; + Row super; /* Process group identifier */ int pgrp; @@ -232,36 +182,6 @@ typedef struct Process_ { /* Current scheduling policy */ int scheduling_policy; - /* Whether the process was updated during the current scan */ - bool updated; - - /* Whether the process was tagged by the user */ - bool tag; - - /* Whether to display this process */ - bool show; - - /* Whether this process was shown last cycle */ - bool wasShown; - - /* Whether to show children of this process in tree-mode */ - bool showChildren; - - /* - * Internal time counts for showing new and exited processes. - */ - uint64_t seenStampMs; - uint64_t tombStampMs; - - /* - * Internal state for tree-mode. - */ - int32_t indent; - unsigned int tree_depth; - - /* Has no known parent process */ - bool isRoot; - /* * Internal state for merged Command display */ @@ -291,39 +211,57 @@ typedef struct ProcessFieldData_ { bool autoWidth; } ProcessFieldData; +#define LAST_PROCESSFIELD LAST_RESERVED_FIELD +typedef int32_t ProcessField; /* see ReservedField list in RowField.h */ + // Implemented in platform-specific code: -void Process_writeField(const Process* this, RichString* str, ProcessField field); +void Process_writeField(const Process* row, RichString* str, ProcessField field); int Process_compare(const void* v1, const void* v2); +int Process_compareByParent(const Row* r1, const Row* v2); void Process_delete(Object* cast); extern const ProcessFieldData Process_fields[LAST_PROCESSFIELD]; -extern uint8_t Process_fieldWidths[LAST_PROCESSFIELD]; -#define PROCESS_MIN_PID_DIGITS 5 -#define PROCESS_MAX_PID_DIGITS 19 -#define PROCESS_MIN_UID_DIGITS 5 -#define PROCESS_MAX_UID_DIGITS 20 -extern int Process_pidDigits; -extern int Process_uidDigits; +#define Process_pidDigits Row_pidDigits +#define Process_uidDigits Row_uidDigits typedef Process* (*Process_New)(const struct Machine_*); -typedef void (*Process_WriteField)(const Process*, RichString*, ProcessField); typedef int (*Process_CompareByKey)(const Process*, const Process*, ProcessField); typedef struct ProcessClass_ { - const ObjectClass super; - const Process_WriteField writeField; + const RowClass super; const Process_CompareByKey compareByKey; } ProcessClass; -#define As_Process(this_) ((const ProcessClass*)((this_)->super.klass)) +#define As_Process(this_) ((const ProcessClass*)((this_)->super.super.klass)) + +#define Process_compareByKey(p1_, p2_, key_) (As_Process(p1_)->compareByKey ? (As_Process(p1_)->compareByKey(p1_, p2_, key_)) : Process_compareByKey_Base(p1_, p2_, key_)) + + +static inline void Process_setPid(Process* this, pid_t pid) { + this->super.id = pid; +} + +static inline pid_t Process_getPid(const Process* this) { + return (pid_t)this->super.id; +} -#define Process_compareByKey(p1_, p2_, key_) (As_Process(p1_)->compareByKey ? (As_Process(p1_)->compareByKey(p1_, p2_, key_)) : Process_compareByKey_Base(p1_, p2_, key_)) +static inline void Process_setThreadGroup(Process* this, pid_t pid) { + this->super.group = pid; +} + +static inline pid_t Process_getThreadGroup(const Process* this) { + return (pid_t)this->super.group; +} -static inline pid_t Process_getParentPid(const Process* this) { - return this->tgid == this->pid ? this->ppid : this->tgid; +static inline void Process_setParent(Process* this, pid_t pid) { + this->super.parent = pid; } -static inline bool Process_isChildOf(const Process* this, pid_t pid) { - return pid == Process_getParentPid(this); +static inline pid_t Process_getParent(const Process* this) { + return (pid_t)this->super.parent; +} + +static inline pid_t Process_getGroupOrParent(const Process* this) { + return Row_getGroupOrParent(&this->super); } static inline bool Process_isKernelThread(const Process* this) { @@ -344,68 +282,30 @@ static inline bool Process_isThread(const Process* this) { #define CMDLINE_HIGHLIGHT_FLAG_DELETED 0x00000008 #define CMDLINE_HIGHLIGHT_FLAG_PREFIXDIR 0x00000010 -#define ONE_K 1024UL -#define ONE_M (ONE_K * ONE_K) -#define ONE_G (ONE_M * ONE_K) -#define ONE_T (1ULL * ONE_G * ONE_K) -#define ONE_P (1ULL * ONE_T * ONE_K) - -#define ONE_DECIMAL_K 1000UL -#define ONE_DECIMAL_M (ONE_DECIMAL_K * ONE_DECIMAL_K) -#define ONE_DECIMAL_G (ONE_DECIMAL_M * ONE_DECIMAL_K) -#define ONE_DECIMAL_T (1ULL * ONE_DECIMAL_G * ONE_DECIMAL_K) -#define ONE_DECIMAL_P (1ULL * ONE_DECIMAL_T * ONE_DECIMAL_K) - -void Process_setupColumnWidths(void); - -/* Sets the size of the UID column based on the passed UID */ -void Process_setUidColumnWidth(uid_t maxUid); - -/* Takes number in bytes (base 1024). Prints 6 columns. */ -void Process_printBytes(RichString* str, unsigned long long number, bool coloring); - -/* Takes number in kilo bytes (base 1024). Prints 6 columns. */ -void Process_printKBytes(RichString* str, unsigned long long number, bool coloring); - -/* Takes number as count (base 1000). Prints 12 columns. */ -void Process_printCount(RichString* str, unsigned long long number, bool coloring); - -/* Takes time in hundredths of a seconds. Prints 9 columns. */ -void Process_printTime(RichString* str, unsigned long long totalHundredths, bool coloring); - -/* Takes rate in bare unit (base 1024) per second. Prints 12 columns. */ -void Process_printRate(RichString* str, double rate, bool coloring); - void Process_fillStarttimeBuffer(Process* this); -void Process_printLeftAlignedField(RichString* str, int attr, const char* content, unsigned int width); - -void Process_printPercentage(float val, char* buffer, int n, uint8_t width, int* attr); - -void Process_display(const Object* cast, RichString* out); - void Process_done(Process* this); extern const ProcessClass Process_class; void Process_init(Process* this, const struct Machine_* host); -void Process_toggleTag(Process* this); +const char* Process_rowGetSortKey(Row* super); + +bool Process_rowSetPriority(Row* super, int priority); -bool Process_isNew(const Process* this); +bool Process_rowChangePriorityBy(Row* super, Arg delta); -bool Process_isTomb(const Process* this); +bool Process_rowSendSignal(Row* super, Arg sgn); -bool Process_setPriority(Process* this, int priority); +bool Process_rowIsHighlighted(const Row* super); -bool Process_changePriorityBy(Process* this, Arg delta); +bool Process_rowIsVisible(const Row* super, const struct Table_* table); -bool Process_sendSignal(Process* this, Arg sgn); +bool Process_rowMatchesFilter(const Row* super, const struct Table_* table); static inline int Process_pidEqualCompare(const void* v1, const void* v2) { - const pid_t p1 = ((const Process*)v1)->pid; - const pid_t p2 = ((const Process*)v2)->pid; - return p1 != p2; /* return zero when equal */ + return Row_idEqualCompare(v1, v2); } int Process_compareByKey_Base(const Process* p1, const Process* p2, ProcessField key); @@ -418,12 +318,10 @@ void Process_updateExe(Process* this, const char* exe); /* This function constructs the string that is displayed by * Process_writeCommand and also returned by Process_getCommand */ -void Process_makeCommandStr(Process* this); +void Process_makeCommandStr(Process* this, const struct Settings_ *settings); void Process_writeCommand(const Process* this, int attr, int baseAttr, RichString* str); -void Process_resetFieldWidths(void); -void Process_updateFieldWidth(ProcessField key, size_t width); void Process_updateCPUFieldWidths(float percentage); #endif diff --git a/vendor/github.com/htop-dev/htop/ProcessList.c b/vendor/github.com/htop-dev/htop/ProcessList.c index 58e63d030b..516dcd7c5c 100644 --- a/vendor/github.com/htop-dev/htop/ProcessList.c +++ b/vendor/github.com/htop-dev/htop/ProcessList.c @@ -21,453 +21,74 @@ in the source distribution for its full text. void ProcessList_init(ProcessList* this, const ObjectClass* klass, Machine* host, Hashtable* pidMatchList) { - this->processes = Vector_new(klass, true, DEFAULT_SIZE); - this->displayList = Vector_new(klass, false, DEFAULT_SIZE); - this->processTable = Hashtable_new(200, false); + Table_init(&this->super, klass, host); + this->pidMatchList = pidMatchList; - this->needsSort = true; - this->following = -1; - this->host = host; } void ProcessList_done(ProcessList* this) { - Hashtable_delete(this->processTable); - Vector_delete(this->displayList); - Vector_delete(this->processes); -} - -void ProcessList_setPanel(ProcessList* this, Panel* panel) { - this->panel = panel; -} - -// helper function to fill an aligned title string for a dynamic column -static const char* alignedTitleDynamicColumn(const Settings* settings, int key, char* titleBuffer, size_t titleBufferSize) { - const DynamicColumn* column = Hashtable_get(settings->dynamicColumns, key); - if (column == NULL) - return "- "; - int width = column->width; - if (!width || abs(width) > DYNAMIC_MAX_COLUMN_WIDTH) - width = DYNAMIC_DEFAULT_COLUMN_WIDTH; - xSnprintf(titleBuffer, titleBufferSize, "%*s", width, column->heading); - return titleBuffer; -} - -// helper function to fill an aligned title string for a process field -static const char* alignedTitleProcessField(ProcessField field, char* titleBuffer, size_t titleBufferSize) { - const char* title = Process_fields[field].title; - if (!title) - return "- "; - - if (Process_fields[field].pidColumn) { - xSnprintf(titleBuffer, titleBufferSize, "%*s ", Process_pidDigits, title); - return titleBuffer; - } - - if (field == ST_UID) { - xSnprintf(titleBuffer, titleBufferSize, "%*s ", Process_uidDigits, title); - return titleBuffer; - } - - if (Process_fields[field].autoWidth) { - if (field == PERCENT_CPU) - xSnprintf(titleBuffer, titleBufferSize, "%*s ", Process_fieldWidths[field], title); - else - xSnprintf(titleBuffer, titleBufferSize, "%-*.*s ", Process_fieldWidths[field], Process_fieldWidths[field], title); - return titleBuffer; - } - - return title; -} - -// helper function to create an aligned title string for a given field -static const char* ProcessField_alignedTitle(const Settings* settings, ProcessField field) { - static char titleBuffer[UINT8_MAX + sizeof(" ")]; - assert(sizeof(titleBuffer) >= DYNAMIC_MAX_COLUMN_WIDTH + sizeof(" ")); - assert(sizeof(titleBuffer) >= PROCESS_MAX_PID_DIGITS + sizeof(" ")); - assert(sizeof(titleBuffer) >= PROCESS_MAX_UID_DIGITS + sizeof(" ")); - - if (field < LAST_PROCESSFIELD) - return alignedTitleProcessField(field, titleBuffer, sizeof(titleBuffer)); - return alignedTitleDynamicColumn(settings, field, titleBuffer, sizeof(titleBuffer)); -} - -void ProcessList_printHeader(const ProcessList* this, RichString* header) { - RichString_rewind(header, RichString_size(header)); - - const Settings* settings = this->host->settings; - const ScreenSettings* ss = settings->ss; - const ProcessField* fields = ss->fields; - - ProcessField key = ScreenSettings_getActiveSortKey(ss); - - for (int i = 0; fields[i]; i++) { - int color; - if (ss->treeView && ss->treeViewAlwaysByPID) { - color = CRT_colors[PANEL_HEADER_FOCUS]; - } else if (key == fields[i]) { - color = CRT_colors[PANEL_SELECTION_FOCUS]; - } else { - color = CRT_colors[PANEL_HEADER_FOCUS]; - } - - RichString_appendWide(header, color, ProcessField_alignedTitle(settings, fields[i])); - if (key == fields[i] && RichString_getCharVal(*header, RichString_size(header) - 1) == ' ') { - bool ascending = ScreenSettings_getActiveDirection(ss) == 1; - RichString_rewind(header, 1); // rewind to override space - RichString_appendnWide(header, - CRT_colors[PANEL_SELECTION_FOCUS], - CRT_treeStr[ascending ? TREE_STR_ASC : TREE_STR_DESC], - 1); - } - if (COMM == fields[i] && settings->showMergedCommand) { - RichString_appendAscii(header, color, "(merged)"); - } - } -} - -void ProcessList_add(ProcessList* this, Process* p) { - assert(Vector_indexOf(this->processes, p, Process_pidEqualCompare) == -1); - assert(Hashtable_get(this->processTable, p->pid) == NULL); - - // highlighting processes found in first scan by first scan marked "far in the past" - p->seenStampMs = this->host->monotonicMs; - - Vector_add(this->processes, p); - Hashtable_put(this->processTable, p->pid, p); - - assert(Vector_indexOf(this->processes, p, Process_pidEqualCompare) != -1); - assert(Hashtable_get(this->processTable, p->pid) != NULL); - assert(Vector_countEquals(this->processes, Hashtable_count(this->processTable))); -} - -// ProcessList_removeIndex removes Process p from the list's map and soft deletes -// it from its vector. Vector_compact *must* be called once the caller is done -// removing items. -// Should only be called from ProcessList_scan to avoid breaking dying process highlighting. -static void ProcessList_removeIndex(ProcessList* this, const Process* p, int idx) { - pid_t pid = p->pid; - - assert(p == (Process*)Vector_get(this->processes, idx)); - assert(Hashtable_get(this->processTable, pid) != NULL); - - Hashtable_remove(this->processTable, pid); - Vector_softRemove(this->processes, idx); - - if (this->following != -1 && this->following == pid) { - this->following = -1; - Panel_setSelectionColor(this->panel, PANEL_SELECTION_FOCUS); - } - - assert(Hashtable_get(this->processTable, pid) == NULL); - assert(Vector_countEquals(this->processes, Hashtable_count(this->processTable))); -} - -static void ProcessList_buildTreeBranch(ProcessList* this, pid_t pid, unsigned int level, int32_t indent, bool show) { - // On OpenBSD the kernel thread 'swapper' has pid 0. - // Do not treat it as root of any tree. - if (pid == 0) - return; - - // The vector is sorted by parent PID, find the start of the range by bisection - int vsize = Vector_size(this->processes); - int l = 0; - int r = vsize; - while (l < r) { - int c = (l + r) / 2; - Process* process = (Process*)Vector_get(this->processes, c); - pid_t ppid = process->isRoot ? 0 : Process_getParentPid(process); - if (ppid < pid) { - l = c + 1; - } else { - r = c; - } - } - // Find the end to know the last line for indent handling purposes - int lastShown = r; - while (r < vsize) { - Process* process = (Process*)Vector_get(this->processes, r); - if (!Process_isChildOf(process, pid)) - break; - if (process->show) - lastShown = r; - r++; - } - - for (int i = l; i < r; i++) { - Process* process = (Process*)Vector_get(this->processes, i); - - if (!show) { - process->show = false; - } - - Vector_add(this->displayList, process); - - int32_t nextIndent = indent | ((int32_t)1 << MINIMUM(level, sizeof(process->indent) * 8 - 2)); - ProcessList_buildTreeBranch(this, process->pid, level + 1, (i < lastShown) ? nextIndent : indent, process->show && process->showChildren); - if (i == lastShown) { - process->indent = -nextIndent; - } else { - process->indent = nextIndent; - } - - process->tree_depth = level + 1; - } -} - -static int compareProcessByKnownParentThenNatural(const void* v1, const void* v2) { - const Process* p1 = (const Process*)v1; - const Process* p2 = (const Process*)v2; - - int result = SPACESHIP_NUMBER( - p1->isRoot ? 0 : Process_getParentPid(p1), - p2->isRoot ? 0 : Process_getParentPid(p2) - ); - - if (result != 0) - return result; - - return Process_compare(v1, v2); -} - -// Builds a sorted tree from scratch, without relying on previously gathered information -static void ProcessList_buildTree(ProcessList* this) { - Vector_prune(this->displayList); - - // Mark root processes - int vsize = Vector_size(this->processes); - for (int i = 0; i < vsize; i++) { - Process* process = (Process*)Vector_get(this->processes, i); - pid_t ppid = Process_getParentPid(process); - process->isRoot = false; - - // If PID corresponds with PPID (e.g. "kernel_task" (PID:0, PPID:0) - // on Mac OS X 10.11.6) regard this process as root. - if (process->pid == ppid) { - process->isRoot = true; - continue; - } - - // On Linux both the init process (pid 1) and the root UMH kernel thread (pid 2) - // use a ppid of 0. As that PID can't exist, we can skip searching for it. - if (!ppid) { - process->isRoot = true; - continue; - } - - // We don't know about its parent for whatever reason - if (ProcessList_findProcess(this, ppid) == NULL) - process->isRoot = true; - } - - // Sort by known parent PID (roots first), then PID - Vector_quickSortCustomCompare(this->processes, compareProcessByKnownParentThenNatural); - - // Find all processes whose parent is not visible - for (int i = 0; i < vsize; i++) { - Process* process = (Process*)Vector_get(this->processes, i); - - // If parent not found, then construct the tree with this node as root - if (process->isRoot) { - process = (Process*)Vector_get(this->processes, i); - process->indent = 0; - process->tree_depth = 0; - Vector_add(this->displayList, process); - ProcessList_buildTreeBranch(this, process->pid, 0, 0, process->showChildren); - continue; - } - } - - this->needsSort = false; - - // Check consistency of the built structures - assert(Vector_size(this->displayList) == vsize); (void)vsize; -} - -void ProcessList_updateDisplayList(ProcessList* this) { - if (this->host->settings->ss->treeView) { - if (this->needsSort) - ProcessList_buildTree(this); - } else { - if (this->needsSort) - Vector_insertionSort(this->processes); - Vector_prune(this->displayList); - int size = Vector_size(this->processes); - for (int i = 0; i < size; i++) - Vector_add(this->displayList, Vector_get(this->processes, i)); - } - this->needsSort = false; -} - -ProcessField ProcessList_keyAt(const ProcessList* this, int at) { - int x = 0; - const Settings* settings = this->host->settings; - const ProcessField* fields = settings->ss->fields; - ProcessField field; - for (int i = 0; (field = fields[i]); i++) { - int len = strlen(ProcessField_alignedTitle(settings, field)); - if (at >= x && at <= x + len) { - return field; - } - x += len; - } - return COMM; -} - -void ProcessList_expandTree(ProcessList* this) { - int size = Vector_size(this->processes); - for (int i = 0; i < size; i++) { - Process* process = (Process*) Vector_get(this->processes, i); - process->showChildren = true; - } -} - -// Called on collapse-all toggle and on startup, possibly in non-tree mode -void ProcessList_collapseAllBranches(ProcessList* this) { - ProcessList_buildTree(this); // Update `tree_depth` fields of the processes - this->needsSort = true; // ProcessList is sorted by parent now, force new sort - int size = Vector_size(this->processes); - for (int i = 0; i < size; i++) { - Process* process = (Process*) Vector_get(this->processes, i); - // FreeBSD has pid 0 = kernel and pid 1 = init, so init has tree_depth = 1 - if (process->tree_depth > 0 && process->pid > 1) - process->showChildren = false; - } -} - -void ProcessList_rebuildPanel(ProcessList* this) { - ProcessList_updateDisplayList(this); - - const char* incFilter = this->incFilter; - - const int currPos = Panel_getSelectedIndex(this->panel); - const int currScrollV = this->panel->scrollV; - const int currSize = Panel_size(this->panel); - - Panel_prune(this->panel); - - /* Follow main process if followed a userland thread and threads are now hidden */ - const Machine* host= this->host; - const Settings* settings = host->settings; - if (this->following != -1 && settings->hideUserlandThreads) { - const Process* followedProcess = (const Process*) Hashtable_get(this->processTable, this->following); - if (followedProcess && Process_isThread(followedProcess) && Hashtable_get(this->processTable, followedProcess->tgid) != NULL) { - this->following = followedProcess->tgid; - } - } - - const int processCount = Vector_size(this->displayList); - int idx = 0; - bool foundFollowed = false; - - for (int i = 0; i < processCount; i++) { - Process* p = (Process*) Vector_get(this->displayList, i); - - if ( (!p->show) - || (host->userId != (uid_t) -1 && (p->st_uid != host->userId)) - || (incFilter && !(String_contains_i(Process_getCommand(p), incFilter, true))) - || (this->pidMatchList && !Hashtable_get(this->pidMatchList, p->tgid)) ) - continue; - - Panel_set(this->panel, idx, (Object*)p); - - if (this->following != -1 && p->pid == this->following) { - foundFollowed = true; - Panel_setSelected(this->panel, idx); - /* Keep scroll position relative to followed process */ - this->panel->scrollV = idx - (currPos-currScrollV); - } - idx++; - } - - if (this->following != -1 && !foundFollowed) { - /* Reset if current followed pid not found */ - this->following = -1; - Panel_setSelectionColor(this->panel, PANEL_SELECTION_FOCUS); - } - - if (this->following == -1) { - /* If the last item was selected, keep the new last item selected */ - if (currPos > 0 && currPos == currSize - 1) - Panel_setSelected(this->panel, Panel_size(this->panel) - 1); - else - Panel_setSelected(this->panel, currPos); - - this->panel->scrollV = currScrollV; - } + Table_done(&this->super); } Process* ProcessList_getProcess(ProcessList* this, pid_t pid, bool* preExisting, Process_New constructor) { - Process* proc = (Process*) Hashtable_get(this->processTable, pid); + const Table* table = &this->super; + Process* proc = (Process*) Hashtable_get(table->table, pid); *preExisting = proc != NULL; if (proc) { - assert(Vector_indexOf(this->processes, proc, Process_pidEqualCompare) != -1); - assert(proc->pid == pid); + assert(Vector_indexOf(table->rows, proc, Row_idEqualCompare) != -1); + assert(Process_getPid(proc) == pid); } else { - proc = constructor(this->host); + proc = constructor(table->host); assert(proc->cmdline == NULL); - proc->pid = pid; + Process_setPid(proc, pid); } return proc; } -void ProcessList_scan(ProcessList* this) { - // mark all process as "dirty" - for (int i = 0; i < Vector_size(this->processes); i++) { - Process* p = (Process*) Vector_get(this->processes, i); - p->updated = false; - p->wasShown = p->show; - p->show = true; - } - +static void ProcessList_prepareEntries(Table* super) { + ProcessList* this = (ProcessList*) super; this->totalTasks = 0; this->userlandThreads = 0; this->kernelThreads = 0; this->runningTasks = 0; - Process_resetFieldWidths(); - - // set scan timestamp - static bool firstScanDone = false; - Machine* host = this->host; - if (firstScanDone) { - Platform_gettime_monotonic(&host->monotonicMs); - } else { - host->monotonicMs = 0; - firstScanDone = true; - } + Table_prepareEntries(super); +} +static void ProcessList_iterateEntries(Table* super) { + ProcessList* this = (ProcessList*) super; + // calling into platform-specific code ProcessList_goThroughEntries(this); +} - uid_t maxUid = 0; +static void ProcessList_cleanupEntries(Table* super) { + Machine* host = super->host; const Settings* settings = host->settings; - for (int i = Vector_size(this->processes) - 1; i >= 0; i--) { - Process* p = (Process*) Vector_get(this->processes, i); - Process_makeCommandStr(p); + + // Finish process table update, culling any exit'd processes + for (int i = Vector_size(super->rows) - 1; i >= 0; i--) { + Process* p = (Process*) Vector_get(super->rows, i); + + // tidy up Process state after refreshing the ProcessList table + Process_makeCommandStr(p, settings); // keep track of the highest UID for column scaling - if (p->st_uid > maxUid) - maxUid = p->st_uid; + if (p->st_uid > host->maxUserId) + host->maxUserId = p->st_uid; - if (p->tombStampMs > 0) { - // remove tombed process - if (host->monotonicMs >= p->tombStampMs) { - ProcessList_removeIndex(this, p, i); - } - } else if (p->updated == false) { - // process no longer exists - if (settings->highlightChanges && p->wasShown) { - // mark tombed - p->tombStampMs = host->monotonicMs + 1000 * settings->highlightDelaySecs; - } else { - // immediately remove - ProcessList_removeIndex(this, p, i); - } - } + Table_cleanupRow(super, (Row*) p, i); } - // Compact the processes vector in case of any deletions - Vector_compact(this->processes); - - // Set UID column width based on max UID. - Process_setUidColumnWidth(maxUid); + // compact the table in case of deletions + Table_compact(super); } + +const TableClass ProcessList_class = { + .super = { + .extends = Class(Table), + .delete = ProcessList_delete, + }, + .prepare = ProcessList_prepareEntries, + .iterate = ProcessList_iterateEntries, + .cleanup = ProcessList_cleanupEntries, +}; diff --git a/vendor/github.com/htop-dev/htop/ProcessList.h b/vendor/github.com/htop-dev/htop/ProcessList.h index 0f0f7d5177..9710a0a545 100644 --- a/vendor/github.com/htop-dev/htop/ProcessList.h +++ b/vendor/github.com/htop-dev/htop/ProcessList.h @@ -21,24 +21,12 @@ in the source distribution for its full text. #include "Panel.h" #include "Process.h" #include "RichString.h" -#include "Settings.h" -#include "UsersTable.h" -#include "Vector.h" +#include "Table.h" typedef struct ProcessList_ { - struct Machine_* host; + Table super; - Vector* processes; /* all known processes; sort order can vary and differ from display order */ - Vector* displayList; /* process tree flattened in display order (borrowed); - updated in ProcessList_updateDisplayList when rebuilding panel */ - Hashtable* processTable; /* fast known process lookup by PID */ - - bool needsSort; - - Panel* panel; - int following; - const char* incFilter; Hashtable* pidMatchList; unsigned int totalTasks; @@ -49,35 +37,23 @@ typedef struct ProcessList_ { /* Implemented by platforms */ ProcessList* ProcessList_new(Machine* host, Hashtable* pidMatchList); -void ProcessList_delete(ProcessList* this); +void ProcessList_delete(Object* cast); void ProcessList_goThroughEntries(ProcessList* this); void ProcessList_init(ProcessList* this, const ObjectClass* klass, Machine* host, Hashtable* pidMatchList); void ProcessList_done(ProcessList* this); -void ProcessList_setPanel(ProcessList* this, Panel* panel); - -void ProcessList_printHeader(const ProcessList* this, RichString* header); - -void ProcessList_add(ProcessList* this, Process* p); - -void ProcessList_updateDisplayList(ProcessList* this); +extern const TableClass ProcessList_class; -ProcessField ProcessList_keyAt(const ProcessList* this, int at); - -void ProcessList_expandTree(ProcessList* this); - -void ProcessList_collapseAllBranches(ProcessList* this); - -void ProcessList_rebuildPanel(ProcessList* this); +static inline void ProcessList_add(ProcessList* this, Process* process) { + Table_add(&this->super, &process->super); +} Process* ProcessList_getProcess(ProcessList* this, pid_t pid, bool* preExisting, Process_New constructor); -void ProcessList_scan(ProcessList* this); - static inline Process* ProcessList_findProcess(ProcessList* this, pid_t pid) { - return (Process*) Hashtable_get(this->processTable, pid); + return (Process*) Table_findRow(&this->super, pid); } #endif diff --git a/vendor/github.com/htop-dev/htop/ProcessLocksScreen.c b/vendor/github.com/htop-dev/htop/ProcessLocksScreen.c index 57c9ce75f0..36a37f927c 100644 --- a/vendor/github.com/htop-dev/htop/ProcessLocksScreen.c +++ b/vendor/github.com/htop-dev/htop/ProcessLocksScreen.c @@ -24,9 +24,9 @@ ProcessLocksScreen* ProcessLocksScreen_new(const Process* process) { ProcessLocksScreen* this = xMalloc(sizeof(ProcessLocksScreen)); Object_setClass(this, Class(ProcessLocksScreen)); if (Process_isThread(process)) - this->pid = process->tgid; + this->pid = Process_getThreadGroup(process); else - this->pid = process->pid; + this->pid = Process_getPid(process); return (ProcessLocksScreen*) InfoScreen_init(&this->super, process, NULL, LINES - 2, " FD TYPE EXCLUSION READ/WRITE DEVICE NODE START END FILENAME"); } diff --git a/vendor/github.com/htop-dev/htop/ProvideTerm.h b/vendor/github.com/htop-dev/htop/ProvideTerm.h new file mode 100644 index 0000000000..0e07b1c497 --- /dev/null +++ b/vendor/github.com/htop-dev/htop/ProvideTerm.h @@ -0,0 +1,24 @@ +#ifndef HEADER_ProvideTerm +#define HEADER_ProvideTerm +/* +htop - Filename.h +(C) 2023 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 + +// IWYU pragma: begin_exports + +#if defined(HAVE_NCURSESW_TERM_H) +#include +#elif defined(HAVE_NCURSES_TERM_H) +#include +#elif defined(HAVE_TERM_H) +#include +#endif + +// IWYU pragma: end_exports + +#endif // HEADER_ProvideTerm diff --git a/vendor/github.com/htop-dev/htop/RichString.h b/vendor/github.com/htop-dev/htop/RichString.h index cbcbe48b7c..9a09166c24 100644 --- a/vendor/github.com/htop-dev/htop/RichString.h +++ b/vendor/github.com/htop-dev/htop/RichString.h @@ -18,7 +18,7 @@ in the source distribution for its full text. #define RichString_begin(this) RichString this; RichString_beginAllocated(this) #define RichString_beginAllocated(this) \ do { \ - (this).chlen = 0, \ + (this).chlen = 0; \ (this).chptr = (this).chstr; \ RichString_setChar(&(this), 0, 0); \ (this).highlightAttr = 0; \ diff --git a/vendor/github.com/htop-dev/htop/Row.c b/vendor/github.com/htop-dev/htop/Row.c new file mode 100644 index 0000000000..67893d39e7 --- /dev/null +++ b/vendor/github.com/htop-dev/htop/Row.c @@ -0,0 +1,491 @@ +/* +htop - Row.c +(C) 2004-2015 Hisham H. Muhammad +(C) 2020-2023 Red Hat, Inc. All Rights Reserved. +Released under the GNU GPLv2+, see the COPYING file +in the source distribution for its full text. +*/ + +#include "config.h" // IWYU pragma: keep + +#include "Row.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "CRT.h" +#include "DynamicColumn.h" +#include "Machine.h" +#include "Macros.h" +#include "RichString.h" +#include "Settings.h" +#include "Table.h" +#include "XUtils.h" + + +int Row_pidDigits = ROW_MIN_PID_DIGITS; +int Row_uidDigits = ROW_MIN_UID_DIGITS; + +void Row_init(Row* this, const Machine* host) { + this->host = host; + this->tag = false; + this->showChildren = true; + this->show = true; + this->wasShown = false; + this->updated = false; +} + +void Row_done(Row* this) { + assert(this != NULL); + (void) this; +} + +static inline bool Row_isNew(const Row* this) { + const Machine* host = this->host; + if (host->monotonicMs < this->seenStampMs) + return false; + + const Settings* settings = host->settings; + return host->monotonicMs - this->seenStampMs <= 1000 * (uint64_t)settings->highlightDelaySecs; +} + +static inline bool Row_isTomb(const Row* this) { + return this->tombStampMs > 0; +} + +void Row_display(const Object* cast, RichString* out) { + const Row* this = (const Row*) cast; + const Settings* settings = this->host->settings; + const RowField* fields = settings->ss->fields; + + for (int i = 0; fields[i]; i++) + As_Row(this)->writeField(this, out, fields[i]); + + if (Row_isHighlighted(this)) + RichString_setAttr(out, CRT_colors[PROCESS_SHADOW]); + + if (this->tag == true) + RichString_setAttr(out, CRT_colors[PROCESS_TAG]); + + if (settings->highlightChanges) { + if (Row_isTomb(this)) + out->highlightAttr = CRT_colors[PROCESS_TOMB]; + else if (Row_isNew(this)) + out->highlightAttr = CRT_colors[PROCESS_NEW]; + } + + assert(RichString_size(out) > 0); +} + +void Row_setPidColumnWidth(pid_t maxPid) { + if (maxPid < (int)pow(10, ROW_MIN_PID_DIGITS)) { + Row_pidDigits = ROW_MIN_PID_DIGITS; + return; + } + + Row_pidDigits = (int)log10(maxPid) + 1; + assert(Row_pidDigits <= ROW_MAX_PID_DIGITS); +} + +void Row_setUidColumnWidth(uid_t maxUid) { + if (maxUid < (uid_t)pow(10, ROW_MIN_UID_DIGITS)) { + Row_uidDigits = ROW_MIN_UID_DIGITS; + return; + } + + Row_uidDigits = (int)log10(maxUid) + 1; + assert(Row_uidDigits <= ROW_MAX_UID_DIGITS); +} + +uint8_t Row_fieldWidths[LAST_PROCESSFIELD] = { 0 }; + +void Row_resetFieldWidths(void) { + for (size_t i = 0; i < LAST_PROCESSFIELD; i++) { + if (!Process_fields[i].autoWidth) + continue; + + size_t len = strlen(Process_fields[i].title); + assert(len <= UINT8_MAX); + Row_fieldWidths[i] = (uint8_t)len; + } +} + +void Row_updateFieldWidth(RowField key, size_t width) { + if (width > UINT8_MAX) + Row_fieldWidths[key] = UINT8_MAX; + else if (width > Row_fieldWidths[key]) + Row_fieldWidths[key] = (uint8_t)width; +} + +// helper function to fill an aligned title string for a dynamic column +static const char* alignedTitleDynamicColumn(const Settings* settings, int key, char* titleBuffer, size_t titleBufferSize) { + const DynamicColumn* column = Hashtable_get(settings->dynamicColumns, key); + if (column == NULL) + return "- "; + + int width = column->width; + if (!width || abs(width) > DYNAMIC_MAX_COLUMN_WIDTH) + width = DYNAMIC_DEFAULT_COLUMN_WIDTH; + + xSnprintf(titleBuffer, titleBufferSize, "%*s ", width, column->heading); + return titleBuffer; +} + +// helper function to fill an aligned title string for a process field +static const char* alignedTitleProcessField(ProcessField field, char* titleBuffer, size_t titleBufferSize) { + const char* title = Process_fields[field].title; + if (!title) + return "- "; + + if (Process_fields[field].pidColumn) { + xSnprintf(titleBuffer, titleBufferSize, "%*s ", Row_pidDigits, title); + return titleBuffer; + } + + if (field == ST_UID) { + xSnprintf(titleBuffer, titleBufferSize, "%*s ", Row_uidDigits, title); + return titleBuffer; + } + + if (Process_fields[field].autoWidth) { + if (field == PERCENT_CPU) + xSnprintf(titleBuffer, titleBufferSize, "%*s ", Row_fieldWidths[field], title); + else + xSnprintf(titleBuffer, titleBufferSize, "%-*.*s ", Row_fieldWidths[field], Row_fieldWidths[field], title); + return titleBuffer; + } + + return title; +} + +// helper function to create an aligned title string for a given field +const char* RowField_alignedTitle(const Settings* settings, RowField field) { + static char titleBuffer[UINT8_MAX + sizeof(" ")]; + assert(sizeof(titleBuffer) >= DYNAMIC_MAX_COLUMN_WIDTH + sizeof(" ")); + assert(sizeof(titleBuffer) >= ROW_MAX_PID_DIGITS + sizeof(" ")); + assert(sizeof(titleBuffer) >= ROW_MAX_UID_DIGITS + sizeof(" ")); + + if (field < LAST_PROCESSFIELD) + return alignedTitleProcessField((ProcessField)field, titleBuffer, sizeof(titleBuffer)); + return alignedTitleDynamicColumn(settings, field, titleBuffer, sizeof(titleBuffer)); +} + +RowField RowField_keyAt(const Settings* settings, int at) { + const RowField* fields = (const RowField*) settings->ss->fields; + RowField field; + int x = 0; + for (int i = 0; (field = fields[i]); i++) { + int len = strlen(RowField_alignedTitle(settings, field)); + if (at >= x && at <= x + len) { + return field; + } + x += len; + } + return COMM; +} + +void Row_printBytes(RichString* str, unsigned long long number, bool coloring) { + char buffer[16]; + int len; + + int largeNumberColor = coloring ? CRT_colors[LARGE_NUMBER] : CRT_colors[PROCESS]; + int megabytesColor = coloring ? CRT_colors[PROCESS_MEGABYTES] : CRT_colors[PROCESS]; + int gigabytesColor = coloring ? CRT_colors[PROCESS_GIGABYTES] : CRT_colors[PROCESS]; + int shadowColor = coloring ? CRT_colors[PROCESS_SHADOW] : CRT_colors[PROCESS]; + int baseColor = CRT_colors[PROCESS]; + + if (number == ULLONG_MAX) { + //Invalid number + RichString_appendAscii(str, shadowColor, " N/A "); + return; + } + + number /= ONE_K; + + if (number < 1000) { + //Plain number, no markings + len = xSnprintf(buffer, sizeof(buffer), "%5llu ", number); + RichString_appendnAscii(str, baseColor, buffer, len); + } else if (number < 100000) { + //2 digit MB, 3 digit KB + len = xSnprintf(buffer, sizeof(buffer), "%2llu", number / 1000); + RichString_appendnAscii(str, megabytesColor, buffer, len); + number %= 1000; + len = xSnprintf(buffer, sizeof(buffer), "%03llu ", number); + RichString_appendnAscii(str, baseColor, buffer, len); + } else if (number < 1000 * ONE_K) { + //3 digit MB + number /= ONE_K; + len = xSnprintf(buffer, sizeof(buffer), "%4lluM ", number); + RichString_appendnAscii(str, megabytesColor, buffer, len); + } else if (number < 10000 * ONE_K) { + //1 digit GB, 3 digit MB + number /= ONE_K; + len = xSnprintf(buffer, sizeof(buffer), "%1llu", number / 1000); + RichString_appendnAscii(str, gigabytesColor, buffer, len); + number %= 1000; + len = xSnprintf(buffer, sizeof(buffer), "%03lluM ", number); + RichString_appendnAscii(str, megabytesColor, buffer, len); + } else if (number < 100 * ONE_M) { + //2 digit GB, 1 digit MB + len = xSnprintf(buffer, sizeof(buffer), "%2llu", number / ONE_M); + RichString_appendnAscii(str, gigabytesColor, buffer, len); + number = (number % ONE_M) * 10 / ONE_M; + len = xSnprintf(buffer, sizeof(buffer), ".%1llu", number); + RichString_appendnAscii(str, megabytesColor, buffer, len); + RichString_appendAscii(str, gigabytesColor, "G "); + } else if (number < 1000 * ONE_M) { + //3 digit GB + number /= ONE_M; + len = xSnprintf(buffer, sizeof(buffer), "%4lluG ", number); + RichString_appendnAscii(str, gigabytesColor, buffer, len); + } else if (number < 10000ULL * ONE_M) { + //1 digit TB, 3 digit GB + number /= ONE_M; + len = xSnprintf(buffer, sizeof(buffer), "%1llu", number / 1000); + RichString_appendnAscii(str, largeNumberColor, buffer, len); + number %= 1000; + len = xSnprintf(buffer, sizeof(buffer), "%03lluG ", number); + RichString_appendnAscii(str, gigabytesColor, buffer, len); + } else if (number < 100ULL * ONE_G) { + //2 digit TB, 1 digit GB + len = xSnprintf(buffer, sizeof(buffer), "%2llu", number / ONE_G); + RichString_appendnAscii(str, largeNumberColor, buffer, len); + number = (number % ONE_G) * 10 / ONE_G; + len = xSnprintf(buffer, sizeof(buffer), ".%1llu", number); + RichString_appendnAscii(str, gigabytesColor, buffer, len); + RichString_appendAscii(str, largeNumberColor, "T "); + } else if (number < 10000ULL * ONE_G) { + //3 digit TB or 1 digit PB, 3 digit TB + number /= ONE_G; + len = xSnprintf(buffer, sizeof(buffer), "%4lluT ", number); + RichString_appendnAscii(str, largeNumberColor, buffer, len); + } else { + //2 digit PB and above + len = xSnprintf(buffer, sizeof(buffer), "%4.1lfP ", (double)number / ONE_T); + RichString_appendnAscii(str, largeNumberColor, buffer, len); + } +} + +void Row_printKBytes(RichString* str, unsigned long long number, bool coloring) { + if (number == ULLONG_MAX) + Row_printBytes(str, ULLONG_MAX, coloring); + else + Row_printBytes(str, number * ONE_K, coloring); +} + +void Row_printCount(RichString* str, unsigned long long number, bool coloring) { + char buffer[13]; + + int largeNumberColor = coloring ? CRT_colors[LARGE_NUMBER] : CRT_colors[PROCESS]; + int megabytesColor = coloring ? CRT_colors[PROCESS_MEGABYTES] : CRT_colors[PROCESS]; + int shadowColor = coloring ? CRT_colors[PROCESS_SHADOW] : CRT_colors[PROCESS]; + int baseColor = CRT_colors[PROCESS]; + + if (number == ULLONG_MAX) { + RichString_appendAscii(str, CRT_colors[PROCESS_SHADOW], " N/A "); + } else if (number >= 100000LL * ONE_DECIMAL_T) { + xSnprintf(buffer, sizeof(buffer), "%11llu ", number / ONE_DECIMAL_G); + RichString_appendnAscii(str, largeNumberColor, buffer, 12); + } else if (number >= 100LL * ONE_DECIMAL_T) { + xSnprintf(buffer, sizeof(buffer), "%11llu ", number / ONE_DECIMAL_M); + RichString_appendnAscii(str, largeNumberColor, buffer, 8); + RichString_appendnAscii(str, megabytesColor, buffer + 8, 4); + } else if (number >= 10LL * ONE_DECIMAL_G) { + xSnprintf(buffer, sizeof(buffer), "%11llu ", number / ONE_DECIMAL_K); + RichString_appendnAscii(str, largeNumberColor, buffer, 5); + RichString_appendnAscii(str, megabytesColor, buffer + 5, 3); + RichString_appendnAscii(str, baseColor, buffer + 8, 4); + } else { + xSnprintf(buffer, sizeof(buffer), "%11llu ", number); + RichString_appendnAscii(str, largeNumberColor, buffer, 2); + RichString_appendnAscii(str, megabytesColor, buffer + 2, 3); + RichString_appendnAscii(str, baseColor, buffer + 5, 3); + RichString_appendnAscii(str, shadowColor, buffer + 8, 4); + } +} + +void Row_printTime(RichString* str, unsigned long long totalHundredths, bool coloring) { + char buffer[10]; + int len; + + unsigned long long totalSeconds = totalHundredths / 100; + unsigned long long hours = totalSeconds / 3600; + unsigned long long days = totalSeconds / 86400; + int minutes = (totalSeconds / 60) % 60; + int seconds = totalSeconds % 60; + int hundredths = totalHundredths - (totalSeconds * 100); + + int yearColor = coloring ? CRT_colors[LARGE_NUMBER] : CRT_colors[PROCESS]; + int dayColor = coloring ? CRT_colors[PROCESS_GIGABYTES] : CRT_colors[PROCESS]; + int hourColor = coloring ? CRT_colors[PROCESS_MEGABYTES] : CRT_colors[PROCESS]; + int baseColor = CRT_colors[PROCESS]; + + if (days >= /* Ignore leap years */365) { + int years = days / 365; + int daysLeft = days - 365 * years; + + if (years >= 10000000) { + RichString_appendnAscii(str, yearColor, "eternity ", 9); + } else if (years >= 1000) { + len = xSnprintf(buffer, sizeof(buffer), "%7dy ", years); + RichString_appendnAscii(str, yearColor, buffer, len); + } else if (daysLeft >= 100) { + len = xSnprintf(buffer, sizeof(buffer), "%3dy", years); + RichString_appendnAscii(str, yearColor, buffer, len); + len = xSnprintf(buffer, sizeof(buffer), "%3dd ", daysLeft); + RichString_appendnAscii(str, dayColor, buffer, len); + } else if (daysLeft >= 10) { + len = xSnprintf(buffer, sizeof(buffer), "%4dy", years); + RichString_appendnAscii(str, yearColor, buffer, len); + len = xSnprintf(buffer, sizeof(buffer), "%2dd ", daysLeft); + RichString_appendnAscii(str, dayColor, buffer, len); + } else { + len = xSnprintf(buffer, sizeof(buffer), "%5dy", years); + RichString_appendnAscii(str, yearColor, buffer, len); + len = xSnprintf(buffer, sizeof(buffer), "%1dd ", daysLeft); + RichString_appendnAscii(str, dayColor, buffer, len); + } + } else if (days >= 100) { + int hoursLeft = hours - days * 24; + + if (hoursLeft >= 10) { + len = xSnprintf(buffer, sizeof(buffer), "%4llud", days); + RichString_appendnAscii(str, dayColor, buffer, len); + len = xSnprintf(buffer, sizeof(buffer), "%2dh ", hoursLeft); + RichString_appendnAscii(str, hourColor, buffer, len); + } else { + len = xSnprintf(buffer, sizeof(buffer), "%5llud", days); + RichString_appendnAscii(str, dayColor, buffer, len); + len = xSnprintf(buffer, sizeof(buffer), "%1dh ", hoursLeft); + RichString_appendnAscii(str, hourColor, buffer, len); + } + } else if (hours >= 100) { + int minutesLeft = totalSeconds / 60 - hours * 60; + + if (minutesLeft >= 10) { + len = xSnprintf(buffer, sizeof(buffer), "%4lluh", hours); + RichString_appendnAscii(str, hourColor, buffer, len); + len = xSnprintf(buffer, sizeof(buffer), "%2dm ", minutesLeft); + RichString_appendnAscii(str, baseColor, buffer, len); + } else { + len = xSnprintf(buffer, sizeof(buffer), "%5lluh", hours); + RichString_appendnAscii(str, hourColor, buffer, len); + len = xSnprintf(buffer, sizeof(buffer), "%1dm ", minutesLeft); + RichString_appendnAscii(str, baseColor, buffer, len); + } + } else if (hours > 0) { + len = xSnprintf(buffer, sizeof(buffer), "%2lluh", hours); + RichString_appendnAscii(str, hourColor, buffer, len); + len = xSnprintf(buffer, sizeof(buffer), "%02d:%02d ", minutes, seconds); + RichString_appendnAscii(str, baseColor, buffer, len); + } else { + len = xSnprintf(buffer, sizeof(buffer), "%2d:%02d.%02d ", minutes, seconds, hundredths); + RichString_appendnAscii(str, baseColor, buffer, len); + } +} + +void Row_printRate(RichString* str, double rate, bool coloring) { + char buffer[16]; + + int largeNumberColor = CRT_colors[LARGE_NUMBER]; + int megabytesColor = CRT_colors[PROCESS_MEGABYTES]; + int shadowColor = CRT_colors[PROCESS_SHADOW]; + int baseColor = CRT_colors[PROCESS]; + + if (!coloring) { + largeNumberColor = CRT_colors[PROCESS]; + megabytesColor = CRT_colors[PROCESS]; + } + + if (!isNonnegative(rate)) { + RichString_appendAscii(str, shadowColor, " N/A "); + } else if (rate < 0.005) { + int len = snprintf(buffer, sizeof(buffer), "%7.2f B/s ", rate); + RichString_appendnAscii(str, shadowColor, buffer, len); + } else if (rate < ONE_K) { + int len = snprintf(buffer, sizeof(buffer), "%7.2f B/s ", rate); + RichString_appendnAscii(str, baseColor, buffer, len); + } else if (rate < ONE_M) { + int len = snprintf(buffer, sizeof(buffer), "%7.2f K/s ", rate / ONE_K); + RichString_appendnAscii(str, baseColor, buffer, len); + } else if (rate < ONE_G) { + int len = snprintf(buffer, sizeof(buffer), "%7.2f M/s ", rate / ONE_M); + RichString_appendnAscii(str, megabytesColor, buffer, len); + } else if (rate < ONE_T) { + int len = snprintf(buffer, sizeof(buffer), "%7.2f G/s ", rate / ONE_G); + RichString_appendnAscii(str, largeNumberColor, buffer, len); + } else if (rate < ONE_P) { + int len = snprintf(buffer, sizeof(buffer), "%7.2f T/s ", rate / ONE_T); + RichString_appendnAscii(str, largeNumberColor, buffer, len); + } else { + int len = snprintf(buffer, sizeof(buffer), "%7.2f P/s ", rate / ONE_P); + RichString_appendnAscii(str, largeNumberColor, buffer, len); + } +} + +void Row_printLeftAlignedField(RichString* str, int attr, const char* content, unsigned int width) { + int columns = width; + RichString_appendnWideColumns(str, attr, content, strlen(content), &columns); + RichString_appendChr(str, attr, ' ', width + 1 - columns); +} + +int Row_printPercentage(float val, char* buffer, size_t n, uint8_t width, int* attr) { + if (isNonnegative(val)) { + if (val < 0.05F) + *attr = CRT_colors[PROCESS_SHADOW]; + else if (val >= 99.9F) + *attr = CRT_colors[PROCESS_MEGABYTES]; + + int precision = 1; + + // Display "val" as "100" for columns like "MEM%". + if (width == 4 && val > 99.9F) { + precision = 0; + val = 100.0F; + } + + return xSnprintf(buffer, n, "%*.*f ", width, precision, val); + } + + *attr = CRT_colors[PROCESS_SHADOW]; + return xSnprintf(buffer, n, "%*.*s ", width, width, "N/A"); +} + +void Row_toggleTag(Row* this) { + this->tag = !this->tag; +} + +int Row_compare(const void* v1, const void* v2) { + const Row* r1 = (const Row*)v1; + const Row* r2 = (const Row*)v2; + + return SPACESHIP_NUMBER(r1->id, r2->id); +} + +int Row_compareByParent_Base(const void* v1, const void* v2) { + const Row* r1 = (const Row*)v1; + const Row* r2 = (const Row*)v2; + + int result = SPACESHIP_NUMBER( + r1->isRoot ? 0 : Row_getGroupOrParent(r1), + r2->isRoot ? 0 : Row_getGroupOrParent(r2) + ); + + if (result != 0) + return result; + + return Row_compare(v1, v2); +} + +const RowClass Row_class = { + .super = { + .extends = Class(Object), + .compare = Row_compare + }, +}; diff --git a/vendor/github.com/htop-dev/htop/Row.h b/vendor/github.com/htop-dev/htop/Row.h new file mode 100644 index 0000000000..c3ae56f030 --- /dev/null +++ b/vendor/github.com/htop-dev/htop/Row.h @@ -0,0 +1,181 @@ +#ifndef HEADER_Row +#define HEADER_Row +/* +htop - Row.h +(C) 2004-2015 Hisham H. Muhammad +(C) 2023 htop dev team +Released under the GNU GPLv2+, see the COPYING file +in the source distribution for its full text. +*/ + +#include +#include +#include +#include + +#include "Object.h" +#include "RichString.h" +#include "RowField.h" + + +extern uint8_t Row_fieldWidths[LAST_RESERVED_FIELD]; +#define ROW_MIN_PID_DIGITS 5 +#define ROW_MAX_PID_DIGITS 19 +#define ROW_MIN_UID_DIGITS 5 +#define ROW_MAX_UID_DIGITS 20 +extern int Row_pidDigits; +extern int Row_uidDigits; + +struct Machine_; +struct Settings_; +struct Table_; + +/* Class representing entities (such as processes) that can be + * represented in a tabular form in the lower half of the htop + * display. */ + +typedef struct Row_ { + /* Super object for emulated OOP */ + Object super; + + /* Pointer to quasi-global data */ + const struct Machine_* host; + + int id; + int group; + int parent; + + /* Has no known parent */ + bool isRoot; + + /* Whether the row was tagged by the user */ + bool tag; + + /* Whether to display this row */ + bool show; + + /* Whether this row was shown last cycle */ + bool wasShown; + + /* Whether to show children of this row in tree-mode */ + bool showChildren; + + /* Whether the row was updated during the last scan */ + bool updated; + + /* + * Internal state for tree-mode. + */ + int32_t indent; + unsigned int tree_depth; + + /* + * Internal time counts for showing new and exited processes. + */ + uint64_t seenStampMs; + uint64_t tombStampMs; +} Row; + +typedef Row* (*Row_New)(const struct Machine_*); +typedef void (*Row_WriteField)(const Row*, RichString*, RowField); +typedef bool (*Row_IsHighlighted)(const Row*); +typedef bool (*Row_IsVisible)(const Row*, const struct Table_*); +typedef bool (*Row_MatchesFilter)(const Row*, const struct Table_*); +typedef const char* (*Row_SortKeyString)(Row*); +typedef int (*Row_CompareByParent)(const Row*, const Row*); + +int Row_compare(const void* v1, const void* v2); + +typedef struct RowClass_ { + const ObjectClass super; + const Row_IsHighlighted isHighlighted; + const Row_IsVisible isVisible; + const Row_WriteField writeField; + const Row_MatchesFilter matchesFilter; + const Row_SortKeyString sortKeyString; + const Row_CompareByParent compareByParent; +} RowClass; + +#define As_Row(this_) ((const RowClass*)((this_)->super.klass)) + +#define Row_isHighlighted(r_) (As_Row(r_)->isHighlighted ? (As_Row(r_)->isHighlighted(r_)) : false) +#define Row_isVisible(r_, t_) (As_Row(r_)->isVisible ? (As_Row(r_)->isVisible(r_, t_)) : true) +#define Row_matchesFilter(r_, t_) (As_Row(r_)->matchesFilter ? (As_Row(r_)->matchesFilter(r_, t_)) : false) +#define Row_sortKeyString(r_) (As_Row(r_)->sortKeyString ? (As_Row(r_)->sortKeyString(r_)) : "") +#define Row_compareByParent(r1_, r2_) (As_Row(r1_)->compareByParent ? (As_Row(r1_)->compareByParent(r1_, r2_)) : Row_compareByParent_Base(r1_, r2_)) + +#define ONE_K 1024UL +#define ONE_M (ONE_K * ONE_K) +#define ONE_G (ONE_M * ONE_K) +#define ONE_T (1ULL * ONE_G * ONE_K) +#define ONE_P (1ULL * ONE_T * ONE_K) + +#define ONE_DECIMAL_K 1000UL +#define ONE_DECIMAL_M (ONE_DECIMAL_K * ONE_DECIMAL_K) +#define ONE_DECIMAL_G (ONE_DECIMAL_M * ONE_DECIMAL_K) +#define ONE_DECIMAL_T (1ULL * ONE_DECIMAL_G * ONE_DECIMAL_K) +#define ONE_DECIMAL_P (1ULL * ONE_DECIMAL_T * ONE_DECIMAL_K) + +extern const RowClass Row_class; + +void Row_init(Row* this, const struct Machine_* host); + +void Row_done(Row* this); + +void Row_display(const Object* cast, RichString* out); + +void Row_toggleTag(Row* this); + +void Row_resetFieldWidths(void); + +void Row_updateFieldWidth(RowField key, size_t width); + +void Row_printLeftAlignedField(RichString* str, int attr, const char* content, unsigned int width); + +const char* RowField_alignedTitle(const struct Settings_* settings, RowField field); + +RowField RowField_keyAt(const struct Settings_* settings, int at); + +/* Sets the size of the PID column based on the passed PID */ +void Row_setPidColumnWidth(pid_t maxPid); + +/* Sets the size of the UID column based on the passed UID */ +void Row_setUidColumnWidth(uid_t maxUid); + +/* Takes number in bytes (base 1024). Prints 6 columns. */ +void Row_printBytes(RichString* str, unsigned long long number, bool coloring); + +/* Takes number in kilo bytes (base 1024). Prints 6 columns. */ +void Row_printKBytes(RichString* str, unsigned long long number, bool coloring); + +/* Takes number as count (base 1000). Prints 12 columns. */ +void Row_printCount(RichString* str, unsigned long long number, bool coloring); + +/* Takes time in hundredths of a seconds. Prints 9 columns. */ +void Row_printTime(RichString* str, unsigned long long totalHundredths, bool coloring); + +/* Takes rate in bare unit (base 1024) per second. Prints 12 columns. */ +void Row_printRate(RichString* str, double rate, bool coloring); + +int Row_printPercentage(float val, char* buffer, size_t n, uint8_t width, int* attr); + +void Row_display(const Object* cast, RichString* out); + +static inline int Row_idEqualCompare(const void* v1, const void* v2) { + const int p1 = ((const Row*)v1)->id; + const int p2 = ((const Row*)v2)->id; + return p1 != p2; /* return zero when equal */ +} + +/* Routines used primarily with the tree view */ +static inline int Row_getGroupOrParent(const Row* this) { + return this->group == this->id ? this->parent : this->group; +} + +static inline bool Row_isChildOf(const Row* this, int id) { + return id == Row_getGroupOrParent(this); +} + +int Row_compareByParent_Base(const void* v1, const void* v2); + +#endif diff --git a/vendor/github.com/htop-dev/htop/RowField.h b/vendor/github.com/htop-dev/htop/RowField.h new file mode 100644 index 0000000000..1e01ea3e98 --- /dev/null +++ b/vendor/github.com/htop-dev/htop/RowField.h @@ -0,0 +1,56 @@ +#ifndef HEADER_RowField +#define HEADER_RowField +/* +htop - RowField.h +(C) 2023 htop dev team +Released under the GNU GPLv2+, see the COPYING file +in the source distribution for its full text. +*/ + +#include "ProcessField.h" // platform-specific fields reserved for processes + + +typedef enum ReservedFields_ { + NULL_FIELD = 0, + PID = 1, + COMM = 2, + STATE = 3, + PPID = 4, + PGRP = 5, + SESSION = 6, + TTY = 7, + TPGID = 8, + MINFLT = 10, + MAJFLT = 12, + PRIORITY = 18, + NICE = 19, + STARTTIME = 21, + PROCESSOR = 38, + M_VIRT = 39, + M_RESIDENT = 40, + ST_UID = 46, + PERCENT_CPU = 47, + PERCENT_MEM = 48, + USER = 49, + TIME = 50, + NLWP = 51, + TGID = 52, + PERCENT_NORM_CPU = 53, + ELAPSED = 54, + SCHEDULERPOLICY = 55, + PROC_COMM = 124, + PROC_EXE = 125, + CWD = 126, + + /* Platform specific fields, defined in ${platform}/ProcessField.h */ + PLATFORM_PROCESS_FIELDS + + /* Do not add new fields after this entry (dynamic entries follow) */ + LAST_RESERVED_FIELD +} ReservedFields; + +/* Follow ReservedField entries with dynamic fields defined at runtime */ +#define ROW_DYNAMIC_FIELDS LAST_RESERVED_FIELD +typedef int32_t RowField; + +#endif diff --git a/vendor/github.com/htop-dev/htop/Scheduling.c b/vendor/github.com/htop-dev/htop/Scheduling.c index 5ca49ae2dc..10846c0b12 100644 --- a/vendor/github.com/htop-dev/htop/Scheduling.c +++ b/vendor/github.com/htop-dev/htop/Scheduling.c @@ -97,7 +97,7 @@ Panel* Scheduling_newPriorityPanel(int policy, int preSelectedPriority) { return this; } -bool Scheduling_setPolicy(Process* proc, Arg arg) { +static bool Scheduling_setPolicy(Process* p, Arg arg) { const SchedulingArg* sarg = arg.v; int policy = sarg->policy; @@ -112,13 +112,19 @@ bool Scheduling_setPolicy(Process* proc, Arg arg) { policy &= SCHED_RESET_ON_FORK; #endif - int r = sched_setscheduler(proc->pid, policy, ¶m); + int r = sched_setscheduler(Process_getPid(p), policy, ¶m); /* POSIX says on success the previous scheduling policy should be returned, * but Linux always returns 0. */ return r != -1; } +bool Scheduling_rowSetPolicy(Row* row, Arg arg) { + Process* p = (Process*) row; + assert(Object_isA((const Object*) p, (const ObjectClass*) &Process_class)); + return Scheduling_setPolicy(p, arg); +} + const char* Scheduling_formatPolicy(int policy) { #ifdef SCHED_RESET_ON_FORK policy = policy & ~SCHED_RESET_ON_FORK; @@ -149,6 +155,6 @@ const char* Scheduling_formatPolicy(int policy) { } void Scheduling_readProcessPolicy(Process* proc) { - proc->scheduling_policy = sched_getscheduler(proc->pid); + proc->scheduling_policy = sched_getscheduler(Process_getPid(proc)); } #endif /* SCHEDULER_SUPPORT */ diff --git a/vendor/github.com/htop-dev/htop/Scheduling.h b/vendor/github.com/htop-dev/htop/Scheduling.h index d91855ae48..e5952b0071 100644 --- a/vendor/github.com/htop-dev/htop/Scheduling.h +++ b/vendor/github.com/htop-dev/htop/Scheduling.h @@ -13,6 +13,7 @@ in the source distribution for its full text. #include #include "Panel.h" +#include "Process.h" #if defined(HAVE_SCHED_SETSCHEDULER) && defined(HAVE_SCHED_GETSCHEDULER) @@ -38,7 +39,7 @@ typedef struct { int priority; } SchedulingArg; -bool Scheduling_setPolicy(Process* proc, Arg arg); +bool Scheduling_rowSetPolicy(Row* proc, Arg arg); const char* Scheduling_formatPolicy(int policy); diff --git a/vendor/github.com/htop-dev/htop/ScreenManager.c b/vendor/github.com/htop-dev/htop/ScreenManager.c index 18e09343ed..6c1dd12efc 100644 --- a/vendor/github.com/htop-dev/htop/ScreenManager.c +++ b/vendor/github.com/htop-dev/htop/ScreenManager.c @@ -133,13 +133,14 @@ static void checkRecalculation(ScreenManager* this, double* oldTime, int* sortTi *oldTime = newTime; int oldUidDigits = Process_uidDigits; if (!this->state->pauseUpdate && (*sortTimeout == 0 || host->settings->ss->treeView)) { - host->pl->needsSort = true; + host->activeTable->needsSort = true; *sortTimeout = 1; } // sample current values for system metrics and processes if not paused Machine_scan(host); if (!this->state->pauseUpdate) - ProcessList_scan(host->pl); + Machine_scanTables(host); + // always update header, especially to avoid gaps in graph meters Header_updateData(this->header); // force redraw if the number of UID digits was changed @@ -149,7 +150,7 @@ static void checkRecalculation(ScreenManager* this, double* oldTime, int* sortTi *redraw = true; } if (*redraw) { - ProcessList_rebuildPanel(host->pl); + Table_rebuildPanel(host->activeTable); if (!this->state->hideMeters) Header_draw(this->header); } @@ -192,7 +193,7 @@ static void ScreenManager_drawScreenTabs(ScreenManager* this) { } for (int s = 0; screens[s]; s++) { - bool ok = drawTab(&y, &x, l, screens[s]->name, s == cur); + bool ok = drawTab(&y, &x, l, screens[s]->heading, s == cur); if (!ok) { break; } @@ -246,6 +247,12 @@ void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey, con if (redraw || force_redraw) { ScreenManager_drawPanels(this, focus, force_redraw); force_redraw = false; + if (this->host->iterationsRemaining != -1) { + if (!--this->host->iterationsRemaining) { + quit = true; + continue; + } + } } int prevCh = ch; diff --git a/vendor/github.com/htop-dev/htop/ScreenTabsPanel.c b/vendor/github.com/htop-dev/htop/ScreenTabsPanel.c new file mode 100644 index 0000000000..f61745e096 --- /dev/null +++ b/vendor/github.com/htop-dev/htop/ScreenTabsPanel.c @@ -0,0 +1,372 @@ +/* +htop - ScreenTabsPanel.c +(C) 2023 htop dev team +Released under the GNU GPLv2+, see the COPYING file +in the source distribution for its full text. +*/ + +#include "ScreenTabsPanel.h" + +#include +#include +#include + +#include "CRT.h" +#include "FunctionBar.h" +#include "Hashtable.h" +#include "ProvideCurses.h" +#include "Settings.h" +#include "XUtils.h" + + +static HandlerResult ScreenNamesPanel_eventHandlerNormal(Panel* super, int ch); + +ObjectClass ScreenTabListItem_class = { + .extends = Class(ListItem), + .display = ListItem_display, + .delete = ListItem_delete, + .compare = ListItem_compare +}; + +static void ScreenNamesPanel_fill(ScreenNamesPanel* this, DynamicScreen* ds) { + const Settings* settings = this->settings; + Panel* super = (Panel*) this; + Panel_prune(super); + + for (unsigned int i = 0; i < settings->nScreens; i++) { + const ScreenSettings* ss = settings->screens[i]; + + if (ds == NULL) { + if (ss->dynamic != NULL) + continue; + /* built-in (processes, not dynamic) - e.g. Main or I/O */ + } else { + if (ss->dynamic == NULL) + continue; + if (!String_eq(ds->name, ss->dynamic)) + continue; + /* matching dynamic screen found, add it into the Panel */ + } + Panel_add(super, (Object*) ListItem_new(ss->heading, i)); + } + + this->ds = ds; +} + +static void ScreenTabsPanel_delete(Object* object) { + Panel* super = (Panel*) object; + ScreenTabsPanel* this = (ScreenTabsPanel*) object; + + Panel_done(super); + free(this); +} + +static HandlerResult ScreenTabsPanel_eventHandler(Panel* super, int ch) { + ScreenTabsPanel* const this = (ScreenTabsPanel* const) super; + + HandlerResult result = IGNORED; + + int selected = Panel_getSelectedIndex(super); + switch (ch) { + case EVENT_SET_SELECTED: + result = HANDLED; + break; + case KEY_F(5): + case KEY_CTRL('N'): + /* pass onto the Names panel for creating new screen */ + return ScreenNamesPanel_eventHandlerNormal(&this->names->super, ch); + case KEY_UP: + case KEY_DOWN: + case KEY_NPAGE: + case KEY_PPAGE: + case KEY_HOME: + case KEY_END: { + int previous = selected; + Panel_onKey(super, ch); + selected = Panel_getSelectedIndex(super); + if (previous != selected) + result = HANDLED; + break; + } + default: + { + if (ch < 255 && isalpha(ch)) + result = Panel_selectByTyping(super, ch); + if (result == BREAK_LOOP) + result = IGNORED; + break; + } + } + if (result == HANDLED) { + ScreenTabListItem* focus = (ScreenTabListItem*) Panel_getSelected(super); + ScreenNamesPanel_fill(this->names, focus->ds); + } + return result; +} + +PanelClass ScreenTabsPanel_class = { + .super = { + .extends = Class(Panel), + .delete = ScreenTabsPanel_delete, + }, + .eventHandler = ScreenTabsPanel_eventHandler +}; + +static ScreenTabListItem* ScreenTabListItem_new(const char* value, DynamicScreen* ds) { + ScreenTabListItem* this = AllocThis(ScreenTabListItem); + ListItem_init((ListItem*)this, value, 0); + this->ds = ds; + return this; +} + +static void addDynamicScreen(ATTR_UNUSED ht_key_t key, void* value, void* userdata) { + DynamicScreen* screen = (DynamicScreen*) value; + Panel* super = (Panel*) userdata; + const char* name = screen->heading ? screen->heading : screen->name; + + Panel_add(super, (Object*) ScreenTabListItem_new(name, screen)); +} + +static const char* const ScreenTabsFunctions[] = {" ", " ", " ", " ", "New ", " ", " ", " ", " ", "Done ", NULL}; + +ScreenTabsPanel* ScreenTabsPanel_new(Settings* settings) { + ScreenTabsPanel* this = AllocThis(ScreenTabsPanel); + Panel* super = (Panel*) this; + FunctionBar* fuBar = FunctionBar_new(ScreenTabsFunctions, NULL, NULL); + Panel_init(super, 1, 1, 1, 1, Class(ListItem), true, fuBar); + + this->settings = settings; + this->names = ScreenNamesPanel_new(settings); + super->cursorOn = false; + this->cursor = 0; + Panel_setHeader(super, "Screen tabs"); + + assert(settings->dynamicScreens != NULL); + Panel_add(super, (Object*) ScreenTabListItem_new("Processes", NULL)); + Hashtable_foreach(settings->dynamicScreens, addDynamicScreen, super); + + return this; +} + +// ------------- + +ObjectClass ScreenNameListItem_class = { + .extends = Class(ListItem), + .display = ListItem_display, + .delete = ListItem_delete, + .compare = ListItem_compare +}; + +ScreenNameListItem* ScreenNameListItem_new(const char* value, ScreenSettings* ss) { + ScreenNameListItem* this = AllocThis(ScreenNameListItem); + ListItem_init((ListItem*)this, value, 0); + this->ss = ss; + return this; +} + +static const char* const ScreenNamesFunctions[] = {" ", " ", " ", " ", "New ", " ", " ", " ", " ", "Done ", NULL}; + +static void ScreenNamesPanel_delete(Object* object) { + Panel* super = (Panel*) object; + ScreenNamesPanel* this = (ScreenNamesPanel*) object; + + /* do not delete screen settings still in use */ + int n = Panel_size(super); + for (int i = 0; i < n; i++) { + ScreenNameListItem* item = (ScreenNameListItem*) Panel_get(super, i); + item->ss = NULL; + } + + /* during renaming the ListItem's value points to our static buffer */ + if (this->renamingItem) + this->renamingItem->value = this->saved; + + Panel_done(super); + free(this); +} + +static void renameScreenSettings(ScreenNamesPanel* this, const ListItem* item) { + const ScreenNameListItem* nameItem = (const ScreenNameListItem*) item; + + ScreenSettings* ss = nameItem->ss; + free_and_xStrdup(&ss->heading, item->value); + + Settings* settings = this->settings; + settings->changed = true; + settings->lastUpdate++; +} + +static HandlerResult ScreenNamesPanel_eventHandlerRenaming(Panel* super, int ch) { + ScreenNamesPanel* const this = (ScreenNamesPanel*) super; + + if (ch >= 32 && ch < 127 && ch != '=') { + if (this->cursor < SCREEN_NAME_LEN - 1) { + this->buffer[this->cursor] = (char)ch; + this->cursor++; + super->selectedLen = strlen(this->buffer); + Panel_setCursorToSelection(super); + } + } else { + switch (ch) { + case 127: + case KEY_BACKSPACE: + { + if (this->cursor > 0) { + this->cursor--; + this->buffer[this->cursor] = '\0'; + super->selectedLen = strlen(this->buffer); + Panel_setCursorToSelection(super); + } + break; + } + case '\n': + case '\r': + case KEY_ENTER: + { + ListItem* item = (ListItem*) Panel_getSelected(super); + if (!item) + break; + assert(item == this->renamingItem); + free(this->saved); + item->value = xStrdup(this->buffer); + this->renamingItem = NULL; + super->cursorOn = false; + Panel_setSelectionColor(super, PANEL_SELECTION_FOCUS); + renameScreenSettings(this, item); + break; + } + case 27: // Esc + { + ListItem* item = (ListItem*) Panel_getSelected(super); + if (!item) + break; + assert(item == this->renamingItem); + item->value = this->saved; + this->renamingItem = NULL; + super->cursorOn = false; + Panel_setSelectionColor(super, PANEL_SELECTION_FOCUS); + break; + } + } + } + return HANDLED; +} + +static void startRenaming(Panel* super) { + ScreenNamesPanel* const this = (ScreenNamesPanel*) super; + + ListItem* item = (ListItem*) Panel_getSelected(super); + if (item == NULL) + return; + this->renamingItem = item; + super->cursorOn = true; + char* name = item->value; + this->saved = name; + strncpy(this->buffer, name, SCREEN_NAME_LEN); + this->buffer[SCREEN_NAME_LEN] = '\0'; + this->cursor = strlen(this->buffer); + item->value = this->buffer; + Panel_setSelectionColor(super, PANEL_EDIT); + super->selectedLen = strlen(this->buffer); + Panel_setCursorToSelection(super); +} + +static void addNewScreen(Panel* super, DynamicScreen* ds) { + ScreenNamesPanel* const this = (ScreenNamesPanel*) super; + const char* name = "New"; + ScreenSettings* ss = (ds != NULL) ? Settings_newDynamicScreen(this->settings, name, ds, NULL) : Settings_newScreen(this->settings, &(const ScreenDefaults) { .name = name, .columns = "PID Command", .sortKey = "PID" }); + ScreenNameListItem* item = ScreenNameListItem_new(name, ss); + int idx = Panel_getSelectedIndex(super); + Panel_insert(super, idx + 1, (Object*) item); + Panel_setSelected(super, idx + 1); +} + +static HandlerResult ScreenNamesPanel_eventHandlerNormal(Panel* super, int ch) { + ScreenNamesPanel* const this = (ScreenNamesPanel*) super; + ScreenNameListItem* oldFocus = (ScreenNameListItem*) Panel_getSelected(super); + HandlerResult result = IGNORED; + switch (ch) { + case '\n': + case '\r': + case KEY_ENTER: + case KEY_MOUSE: + case KEY_RECLICK: + { + Panel_setSelectionColor(super, PANEL_SELECTION_FOCUS); + result = HANDLED; + break; + } + case EVENT_SET_SELECTED: + result = HANDLED; + break; + case KEY_NPAGE: + case KEY_PPAGE: + case KEY_HOME: + case KEY_END: + { + Panel_onKey(super, ch); + break; + } + case KEY_F(5): + case KEY_CTRL('N'): + { + addNewScreen(super, this->ds); + startRenaming(super); + result = HANDLED; + break; + } + default: + { + if (ch < 255 && isalpha(ch)) + result = Panel_selectByTyping(super, ch); + if (result == BREAK_LOOP) + result = IGNORED; + break; + } + } + ScreenNameListItem* newFocus = (ScreenNameListItem*) Panel_getSelected(super); + if (newFocus && oldFocus != newFocus) + result = HANDLED; + return result; +} + +static HandlerResult ScreenNamesPanel_eventHandler(Panel* super, int ch) { + ScreenNamesPanel* const this = (ScreenNamesPanel*) super; + + if (!this->renamingItem) + return ScreenNamesPanel_eventHandlerNormal(super, ch); + return ScreenNamesPanel_eventHandlerRenaming(super, ch); +} + +PanelClass ScreenNamesPanel_class = { + .super = { + .extends = Class(Panel), + .delete = ScreenNamesPanel_delete + }, + .eventHandler = ScreenNamesPanel_eventHandler +}; + +ScreenNamesPanel* ScreenNamesPanel_new(Settings* settings) { + ScreenNamesPanel* this = AllocThis(ScreenNamesPanel); + Panel* super = (Panel*) this; + FunctionBar* fuBar = FunctionBar_new(ScreenNamesFunctions, NULL, NULL); + Panel_init(super, 1, 1, 1, 1, Class(ListItem), true, fuBar); + + this->settings = settings; + this->renamingItem = NULL; + memset(this->buffer, 0, sizeof(this->buffer)); + this->ds = NULL; + this->saved = NULL; + this->cursor = 0; + super->cursorOn = false; + Panel_setHeader(super, "Screens"); + + for (unsigned int i = 0; i < settings->nScreens; i++) { + ScreenSettings* ss = settings->screens[i]; + /* initially show only for Processes tabs (selected) */ + if (ss->dynamic) + continue; + Panel_add(super, (Object*) ScreenNameListItem_new(ss->heading, ss)); + } + return this; +} diff --git a/vendor/github.com/htop-dev/htop/ScreenTabsPanel.h b/vendor/github.com/htop-dev/htop/ScreenTabsPanel.h new file mode 100644 index 0000000000..3b89ffc2d8 --- /dev/null +++ b/vendor/github.com/htop-dev/htop/ScreenTabsPanel.h @@ -0,0 +1,60 @@ +#ifndef HEADER_ScreenTabsPanel +#define HEADER_ScreenTabsPanel +/* +htop - ScreenTabsPanel.h +(C) 2023 htop dev team +Released under the GNU GPLv2+, see the COPYING file +in the source distribution for its full text. +*/ + +#include "DynamicScreen.h" +#include "ListItem.h" +#include "Panel.h" +#include "ScreensPanel.h" +#include "ScreenManager.h" +#include "Settings.h" + + +typedef struct ScreenNamesPanel_ { + Panel super; + + ScreenManager* scr; + Settings* settings; + char buffer[SCREEN_NAME_LEN + 1]; + DynamicScreen* ds; + char* saved; + int cursor; + ListItem* renamingItem; +} ScreenNamesPanel; + +typedef struct ScreenNameListItem_ { + ListItem super; + ScreenSettings* ss; +} ScreenNameListItem; + +typedef struct ScreenTabsPanel_ { + Panel super; + + ScreenManager* scr; + Settings* settings; + ScreenNamesPanel* names; + int cursor; +} ScreenTabsPanel; + +typedef struct ScreenTabListItem_ { + ListItem super; + DynamicScreen* ds; +} ScreenTabListItem; + + +ScreenTabsPanel* ScreenTabsPanel_new(Settings* settings); + +extern ObjectClass ScreenNameListItem_class; + +ScreenNameListItem* ScreenNameListItem_new(const char* value, ScreenSettings* ss); + +extern PanelClass ScreenNamesPanel_class; + +ScreenNamesPanel* ScreenNamesPanel_new(Settings* settings); + +#endif diff --git a/vendor/github.com/htop-dev/htop/ScreensPanel.c b/vendor/github.com/htop-dev/htop/ScreensPanel.c index cb664ac450..d00388098a 100644 --- a/vendor/github.com/htop-dev/htop/ScreensPanel.c +++ b/vendor/github.com/htop-dev/htop/ScreensPanel.c @@ -1,7 +1,7 @@ /* htop - ScreensPanel.c (C) 2004-2011 Hisham H. Muhammad -(C) 2020-2022 htop dev team +(C) 2020-2023 htop dev team Released under the GNU GPLv2+, see the COPYING file in the source distribution for its full text. */ @@ -12,6 +12,7 @@ in the source distribution for its full text. #include #include +#include "AvailableColumnsPanel.h" #include "CRT.h" #include "FunctionBar.h" #include "Hashtable.h" @@ -43,6 +44,7 @@ ScreenListItem* ScreenListItem_new(const char* value, ScreenSettings* ss) { } static const char* const ScreensFunctions[] = {" ", "Rename", " ", " ", "New ", " ", "MoveUp", "MoveDn", "Remove", "Done ", NULL}; +static const char* const DynamicFunctions[] = {" ", "Rename", " ", " ", " ", " ", "MoveUp", "MoveDn", "Remove", "Done ", NULL}; static void ScreensPanel_delete(Object* object) { Panel* super = (Panel*) object; @@ -55,11 +57,6 @@ static void ScreensPanel_delete(Object* object) { item->ss = NULL; } - /* during renaming the ListItem's value points to our static buffer */ - if (this->renamingItem) - this->renamingItem->value = this->saved; - - Panel_done(super); free(this); } @@ -212,6 +209,8 @@ static HandlerResult ScreensPanel_eventHandlerNormal(Panel* super, int ch) { case KEY_F(5): case KEY_CTRL('N'): { + if (this->settings->dynamicScreens) + break; addNewScreen(super); startRenaming(super); shouldRebuildArray = true; @@ -272,7 +271,9 @@ static HandlerResult ScreensPanel_eventHandlerNormal(Panel* super, int ch) { } ScreenListItem* newFocus = (ScreenListItem*) Panel_getSelected(super); if (newFocus && oldFocus != newFocus) { - ColumnsPanel_fill(this->columns, newFocus->ss, this->settings->dynamicColumns); + Hashtable* dynamicColumns = this->settings->dynamicColumns; + ColumnsPanel_fill(this->columns, newFocus->ss, dynamicColumns); + AvailableColumnsPanel_fill(this->availableColumns, newFocus->ss->dynamic, dynamicColumns); result = HANDLED; } if (shouldRebuildArray) @@ -304,11 +305,12 @@ ScreensPanel* ScreensPanel_new(Settings* settings) { ScreensPanel* this = AllocThis(ScreensPanel); Panel* super = (Panel*) this; Hashtable* columns = settings->dynamicColumns; - FunctionBar* fuBar = FunctionBar_new(ScreensFunctions, NULL, NULL); + FunctionBar* fuBar = FunctionBar_new(settings->dynamicScreens ? DynamicFunctions : ScreensFunctions, NULL, NULL); Panel_init(super, 1, 1, 1, 1, Class(ListItem), true, fuBar); this->settings = settings; this->columns = ColumnsPanel_new(settings->screens[0], columns, &(settings->changed)); + this->availableColumns = AvailableColumnsPanel_new((Panel*) this->columns, columns); this->moving = false; this->renamingItem = NULL; super->cursorOn = false; @@ -317,7 +319,7 @@ ScreensPanel* ScreensPanel_new(Settings* settings) { for (unsigned int i = 0; i < settings->nScreens; i++) { ScreenSettings* ss = settings->screens[i]; - char* name = ss->name; + char* name = ss->heading; Panel_add(super, (Object*) ScreenListItem_new(name, ss)); } return this; @@ -332,9 +334,8 @@ void ScreensPanel_update(Panel* super) { for (int i = 0; i < size; i++) { ScreenListItem* item = (ScreenListItem*) Panel_get(super, i); ScreenSettings* ss = item->ss; - free(ss->name); + free_and_xStrdup(&ss->heading, ((ListItem*) item)->value); this->settings->screens[i] = ss; - ss->name = xStrdup(((ListItem*) item)->value); } this->settings->screens[size] = NULL; } diff --git a/vendor/github.com/htop-dev/htop/ScreensPanel.h b/vendor/github.com/htop-dev/htop/ScreensPanel.h index 60aaf2a2d4..0be0b82446 100644 --- a/vendor/github.com/htop-dev/htop/ScreensPanel.h +++ b/vendor/github.com/htop-dev/htop/ScreensPanel.h @@ -10,7 +10,9 @@ in the source distribution for its full text. #include +#include "AvailableColumnsPanel.h" #include "ColumnsPanel.h" +#include "DynamicScreen.h" #include "ListItem.h" #include "Object.h" #include "Panel.h" @@ -27,6 +29,7 @@ typedef struct ScreensPanel_ { ScreenManager* scr; Settings* settings; ColumnsPanel* columns; + AvailableColumnsPanel* availableColumns; char buffer[SCREEN_NAME_LEN + 1]; char* saved; int cursor; @@ -36,6 +39,7 @@ typedef struct ScreensPanel_ { typedef struct ScreenListItem_ { ListItem super; + DynamicScreen* ds; ScreenSettings* ss; } ScreenListItem; @@ -44,8 +48,6 @@ extern ObjectClass ScreenListItem_class; ScreenListItem* ScreenListItem_new(const char* value, ScreenSettings* ss); -extern PanelClass ScreensPanel_class; - ScreensPanel* ScreensPanel_new(Settings* settings); void ScreensPanel_update(Panel* super); diff --git a/vendor/github.com/htop-dev/htop/Settings.c b/vendor/github.com/htop-dev/htop/Settings.c index c712966e3f..5265ce4d61 100644 --- a/vendor/github.com/htop-dev/htop/Settings.c +++ b/vendor/github.com/htop-dev/htop/Settings.c @@ -19,6 +19,7 @@ in the source distribution for its full text. #include "CRT.h" #include "DynamicColumn.h" +#include "DynamicScreen.h" #include "Macros.h" #include "Meter.h" #include "Platform.h" @@ -203,13 +204,25 @@ static void Settings_defaultMeters(Settings* this, unsigned int initialCpuCount) this->hColumns[1].modes[r++] = TEXT_METERMODE; } -static const char* toFieldName(Hashtable* columns, int id) { - if (id < 0) +static const char* toFieldName(Hashtable* columns, int id, bool* enabled) { + if (id < 0) { + if (enabled) + *enabled = false; return NULL; - if (id >= LAST_PROCESSFIELD) { + } + if (id >= ROW_DYNAMIC_FIELDS) { const DynamicColumn* column = DynamicColumn_lookup(columns, id); + if (!column) { + if (enabled) + *enabled = false; + return NULL; + } + if (enabled) + *enabled = column->enabled; return column->name; } + if (enabled) + *enabled = true; return Process_fields[id].name; } @@ -217,7 +230,7 @@ static int toFieldIndex(Hashtable* columns, const char* str) { if (isdigit(str[0])) { // This "+1" is for compatibility with the older enum format. int id = atoi(str) + 1; - if (toFieldName(columns, id)) { + if (toFieldName(columns, id, NULL)) { return id; } } else { @@ -237,7 +250,7 @@ static int toFieldIndex(Hashtable* columns, const char* str) { } // Fallback to iterative scan of table of fields by-name. for (int p = 1; p < LAST_PROCESSFIELD; p++) { - const char* pName = toFieldName(columns, p); + const char* pName = toFieldName(columns, p, NULL); if (pName && strcmp(pName, str) == 0) return p; } @@ -269,34 +282,57 @@ static void ScreenSettings_readFields(ScreenSettings* ss, Hashtable* columns, co String_freeArray(ids); } +static ScreenSettings* Settings_initScreenSettings(ScreenSettings* ss, Settings* this, const char *columns) { + ScreenSettings_readFields(ss, this->dynamicColumns, columns); + this->screens[this->nScreens] = ss; + this->nScreens++; + this->screens = xRealloc(this->screens, sizeof(ScreenSettings*) * (this->nScreens + 1)); + this->screens[this->nScreens] = NULL; + return ss; +} + ScreenSettings* Settings_newScreen(Settings* this, const ScreenDefaults* defaults) { int sortKey = defaults->sortKey ? toFieldIndex(this->dynamicColumns, defaults->sortKey) : PID; + int treeSortKey = defaults->treeSortKey ? toFieldIndex(this->dynamicColumns, defaults->treeSortKey) : PID; int sortDesc = (sortKey >= 0 && sortKey < LAST_PROCESSFIELD) ? Process_fields[sortKey].defaultSortDesc : 1; ScreenSettings* ss = xMalloc(sizeof(ScreenSettings)); *ss = (ScreenSettings) { - .name = xStrdup(defaults->name), + .heading = xStrdup(defaults->name), + .dynamic = NULL, + .table = NULL, .fields = xCalloc(LAST_PROCESSFIELD, sizeof(ProcessField)), .flags = 0, .direction = sortDesc ? -1 : 1, .treeDirection = 1, .sortKey = sortKey, - .treeSortKey = PID, + .treeSortKey = treeSortKey, .treeView = false, .treeViewAlwaysByPID = false, .allBranchesCollapsed = false, }; + return Settings_initScreenSettings(ss, this, defaults->columns); +} - ScreenSettings_readFields(ss, this->dynamicColumns, defaults->columns); - this->screens[this->nScreens] = ss; - this->nScreens++; - this->screens = xRealloc(this->screens, sizeof(ScreenSettings*) * (this->nScreens + 1)); - this->screens[this->nScreens] = NULL; - return ss; +ScreenSettings* Settings_newDynamicScreen(Settings* this, const char* tab, const DynamicScreen* screen, Table* table) { + int sortKey = toFieldIndex(this->dynamicColumns, screen->columnKeys); + + ScreenSettings* ss = xMalloc(sizeof(ScreenSettings)); + *ss = (ScreenSettings) { + .heading = xStrdup(tab), + .dynamic = xStrdup(screen->name), + .table = table, + .fields = xCalloc(LAST_PROCESSFIELD, sizeof(ProcessField)), + .direction = screen->direction, + .treeDirection = 1, + .sortKey = sortKey, + }; + return Settings_initScreenSettings(ss, this, screen->columnKeys); } void ScreenSettings_delete(ScreenSettings* this) { - free(this->name); + free(this->heading); + free(this->dynamic); free(this->fields); free(this); } @@ -308,6 +344,7 @@ static ScreenSettings* Settings_defaultScreens(Settings* this) { const ScreenDefaults* defaults = &Platform_defaultScreens[i]; Settings_newScreen(this, defaults); } + Platform_defaultDynamicScreens(this); return this->screens[0]; } @@ -505,6 +542,10 @@ static bool Settings_read(Settings* this, const char* fileName, unsigned int ini } else if (String_eq(option[0], ".all_branches_collapsed")) { if (screen) screen->allBranchesCollapsed = atoi(option[1]); + } else if (String_eq(option[0], ".dynamic")) { + if (screen) + free_and_xStrdup(&screen->dynamic, option[1]); + Platform_addDynamicScreen(screen); } String_freeArray(option); } @@ -520,11 +561,13 @@ static void writeFields(FILE* fd, const ProcessField* fields, Hashtable* columns const char* sep = ""; for (unsigned int i = 0; fields[i]; i++) { if (fields[i] < LAST_PROCESSFIELD && byName) { - const char* pName = toFieldName(columns, fields[i]); + const char* pName = toFieldName(columns, fields[i], NULL); fprintf(fd, "%s%s", sep, pName); } else if (fields[i] >= LAST_PROCESSFIELD && byName) { - const char* pName = toFieldName(columns, fields[i]); - fprintf(fd, " Dynamic(%s)", pName); + bool enabled; + const char* pName = toFieldName(columns, fields[i], &enabled); + if (enabled) + fprintf(fd, "%sDynamic(%s)", sep, pName); } else { // This "-1" is for compatibility with the older enum format. fprintf(fd, "%s%d", sep, (int) fields[i] - 1); @@ -639,12 +682,23 @@ int Settings_write(const Settings* this, bool onCrash) { for (unsigned int i = 0; i < this->nScreens; i++) { ScreenSettings* ss = this->screens[i]; - fprintf(fd, "screen:%s=", ss->name); + const char* sortKey = toFieldName(this->dynamicColumns, ss->sortKey, NULL); + const char* treeSortKey = toFieldName(this->dynamicColumns, ss->treeSortKey, NULL); + + fprintf(fd, "screen:%s=", ss->heading); writeFields(fd, ss->fields, this->dynamicColumns, true, separator); - printSettingString(".sort_key", toFieldName(this->dynamicColumns, ss->sortKey)); - printSettingString(".tree_sort_key", toFieldName(this->dynamicColumns, ss->treeSortKey)); + if (ss->dynamic) { + printSettingString(".dynamic", ss->dynamic); + if (ss->sortKey && ss->sortKey != PID) + fprintf(fd, "%s=Dynamic(%s)%c", ".sort_key", sortKey, separator); + if (ss->treeSortKey && ss->treeSortKey != PID) + fprintf(fd, "%s=Dynamic(%s)%c", ".tree_sort_key", treeSortKey, separator); + } else { + printSettingString(".sort_key", sortKey); + printSettingString(".tree_sort_key", treeSortKey); + printSettingInteger(".tree_view_always_by_pid", ss->treeViewAlwaysByPID); + } printSettingInteger(".tree_view", ss->treeView); - printSettingInteger(".tree_view_always_by_pid", ss->treeViewAlwaysByPID); printSettingInteger(".sort_direction", ss->direction); printSettingInteger(".tree_sort_direction", ss->treeDirection); printSettingInteger(".all_branches_collapsed", ss->allBranchesCollapsed); @@ -667,9 +721,10 @@ int Settings_write(const Settings* this, bool onCrash) { return r; } -Settings* Settings_new(unsigned int initialCpuCount, Hashtable* dynamicMeters, Hashtable* dynamicColumns) { +Settings* Settings_new(unsigned int initialCpuCount, Hashtable* dynamicMeters, Hashtable* dynamicColumns, Hashtable* dynamicScreens) { Settings* this = xCalloc(1, sizeof(Settings)); + this->dynamicScreens = dynamicScreens; this->dynamicColumns = dynamicColumns; this->dynamicMeters = dynamicMeters; this->hLayout = HF_TWO_50_50; diff --git a/vendor/github.com/htop-dev/htop/Settings.h b/vendor/github.com/htop-dev/htop/Settings.h index 48c62590aa..0c202f8a41 100644 --- a/vendor/github.com/htop-dev/htop/Settings.h +++ b/vendor/github.com/htop-dev/htop/Settings.h @@ -14,17 +14,21 @@ in the source distribution for its full text. #include "Hashtable.h" #include "HeaderLayout.h" -#include "Process.h" +#include "Row.h" #define DEFAULT_DELAY 15 #define CONFIG_READER_MIN_VERSION 3 +struct DynamicScreen_; +struct Table_; + typedef struct { const char* name; const char* columns; const char* sortKey; + const char* treeSortKey; } ScreenDefaults; typedef struct { @@ -33,14 +37,16 @@ typedef struct { int* modes; } MeterColumnSetting; -typedef struct { - char* name; - ProcessField* fields; +typedef struct ScreenSettings_ { + char* heading; /* user-editable screen name (pretty) */ + char* dynamic; /* from DynamicScreen config (fixed) */ + struct Table_* table; + RowField* fields; uint32_t flags; int direction; int treeDirection; - ProcessField sortKey; - ProcessField treeSortKey; + RowField sortKey; + RowField treeSortKey; bool treeView; bool treeViewAlwaysByPID; bool allBranchesCollapsed; @@ -53,6 +59,7 @@ typedef struct Settings_ { MeterColumnSetting* hColumns; Hashtable* dynamicColumns; /* runtime-discovered columns */ Hashtable* dynamicMeters; /* runtime-discovered meters */ + Hashtable* dynamicScreens; /* runtime-discovered screens */ ScreenSettings** screens; unsigned int nScreens; @@ -104,9 +111,9 @@ typedef struct Settings_ { #define Settings_cpuId(settings, cpu) ((settings)->countCPUsFromOne ? (cpu)+1 : (cpu)) -static inline ProcessField ScreenSettings_getActiveSortKey(const ScreenSettings* this) { +static inline RowField ScreenSettings_getActiveSortKey(const ScreenSettings* this) { return (this->treeView) - ? (this->treeViewAlwaysByPID ? PID : this->treeSortKey) + ? (this->treeViewAlwaysByPID ? 1 : this->treeSortKey) : this->sortKey; } @@ -118,15 +125,17 @@ void Settings_delete(Settings* this); int Settings_write(const Settings* this, bool onCrash); -Settings* Settings_new(unsigned int initialCpuCount, Hashtable* dynamicMeters, Hashtable* dynamicColumns); +Settings* Settings_new(unsigned int initialCpuCount, Hashtable* dynamicMeters, Hashtable* dynamicColumns, Hashtable* dynamicScreens); ScreenSettings* Settings_newScreen(Settings* this, const ScreenDefaults* defaults); +ScreenSettings* Settings_newDynamicScreen(Settings* this, const char* tab, const struct DynamicScreen_* screen, struct Table_* table); + void ScreenSettings_delete(ScreenSettings* this); void ScreenSettings_invertSortOrder(ScreenSettings* this); -void ScreenSettings_setSortKey(ScreenSettings* this, ProcessField sortKey); +void ScreenSettings_setSortKey(ScreenSettings* this, RowField sortKey); void Settings_enableReadonly(void); diff --git a/vendor/github.com/htop-dev/htop/SwapMeter.c b/vendor/github.com/htop-dev/htop/SwapMeter.c index 84e58a26ef..1055a6e70e 100644 --- a/vendor/github.com/htop-dev/htop/SwapMeter.c +++ b/vendor/github.com/htop-dev/htop/SwapMeter.c @@ -13,6 +13,7 @@ in the source distribution for its full text. #include #include "CRT.h" +#include "Macros.h" #include "Object.h" #include "Platform.h" #include "RichString.h" @@ -51,13 +52,13 @@ static void SwapMeter_display(const Object* cast, RichString* out) { RichString_appendAscii(out, CRT_colors[METER_TEXT], " used:"); RichString_appendAscii(out, CRT_colors[METER_VALUE], buffer); - if (!isnan(this->values[SWAP_METER_CACHE])) { + if (isNonnegative(this->values[SWAP_METER_CACHE])) { Meter_humanUnit(buffer, this->values[SWAP_METER_CACHE], sizeof(buffer)); RichString_appendAscii(out, CRT_colors[METER_TEXT], " cache:"); RichString_appendAscii(out, CRT_colors[SWAP_CACHE], buffer); } - if (!isnan(this->values[SWAP_METER_FRONTSWAP])) { + if (isNonnegative(this->values[SWAP_METER_FRONTSWAP])) { Meter_humanUnit(buffer, this->values[SWAP_METER_FRONTSWAP], sizeof(buffer)); RichString_appendAscii(out, CRT_colors[METER_TEXT], " frontswap:"); RichString_appendAscii(out, CRT_colors[SWAP_FRONTSWAP], buffer); diff --git a/vendor/github.com/htop-dev/htop/Table.c b/vendor/github.com/htop-dev/htop/Table.c new file mode 100644 index 0000000000..aecc7e6d88 --- /dev/null +++ b/vendor/github.com/htop-dev/htop/Table.c @@ -0,0 +1,371 @@ +/* +htop - Table.c +(C) 2004,2005 Hisham H. Muhammad +(C) 2023 htop dev team +Released under the GNU GPLv2+, see the COPYING file +in the source distribution for its full text. +*/ + +#include "Table.h" + +#include +#include +#include + +#include "CRT.h" +#include "DynamicColumn.h" +#include "Hashtable.h" +#include "Machine.h" +#include "Macros.h" +#include "Platform.h" +#include "Vector.h" +#include "XUtils.h" + + +Table* Table_init(Table* this, const ObjectClass* klass, Machine* host) { + this->rows = Vector_new(klass, true, DEFAULT_SIZE); + this->displayList = Vector_new(klass, false, DEFAULT_SIZE); + this->table = Hashtable_new(200, false); + this->needsSort = true; + this->following = -1; + this->host = host; + return this; +} + +void Table_done(Table* this) { + Hashtable_delete(this->table); + Vector_delete(this->displayList); + Vector_delete(this->rows); +} + +static void Table_delete(Object* cast) { + Table* this = (Table*) cast; + Table_done(this); + free(this); +} + +void Table_setPanel(Table* this, Panel* panel) { + this->panel = panel; +} + +void Table_add(Table* this, Row* row) { + assert(Vector_indexOf(this->rows, row, Row_idEqualCompare) == -1); + assert(Hashtable_get(this->table, row->id) == NULL); + + // highlighting row found in first scan by first scan marked "far in the past" + row->seenStampMs = this->host->monotonicMs; + + Vector_add(this->rows, row); + Hashtable_put(this->table, row->id, row); + + assert(Vector_indexOf(this->rows, row, Row_idEqualCompare) != -1); + assert(Hashtable_get(this->table, row->id) != NULL); + assert(Vector_countEquals(this->rows, Hashtable_count(this->table))); +} + +// Table_removeIndex removes a given row from the lists map and soft deletes +// it from its vector. Vector_compact *must* be called once the caller is done +// removing items. +// Note: for processes should only be called from ProcessList_iterate to avoid +// breaking dying process highlighting. +void Table_removeIndex(Table* this, const Row* row, int idx) { + int rowid = row->id; + + assert(row == (Row*)Vector_get(this->rows, idx)); + assert(Hashtable_get(this->table, rowid) != NULL); + + Hashtable_remove(this->table, rowid); + Vector_softRemove(this->rows, idx); + + if (this->following != -1 && this->following == rowid) { + this->following = -1; + Panel_setSelectionColor(this->panel, PANEL_SELECTION_FOCUS); + } + + assert(Hashtable_get(this->table, rowid) == NULL); + assert(Vector_countEquals(this->rows, Hashtable_count(this->table))); +} + +static void Table_buildTreeBranch(Table* this, int rowid, unsigned int level, int32_t indent, bool show) { + // Do not treat zero as root of any tree. + // (e.g. on OpenBSD the kernel thread 'swapper' has pid 0.) + if (rowid == 0) + return; + + // The vector is sorted by parent, find the start of the range by bisection + int vsize = Vector_size(this->rows); + int l = 0; + int r = vsize; + while (l < r) { + int c = (l + r) / 2; + Row* row = (Row*)Vector_get(this->rows, c); + int parent = row->isRoot ? 0 : Row_getGroupOrParent(row); + if (parent < rowid) { + l = c + 1; + } else { + r = c; + } + } + // Find the end to know the last line for indent handling purposes + int lastShown = r; + while (r < vsize) { + Row* row = (Row*)Vector_get(this->rows, r); + if (!Row_isChildOf(row, rowid)) + break; + if (row->show) + lastShown = r; + r++; + } + + for (int i = l; i < r; i++) { + Row* row = (Row*)Vector_get(this->rows, i); + + if (!show) + row->show = false; + + Vector_add(this->displayList, row); + + int32_t nextIndent = indent | ((int32_t)1 << MINIMUM(level, sizeof(row->indent) * 8 - 2)); + Table_buildTreeBranch(this, row->id, level + 1, (i < lastShown) ? nextIndent : indent, row->show && row->showChildren); + if (i == lastShown) + row->indent = -nextIndent; + else + row->indent = nextIndent; + + row->tree_depth = level + 1; + } +} + +static int compareRowByKnownParentThenNatural(const void* v1, const void* v2) { + return Row_compareByParent((const Row*) v1, (const Row*) v2); +} + +// Builds a sorted tree from scratch, without relying on previously gathered information +static void Table_buildTree(Table* this) { + Vector_prune(this->displayList); + + // Mark root processes + int vsize = Vector_size(this->rows); + for (int i = 0; i < vsize; i++) { + Row* row = (Row*) Vector_get(this->rows, i); + int parent = Row_getGroupOrParent(row); + row->isRoot = false; + + if (row->id == parent) { + row->isRoot = true; + continue; + } + + if (!parent) { + row->isRoot = true; + continue; + } + + // We don't know about its parent for whatever reason + if (Table_findRow(this, parent) == NULL) + row->isRoot = true; + } + + // Sort by known parent (roots first), then row ID + Vector_quickSortCustomCompare(this->rows, compareRowByKnownParentThenNatural); + + // Find all processes whose parent is not visible + for (int i = 0; i < vsize; i++) { + Row* row = (Row*)Vector_get(this->rows, i); + + // If parent not found, then construct the tree with this node as root + if (row->isRoot) { + row = (Row*)Vector_get(this->rows, i); + row->indent = 0; + row->tree_depth = 0; + Vector_add(this->displayList, row); + Table_buildTreeBranch(this, row->id, 0, 0, row->showChildren); + continue; + } + } + + this->needsSort = false; + + // Check consistency of the built structures + assert(Vector_size(this->displayList) == vsize); (void)vsize; +} + +void Table_updateDisplayList(Table* this) { + const Settings* settings = this->host->settings; + + if (settings->ss->treeView) { + if (this->needsSort) + Table_buildTree(this); + } else { + if (this->needsSort) + Vector_insertionSort(this->rows); + Vector_prune(this->displayList); + int size = Vector_size(this->rows); + for (int i = 0; i < size; i++) + Vector_add(this->displayList, Vector_get(this->rows, i)); + } + this->needsSort = false; +} + +void Table_expandTree(Table* this) { + int size = Vector_size(this->rows); + for (int i = 0; i < size; i++) { + Row* row = (Row*) Vector_get(this->rows, i); + row->showChildren = true; + } +} + +// Called on collapse-all toggle and on startup, possibly in non-tree mode +void Table_collapseAllBranches(Table* this) { + Table_buildTree(this); // Update `tree_depth` fields of the rows + this->needsSort = true; // Table is sorted by parent now, force new sort + int size = Vector_size(this->rows); + for (int i = 0; i < size; i++) { + Row* row = (Row*) Vector_get(this->rows, i); + // FreeBSD has pid 0 = kernel and pid 1 = init, so init has tree_depth = 1 + if (row->tree_depth > 0 && row->id > 1) + row->showChildren = false; + } +} + +void Table_rebuildPanel(Table* this) { + Table_updateDisplayList(this); + + const int currPos = Panel_getSelectedIndex(this->panel); + const int currScrollV = this->panel->scrollV; + const int currSize = Panel_size(this->panel); + + Panel_prune(this->panel); + + /* Follow main group row instead if following a row that is occluded (hidden) */ + if (this->following != -1) { + const Row* followed = (const Row*) Hashtable_get(this->table, this->following); + if (followed != NULL + && Hashtable_get(this->table, followed->group) + && Row_isVisible(followed, this) == false ) { + this->following = followed->group; + } + } + + const int rowCount = Vector_size(this->displayList); + bool foundFollowed = false; + int idx = 0; + + for (int i = 0; i < rowCount; i++) { + Row* row = (Row*) Vector_get(this->displayList, i); + + if ( !row->show || (Row_matchesFilter(row, this) == true) ) + continue; + + Panel_set(this->panel, idx, (Object*)row); + + if (this->following != -1 && row->id == this->following) { + foundFollowed = true; + Panel_setSelected(this->panel, idx); + /* Keep scroll position relative to followed row */ + this->panel->scrollV = idx - (currPos-currScrollV); + } + idx++; + } + + if (this->following != -1 && !foundFollowed) { + /* Reset if current followed row not found */ + this->following = -1; + Panel_setSelectionColor(this->panel, PANEL_SELECTION_FOCUS); + } + + if (this->following == -1) { + /* If the last item was selected, keep the new last item selected */ + if (currPos > 0 && currPos == currSize - 1) + Panel_setSelected(this->panel, Panel_size(this->panel) - 1); + else + Panel_setSelected(this->panel, currPos); + + this->panel->scrollV = currScrollV; + } +} + +void Table_printHeader(const Settings* settings, RichString* header) { + RichString_rewind(header, RichString_size(header)); + + const ScreenSettings* ss = settings->ss; + const RowField* fields = ss->fields; + + RowField key = ScreenSettings_getActiveSortKey(ss); + + for (int i = 0; fields[i]; i++) { + int color; + if (ss->treeView && ss->treeViewAlwaysByPID) { + color = CRT_colors[PANEL_HEADER_FOCUS]; + } else if (key == fields[i]) { + color = CRT_colors[PANEL_SELECTION_FOCUS]; + } else { + color = CRT_colors[PANEL_HEADER_FOCUS]; + } + + RichString_appendWide(header, color, RowField_alignedTitle(settings, fields[i])); + if (key == fields[i] && RichString_getCharVal(*header, RichString_size(header) - 1) == ' ') { + bool ascending = ScreenSettings_getActiveDirection(ss) == 1; + RichString_rewind(header, 1); // rewind to override space + RichString_appendnWide(header, + CRT_colors[PANEL_SELECTION_FOCUS], + CRT_treeStr[ascending ? TREE_STR_ASC : TREE_STR_DESC], + 1); + } + if (COMM == fields[i] && settings->showMergedCommand) { + RichString_appendAscii(header, color, "(merged)"); + } + } +} + +// set flags on an existing rows before refreshing table +void Table_prepareEntries(Table* this) { + for (int i = 0; i < Vector_size(this->rows); i++) { + Row* row = (struct Row_*) Vector_get(this->rows, i); + row->updated = false; + row->wasShown = row->show; + row->show = true; + } +} + +// tidy up Row state after refreshing the table +void Table_cleanupRow(Table* table, Row* row, int idx) { + Machine* host = table->host; + const Settings* settings = host->settings; + + if (row->tombStampMs > 0) { + // remove tombed process + if (host->monotonicMs >= row->tombStampMs) { + Table_removeIndex(table, row, idx); + } + } else if (row->updated == false) { + // process no longer exists + if (settings->highlightChanges && row->wasShown) { + // mark tombed + row->tombStampMs = host->monotonicMs + 1000 * settings->highlightDelaySecs; + } else { + // immediately remove + Table_removeIndex(table, row, idx); + } + } +} + +void Table_cleanupEntries(Table* this) { + // Finish process table update, culling any removed rows + for (int i = Vector_size(this->rows) - 1; i >= 0; i--) { + Row* row = (Row*) Vector_get(this->rows, i); + Table_cleanupRow(this, row, i); + } + + // compact the table in case of any earlier row removals + Table_compact(this); +} + +const TableClass Table_class = { + .super = { + .extends = Class(Object), + .delete = Table_delete, + }, + .prepare = Table_prepareEntries, + .cleanup = Table_cleanupEntries, +}; diff --git a/vendor/github.com/htop-dev/htop/Table.h b/vendor/github.com/htop-dev/htop/Table.h new file mode 100644 index 0000000000..d16e47daa0 --- /dev/null +++ b/vendor/github.com/htop-dev/htop/Table.h @@ -0,0 +1,101 @@ +#ifndef HEADER_Table +#define HEADER_Table +/* +htop - Table.h +(C) 2004,2005 Hisham H. Muhammad +(C) 2023 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 + +#include +#include +#include +#include +#include + +#include "Hashtable.h" +#include "Object.h" +#include "RichString.h" +#include "Settings.h" +#include "Vector.h" + + +struct Machine_; +struct Panel_; +struct Row_; + +typedef struct Table_ { + /* Super object for emulated OOP */ + Object super; + + Vector* rows; /* all known; sort order can vary and differ from display order */ + Vector* displayList; /* row tree flattened in display order (borrowed); + updated in Table_updateDisplayList when rebuilding panel */ + Hashtable* table; /* fast known row lookup by identifier */ + + struct Machine_* host; + const char* incFilter; + bool needsSort; + int following; /* -1 or row being visually tracked in the user interface */ + + struct Panel_* panel; +} Table; + +typedef Table* (*Table_New)(const struct Machine_*); +typedef void (*Table_ScanPrepare)(Table* this); +typedef void (*Table_ScanIterate)(Table* this); +typedef void (*Table_ScanCleanup)(Table* this); + +typedef struct TableClass_ { + const ObjectClass super; + const Table_ScanPrepare prepare; + const Table_ScanIterate iterate; + const Table_ScanCleanup cleanup; +} TableClass; + +#define As_Table(this_) ((const TableClass*)((this_)->super.klass)) + +#define Table_scanPrepare(t_) (As_Table(t_)->prepare ? (As_Table(t_)->prepare(t_)) : Table_prepareEntries(t_)) +#define Table_scanIterate(t_) (As_Table(t_)->iterate(t_)) /* mandatory; must have a custom iterate method */ +#define Table_scanCleanup(t_) (As_Table(t_)->cleanup ? (As_Table(t_)->cleanup(t_)) : Table_cleanupEntries(t_)) + +Table* Table_init(Table* this, const ObjectClass* klass, struct Machine_* host); + +void Table_done(Table* this); + +extern const TableClass Table_class; + +void Table_setPanel(Table* this, struct Panel_* panel); + +void Table_printHeader(const Settings* settings, RichString* header); + +void Table_add(Table* this, struct Row_* row); + +void Table_removeIndex(Table* this, const struct Row_* row, int idx); + +void Table_updateDisplayList(Table* this); + +void Table_expandTree(Table* this); + +void Table_collapseAllBranches(Table* this); + +void Table_rebuildPanel(Table* this); + +static inline struct Row_* Table_findRow(Table* this, int id) { + return (struct Row_*) Hashtable_get(this->table, id); +} + +void Table_prepareEntries(Table* this); + +void Table_cleanupEntries(Table* this); + +void Table_cleanupRow(Table* this, Row* row, int idx); + +static inline void Table_compact(Table* this) { + Vector_compact(this->rows); +} + +#endif diff --git a/vendor/github.com/htop-dev/htop/TasksMeter.c b/vendor/github.com/htop-dev/htop/TasksMeter.c index b5563fcab0..7dd6fdb419 100644 --- a/vendor/github.com/htop-dev/htop/TasksMeter.c +++ b/vendor/github.com/htop-dev/htop/TasksMeter.c @@ -25,7 +25,8 @@ static const int TasksMeter_attributes[] = { static void TasksMeter_updateValues(Meter* this) { const Machine* host = this->host; - const ProcessList* pl = host->pl; + const ProcessList* pl = (const ProcessList*) host->processTable; + this->values[0] = pl->kernelThreads; this->values[1] = pl->userlandThreads; this->values[2] = pl->totalTasks - pl->kernelThreads - pl->userlandThreads; diff --git a/vendor/github.com/htop-dev/htop/TraceScreen.c b/vendor/github.com/htop-dev/htop/TraceScreen.c index e8f55ff561..03315482b3 100644 --- a/vendor/github.com/htop-dev/htop/TraceScreen.c +++ b/vendor/github.com/htop-dev/htop/TraceScreen.c @@ -62,7 +62,7 @@ void TraceScreen_delete(Object* cast) { } static void TraceScreen_draw(InfoScreen* this) { - InfoScreen_drawTitled(this, "Trace of process %d - %s", this->process->pid, Process_getCommand(this->process)); + InfoScreen_drawTitled(this, "Trace of process %d - %s", Process_getPid(this->process), Process_getCommand(this->process)); } bool TraceScreen_forkTracer(TraceScreen* this) { @@ -89,7 +89,7 @@ bool TraceScreen_forkTracer(TraceScreen* this) { close(fdpair[1]); char buffer[32] = {0}; - xSnprintf(buffer, sizeof(buffer), "%d", this->super.process->pid); + xSnprintf(buffer, sizeof(buffer), "%d", Process_getPid(this->super.process)); // Use of NULL in variadic functions must have a pointer cast. // The NULL constant is not required by standard to have a pointer type. execlp("strace", "strace", "-T", "-tt", "-s", "512", "-p", buffer, (char*)NULL); diff --git a/vendor/github.com/htop-dev/htop/XUtils.c b/vendor/github.com/htop-dev/htop/XUtils.c index f54ad49f85..1af0dd4fac 100644 --- a/vendor/github.com/htop-dev/htop/XUtils.c +++ b/vendor/github.com/htop-dev/htop/XUtils.c @@ -12,6 +12,7 @@ in the source distribution for its full text. #include #include #include +#include #include #include #include @@ -19,6 +20,7 @@ in the source distribution for its full text. #include #include "CRT.h" +#include "Macros.h" void fail(void) { @@ -337,3 +339,25 @@ ssize_t full_write(int fd, const void* buf, size_t count) { return written; } + +/* Compares floating point values for ordering data entries. In this function, + NaN is considered "less than" any other floating point value (regardless of + sign), and two NaNs are considered "equal" regardless of payload. */ +int compareRealNumbers(double a, double b) { + int result = isgreater(a, b) - isgreater(b, a); + if (result) + return result; + return !isNaN(a) - !isNaN(b); +} + +/* Computes the sum of all positive floating point values in an array. + NaN values in the array are skipped. The returned sum will always be + nonnegative. */ +double sumPositiveValues(const double* array, size_t count) { + double sum = 0.0; + for (size_t i = 0; i < count; i++) { + if (isPositive(array[i])) + sum += array[i]; + } + return sum; +} diff --git a/vendor/github.com/htop-dev/htop/XUtils.h b/vendor/github.com/htop-dev/htop/XUtils.h index 64583db8bf..fd1087d534 100644 --- a/vendor/github.com/htop-dev/htop/XUtils.h +++ b/vendor/github.com/htop-dev/htop/XUtils.h @@ -82,4 +82,14 @@ ssize_t xReadfileat(openat_arg_t dirfd, const char* pathname, void* buffer, size ATTR_ACCESS3_R(2, 3) ssize_t full_write(int fd, const void* buf, size_t count); +/* Compares floating point values for ordering data entries. In this function, + NaN is considered "less than" any other floating point value (regardless of + sign), and two NaNs are considered "equal" regardless of payload. */ +int compareRealNumbers(double a, double b); + +/* Computes the sum of all positive floating point values in an array. + NaN values in the array are skipped. The returned sum will always be + nonnegative. */ +double sumPositiveValues(const double* array, size_t count); + #endif diff --git a/vendor/github.com/htop-dev/htop/configure.ac b/vendor/github.com/htop-dev/htop/configure.ac index 36f25b22c3..c05f4d62c1 100644 --- a/vendor/github.com/htop-dev/htop/configure.ac +++ b/vendor/github.com/htop-dev/htop/configure.ac @@ -149,7 +149,7 @@ dnl been updated in Autoconf 2.69, so use a workaround: m4_version_prereq([2.70], [], [if test "x$ac_cv_header_sys_mkdev_h" != xyes; then AC_CHECK_HEADER([sys/sysmacros.h], [AC_DEFINE([MAJOR_IN_SYSMACROS], [1], - [Define to 1 if `major', `minor', and `makedev' are declared in .])]) + [Define to 1 if 'major', 'minor', and 'makedev' are declared in .])]) fi]) # Optional Section @@ -203,21 +203,42 @@ AC_COMPILE_IFELSE([ CFLAGS="$old_CFLAGS" AC_MSG_CHECKING(for NaN support) -AC_RUN_IFELSE([ +dnl Note: AC_RUN_IFELSE does not try compiling the program at all when +dnl $cross_compiling is 'yes'. +AC_LINK_IFELSE([ AC_LANG_PROGRAM( [[ - #include +#include ]], [[ - double x = NAN; return !isnan(x); + double x = NAN; + /* Both should evaluate to false -> 0 (exit success) */ + return isgreater(x, x) || isgreaterequal(x, x); ]] )], - [AC_MSG_RESULT(yes)], - [ + [flag_finite_math_only=unknown + if test "$cross_compiling" = yes; then + AC_COMPILE_IFELSE([ + AC_LANG_SOURCE([[ +/* __FINITE_MATH_ONLY__ is documented in Clang. */ +#ifdef __FINITE_MATH_ONLY__ +#error "should not enable -ffinite-math-only" +#endif + ]])], + AC_MSG_RESULT([assume yes (cross compiling)]), + flag_finite_math_only=yes) + elif ./conftest$EXEEXT >&AS_MESSAGE_LOG_FD; then + flag_finite_math_only=no + AC_MSG_RESULT(yes) + else + flag_finite_math_only=yes + fi + if test "$flag_finite_math_only" = yes; then AC_MSG_RESULT(no) - AC_MSG_WARN([Compiler does not respect NaN, some functionality might break; consider using '-fno-finite-math-only']) - ], - [AC_MSG_RESULT(skipped)]) + AC_MSG_WARN([runtime behavior with NaN is not compliant - some functionality might break; consider using '-fno-finite-math-only']) + fi], + [AC_MSG_RESULT(no) + AC_MSG_ERROR([can not find required macros: NAN, isgreater() and isgreaterequal()])]) # ---------------------------------------------------------------------- @@ -360,6 +381,11 @@ if test "x$enable_unicode" = xyes; then [AC_CHECK_HEADERS([ncurses.h], [], [AC_MSG_ERROR([can not find required ncurses header file])])])])]) + AC_CHECK_HEADERS([ncursesw/term.h], [], + [AC_CHECK_HEADERS([ncurses/term.h], [], + [AC_CHECK_HEADERS([term.h], [], + [AC_MSG_ERROR([can not find required term header file])])])]) + # check if additional linker flags are needed for keypad(3) # (at this point we already link against a working ncurses library with wide character support) AC_SEARCH_LIBS([keypad], [tinfow tinfo]) @@ -375,13 +401,18 @@ else AC_CHECK_HEADERS([curses.h], [], [AC_CHECK_HEADERS([ncurses/curses.h], [], [AC_CHECK_HEADERS([ncurses/ncurses.h], [], - [AC_CHECK_HEADERS([ncurses.h] ,[], + [AC_CHECK_HEADERS([ncurses.h], [], [AC_MSG_ERROR([can not find required ncurses header file])])])])]) + AC_CHECK_HEADERS([ncurses/term.h], [], + [AC_CHECK_HEADERS([term.h], [], + [AC_MSG_ERROR([can not find required term header file])])]) + # check if additional linker flags are needed for keypad(3) # (at this point we already link against a working ncurses library) AC_SEARCH_LIBS([keypad], [tinfo]) fi + if test "$enable_static" = yes; then AC_SEARCH_LIBS([Gpm_GetEvent], [gpm]) fi @@ -418,7 +449,7 @@ if test "x$enable_affinity" = xcheck; then AC_MSG_RESULT([yes])], [enable_affinity=no AC_MSG_RESULT([no])], - [AC_MSG_RESULT([yes (assumed while cross compiling)])]) + [AC_MSG_RESULT([assume yes (cross compiling)])]) fi fi if test "x$enable_affinity" = xyes; then @@ -483,7 +514,7 @@ case "$enable_hwloc" in PKG_CHECK_MODULES(HWLOC, hwloc, [ CFLAGS="$CFLAGS $HWLOC_CFLAGS" LIBS="$LIBS $HWLOC_LIBS" - AC_DEFINE([HAVE_LIBHWLOC], [1], [Define to 1 if you have the `hwloc' library (-lhwloc).]) + AC_DEFINE([HAVE_LIBHWLOC], [1], [Define to 1 if you have the 'hwloc' library (-lhwloc).]) ], [ AC_CHECK_LIB([hwloc], [hwloc_get_proc_cpubind], [], [AC_MSG_ERROR([can not find required library libhwloc])]) AC_CHECK_HEADERS([hwloc.h], [], [AC_MSG_ERROR([can not find require header file hwloc.h])]) @@ -690,11 +721,6 @@ AM_CFLAGS="\ -Wunused\ -Wwrite-strings" -# FreeBSD uses C11 _Generic in its isnan implementation, even with -std=c99 -if test "$my_htop_platform" = freebsd; then - AM_CFLAGS="$AM_CFLAGS -Wno-c11-extensions" -fi - dnl https://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html AC_DEFUN([AX_CHECK_COMPILE_FLAG], [ @@ -732,6 +758,22 @@ AC_ARG_ENABLE([debug], [enable_debug=no]) if test "x$enable_debug" != xyes; then AM_CPPFLAGS="$AM_CPPFLAGS -DNDEBUG" + + AC_COMPILE_IFELSE([ + AC_LANG_SOURCE([[ +#ifdef __SUPPORT_SNAN__ +#error "signaling NaN support not recommended" +#endif + ]])], + :, + [warning_msg="signaling NaN support is enabled; not recommended for htop" + case "$CC" in + *gcc*) + warning_msg="$warning_msg (use '-fno-signaling-nans' compiler flag to disable)" + ;; + esac + AC_MSG_WARN([$warning_msg]) + ]) else AM_CPPFLAGS="$AM_CPPFLAGS -ggdb3" fi diff --git a/vendor/github.com/htop-dev/htop/darwin/DarwinProcess.c b/vendor/github.com/htop-dev/htop/darwin/DarwinProcess.c index e6366d70f9..ec98341e3f 100644 --- a/vendor/github.com/htop-dev/htop/darwin/DarwinProcess.c +++ b/vendor/github.com/htop-dev/htop/darwin/DarwinProcess.c @@ -72,8 +72,8 @@ void Process_delete(Object* cast) { free(this); } -static void DarwinProcess_writeField(const Process* this, RichString* str, ProcessField field) { - const DarwinProcess* dp = (const DarwinProcess*) this; +static void DarwinProcess_rowWriteField(const Row* super, RichString* str, ProcessField field) { + const DarwinProcess* dp = (const DarwinProcess*) super; char buffer[256]; buffer[255] = '\0'; int attr = CRT_colors[DEFAULT_COLOR]; int n = sizeof(buffer) - 1; @@ -81,7 +81,7 @@ static void DarwinProcess_writeField(const Process* this, RichString* str, Proce // add Platform-specific fields here case TRANSLATED: xSnprintf(buffer, n, "%c ", dp->translated ? 'T' : 'N'); break; default: - Process_writeField(this, str, field); + Process_writeField(&dp->super, str, field); return; } RichString_appendWide(str, attr, buffer); @@ -292,7 +292,7 @@ static char* DarwinProcess_getDevname(dev_t dev) { void DarwinProcess_setFromKInfoProc(Process* proc, const struct kinfo_proc* ps, bool exists) { DarwinProcess* dp = (DarwinProcess*)proc; - const Settings* settings = proc->host->settings; + const Settings* settings = proc->super.host->settings; const struct extern_proc* ep = &ps->kp_proc; @@ -312,12 +312,12 @@ void DarwinProcess_setFromKInfoProc(Process* proc, const struct kinfo_proc* ps, /* First, the "immutable" parts */ if (!exists) { /* Set the PID/PGID/etc. */ - proc->pid = ep->p_pid; - proc->ppid = ps->kp_eproc.e_ppid; + Process_setPid(proc, ep->p_pid); + Process_setThreadGroup(proc, ep->p_pid); + Process_setParent(proc, ps->kp_eproc.e_ppid); proc->pgrp = ps->kp_eproc.e_pgid; proc->session = 0; /* TODO Get the session id */ proc->tpgid = ps->kp_eproc.e_tpgid; - proc->tgid = proc->pid; proc->isKernelThread = false; proc->isUserlandThread = false; dp->translated = ps->kp_proc.p_flag & P_TRANSLATED; @@ -359,14 +359,14 @@ void DarwinProcess_setFromKInfoProc(Process* proc, const struct kinfo_proc* ps, proc->state = (ep->p_stat == SZOMB) ? ZOMBIE : UNKNOWN; /* Make sure the updated flag is set */ - proc->updated = true; + proc->super.updated = true; } void DarwinProcess_setFromLibprocPidinfo(DarwinProcess* proc, DarwinProcessList* dpl, double timeIntervalNS) { struct proc_taskinfo pti; - if (sizeof(pti) == proc_pidinfo(proc->super.pid, PROC_PIDTASKINFO, 0, &pti, sizeof(pti))) { - const DarwinMachine* dhost = (const DarwinMachine*) proc->super.host; + if (sizeof(pti) == proc_pidinfo(Process_getPid(&proc->super), PROC_PIDTASKINFO, 0, &pti, sizeof(pti))) { + const DarwinMachine* dhost = (const DarwinMachine*) proc->super.super.host; uint64_t total_existing_time_ns = proc->stime + proc->utime; @@ -419,7 +419,7 @@ void DarwinProcess_scanThreads(DarwinProcess* dp) { } task_t port; - ret = task_for_pid(mach_task_self(), proc->pid, &port); + ret = task_for_pid(mach_task_self(), Process_getPid(proc), &port); if (ret != KERN_SUCCESS) { dp->taskAccess = false; return; @@ -472,11 +472,18 @@ void DarwinProcess_scanThreads(DarwinProcess* dp) { const ProcessClass DarwinProcess_class = { .super = { - .extends = Class(Process), - .display = Process_display, - .delete = Process_delete, - .compare = Process_compare + .super = { + .extends = Class(Process), + .display = Row_display, + .delete = Process_delete, + .compare = Process_compare + }, + .isHighlighted = Process_rowIsHighlighted, + .isVisible = Process_rowIsVisible, + .matchesFilter = Process_rowMatchesFilter, + .compareByParent = Process_compareByParent, + .sortKeyString = Process_rowGetSortKey, + .writeField = DarwinProcess_rowWriteField }, - .writeField = DarwinProcess_writeField, - .compareByKey = DarwinProcess_compareByKey, + .compareByKey = DarwinProcess_compareByKey }; diff --git a/vendor/github.com/htop-dev/htop/darwin/DarwinProcessList.c b/vendor/github.com/htop-dev/htop/darwin/DarwinProcessList.c index bf311dc7a6..1545600ebc 100644 --- a/vendor/github.com/htop-dev/htop/darwin/DarwinProcessList.c +++ b/vendor/github.com/htop-dev/htop/darwin/DarwinProcessList.c @@ -55,20 +55,22 @@ static struct kinfo_proc* ProcessList_getKInfoProcs(size_t* count) { ProcessList* ProcessList_new(Machine* host, Hashtable* pidMatchList) { DarwinProcessList* this = xCalloc(1, sizeof(DarwinProcessList)); - ProcessList* super = &this->super; + Object_setClass(this, Class(ProcessList)); + ProcessList* super = &this->super; ProcessList_init(super, Class(DarwinProcess), host, pidMatchList); return super; } -void ProcessList_delete(ProcessList* this) { - ProcessList_done(this); +void ProcessList_delete(Object* cast) { + DarwinProcessList* this = (DarwinProcessList*) cast; + ProcessList_done(&this->super); free(this); } void ProcessList_goThroughEntries(ProcessList* super) { - const Machine* host = super->host; + const Machine* host = super->super.host; const DarwinMachine* dhost = (const DarwinMachine*) host; DarwinProcessList* dpl = (DarwinProcessList*) super; bool preExisting = true; @@ -86,12 +88,6 @@ void ProcessList_goThroughEntries(ProcessList* super) { const double time_interval_ns = Platform_schedulerTicksToNanoseconds(dpl->global_diff) / (double) host->activeCPUs; - /* Clear the thread counts */ - super->kernelThreads = 0; - super->userlandThreads = 0; - super->totalTasks = 0; - super->runningTasks = 0; - /* We use kinfo_procs for initial data since : * * 1) They always succeed. diff --git a/vendor/github.com/htop-dev/htop/darwin/Platform.h b/vendor/github.com/htop-dev/htop/darwin/Platform.h index 5cd672979f..cf00919fbe 100644 --- a/vendor/github.com/htop-dev/htop/darwin/Platform.h +++ b/vendor/github.com/htop-dev/htop/darwin/Platform.h @@ -118,7 +118,7 @@ static inline Hashtable* Platform_dynamicColumns(void) { static inline void Platform_dynamicColumnsDone(ATTR_UNUSED Hashtable* table) { } -static inline const char* Platform_dynamicColumnInit(ATTR_UNUSED unsigned int key) { +static inline const char* Platform_dynamicColumnName(ATTR_UNUSED unsigned int key) { return NULL; } @@ -126,4 +126,16 @@ static inline bool Platform_dynamicColumnWriteField(ATTR_UNUSED const Process* p return false; } +static inline Hashtable* Platform_dynamicScreens(void) { + return NULL; +} + +static inline void Platform_defaultDynamicScreens(ATTR_UNUSED Settings* settings) { } + +static inline void Platform_addDynamicScreen(ATTR_UNUSED ScreenSettings* ss) { } + +static inline void Platform_addDynamicScreenAvailableColumns(ATTR_UNUSED Panel* availableColumns, ATTR_UNUSED const char* screen) { } + +static inline void Platform_dynamicScreensDone(ATTR_UNUSED Hashtable* screens) { } + #endif diff --git a/vendor/github.com/htop-dev/htop/darwin/PlatformHelpers.c b/vendor/github.com/htop-dev/htop/darwin/PlatformHelpers.c index 97f0741a1d..a4ea82bebf 100644 --- a/vendor/github.com/htop-dev/htop/darwin/PlatformHelpers.c +++ b/vendor/github.com/htop-dev/htop/darwin/PlatformHelpers.c @@ -103,9 +103,8 @@ double Platform_calculateNanosecondsPerMachTick(void) { * the "Apple M1" chip specifically when running under Rosetta 2. */ - size_t cpuBrandStringSize = 1024; - char cpuBrandString[cpuBrandStringSize]; - Platform_getCPUBrandString(cpuBrandString, cpuBrandStringSize); + char cpuBrandString[1024] = ""; + Platform_getCPUBrandString(cpuBrandString, sizeof(cpuBrandString)); bool isRunningUnderRosetta2 = Platform_isRunningTranslated(); diff --git a/vendor/github.com/htop-dev/htop/docs/styleguide.md b/vendor/github.com/htop-dev/htop/docs/styleguide.md index 977ee38b44..82198f6b31 100644 --- a/vendor/github.com/htop-dev/htop/docs/styleguide.md +++ b/vendor/github.com/htop-dev/htop/docs/styleguide.md @@ -8,12 +8,12 @@ Names are important to convey what all those things inside the project are for. Filenames for source code traditionally used camel-case naming with the first letter written in uppercase. The file extension is always lowercase. -The only exception here is `htop.c` which is the main entrance point into the code. +The only exceptions here are `htop.c` and `pcp-htop.c`, which contain the main entrance points into the code. Folders for e.g. platform-specific code or complex features spawning multiple files are written in lowercase, e.g. `linux`, `freebsd`, `zfs`. Inside files, the naming somewhat depends on the context. -For functions names should include a camel-case prefix before the actual name, separated by an underscore. +Function names should include a camel-case prefix before the actual name, separated by an underscore. While this prefix usually coincides with the module name, this is not required, yet strongly advised. One important exception to this rule are the memory management and the string utility functions from `XUtils.h`. @@ -65,7 +65,7 @@ The list of includes should be the first thing in the file, after the copyright The include list should be in the following order, with each group separated by one blank line: 1. `include "config.h" // IWYU pragma: keep` if the global configuration - from automake&autoconfigure or any of the feature guards for C library headers + from `automake`&`autoconfigure` or any of the feature guards for C library headers (like `__GNU_SOURCE`) are required, optional otherwise. Beware of the IWYU comment. 2. Accompanying module header file (for C source files only, missing inside headers) 3. List of used system headers (non-conditional includes) @@ -97,6 +97,8 @@ Allocation functions assert the amount of memory requested is non-zero. Trying to allocate 0 bytes of memory is an error. Please use the explicit value `NULL` in this case and handle it in your code accordingly. +If the allocated block of memory is intended to hold an array of values, you should use the alternate functions `xReallocArray` and `xReallocArrayZero` instead. + Working with Strings -------------------- @@ -169,7 +171,7 @@ if (fd >= 0) While the existing code base isn't fully consistent with this code style yet it is strongly recommended that new code follows these rules. Adapting surrounding code near places you need to touch is encouraged. -Try to separate such changes into a single, clean-up only commit to reduce noise while reviewing your changes. +Try to split off such changes into a separate, clean-up only commit to reduce noise while reviewing your changes. When writing your code consistency with the surrounding codebase is favoured. @@ -230,6 +232,8 @@ Writing pull-requests (PRs) When writing your PR or patch, the set of patches should contain the minimal changes required. Each patch in itself should ideally be self-contained and runable. +The commit comment should be descriptive (`Updated Foo.c` is not), explain what the changes are and describe why they were made. +While in trivial cases a short subject suffices, more complex changes might warrant a longer description and explanation of the rationale behind the changes. A PR should not contain any merge commits. To follow the upstream branch of your PR rebase your work instead. @@ -239,5 +243,7 @@ Instead squash those changes in the appropriate commit that introduced that mist Git offers `git commit --fixup=` and `git rebase -i --autosquash` to help you with this. Your final PR should contain a minimal set of reasonably sized commits that by themselves are easy to review. +If you open a PR you need to follow up to resolve any comments/change requests. +Otherwise it may be closed without merging. Rebase early. Rebase often. diff --git a/vendor/github.com/htop-dev/htop/dragonflybsd/DragonFlyBSDProcess.c b/vendor/github.com/htop-dev/htop/dragonflybsd/DragonFlyBSDProcess.c index 7cfc71be52..a85b6efb0c 100644 --- a/vendor/github.com/htop-dev/htop/dragonflybsd/DragonFlyBSDProcess.c +++ b/vendor/github.com/htop-dev/htop/dragonflybsd/DragonFlyBSDProcess.c @@ -66,16 +66,17 @@ void Process_delete(Object* cast) { free(this); } -static void DragonFlyBSDProcess_writeField(const Process* this, RichString* str, ProcessField field) { +static void DragonFlyBSDProcess_rowWriteField(const Row* super, RichString* str, ProcessField field) { + const Process* this = (const Process*) super; const DragonFlyBSDProcess* fp = (const DragonFlyBSDProcess*) this; char buffer[256]; buffer[255] = '\0'; int attr = CRT_colors[DEFAULT_COLOR]; size_t n = sizeof(buffer) - 1; switch (field) { // add Platform-specific fields here - case PID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, Process_isKernelThread(this) ? -1 : this->pid); break; + case PID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, Process_isKernelThread(this) ? -1 : Process_getPid(this)); break; case JID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, fp->jid); break; - case JAIL: Process_printLeftAlignedField(str, attr, fp->jname, 11); return; + case JAIL: Row_printLeftAlignedField(str, attr, fp->jname, 11); return; default: Process_writeField(this, str, field); return; @@ -100,11 +101,18 @@ static int DragonFlyBSDProcess_compareByKey(const Process* v1, const Process* v2 const ProcessClass DragonFlyBSDProcess_class = { .super = { - .extends = Class(Process), - .display = Process_display, - .delete = Process_delete, - .compare = Process_compare + .super = { + .extends = Class(Process), + .display = Row_display, + .delete = Process_delete, + .compare = Process_compare + }, + .isHighlighted = Process_rowIsHighlighted, + .isVisible = Process_rowIsVisible, + .matchesFilter = Process_rowMatchesFilter, + .compareByParent = Process_compareByParent, + .sortKeyString = Process_rowGetSortKey, + .writeField = DragonFlyBSDProcess_rowWriteField }, - .writeField = DragonFlyBSDProcess_writeField, .compareByKey = DragonFlyBSDProcess_compareByKey }; diff --git a/vendor/github.com/htop-dev/htop/dragonflybsd/DragonFlyBSDProcessList.c b/vendor/github.com/htop-dev/htop/dragonflybsd/DragonFlyBSDProcessList.c index 4ff17932cd..6330e911d2 100644 --- a/vendor/github.com/htop-dev/htop/dragonflybsd/DragonFlyBSDProcessList.c +++ b/vendor/github.com/htop-dev/htop/dragonflybsd/DragonFlyBSDProcessList.c @@ -28,16 +28,17 @@ in the source distribution for its full text. ProcessList* ProcessList_new(Machine* host, Hashtable* pidMatchList) { DragonFlyBSDProcessList* this = xCalloc(1, sizeof(DragonFlyBSDProcessList)); - ProcessList* super = (ProcessList*) this; + Object_setClass(this, Class(ProcessList)); + ProcessList* super = (ProcessList*) this; ProcessList_init(super, Class(DragonFlyBSDProcess), host, pidMatchList); return super; } -void ProcessList_delete(ProcessList* super) { - const DragonFlyBSDProcessList* this = (DragonFlyBSDProcessList*) super; - ProcessList_done(super); +void ProcessList_delete(Object* cast) { + const DragonFlyBSDProcessList* this = (DragonFlyBSDProcessList*) cast; + ProcessList_done(&this->super); free(this); } @@ -153,17 +154,17 @@ void ProcessList_goThroughEntries(ProcessList* super) { dfp->jid = kproc->kp_jailid; if (kproc->kp_ktaddr && kproc->kp_flags & P_SYSTEM) { // dfb kernel threads all have the same pid, so we misuse the kernel thread address to give them a unique identifier - proc->pid = (pid_t)kproc->kp_ktaddr; + Process_setPid(proc, (pid_t)kproc->kp_ktaddr); proc->isKernelThread = true; } else { - proc->pid = kproc->kp_pid; // process ID + Process_setPid(proc, kproc->kp_pid); // process ID proc->isKernelThread = false; } proc->isUserlandThread = kproc->kp_nthreads > 1; - proc->ppid = kproc->kp_ppid; // parent process id + Process_setParent(proc, kproc->kp_ppid); // parent process id proc->tpgid = kproc->kp_tpgid; // tty process group id - //proc->tgid = kproc->kp_lwp.kl_tid; // thread group id - proc->tgid = kproc->kp_pid; // thread group id + //Process_setThreadGroup(proc, kproc->kp_lwp.kl_tid); // thread group id + Process_setThreadGroup(proc, kproc->kp_pid); proc->pgrp = kproc->kp_pgid; // process group id proc->session = kproc->kp_sid; proc->st_uid = kproc->kp_uid; // user ID @@ -199,7 +200,7 @@ void ProcessList_goThroughEntries(ProcessList* super) { dfp->jname = DragonFlyBSDMachine_readJailName(dhost, kproc->kp_jailid); } // if there are reapers in the system, process can get reparented anytime - proc->ppid = kproc->kp_ppid; + Process_setParent(proc, kproc->kp_ppid); if (proc->st_uid != kproc->kp_uid) { // some processes change users (eg. to lower privs) proc->st_uid = kproc->kp_uid; proc->user = UsersTable_getRef(host->usersTable, proc->st_uid); @@ -303,7 +304,7 @@ void ProcessList_goThroughEntries(ProcessList* super) { if (proc->state == RUNNING) super->runningTasks++; - proc->show = ! ((hideKernelThreads && Process_isKernelThread(proc)) || (hideUserlandThreads && Process_isUserlandThread(proc))); - proc->updated = true; + proc->super.show = ! ((hideKernelThreads && Process_isKernelThread(proc)) || (hideUserlandThreads && Process_isUserlandThread(proc))); + proc->super.updated = true; } } diff --git a/vendor/github.com/htop-dev/htop/dragonflybsd/Platform.c b/vendor/github.com/htop-dev/htop/dragonflybsd/Platform.c index 36307e931f..51d89467fe 100644 --- a/vendor/github.com/htop-dev/htop/dragonflybsd/Platform.c +++ b/vendor/github.com/htop-dev/htop/dragonflybsd/Platform.c @@ -23,6 +23,7 @@ in the source distribution for its full text. #include "FileDescriptorMeter.h" #include "HostnameMeter.h" #include "LoadAverageMeter.h" +#include "Macros.h" #include "MemoryMeter.h" #include "MemorySwapMeter.h" #include "ProcessList.h" @@ -30,6 +31,7 @@ in the source distribution for its full text. #include "SysArchMeter.h" #include "TasksMeter.h" #include "UptimeMeter.h" +#include "XUtils.h" #include "dragonflybsd/DragonFlyBSDProcess.h" #include "dragonflybsd/DragonFlyBSDProcessList.h" #include "generic/fdstat_sysctl.h" @@ -193,14 +195,13 @@ double Platform_setCPUValues(Meter* this, unsigned int cpu) { v[CPU_METER_KERNEL] = cpuData->systemPercent; v[CPU_METER_IRQ] = cpuData->irqPercent; this->curItems = 4; - percent = v[CPU_METER_NICE] + v[CPU_METER_NORMAL] + v[CPU_METER_KERNEL] + v[CPU_METER_IRQ]; } else { v[CPU_METER_KERNEL] = cpuData->systemAllPercent; this->curItems = 3; - percent = v[CPU_METER_NICE] + v[CPU_METER_NORMAL] + v[CPU_METER_KERNEL]; } - percent = isnan(percent) ? 0.0 : CLAMP(percent, 0.0, 100.0); + percent = sumPositiveValues(v, this->curItems); + percent = MINIMUM(percent, 100.0); v[CPU_METER_FREQUENCY] = NAN; v[CPU_METER_TEMPERATURE] = NAN; diff --git a/vendor/github.com/htop-dev/htop/dragonflybsd/Platform.h b/vendor/github.com/htop-dev/htop/dragonflybsd/Platform.h index b37cea2a13..91616d4fe0 100644 --- a/vendor/github.com/htop-dev/htop/dragonflybsd/Platform.h +++ b/vendor/github.com/htop-dev/htop/dragonflybsd/Platform.h @@ -111,7 +111,7 @@ static inline Hashtable* Platform_dynamicColumns(void) { static inline void Platform_dynamicColumnsDone(ATTR_UNUSED Hashtable* table) { } -static inline const char* Platform_dynamicColumnInit(ATTR_UNUSED unsigned int key) { +static inline const char* Platform_dynamicColumnName(ATTR_UNUSED unsigned int key) { return NULL; } @@ -119,4 +119,16 @@ static inline bool Platform_dynamicColumnWriteField(ATTR_UNUSED const Process* p return false; } +static inline Hashtable* Platform_dynamicScreens(void) { + return NULL; +} + +static inline void Platform_defaultDynamicScreens(ATTR_UNUSED Settings* settings) { } + +static inline void Platform_addDynamicScreen(ATTR_UNUSED ScreenSettings* ss) { } + +static inline void Platform_addDynamicScreenAvailableColumns(ATTR_UNUSED Panel* availableColumns, ATTR_UNUSED const char* screen) { } + +static inline void Platform_dynamicScreensDone(ATTR_UNUSED Hashtable* screens) { } + #endif diff --git a/vendor/github.com/htop-dev/htop/freebsd/FreeBSDMachine.c b/vendor/github.com/htop-dev/htop/freebsd/FreeBSDMachine.c index 26da667a20..f5d228c82a 100644 --- a/vendor/github.com/htop-dev/htop/freebsd/FreeBSDMachine.c +++ b/vendor/github.com/htop-dev/htop/freebsd/FreeBSDMachine.c @@ -281,24 +281,21 @@ static inline void FreeBSDMachine_scanCPU(Machine* super) { // propagate frequency to all cores if only supplied for CPU 0 if (cpus > 1) { if (super->settings->showCPUTemperature) { - double maxTemp = NAN; + double maxTemp = -HUGE_VAL; for (unsigned int i = 1; i < maxcpu; i++) { - const double coreTemp = this->cpus[i].temperature; - if (isnan(coreTemp)) - continue; - - maxTemp = MAXIMUM(maxTemp, coreTemp); + if (isgreater(this->cpus[i].temperature, maxTemp)) { + maxTemp = this->cpus[i].temperature; + this->cpus[0].temperature = maxTemp; + } } - - this->cpus[0].temperature = maxTemp; } if (super->settings->showCPUFrequency) { const double coreZeroFreq = this->cpus[1].frequency; double freqSum = coreZeroFreq; - if (!isnan(coreZeroFreq)) { + if (isNonnegative(coreZeroFreq)) { for (unsigned int i = 2; i < maxcpu; i++) { - if (isnan(this->cpus[i].frequency)) + if (!isNonnegative(this->cpus[i].frequency)) this->cpus[i].frequency = coreZeroFreq; freqSum += this->cpus[i].frequency; diff --git a/vendor/github.com/htop-dev/htop/freebsd/FreeBSDProcess.c b/vendor/github.com/htop-dev/htop/freebsd/FreeBSDProcess.c index 4970ff2cc0..f6d3451dad 100644 --- a/vendor/github.com/htop-dev/htop/freebsd/FreeBSDProcess.c +++ b/vendor/github.com/htop-dev/htop/freebsd/FreeBSDProcess.c @@ -71,8 +71,8 @@ void Process_delete(Object* cast) { free(this); } -static void FreeBSDProcess_writeField(const Process* this, RichString* str, ProcessField field) { - const FreeBSDProcess* fp = (const FreeBSDProcess*) this; +static void FreeBSDProcess_rowWriteField(const Row* super, RichString* str, ProcessField field) { + const FreeBSDProcess* fp = (const FreeBSDProcess*) super; char buffer[256]; size_t n = sizeof(buffer); int attr = CRT_colors[DEFAULT_COLOR]; @@ -81,13 +81,13 @@ static void FreeBSDProcess_writeField(const Process* this, RichString* str, Proc // add FreeBSD-specific fields here case JID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, fp->jid); break; case JAIL: - Process_printLeftAlignedField(str, attr, fp->jname ? fp->jname : "N/A", 11); + Row_printLeftAlignedField(str, attr, fp->jname ? fp->jname : "N/A", 11); return; case EMULATION: - Process_printLeftAlignedField(str, attr, fp->emul ? fp->emul : "N/A", 16); + Row_printLeftAlignedField(str, attr, fp->emul ? fp->emul : "N/A", 16); return; default: - Process_writeField(this, str, field); + Process_writeField(&fp->super, str, field); return; } RichString_appendWide(str, attr, buffer); @@ -112,11 +112,18 @@ static int FreeBSDProcess_compareByKey(const Process* v1, const Process* v2, Pro const ProcessClass FreeBSDProcess_class = { .super = { - .extends = Class(Process), - .display = Process_display, - .delete = Process_delete, - .compare = Process_compare + .super = { + .extends = Class(Process), + .display = Row_display, + .delete = Process_delete, + .compare = Process_compare + }, + .isHighlighted = Process_rowIsHighlighted, + .isVisible = Process_rowIsVisible, + .matchesFilter = Process_rowMatchesFilter, + .compareByParent = Process_compareByParent, + .sortKeyString = Process_rowGetSortKey, + .writeField = FreeBSDProcess_rowWriteField }, - .writeField = FreeBSDProcess_writeField, .compareByKey = FreeBSDProcess_compareByKey }; diff --git a/vendor/github.com/htop-dev/htop/freebsd/FreeBSDProcessList.c b/vendor/github.com/htop-dev/htop/freebsd/FreeBSDProcessList.c index d8d4bbe047..aabb61ccde 100644 --- a/vendor/github.com/htop-dev/htop/freebsd/FreeBSDProcessList.c +++ b/vendor/github.com/htop-dev/htop/freebsd/FreeBSDProcessList.c @@ -43,18 +43,17 @@ in the source distribution for its full text. ProcessList* ProcessList_new(Machine* host, Hashtable* pidMatchList) { FreeBSDProcessList* this = xCalloc(1, sizeof(FreeBSDProcessList)); - ProcessList* super = &this->super; + Object_setClass(this, Class(ProcessList)); + ProcessList* super = &this->super; ProcessList_init(super, Class(FreeBSDProcess), host, pidMatchList); return super; } -void ProcessList_delete(ProcessList* super) { - FreeBSDProcessList* this = (FreeBSDProcessList*) super; - - ProcessList_done(super); - +void ProcessList_delete(Object* cast) { + FreeBSDProcessList* this = (FreeBSDProcessList*) cast; + ProcessList_done(&this->super); free(this); } @@ -174,12 +173,12 @@ void ProcessList_goThroughEntries(ProcessList* super) { if (!preExisting) { fp->jid = kproc->ki_jid; - proc->pid = kproc->ki_pid; + Process_setPid(proc, kproc->ki_pid); + Process_setThreadGroup(proc, kproc->ki_pid); + Process_setParent(proc, kproc->ki_ppid); proc->isKernelThread = kproc->ki_pid != 1 && (kproc->ki_flag & P_SYSTEM); proc->isUserlandThread = false; - proc->ppid = kproc->ki_ppid; proc->tpgid = kproc->ki_tpgid; - proc->tgid = kproc->ki_pid; proc->session = kproc->ki_sid; proc->pgrp = kproc->ki_pgid; proc->st_uid = kproc->ki_uid; @@ -279,11 +278,11 @@ void ProcessList_goThroughEntries(ProcessList* super) { Scheduling_readProcessPolicy(proc); #endif - proc->show = ! ((hideKernelThreads && Process_isKernelThread(proc)) || (hideUserlandThreads && Process_isUserlandThread(proc))); + proc->super.show = ! ((hideKernelThreads && Process_isKernelThread(proc)) || (hideUserlandThreads && Process_isUserlandThread(proc))); super->totalTasks++; if (proc->state == RUNNING) super->runningTasks++; - proc->updated = true; + proc->super.updated = true; } } diff --git a/vendor/github.com/htop-dev/htop/freebsd/Platform.h b/vendor/github.com/htop-dev/htop/freebsd/Platform.h index 849f7ddf31..cc86456928 100644 --- a/vendor/github.com/htop-dev/htop/freebsd/Platform.h +++ b/vendor/github.com/htop-dev/htop/freebsd/Platform.h @@ -109,7 +109,7 @@ static inline Hashtable* Platform_dynamicColumns(void) { return NULL; } -static inline const char* Platform_dynamicColumnInit(ATTR_UNUSED unsigned int key) { +static inline const char* Platform_dynamicColumnName(ATTR_UNUSED unsigned int key) { return NULL; } @@ -119,4 +119,16 @@ static inline bool Platform_dynamicColumnWriteField(ATTR_UNUSED const Process* p return false; } +static inline Hashtable* Platform_dynamicScreens(void) { + return NULL; +} + +static inline void Platform_defaultDynamicScreens(ATTR_UNUSED Settings* settings) { } + +static inline void Platform_addDynamicScreen(ATTR_UNUSED ScreenSettings* ss) { } + +static inline void Platform_addDynamicScreenAvailableColumns(ATTR_UNUSED Panel* availableColumns, ATTR_UNUSED const char* screen) { } + +static inline void Platform_dynamicScreensDone(ATTR_UNUSED Hashtable* screens) { } + #endif diff --git a/vendor/github.com/htop-dev/htop/generic/fdstat_sysctl.c b/vendor/github.com/htop-dev/htop/generic/fdstat_sysctl.c index 49e8e362a6..432114c201 100644 --- a/vendor/github.com/htop-dev/htop/generic/fdstat_sysctl.c +++ b/vendor/github.com/htop-dev/htop/generic/fdstat_sysctl.c @@ -43,9 +43,6 @@ static void Generic_getFileDescriptors_sysctl_internal( len = sizeof(open_fd); if (sysctlname_numfiles && sysctlbyname(sysctlname_numfiles, &open_fd, &len, NULL, 0) == 0) { *used = open_fd; - } - - if (!isnan(*used)) { return; } diff --git a/vendor/github.com/htop-dev/htop/htop.1.in b/vendor/github.com/htop-dev/htop/htop.1.in index 72a98fbe84..18be08dc6a 100644 --- a/vendor/github.com/htop-dev/htop/htop.1.in +++ b/vendor/github.com/htop-dev/htop/htop.1.in @@ -258,6 +258,10 @@ Hide user threads: on systems that represent them differently than ordinary processes (such as recent NPTL-based systems), this can hide threads from userspace processes in the process list. (This is a toggle key.) .TP +.B O +Hide containerized processes: prevent processes running in a container +from being displayed in the process list. (This is a toggle key.) +.TP .B p Show full paths to running programs, where applicable. (This is a toggle key.) .TP diff --git a/vendor/github.com/htop-dev/htop/iwyu/htop.imp b/vendor/github.com/htop-dev/htop/iwyu/htop.imp index 1416d7433f..5e87cdbff3 100644 --- a/vendor/github.com/htop-dev/htop/iwyu/htop.imp +++ b/vendor/github.com/htop-dev/htop/iwyu/htop.imp @@ -4,6 +4,10 @@ { include: ["", "private", "\"ProvideCurses.h\"", "public"] }, { include: ["", "private", "\"ProvideCurses.h\"", "public"] }, + { include: ["", "private", "\"ProvideTerm.h\"", "public"] }, + { include: ["", "private", "\"ProvideTerm.h\"", "public"] }, + { include: ["", "private", "\"ProvideTerm.h\"", "public"] }, + { include: ["", "private", "", "public"] }, { include: ["", "private", "", "public"] }, diff --git a/vendor/github.com/htop-dev/htop/linux/HugePageMeter.c b/vendor/github.com/htop-dev/htop/linux/HugePageMeter.c index ec3804eee5..62f8e7eb4a 100644 --- a/vendor/github.com/htop-dev/htop/linux/HugePageMeter.c +++ b/vendor/github.com/htop-dev/htop/linux/HugePageMeter.c @@ -80,7 +80,7 @@ static void HugePageMeter_display(const Object* cast, RichString* out) { RichString_appendAscii(out, CRT_colors[METER_VALUE], buffer); for (unsigned i = 0; i < ARRAYSIZE(HugePageMeter_active_labels); i++) { - if (isnan(this->values[i])) { + if (!HugePageMeter_active_labels[i]) { break; } RichString_appendAscii(out, CRT_colors[METER_TEXT], HugePageMeter_active_labels[i]); diff --git a/vendor/github.com/htop-dev/htop/linux/LibSensors.c b/vendor/github.com/htop-dev/htop/linux/LibSensors.c index ff084b6489..891dd01ad5 100644 --- a/vendor/github.com/htop-dev/htop/linux/LibSensors.c +++ b/vendor/github.com/htop-dev/htop/linux/LibSensors.c @@ -9,9 +9,10 @@ #include #include #include -#include #include +#include #include + #include #include "Macros.h" @@ -143,7 +144,8 @@ static int tempDriverPriority(const sensors_chip_name* chip) { void LibSensors_getCPUTemperatures(CPUData* cpus, unsigned int existingCPUs, unsigned int activeCPUs) { assert(existingCPUs > 0 && existingCPUs < 16384); - double data[existingCPUs + 1]; + + double* data = xMallocArray(existingCPUs + 1, sizeof(double)); for (size_t i = 0; i < existingCPUs + 1; i++) data[i] = NAN; @@ -200,7 +202,7 @@ void LibSensors_getCPUTemperatures(CPUData* cpus, unsigned int existingCPUs, uns continue; /* If already set, e.g. Ryzen reporting platform temperature for each die, use the bigger one */ - if (isnan(data[tempID])) { + if (isNaN(data[tempID])) { data[tempID] = temp; if (tempID > 0) coreTempCount++; @@ -220,7 +222,7 @@ void LibSensors_getCPUTemperatures(CPUData* cpus, unsigned int existingCPUs, uns } /* Only package temperature - copy to all cores */ - if (coreTempCount == 0 && !isnan(data[0])) { + if (coreTempCount == 0 && !isNaN(data[0])) { for (unsigned int i = 1; i <= existingCPUs; i++) data[i] = data[0]; @@ -229,22 +231,20 @@ void LibSensors_getCPUTemperatures(CPUData* cpus, unsigned int existingCPUs, uns } /* No package temperature - set to max core temperature */ - if (isnan(data[0]) && coreTempCount != 0) { - double maxTemp = NAN; + if (coreTempCount > 0 && isNaN(data[0])) { + double maxTemp = -HUGE_VAL; for (unsigned int i = 1; i <= existingCPUs; i++) { - if (isnan(data[i])) - continue; - - maxTemp = MAXIMUM(maxTemp, data[i]); + if (isgreater(data[i], maxTemp)) { + maxTemp = data[i]; + data[0] = data[i]; + } } - data[0] = maxTemp; - /* Check for further adjustments */ } /* Only temperature for core 0, maybe Ryzen - copy to all other cores */ - if (coreTempCount == 1 && !isnan(data[1])) { + if (coreTempCount == 1 && !isNaN(data[1])) { for (unsigned int i = 2; i <= existingCPUs; i++) data[i] = data[1]; @@ -264,6 +264,8 @@ void LibSensors_getCPUTemperatures(CPUData* cpus, unsigned int existingCPUs, uns out: for (unsigned int i = 0; i <= existingCPUs; i++) cpus[i].temperature = data[i]; + + free(data); } #endif /* HAVE_SENSORS_SENSORS_H */ diff --git a/vendor/github.com/htop-dev/htop/linux/LinuxMachine.c b/vendor/github.com/htop-dev/htop/linux/LinuxMachine.c index 7b6abfa01d..ff2087c756 100644 --- a/vendor/github.com/htop-dev/htop/linux/LinuxMachine.c +++ b/vendor/github.com/htop-dev/htop/linux/LinuxMachine.c @@ -27,6 +27,7 @@ in the source distribution for its full text. #include #include "Compat.h" +#include "Macros.h" #include "XUtils.h" #include "linux/LinuxMachine.h" #include "linux/Platform.h" // needed for GNU/hurd to get PATH_MAX // IWYU pragma: keep @@ -336,6 +337,9 @@ static void LinuxMachine_scanZramInfo(LinuxMachine* this) { this->zram.totalZram = totalZram / 1024; this->zram.usedZramComp = usedZramComp / 1024; this->zram.usedZramOrig = usedZramOrig / 1024; + if (this->zram.usedZramComp > this->zram.usedZramOrig) { + this->zram.usedZramComp = this->zram.usedZramOrig; + } } static void LinuxMachine_scanZfsArcstats(LinuxMachine* this) { @@ -501,7 +505,8 @@ static void LinuxMachine_scanCPUTime(LinuxMachine* this) { char buffer[PROC_LINE_LENGTH + 1]; while (fgets(buffer, sizeof(buffer), file)) { if (String_startsWith(buffer, "procs_running")) { - super->pl->runningTasks = strtoul(buffer + strlen("procs_running"), NULL, 10); + ProcessList* pl = (ProcessList*) super->processTable; + pl->runningTasks = strtoul(buffer + strlen("procs_running"), NULL, 10); break; } } @@ -601,7 +606,7 @@ static void scanCPUFrequencyFromCPUinfo(LinuxMachine* this) { CPUData* cpuData = &(this->cpuData[cpuid + 1]); /* do not override sysfs data */ - if (isnan(cpuData->frequency)) { + if (!isNonnegative(cpuData->frequency)) { cpuData->frequency = frequency; } numCPUsWithFrequency++; diff --git a/vendor/github.com/htop-dev/htop/linux/LinuxMachine.h b/vendor/github.com/htop-dev/htop/linux/LinuxMachine.h index 7dba905fdb..c3076a304f 100644 --- a/vendor/github.com/htop-dev/htop/linux/LinuxMachine.h +++ b/vendor/github.com/htop-dev/htop/linux/LinuxMachine.h @@ -61,10 +61,13 @@ typedef struct LinuxMachine_ { Machine super; long jiffies; - long long boottime; int pageSize; int pageSizeKB; + /* see Linux kernel source for further detail, fs/proc/stat.c */ + unsigned int runningTasks; /* procs_running from /proc/stat */ + long long boottime; /* btime field from /proc/stat */ + double period; CPUData* cpuData; diff --git a/vendor/github.com/htop-dev/htop/linux/LinuxProcess.c b/vendor/github.com/htop-dev/htop/linux/LinuxProcess.c index b815c5b55e..e348f9ab1b 100644 --- a/vendor/github.com/htop-dev/htop/linux/LinuxProcess.c +++ b/vendor/github.com/htop-dev/htop/linux/LinuxProcess.c @@ -143,22 +143,29 @@ static int LinuxProcess_effectiveIOPriority(const LinuxProcess* this) { #define SYS_ioprio_set __NR_ioprio_set #endif -IOPriority LinuxProcess_updateIOPriority(LinuxProcess* this) { +IOPriority LinuxProcess_updateIOPriority(Process* p) { IOPriority ioprio = 0; // Other OSes masquerading as Linux (NetBSD?) don't have this syscall #ifdef SYS_ioprio_get - ioprio = syscall(SYS_ioprio_get, IOPRIO_WHO_PROCESS, this->super.pid); + ioprio = syscall(SYS_ioprio_get, IOPRIO_WHO_PROCESS, Process_getPid(p)); #endif + LinuxProcess* this = (LinuxProcess*) p; this->ioPriority = ioprio; return ioprio; } -bool LinuxProcess_setIOPriority(Process* this, Arg ioprio) { +static bool LinuxProcess_setIOPriority(Process* p, Arg ioprio) { // Other OSes masquerading as Linux (NetBSD?) don't have this syscall #ifdef SYS_ioprio_set - syscall(SYS_ioprio_set, IOPRIO_WHO_PROCESS, this->pid, ioprio.i); + syscall(SYS_ioprio_set, IOPRIO_WHO_PROCESS, Process_getPid(p), ioprio.i); #endif - return (LinuxProcess_updateIOPriority((LinuxProcess*)this) == ioprio.i); + return LinuxProcess_updateIOPriority(p) == ioprio.i; +} + +bool LinuxProcess_rowSetIOPriority(Row* super, Arg ioprio) { + Process* p = (Process*) super; + assert(Object_isA((const Object*) p, (const ObjectClass*) &Process_class)); + return LinuxProcess_setIOPriority(p, ioprio); } bool LinuxProcess_isAutogroupEnabled(void) { @@ -168,9 +175,10 @@ bool LinuxProcess_isAutogroupEnabled(void) { return buf[0] == '1'; } -bool LinuxProcess_changeAutogroupPriorityBy(Process* this, Arg delta) { +static bool LinuxProcess_changeAutogroupPriorityBy(Process* p, Arg delta) { char buffer[256]; - xSnprintf(buffer, sizeof(buffer), PROCDIR "/%d/autogroup", this->pid); + pid_t pid = Process_getPid(p); + xSnprintf(buffer, sizeof(buffer), PROCDIR "/%d/autogroup", pid); FILE* file = fopen(buffer, "r+"); if (!file) @@ -192,57 +200,66 @@ bool LinuxProcess_changeAutogroupPriorityBy(Process* this, Arg delta) { return success; } -static void LinuxProcess_writeField(const Process* this, RichString* str, ProcessField field) { +bool LinuxProcess_rowChangeAutogroupPriorityBy(Row* super, Arg delta) { + Process* p = (Process*) super; + assert(Object_isA((const Object*) p, (const ObjectClass*) &Process_class)); + return LinuxProcess_changeAutogroupPriorityBy(p, delta); +} + +static double LinuxProcess_totalIORate(const LinuxProcess* lp) { + double totalRate = NAN; + if (isNonnegative(lp->io_rate_read_bps)) { + totalRate = lp->io_rate_read_bps; + if (isNonnegative(lp->io_rate_write_bps)) { + totalRate += lp->io_rate_write_bps; + } + } else if (isNonnegative(lp->io_rate_write_bps)) { + totalRate = lp->io_rate_write_bps; + } + return totalRate; +} + +static void LinuxProcess_rowWriteField(const Row* super, RichString* str, ProcessField field) { + const Process* this = (const Process*) super; + const Machine* host = (const Machine*) super->host; + const LinuxMachine* lhost = (const LinuxMachine*) host; const LinuxProcess* lp = (const LinuxProcess*) this; - const LinuxMachine* lhost = (const LinuxMachine*) this->host; - bool coloring = this->host->settings->highlightMegabytes; + bool coloring = host->settings->highlightMegabytes; char buffer[256]; buffer[255] = '\0'; int attr = CRT_colors[DEFAULT_COLOR]; size_t n = sizeof(buffer) - 1; switch (field) { - case CMINFLT: Process_printCount(str, lp->cminflt, coloring); return; - case CMAJFLT: Process_printCount(str, lp->cmajflt, coloring); return; - case M_DRS: Process_printBytes(str, lp->m_drs * lhost->pageSize, coloring); return; + case CMINFLT: Row_printCount(str, lp->cminflt, coloring); return; + case CMAJFLT: Row_printCount(str, lp->cmajflt, coloring); return; + case M_DRS: Row_printBytes(str, lp->m_drs * lhost->pageSize, coloring); return; case M_LRS: if (lp->m_lrs) { - Process_printBytes(str, lp->m_lrs * lhost->pageSize, coloring); + Row_printBytes(str, lp->m_lrs * lhost->pageSize, coloring); return; } attr = CRT_colors[PROCESS_SHADOW]; xSnprintf(buffer, n, " N/A "); break; - case M_TRS: Process_printBytes(str, lp->m_trs * lhost->pageSize, coloring); return; - case M_SHARE: Process_printBytes(str, lp->m_share * lhost->pageSize, coloring); return; - case M_PSS: Process_printKBytes(str, lp->m_pss, coloring); return; - case M_SWAP: Process_printKBytes(str, lp->m_swap, coloring); return; - case M_PSSWP: Process_printKBytes(str, lp->m_psswp, coloring); return; - case UTIME: Process_printTime(str, lp->utime, coloring); return; - case STIME: Process_printTime(str, lp->stime, coloring); return; - case CUTIME: Process_printTime(str, lp->cutime, coloring); return; - case CSTIME: Process_printTime(str, lp->cstime, coloring); return; - case RCHAR: Process_printBytes(str, lp->io_rchar, coloring); return; - case WCHAR: Process_printBytes(str, lp->io_wchar, coloring); return; - case SYSCR: Process_printCount(str, lp->io_syscr, coloring); return; - case SYSCW: Process_printCount(str, lp->io_syscw, coloring); return; - case RBYTES: Process_printBytes(str, lp->io_read_bytes, coloring); return; - case WBYTES: Process_printBytes(str, lp->io_write_bytes, coloring); return; - case CNCLWB: Process_printBytes(str, lp->io_cancelled_write_bytes, coloring); return; - case IO_READ_RATE: Process_printRate(str, lp->io_rate_read_bps, coloring); return; - case IO_WRITE_RATE: Process_printRate(str, lp->io_rate_write_bps, coloring); return; - case IO_RATE: { - double totalRate; - if (!isnan(lp->io_rate_read_bps) && !isnan(lp->io_rate_write_bps)) - totalRate = lp->io_rate_read_bps + lp->io_rate_write_bps; - else if (!isnan(lp->io_rate_read_bps)) - totalRate = lp->io_rate_read_bps; - else if (!isnan(lp->io_rate_write_bps)) - totalRate = lp->io_rate_write_bps; - else - totalRate = NAN; - Process_printRate(str, totalRate, coloring); - return; - } + case M_TRS: Row_printBytes(str, lp->m_trs * lhost->pageSize, coloring); return; + case M_SHARE: Row_printBytes(str, lp->m_share * lhost->pageSize, coloring); return; + case M_PSS: Row_printKBytes(str, lp->m_pss, coloring); return; + case M_SWAP: Row_printKBytes(str, lp->m_swap, coloring); return; + case M_PSSWP: Row_printKBytes(str, lp->m_psswp, coloring); return; + case UTIME: Row_printTime(str, lp->utime, coloring); return; + case STIME: Row_printTime(str, lp->stime, coloring); return; + case CUTIME: Row_printTime(str, lp->cutime, coloring); return; + case CSTIME: Row_printTime(str, lp->cstime, coloring); return; + case RCHAR: Row_printBytes(str, lp->io_rchar, coloring); return; + case WCHAR: Row_printBytes(str, lp->io_wchar, coloring); return; + case SYSCR: Row_printCount(str, lp->io_syscr, coloring); return; + case SYSCW: Row_printCount(str, lp->io_syscw, coloring); return; + case RBYTES: Row_printBytes(str, lp->io_read_bytes, coloring); return; + case WBYTES: Row_printBytes(str, lp->io_write_bytes, coloring); return; + case CNCLWB: Row_printBytes(str, lp->io_cancelled_write_bytes, coloring); return; + case IO_READ_RATE: Row_printRate(str, lp->io_rate_read_bps, coloring); return; + case IO_WRITE_RATE: Row_printRate(str, lp->io_rate_write_bps, coloring); return; + case IO_RATE: Row_printRate(str, LinuxProcess_totalIORate(lp), coloring); return; #ifdef HAVE_OPENVZ case CTID: xSnprintf(buffer, n, "%-8s ", lp->ctid ? lp->ctid : ""); break; case VPID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, lp->vpid); break; @@ -250,8 +267,8 @@ static void LinuxProcess_writeField(const Process* this, RichString* str, Proces #ifdef HAVE_VSERVER case VXID: xSnprintf(buffer, n, "%5u ", lp->vxid); break; #endif - case CGROUP: xSnprintf(buffer, n, "%-*.*s ", Process_fieldWidths[CGROUP], Process_fieldWidths[CGROUP], lp->cgroup ? lp->cgroup : "N/A"); break; - case CCGROUP: xSnprintf(buffer, n, "%-*.*s ", Process_fieldWidths[CCGROUP], Process_fieldWidths[CCGROUP], lp->cgroup_short ? lp->cgroup_short : (lp->cgroup ? lp->cgroup : "N/A")); break; + case CGROUP: xSnprintf(buffer, n, "%-*.*s ", Row_fieldWidths[CGROUP], Row_fieldWidths[CGROUP], lp->cgroup ? lp->cgroup : "N/A"); break; + case CCGROUP: xSnprintf(buffer, n, "%-*.*s ", Row_fieldWidths[CCGROUP], Row_fieldWidths[CCGROUP], lp->cgroup_short ? lp->cgroup_short : (lp->cgroup ? lp->cgroup : "N/A")); break; case OOM: xSnprintf(buffer, n, "%4u ", lp->oom); break; case IO_PRIORITY: { int klass = IOPriority_class(lp->ioPriority); @@ -272,9 +289,9 @@ static void LinuxProcess_writeField(const Process* this, RichString* str, Proces break; } #ifdef HAVE_DELAYACCT - case PERCENT_CPU_DELAY: Process_printPercentage(lp->cpu_delay_percent, buffer, n, 5, &attr); break; - case PERCENT_IO_DELAY: Process_printPercentage(lp->blkio_delay_percent, buffer, n, 5, &attr); break; - case PERCENT_SWAP_DELAY: Process_printPercentage(lp->swapin_delay_percent, buffer, n, 5, &attr); break; + case PERCENT_CPU_DELAY: Row_printPercentage(lp->cpu_delay_percent, buffer, n, 5, &attr); break; + case PERCENT_IO_DELAY: Row_printPercentage(lp->blkio_delay_percent, buffer, n, 5, &attr); break; + case PERCENT_SWAP_DELAY: Row_printPercentage(lp->swapin_delay_percent, buffer, n, 5, &attr); break; #endif case CTXT: if (lp->ctxt_diff > 1000) { @@ -282,7 +299,7 @@ static void LinuxProcess_writeField(const Process* this, RichString* str, Proces } xSnprintf(buffer, n, "%5lu ", lp->ctxt_diff); break; - case SECATTR: snprintf(buffer, n, "%-*.*s ", Process_fieldWidths[SECATTR], Process_fieldWidths[SECATTR], lp->secattr ? lp->secattr : "N/A"); break; + case SECATTR: snprintf(buffer, n, "%-*.*s ", Row_fieldWidths[SECATTR], Row_fieldWidths[SECATTR], lp->secattr ? lp->secattr : "N/A"); break; case AUTOGROUP_ID: if (lp->autogroup_id != -1) { xSnprintf(buffer, n, "%4ld ", lp->autogroup_id); @@ -309,13 +326,6 @@ static void LinuxProcess_writeField(const Process* this, RichString* str, Proces RichString_appendAscii(str, attr, buffer); } -static double adjustNaN(double num) { - if (isnan(num)) - return -0.0005; - - return num; -} - static int LinuxProcess_compareByKey(const Process* v1, const Process* v2, ProcessField key) { const LinuxProcess* p1 = (const LinuxProcess*)v1; const LinuxProcess* p2 = (const LinuxProcess*)v2; @@ -358,11 +368,11 @@ static int LinuxProcess_compareByKey(const Process* v1, const Process* v2, Proce case CNCLWB: return SPACESHIP_NUMBER(p1->io_cancelled_write_bytes, p2->io_cancelled_write_bytes); case IO_READ_RATE: - return SPACESHIP_NUMBER(adjustNaN(p1->io_rate_read_bps), adjustNaN(p2->io_rate_read_bps)); + return compareRealNumbers(p1->io_rate_read_bps, p2->io_rate_read_bps); case IO_WRITE_RATE: - return SPACESHIP_NUMBER(adjustNaN(p1->io_rate_write_bps), adjustNaN(p2->io_rate_write_bps)); + return compareRealNumbers(p1->io_rate_write_bps, p2->io_rate_write_bps); case IO_RATE: - return SPACESHIP_NUMBER(adjustNaN(p1->io_rate_read_bps) + adjustNaN(p1->io_rate_write_bps), adjustNaN(p2->io_rate_read_bps) + adjustNaN(p2->io_rate_write_bps)); + return compareRealNumbers(LinuxProcess_totalIORate(p1), LinuxProcess_totalIORate(p2)); #ifdef HAVE_OPENVZ case CTID: return SPACESHIP_NULLSTR(p1->ctid, p2->ctid); @@ -381,11 +391,11 @@ static int LinuxProcess_compareByKey(const Process* v1, const Process* v2, Proce return SPACESHIP_NUMBER(p1->oom, p2->oom); #ifdef HAVE_DELAYACCT case PERCENT_CPU_DELAY: - return SPACESHIP_NUMBER(p1->cpu_delay_percent, p2->cpu_delay_percent); + return compareRealNumbers(p1->cpu_delay_percent, p2->cpu_delay_percent); case PERCENT_IO_DELAY: - return SPACESHIP_NUMBER(p1->blkio_delay_percent, p2->blkio_delay_percent); + return compareRealNumbers(p1->blkio_delay_percent, p2->blkio_delay_percent); case PERCENT_SWAP_DELAY: - return SPACESHIP_NUMBER(p1->swapin_delay_percent, p2->swapin_delay_percent); + return compareRealNumbers(p1->swapin_delay_percent, p2->swapin_delay_percent); #endif case IO_PRIORITY: return SPACESHIP_NUMBER(LinuxProcess_effectiveIOPriority(p1), LinuxProcess_effectiveIOPriority(p2)); @@ -404,11 +414,18 @@ static int LinuxProcess_compareByKey(const Process* v1, const Process* v2, Proce const ProcessClass LinuxProcess_class = { .super = { - .extends = Class(Process), - .display = Process_display, - .delete = Process_delete, - .compare = Process_compare + .super = { + .extends = Class(Process), + .display = Row_display, + .delete = Process_delete, + .compare = Process_compare + }, + .isHighlighted = Process_rowIsHighlighted, + .isVisible = Process_rowIsVisible, + .matchesFilter = Process_rowMatchesFilter, + .compareByParent = Process_compareByParent, + .sortKeyString = Process_rowGetSortKey, + .writeField = LinuxProcess_rowWriteField }, - .writeField = LinuxProcess_writeField, .compareByKey = LinuxProcess_compareByKey }; diff --git a/vendor/github.com/htop-dev/htop/linux/LinuxProcess.h b/vendor/github.com/htop-dev/htop/linux/LinuxProcess.h index 6c309893c0..1cd0eaaff7 100644 --- a/vendor/github.com/htop-dev/htop/linux/LinuxProcess.h +++ b/vendor/github.com/htop-dev/htop/linux/LinuxProcess.h @@ -122,13 +122,13 @@ Process* LinuxProcess_new(const Machine* host); void Process_delete(Object* cast); -IOPriority LinuxProcess_updateIOPriority(LinuxProcess* this); +IOPriority LinuxProcess_updateIOPriority(Process* proc); -bool LinuxProcess_setIOPriority(Process* this, Arg ioprio); +bool LinuxProcess_rowSetIOPriority(Row* super, Arg ioprio); bool LinuxProcess_isAutogroupEnabled(void); -bool LinuxProcess_changeAutogroupPriorityBy(Process* this, Arg delta); +bool LinuxProcess_rowChangeAutogroupPriorityBy(Row* super, Arg delta); bool Process_isThread(const Process* this); diff --git a/vendor/github.com/htop-dev/htop/linux/LinuxProcessList.c b/vendor/github.com/htop-dev/htop/linux/LinuxProcessList.c index e0a33e2870..9be2433e9a 100644 --- a/vendor/github.com/htop-dev/htop/linux/LinuxProcessList.c +++ b/vendor/github.com/htop-dev/htop/linux/LinuxProcessList.c @@ -202,9 +202,11 @@ static void LinuxProcessList_initNetlinkSocket(LinuxProcessList* this) { ProcessList* ProcessList_new(Machine* host, Hashtable* pidMatchList) { LinuxProcessList* this = xCalloc(1, sizeof(LinuxProcessList)); - ProcessList* super = &this->super; + Object_setClass(this, Class(ProcessList)); + ProcessList* super = &this->super; ProcessList_init(super, Class(LinuxProcess), host, pidMatchList); + LinuxProcessList_initTtyDrivers(this); // Test /proc/PID/smaps_rollup availability (faster to parse, Linux 4.14+) @@ -213,9 +215,9 @@ ProcessList* ProcessList_new(Machine* host, Hashtable* pidMatchList) { return super; } -void ProcessList_delete(ProcessList* pl) { - LinuxProcessList* this = (LinuxProcessList*) pl; - ProcessList_done(pl); +void ProcessList_delete(Object* cast) { + LinuxProcessList* this = (LinuxProcessList*) cast; + ProcessList_done(&this->super); if (this->ttyDrivers) { for (int i = 0; this->ttyDrivers[i].path; i++) { free(this->ttyDrivers[i].path); @@ -257,14 +259,14 @@ static bool LinuxProcessList_readStatFile(LinuxProcess* lp, openat_arg_t procFd, char buf[MAX_READ + 1]; char path[22] = "stat"; if (scanMainThread) { - xSnprintf(path, sizeof(path), "task/%"PRIi32"/stat", (int32_t)process->pid); + xSnprintf(path, sizeof(path), "task/%"PRIi32"/stat", (int32_t)Process_getPid(process)); } ssize_t r = xReadfileat(procFd, path, buf, sizeof(buf)); if (r < 0) return false; /* (1) pid - %d */ - assert(process->pid == atoi(buf)); + assert(Process_getPid(process) == atoi(buf)); char* location = strchr(buf, ' '); if (!location) return false; @@ -284,7 +286,7 @@ static bool LinuxProcessList_readStatFile(LinuxProcess* lp, openat_arg_t procFd, location += 2; /* (4) ppid - %d */ - process->ppid = strtol(location, &location, 10); + Process_setParent(process, strtol(location, &location, 10)); location += 1; /* (5) pgrp - %d */ @@ -482,11 +484,11 @@ static bool LinuxProcessList_updateUser(const Machine* host, Process* process, o static void LinuxProcessList_readIoFile(LinuxProcess* lp, openat_arg_t procFd, bool scanMainThread) { Process* process = &lp->super; - const Machine* host = process->host; + const Machine* host = process->super.host; char path[20] = "io"; char buffer[1024]; if (scanMainThread) { - xSnprintf(path, sizeof(path), "task/%"PRIi32"/io", (int32_t)process->pid); + xSnprintf(path, sizeof(path), "task/%"PRIi32"/io", (int32_t)Process_getPid(process)); } ssize_t r = xReadfileat(procFd, path, buffer, sizeof(buffer)); if (r < 0) { @@ -505,7 +507,10 @@ static void LinuxProcessList_readIoFile(LinuxProcess* lp, openat_arg_t procFd, b unsigned long long last_read = lp->io_read_bytes; unsigned long long last_write = lp->io_write_bytes; - unsigned long long time_delta = host->realtimeMs > lp->io_last_scan_time_ms ? host->realtimeMs - lp->io_last_scan_time_ms : 0; + unsigned long long time_delta = saturatingSub(host->realtimeMs, lp->io_last_scan_time_ms); + + // Note: Linux Kernel documentation states that /proc//io may be racy + // on 32-bit machines. (Documentation/filesystems/proc.rst) char* buf = buffer; const char* line; @@ -516,7 +521,7 @@ static void LinuxProcessList_readIoFile(LinuxProcess* lp, openat_arg_t procFd, b lp->io_rchar = strtoull(line + 7, NULL, 10); } else if (String_startsWith(line + 1, "ead_bytes: ")) { lp->io_read_bytes = strtoull(line + 12, NULL, 10); - lp->io_rate_read_bps = time_delta ? (lp->io_read_bytes - last_read) * /*ms to s*/1000. / time_delta : NAN; + lp->io_rate_read_bps = time_delta ? saturatingSub(lp->io_read_bytes, last_read) * /*ms to s*/1000. / time_delta : NAN; } break; case 'w': @@ -524,7 +529,7 @@ static void LinuxProcessList_readIoFile(LinuxProcess* lp, openat_arg_t procFd, b lp->io_wchar = strtoull(line + 7, NULL, 10); } else if (String_startsWith(line + 1, "rite_bytes: ")) { lp->io_write_bytes = strtoull(line + 13, NULL, 10); - lp->io_rate_write_bps = time_delta ? (lp->io_write_bytes - last_write) * /*ms to s*/1000. / time_delta : NAN; + lp->io_rate_write_bps = time_delta ? saturatingSub(lp->io_write_bytes, last_write) * /*ms to s*/1000. / time_delta : NAN; } break; case 's': @@ -740,7 +745,7 @@ static void LinuxProcessList_readOpenVZData(LinuxProcess* process, openat_arg_t if (access(PROCDIR "/vz", R_OK) != 0) { free(process->ctid); process->ctid = NULL; - process->vpid = process->super.pid; + process->vpid = Process_getPid(&process->super); return; } @@ -748,7 +753,7 @@ static void LinuxProcessList_readOpenVZData(LinuxProcess* process, openat_arg_t if (!file) { free(process->ctid); process->ctid = NULL; - process->vpid = process->super.pid; + process->vpid = Process_getPid(&process->super); return; } @@ -820,7 +825,7 @@ static void LinuxProcessList_readOpenVZData(LinuxProcess* process, openat_arg_t } if (!foundVPid) { - process->vpid = process->super.pid; + process->vpid = Process_getPid(&process->super); } } @@ -872,27 +877,27 @@ static void LinuxProcessList_readCGroupFile(LinuxProcess* process, openat_arg_t bool changed = !process->cgroup || !String_eq(process->cgroup, output); - Process_updateFieldWidth(CGROUP, strlen(output)); + Row_updateFieldWidth(CGROUP, strlen(output)); free_and_xStrdup(&process->cgroup, output); if (!changed) { if (process->cgroup_short) { - Process_updateFieldWidth(CCGROUP, strlen(process->cgroup_short)); + Row_updateFieldWidth(CCGROUP, strlen(process->cgroup_short)); } else { //CCGROUP is alias to normal CGROUP if shortening fails - Process_updateFieldWidth(CCGROUP, strlen(process->cgroup)); + Row_updateFieldWidth(CCGROUP, strlen(process->cgroup)); } return; } char* cgroup_short = CGroup_filterName(process->cgroup); if (cgroup_short) { - Process_updateFieldWidth(CCGROUP, strlen(cgroup_short)); + Row_updateFieldWidth(CCGROUP, strlen(cgroup_short)); free_and_xStrdup(&process->cgroup_short, cgroup_short); free(cgroup_short); } else { //CCGROUP is alias to normal CGROUP if shortening fails - Process_updateFieldWidth(CCGROUP, strlen(process->cgroup)); + Row_updateFieldWidth(CCGROUP, strlen(process->cgroup)); free(process->cgroup_short); process->cgroup_short = NULL; } @@ -952,7 +957,7 @@ static void LinuxProcessList_readSecattrData(LinuxProcess* process, openat_arg_t *newline = '\0'; } - Process_updateFieldWidth(SECATTR, strlen(buffer)); + Row_updateFieldWidth(SECATTR, strlen(buffer)); if (process->secattr && String_eq(process->secattr, buffer)) { return; @@ -1001,16 +1006,16 @@ static int handleNetlinkMsg(struct nl_msg* nlmsg, void* linuxProcess) { 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(lp->super.pid == (pid_t)stats.ac_pid); + 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 BOUNDS(x) (isnan(x) ? 0.0 : ((x) > 100) ? 100.0 : (x)) - #define DELTAPERC(x,y) BOUNDS((float) ((x) - (y)) / timeDelta * 100) + #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 - #undef BOUNDS lp->swapin_delay_total = stats.swapin_delay_total; lp->blkio_delay_total = stats.blkio_delay_total; @@ -1042,7 +1047,7 @@ static void LinuxProcessList_readDelayAcctData(LinuxProcessList* this, LinuxProc nlmsg_free(msg); } - if (nla_put_u32(msg, TASKSTATS_CMD_ATTR_PID, process->super.pid) < 0) { + if (nla_put_u32(msg, TASKSTATS_CMD_ATTR_PID, Process_getPid(&process->super)) < 0) { nlmsg_free(msg); } @@ -1291,13 +1296,15 @@ static char* LinuxProcessList_updateTtyDevice(TtyDriver* ttyDrivers, unsigned lo } static bool isOlderThan(const Process* proc, unsigned int seconds) { - assert(proc->host->realtimeMs > 0); + const Machine* host = proc->super.host; + + assert(host->realtimeMs > 0); /* Starttime might not yet be parsed */ if (proc->starttime_ctime <= 0) return false; - uint64_t realtime = proc->host->realtimeMs / 1000; + uint64_t realtime = host->realtimeMs / 1000; if (realtime < (uint64_t)proc->starttime_ctime) return false; @@ -1312,6 +1319,9 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, openat_arg_ const ScreenSettings* ss = settings->ss; const struct dirent* entry; + /* set runningTasks from /proc/stat (from Machine_scanCPUTime) */ + pl->runningTasks = lhost->runningTasks; + #ifdef HAVE_OPENAT int dirFd = openat(parentFd, dirname, O_RDONLY | O_DIRECTORY | O_NOFOLLOW); if (dirFd < 0) @@ -1360,7 +1370,7 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, openat_arg_ } // Skip task directory of main thread - if (parent && pid == parent->pid) + if (parent && pid == Process_getPid(parent)) continue; #ifdef HAVE_OPENAT @@ -1376,8 +1386,8 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, openat_arg_ Process* proc = ProcessList_getProcess(pl, pid, &preExisting, LinuxProcess_new); LinuxProcess* lp = (LinuxProcess*) proc; - proc->tgid = parent ? parent->pid : pid; - proc->isUserlandThread = proc->pid != proc->tgid; + Process_setThreadGroup(proc, parent ? Process_getPid(parent) : pid); + proc->isUserlandThread = Process_getPid(proc) != Process_getThreadGroup(proc); LinuxProcessList_recurseProcTree(this, procFd, lhost, "task", proc); @@ -1388,24 +1398,24 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, openat_arg_ * But it will short-circuit subsequent scans. */ if (preExisting && hideKernelThreads && Process_isKernelThread(proc)) { - proc->updated = true; - proc->show = false; + proc->super.updated = true; + proc->super.show = false; pl->kernelThreads++; pl->totalTasks++; Compat_openatArgClose(procFd); continue; } if (preExisting && hideUserlandThreads && Process_isUserlandThread(proc)) { - proc->updated = true; - proc->show = false; + proc->super.updated = true; + proc->super.show = false; pl->userlandThreads++; pl->totalTasks++; Compat_openatArgClose(procFd); continue; } if (preExisting && hideRunningInContainer && proc->isRunningInContainer) { - proc->updated = true; - proc->show = false; + proc->super.updated = true; + proc->super.show = false; Compat_openatArgClose(procFd); continue; } @@ -1473,12 +1483,15 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, openat_arg_ } if (ss->flags & PROCESS_FLAG_LINUX_IOPRIO) { - LinuxProcess_updateIOPriority(lp); + LinuxProcess_updateIOPriority(proc); } - /* period might be 0 after system sleep */ - float percent_cpu = (lhost->period < 1E-6) ? 0.0F : ((lp->utime + lp->stime - lasttimes) / lhost->period * 100.0); - proc->percent_cpu = CLAMP(percent_cpu, 0.0F, host->activeCPUs * 100.0F); + proc->percent_cpu = NAN; + /* lhost->period might be 0 after system sleep */ + if (lhost->period > 0.0) { + float percent_cpu = saturatingSub(lp->utime + lp->stime, lasttimes) / lhost->period * 100.0; + proc->percent_cpu = MINIMUM(percent_cpu, host->activeCPUs * 100.0F); + } proc->percent_mem = proc->m_resident / (double)(host->totalMem) * 100.0; Process_updateCPUFieldWidths(proc->percent_cpu); @@ -1555,11 +1568,11 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, openat_arg_ * Final section after all data has been gathered */ - proc->updated = true; + proc->super.updated = true; Compat_openatArgClose(procFd); if (hideRunningInContainer && proc->isRunningInContainer) { - proc->show = false; + proc->super.show = false; continue; } @@ -1570,7 +1583,7 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, openat_arg_ } /* Set at the end when we know if a new entry is a thread */ - proc->show = ! ((hideKernelThreads && Process_isKernelThread(proc)) || (hideUserlandThreads && Process_isUserlandThread(proc))); + proc->super.show = ! ((hideKernelThreads && Process_isKernelThread(proc)) || (hideUserlandThreads && Process_isUserlandThread(proc))); pl->totalTasks++; /* runningTasks is set in Machine_scanCPUTime() from /proc/stat */ @@ -1603,7 +1616,7 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, openat_arg_ void ProcessList_goThroughEntries(ProcessList* super) { LinuxProcessList* this = (LinuxProcessList*) super; - const Machine* host = super->host; + const Machine* host = super->super.host; const Settings* settings = host->settings; const LinuxMachine* lhost = (const LinuxMachine*) host; diff --git a/vendor/github.com/htop-dev/htop/linux/Platform.c b/vendor/github.com/htop-dev/htop/linux/Platform.c index 693044af16..33bd8ced48 100644 --- a/vendor/github.com/htop-dev/htop/linux/Platform.c +++ b/vendor/github.com/htop-dev/htop/linux/Platform.c @@ -164,7 +164,7 @@ static Htop_Reaction Platform_actionSetIOPriority(State* st) { const void* set = Action_pickFromVector(st, ioprioPanel, 20, true); if (set) { IOPriority ioprio2 = IOPriorityPanel_getIOPriority(ioprioPanel); - bool ok = MainPanel_foreachProcess(st->mainPanel, LinuxProcess_setIOPriority, (Arg) { .i = ioprio2 }, NULL); + bool ok = MainPanel_foreachRow(st->mainPanel, LinuxProcess_rowSetIOPriority, (Arg) { .i = ioprio2 }, NULL); if (!ok) { beep(); } @@ -179,7 +179,7 @@ static bool Platform_changeAutogroupPriority(MainPanel* panel, int delta) { return false; } bool anyTagged; - bool ok = MainPanel_foreachProcess(panel, LinuxProcess_changeAutogroupPriorityBy, (Arg) { .i = delta }, &anyTagged); + bool ok = MainPanel_foreachRow(panel, LinuxProcess_rowChangeAutogroupPriorityBy, (Arg) { .i = delta }, &anyTagged); if (!ok) beep(); return anyTagged; @@ -322,23 +322,26 @@ double Platform_setCPUValues(Meter* this, unsigned int cpu) { v[CPU_METER_KERNEL] = cpuData->systemPeriod / total * 100.0; v[CPU_METER_IRQ] = cpuData->irqPeriod / total * 100.0; v[CPU_METER_SOFTIRQ] = cpuData->softIrqPeriod / total * 100.0; + this->curItems = 5; + v[CPU_METER_STEAL] = cpuData->stealPeriod / total * 100.0; v[CPU_METER_GUEST] = cpuData->guestPeriod / total * 100.0; - v[CPU_METER_IOWAIT] = cpuData->ioWaitPeriod / total * 100.0; - this->curItems = 8; - percent = v[CPU_METER_NICE] + v[CPU_METER_NORMAL] + v[CPU_METER_KERNEL] + v[CPU_METER_IRQ] + v[CPU_METER_SOFTIRQ]; if (settings->accountGuestInCPUMeter) { - percent += v[CPU_METER_STEAL] + v[CPU_METER_GUEST]; + this->curItems = 7; } + + v[CPU_METER_IOWAIT] = cpuData->ioWaitPeriod / total * 100.0; } else { v[CPU_METER_KERNEL] = cpuData->systemAllPeriod / total * 100.0; v[CPU_METER_IRQ] = (cpuData->stealPeriod + cpuData->guestPeriod) / total * 100.0; this->curItems = 4; - percent = v[CPU_METER_NICE] + v[CPU_METER_NORMAL] + v[CPU_METER_KERNEL] + v[CPU_METER_IRQ]; } - percent = CLAMP(percent, 0.0, 100.0); - if (isnan(percent)) { - percent = 0.0; + + percent = sumPositiveValues(v, this->curItems); + percent = MINIMUM(percent, 100.0); + + if (settings->detailedCPUTime) { + this->curItems = 8; } v[CPU_METER_FREQUENCY] = cpuData->frequency; @@ -415,7 +418,7 @@ void Platform_setZramValues(Meter* this) { this->total = lhost->zram.totalZram; this->values[ZRAM_METER_COMPRESSED] = lhost->zram.usedZramComp; - this->values[ZRAM_METER_UNCOMPRESSED] = lhost->zram.usedZramOrig; + this->values[ZRAM_METER_UNCOMPRESSED] = lhost->zram.usedZramOrig - lhost->zram.usedZramComp; } void Platform_setZfsArcValues(Meter* this) { @@ -842,7 +845,7 @@ static void Platform_Battery_getSysData(double* percent, ACPresence* isOnAC) { } } - if (!now && full && !isnan(capacityLevel)) + if (!now && full && isNonnegative(capacityLevel)) totalRemain += capacityLevel * fullCharge; } else if (type == AC) { @@ -882,12 +885,12 @@ void Platform_getBattery(double* percent, ACPresence* isOnAC) { if (Platform_Battery_method == BAT_PROC) { Platform_Battery_getProcData(percent, isOnAC); - if (isnan(*percent)) + if (!isNonnegative(*percent)) Platform_Battery_method = BAT_SYS; } if (Platform_Battery_method == BAT_SYS) { Platform_Battery_getSysData(percent, isOnAC); - if (isnan(*percent)) + if (!isNonnegative(*percent)) Platform_Battery_method = BAT_ERR; } if (Platform_Battery_method == BAT_ERR) { @@ -1067,7 +1070,7 @@ bool Platform_init(void) { char lineBuffer[256]; while (fgets(lineBuffer, sizeof(lineBuffer), fd)) { // detect lxc or overlayfs and guess that this means we are running containerized - if (String_startsWith(lineBuffer, "lxcfs /proc") || String_startsWith(lineBuffer, "overlay ")) { + if (String_startsWith(lineBuffer, "lxcfs /proc") || String_startsWith(lineBuffer, "overlay / overlay")) { Running_containerized = true; break; } diff --git a/vendor/github.com/htop-dev/htop/linux/Platform.h b/vendor/github.com/htop-dev/htop/linux/Platform.h index 1621d56280..a64e54a78c 100644 --- a/vendor/github.com/htop-dev/htop/linux/Platform.h +++ b/vendor/github.com/htop-dev/htop/linux/Platform.h @@ -132,7 +132,7 @@ static inline Hashtable* Platform_dynamicColumns(void) { static inline void Platform_dynamicColumnsDone(ATTR_UNUSED Hashtable* table) { } -static inline const char* Platform_dynamicColumnInit(ATTR_UNUSED unsigned int key) { +static inline const char* Platform_dynamicColumnName(ATTR_UNUSED unsigned int key) { return NULL; } @@ -140,4 +140,16 @@ static inline bool Platform_dynamicColumnWriteField(ATTR_UNUSED const Process* p return false; } +static inline Hashtable* Platform_dynamicScreens(void) { + return NULL; +} + +static inline void Platform_defaultDynamicScreens(ATTR_UNUSED Settings* settings) { } + +static inline void Platform_addDynamicScreen(ATTR_UNUSED ScreenSettings* ss) { } + +static inline void Platform_addDynamicScreenAvailableColumns(ATTR_UNUSED Panel* availableColumns, ATTR_UNUSED const char* screen) { } + +static inline void Platform_dynamicScreensDone(ATTR_UNUSED Hashtable* screens) { } + #endif diff --git a/vendor/github.com/htop-dev/htop/linux/ZramMeter.c b/vendor/github.com/htop-dev/htop/linux/ZramMeter.c index 6e80eb1a77..a1a98b34f6 100644 --- a/vendor/github.com/htop-dev/htop/linux/ZramMeter.c +++ b/vendor/github.com/htop-dev/htop/linux/ZramMeter.c @@ -27,7 +27,8 @@ static void ZramMeter_updateValues(Meter* this) { METER_BUFFER_APPEND_CHR(buffer, size, '('); - written = Meter_humanUnit(buffer, this->values[ZRAM_METER_UNCOMPRESSED], size); + double uncompressed = this->values[ZRAM_METER_COMPRESSED] + this->values[ZRAM_METER_UNCOMPRESSED]; + written = Meter_humanUnit(buffer, uncompressed, size); METER_BUFFER_CHECK(buffer, size, written); METER_BUFFER_APPEND_CHR(buffer, size, ')'); @@ -50,7 +51,8 @@ static void ZramMeter_display(const Object* cast, RichString* out) { RichString_appendAscii(out, CRT_colors[METER_TEXT], " used:"); RichString_appendAscii(out, CRT_colors[METER_VALUE], buffer); - Meter_humanUnit(buffer, this->values[ZRAM_METER_UNCOMPRESSED], sizeof(buffer)); + double uncompressed = this->values[ZRAM_METER_COMPRESSED] + this->values[ZRAM_METER_UNCOMPRESSED]; + Meter_humanUnit(buffer, uncompressed, sizeof(buffer)); RichString_appendAscii(out, CRT_colors[METER_TEXT], " uncompressed:"); RichString_appendAscii(out, CRT_colors[METER_VALUE], buffer); } @@ -64,7 +66,6 @@ const MeterClass ZramMeter_class = { .updateValues = ZramMeter_updateValues, .defaultMode = BAR_METERMODE, .maxItems = ZRAM_METER_ITEMCOUNT, - .comprisedValues = true, .total = 100.0, .attributes = ZramMeter_attributes, .name = "Zram", diff --git a/vendor/github.com/htop-dev/htop/netbsd/NetBSDProcess.c b/vendor/github.com/htop-dev/htop/netbsd/NetBSDProcess.c index bdb0f50c05..605b56c808 100644 --- a/vendor/github.com/htop-dev/htop/netbsd/NetBSDProcess.c +++ b/vendor/github.com/htop-dev/htop/netbsd/NetBSDProcess.c @@ -225,7 +225,8 @@ void Process_delete(Object* cast) { free(this); } -static void NetBSDProcess_writeField(const Process* this, RichString* str, ProcessField field) { +static void NetBSDProcess_rowWriteField(const Row* super, RichString* str, ProcessField field) { + const Process* this = (const Process*) super; char buffer[256]; buffer[255] = '\0'; int attr = CRT_colors[DEFAULT_COLOR]; @@ -254,11 +255,18 @@ static int NetBSDProcess_compareByKey(const Process* v1, const Process* v2, Proc const ProcessClass NetBSDProcess_class = { .super = { - .extends = Class(Process), - .display = Process_display, - .delete = Process_delete, - .compare = Process_compare + .super = { + .extends = Class(Process), + .display = Row_display, + .delete = Process_delete, + .compare = Process_compare + }, + .isHighlighted = Process_rowIsHighlighted, + .isVisible = Process_rowIsVisible, + .matchesFilter = Process_rowMatchesFilter, + .compareByParent = Process_compareByParent, + .sortKeyString = Process_rowGetSortKey, + .writeField = NetBSDProcess_rowWriteField }, - .writeField = NetBSDProcess_writeField, .compareByKey = NetBSDProcess_compareByKey }; diff --git a/vendor/github.com/htop-dev/htop/netbsd/NetBSDProcessList.c b/vendor/github.com/htop-dev/htop/netbsd/NetBSDProcessList.c index 9e5a9be4d8..1327de7060 100644 --- a/vendor/github.com/htop-dev/htop/netbsd/NetBSDProcessList.c +++ b/vendor/github.com/htop-dev/htop/netbsd/NetBSDProcessList.c @@ -37,17 +37,18 @@ in the source distribution for its full text. ProcessList* ProcessList_new(Machine* host, Hashtable* pidMatchList) { NetBSDProcessList* this = xCalloc(1, sizeof(NetBSDProcessList)); - ProcessList* super = (ProcessList*) this; + Object_setClass(this, Class(ProcessList)); + ProcessList* super = (ProcessList*) this; ProcessList_init(super, Class(NetBSDProcess), host, pidMatchList); return super; } -void ProcessList_delete(ProcessList* this) { - NetBSDProcessList* npl = (NetBSDProcessList*) this; - ProcessList_done(this); - free(npl); +void ProcessList_delete(Object* cast) { + NetBSDProcessList* this = (NetBSDProcessList*) cast; + ProcessList_done(&this->super); + free(this); } static void NetBSDProcessList_updateExe(const struct kinfo_proc2* kproc, Process* proc) { @@ -163,17 +164,17 @@ static void NetBSDProcessList_scanProcs(NetBSDProcessList* this) { bool preExisting = false; Process* proc = ProcessList_getProcess(&this->super, kproc->p_pid, &preExisting, NetBSDProcess_new); - proc->show = ! ((hideKernelThreads && Process_isKernelThread(proc)) || (hideUserlandThreads && Process_isUserlandThread(proc))); + proc->super.show = ! ((hideKernelThreads && Process_isKernelThread(proc)) || (hideUserlandThreads && Process_isUserlandThread(proc))); if (!preExisting) { - proc->pid = kproc->p_pid; - proc->ppid = kproc->p_ppid; + Process_setPid(proc, kproc->p_pid); + Process_setParent(proc, kproc->p_ppid); + Process_setThreadGroup(proc, kproc->p_pid); proc->tpgid = kproc->p_tpgid; - proc->tgid = kproc->p_pid; proc->session = kproc->p_sid; proc->pgrp = kproc->p__pgid; proc->isKernelThread = !!(kproc->p_flag & P_SYSTEM); - proc->isUserlandThread = proc->pid != proc->tgid; + proc->isUserlandThread = Process_getPid(proc) != Process_getThreadGroup(proc); // eh? proc->starttime_ctime = kproc->p_ustart_sec; Process_fillStarttimeBuffer(proc); ProcessList_add(&this->super, proc); @@ -261,7 +262,7 @@ static void NetBSDProcessList_scanProcs(NetBSDProcessList* this) { if (proc->state == RUNNING) { this->super.runningTasks++; } - proc->updated = true; + proc->super.updated = true; } } diff --git a/vendor/github.com/htop-dev/htop/netbsd/Platform.h b/vendor/github.com/htop-dev/htop/netbsd/Platform.h index a75c766cfb..ae34198cc2 100644 --- a/vendor/github.com/htop-dev/htop/netbsd/Platform.h +++ b/vendor/github.com/htop-dev/htop/netbsd/Platform.h @@ -115,7 +115,7 @@ static inline Hashtable* Platform_dynamicColumns(void) { static inline void Platform_dynamicColumnsDone(ATTR_UNUSED Hashtable* table) { } -static inline const char* Platform_dynamicColumnInit(ATTR_UNUSED unsigned int key) { +static inline const char* Platform_dynamicColumnName(ATTR_UNUSED unsigned int key) { return NULL; } @@ -123,4 +123,16 @@ static inline bool Platform_dynamicColumnWriteField(ATTR_UNUSED const Process* p return false; } +static inline Hashtable* Platform_dynamicScreens(void) { + return NULL; +} + +static inline void Platform_defaultDynamicScreens(ATTR_UNUSED Settings* settings) { } + +static inline void Platform_addDynamicScreen(ATTR_UNUSED ScreenSettings* ss) { } + +static inline void Platform_addDynamicScreenAvailableColumns(ATTR_UNUSED Panel* availableColumns, ATTR_UNUSED const char* screen) { } + +static inline void Platform_dynamicScreensDone(ATTR_UNUSED Hashtable* screens) { } + #endif diff --git a/vendor/github.com/htop-dev/htop/openbsd/OpenBSDMachine.c b/vendor/github.com/htop-dev/htop/openbsd/OpenBSDMachine.c index e3e30990be..177e7d2900 100644 --- a/vendor/github.com/htop-dev/htop/openbsd/OpenBSDMachine.c +++ b/vendor/github.com/htop-dev/htop/openbsd/OpenBSDMachine.c @@ -129,7 +129,7 @@ void Machine_delete(Machine* super) { } static void OpenBSDMachine_scanMemoryInfo(OpenBSDMachine* this) { - Machine* host = &this->super; + Machine* super = &this->super; const int uvmexp_mib[] = { CTL_VM, VM_UVMEXP }; struct uvmexp uvmexp; size_t size_uvmexp = sizeof(uvmexp); @@ -163,7 +163,7 @@ static void OpenBSDMachine_scanMemoryInfo(OpenBSDMachine* this) { */ int nswap = swapctl(SWAP_NSWAP, 0, 0); if (nswap > 0) { - struct swapent swdev[nswap]; + struct swapent* swdev = xMallocArray(nswap, sizeof(struct swapent)); int rnswap = swapctl(SWAP_STATS, swdev, nswap); /* Total things up */ @@ -177,6 +177,8 @@ static void OpenBSDMachine_scanMemoryInfo(OpenBSDMachine* this) { super->totalSwap = total; super->usedSwap = used; + + free(swdev); } else { super->totalSwap = super->usedSwap = 0; } @@ -228,7 +230,7 @@ static void kernelCPUTimesToHtop(const u_int64_t* times, CPUData* cpu) { } static void OpenBSDMachine_scanCPUTime(OpenBSDMachine* this) { - Machine* host = &this->super; + Machine* super = &this->super; u_int64_t kernelTimes[CPUSTATES] = {0}; u_int64_t avg[CPUSTATES] = {0}; diff --git a/vendor/github.com/htop-dev/htop/openbsd/OpenBSDProcess.c b/vendor/github.com/htop-dev/htop/openbsd/OpenBSDProcess.c index 0875dc00f1..c54a1763bd 100644 --- a/vendor/github.com/htop-dev/htop/openbsd/OpenBSDProcess.c +++ b/vendor/github.com/htop-dev/htop/openbsd/OpenBSDProcess.c @@ -217,8 +217,9 @@ void Process_delete(Object* cast) { free(this); } -static void OpenBSDProcess_writeField(const Process* this, RichString* str, ProcessField field) { - //const OpenBSDProcess* op = (const OpenBSDProcess*) this; +static void OpenBSDProcess_rowWriteField(const Row* super, RichString* str, ProcessField field) { + //const OpenBSDProcess* op = (const OpenBSDProcess*) super; + const Process* this = (const Process*) super; char buffer[256]; buffer[255] = '\0'; int attr = CRT_colors[DEFAULT_COLOR]; //int n = sizeof(buffer) - 1; @@ -247,11 +248,18 @@ static int OpenBSDProcess_compareByKey(const Process* v1, const Process* v2, Pro const ProcessClass OpenBSDProcess_class = { .super = { - .extends = Class(Process), - .display = Process_display, - .delete = Process_delete, - .compare = Process_compare + .super = { + .extends = Class(Process), + .display = Row_display, + .delete = Process_delete, + .compare = Process_compare + }, + .isHighlighted = Process_rowIsHighlighted, + .isVisible = Process_rowIsVisible, + .matchesFilter = Process_rowMatchesFilter, + .compareByParent = Process_compareByParent, + .sortKeyString = Process_rowGetSortKey, + .writeField = OpenBSDProcess_rowWriteField }, - .writeField = OpenBSDProcess_writeField, .compareByKey = OpenBSDProcess_compareByKey }; diff --git a/vendor/github.com/htop-dev/htop/openbsd/OpenBSDProcessList.c b/vendor/github.com/htop-dev/htop/openbsd/OpenBSDProcessList.c index 84c833c3c6..1706639727 100644 --- a/vendor/github.com/htop-dev/htop/openbsd/OpenBSDProcessList.c +++ b/vendor/github.com/htop-dev/htop/openbsd/OpenBSDProcessList.c @@ -34,17 +34,17 @@ in the source distribution for its full text. ProcessList* ProcessList_new(Machine* host, Hashtable* pidMatchList) { OpenBSDProcessList* this = xCalloc(1, sizeof(OpenBSDProcessList)); - ProcessList* super = (ProcessList*) this; + Object_setClass(this, Class(ProcessList)); + ProcessList* super = &this->super; ProcessList_init(super, Class(OpenBSDProcess), host, pidMatchList); return this; } -void ProcessList_delete(ProcessList* super) { +void ProcessList_delete(Object* cast) { OpenBSDProcessList* this = (OpenBSDProcessList*) super; - - ProcessList_done(super); + ProcessList_done(&this->super); free(this); } @@ -156,9 +156,9 @@ static void OpenBSDProcessList_scanProcs(OpenBSDProcessList* this) { OpenBSDProcess* op = (OpenBSDProcess*) proc; if (!preExisting) { - proc->ppid = kproc->p_ppid; + Process_setParent(proc, kproc->p_ppid); + Process_setThreadGroup(proc, kproc->p_pid); proc->tpgid = kproc->p_tpgid; - proc->tgid = kproc->p_pid; proc->session = kproc->p_sid; proc->pgrp = kproc->p__pgid; proc->isKernelThread = proc->pgrp == 0; @@ -231,8 +231,8 @@ static void OpenBSDProcessList_scanProcs(OpenBSDProcessList* this) { this->super.runningTasks++; } - proc->show = ! ((hideKernelThreads && Process_isKernelThread(proc)) || (hideUserlandThreads && Process_isUserlandThread(proc))); - proc->updated = true; + proc->super.show = ! ((hideKernelThreads && Process_isKernelThread(proc)) || (hideUserlandThreads && Process_isUserlandThread(proc))); + proc->super.updated = true; } } diff --git a/vendor/github.com/htop-dev/htop/openbsd/Platform.h b/vendor/github.com/htop-dev/htop/openbsd/Platform.h index f357006cc6..790dc47359 100644 --- a/vendor/github.com/htop-dev/htop/openbsd/Platform.h +++ b/vendor/github.com/htop-dev/htop/openbsd/Platform.h @@ -109,7 +109,7 @@ static inline Hashtable* Platform_dynamicColumns(void) { static inline void Platform_dynamicColumnsDone(ATTR_UNUSED Hashtable* table) { } -static inline const char* Platform_dynamicColumnInit(ATTR_UNUSED unsigned int key) { +static inline const char* Platform_dynamicColumnName(ATTR_UNUSED unsigned int key) { return NULL; } @@ -117,4 +117,16 @@ static inline bool Platform_dynamicColumnWriteField(ATTR_UNUSED const Process* p return false; } +static inline Hashtable* Platform_dynamicScreens(void) { + return NULL; +} + +static inline void Platform_defaultDynamicScreens(ATTR_UNUSED Settings* settings) { } + +static inline void Platform_addDynamicScreen(ATTR_UNUSED ScreenSettings* ss) { } + +static inline void Platform_addDynamicScreenAvailableColumns(ATTR_UNUSED Panel* availableColumns, ATTR_UNUSED const char* screen) { } + +static inline void Platform_dynamicScreensDone(ATTR_UNUSED Hashtable* screens) { } + #endif diff --git a/vendor/github.com/htop-dev/htop/pcp/InDomTable.c b/vendor/github.com/htop-dev/htop/pcp/InDomTable.c new file mode 100644 index 0000000000..b96f8a81e7 --- /dev/null +++ b/vendor/github.com/htop-dev/htop/pcp/InDomTable.c @@ -0,0 +1,97 @@ +/* +htop - InDomTable.c +(C) 2023 htop dev team +(C) 2022-2023 Sohaib Mohammed +Released under the GNU GPLv2+, see the COPYING file +in the source distribution for its full text. +*/ + +#include "InDomTable.h" + +#include +#include +#include + +#include "CRT.h" +#include "DynamicColumn.h" +#include "Hashtable.h" +#include "Macros.h" +#include "Platform.h" +#include "Table.h" +#include "Vector.h" +#include "XUtils.h" + +#include "pcp/Instance.h" +#include "pcp/Metric.h" +#include "pcp/PCPDynamicColumn.h" + + +InDomTable* InDomTable_new(Machine* host, pmInDom indom, int metricKey) { + InDomTable* this = xCalloc(1, sizeof(InDomTable)); + Object_setClass(this, Class(InDomTable)); + this->metricKey = metricKey; + this->id = indom; + + Table* super = &this->super; + Table_init(super, Class(Row), host); + + return this; +} + +void InDomTable_done(InDomTable* this) { + Table_done(&this->super); +} + +static void InDomTable_delete(Object* cast) { + InDomTable* this = (InDomTable*) cast; + InDomTable_done(this); + free(this); +} + +static Instance* InDomTable_getInstance(InDomTable* this, int id, bool* preExisting) { + const Table* super = &this->super; + Instance* inst = (Instance*) Hashtable_get(super->table, id); + *preExisting = inst != NULL; + if (inst) { + assert(Vector_indexOf(super->rows, inst, Row_idEqualCompare) != -1); + assert(Instance_getId(inst) == id); + } else { + inst = Instance_new(super->host, this); + assert(inst->name == NULL); + Instance_setId(inst, id); + } + return inst; +} + +static void InDomTable_goThroughEntries(InDomTable* this) { + Table* super = &this->super; + + /* for every instance ... */ + int instid = -1, offset = -1; + while (Metric_iterate(this->metricKey, &instid, &offset)) { + bool preExisting; + Instance* inst = InDomTable_getInstance(this, instid, &preExisting); + inst->offset = offset >= 0 ? offset : 0; + + Row* row = &inst->super; + if (!preExisting) + Table_add(super, row); + row->updated = true; + row->show = true; + } +} + +static void InDomTable_iterateEntries(Table* super) { + InDomTable* this = (InDomTable*) super; + InDomTable_goThroughEntries(this); +} + +const TableClass InDomTable_class = { + .super = { + .extends = Class(Table), + .delete = InDomTable_delete, + }, + .prepare = Table_prepareEntries, + .iterate = InDomTable_iterateEntries, + .cleanup = Table_cleanupEntries, +}; diff --git a/vendor/github.com/htop-dev/htop/pcp/InDomTable.h b/vendor/github.com/htop-dev/htop/pcp/InDomTable.h new file mode 100644 index 0000000000..7d848d572e --- /dev/null +++ b/vendor/github.com/htop-dev/htop/pcp/InDomTable.h @@ -0,0 +1,36 @@ +#ifndef HEADER_InDomTable +#define HEADER_InDomTable +/* +htop - InDomTable.h +(C) 2023 htop dev team +(C) 2022-2023 Sohaib Mohammed +Released under the GNU GPLv2+, see the COPYING file +in the source distribution for its full text. +*/ + +#include "config.h" // IWYU pragma: keep + +#include +#include + +#include "Platform.h" +#include "Table.h" + + +typedef struct InDomTable_ { + Table super; + pmInDom id; /* shared by metrics in the table */ + unsigned int metricKey; /* representative metric using this indom */ +} InDomTable; + +extern const TableClass InDomTable_class; + +InDomTable* InDomTable_new(Machine* host, pmInDom indom, int metricKey); + +void InDomTable_done(InDomTable* this); + +RowField RowField_keyAt(const Settings* settings, int at); + +void InDomTable_scan(Table* super); + +#endif diff --git a/vendor/github.com/htop-dev/htop/pcp/Instance.c b/vendor/github.com/htop-dev/htop/pcp/Instance.c new file mode 100644 index 0000000000..e70e7b7030 --- /dev/null +++ b/vendor/github.com/htop-dev/htop/pcp/Instance.c @@ -0,0 +1,160 @@ +/* +htop - Instance.c +(C) 2022-2023 Sohaib Mohammed +(C) 2022-2023 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 + +#include "pcp/Instance.h" + +#include +#include + +#include "CRT.h" +#include "DynamicColumn.h" +#include "DynamicScreen.h" +#include "Hashtable.h" +#include "Machine.h" +#include "Macros.h" +#include "Metric.h" +#include "Platform.h" +#include "PCPDynamicColumn.h" +#include "PCPDynamicScreen.h" +#include "Row.h" +#include "RichString.h" +#include "XUtils.h" + +#include "pcp/InDomTable.h" +#include "pcp/Metric.h" + + +Instance* Instance_new(const Machine* host, const InDomTable* indom) { + Instance* this = xCalloc(1, sizeof(Instance)); + Object_setClass(this, Class(Instance)); + + Row* super = &this->super; + Row_init(super, host); + + this->indom = indom; + + return this; +} + +void Instance_done(Instance* this) { + if (this->name) + free(this->name); + Row_done(&this->super); +} + +static void Instance_delete(Object* cast) { + Instance* this = (Instance*) cast; + Instance_done(this); + free(this); +} + +static void Instance_writeField(const Row* super, RichString* str, RowField field) { + const Instance* this = (const Instance*) super; + int instid = Instance_getId(this); + + const Settings* settings = super->host->settings; + DynamicColumn* column = Hashtable_get(settings->dynamicColumns, field); + PCPDynamicColumn* cp = (PCPDynamicColumn*) column; + const pmDesc* descp = Metric_desc(cp->id); + + pmAtomValue atom; + pmAtomValue *ap = &atom; + if (!Metric_instance(cp->id, instid, this->offset, ap, descp->type)) + ap = NULL; + + PCPDynamicColumn_writeAtomValue(cp, str, settings, cp->id, instid, descp, ap); + + if (ap && descp->type == PM_TYPE_STRING) + free(ap->cp); +} + +static const char* Instance_externalName(Row* super) { + Instance* this = (Instance*) super; + + if (!this->name) + pmNameInDom(InDom_getId(this), Instance_getId(this), &this->name); + return this->name; +} + +static int Instance_compareByKey(const Row* v1, const Row* v2, int key) { + const Instance* i1 = (const Instance*)v1; + const Instance* i2 = (const Instance*)v2; + + if (key < 0) + return 0; + + Hashtable* dc = Platform_dynamicColumns(); + const PCPDynamicColumn* column = Hashtable_get(dc, key); + if (!column) + return -1; + + size_t metric = column->id; + unsigned int type = Metric_type(metric); + + pmAtomValue atom1 = {0}, atom2 = {0}; + if (!Metric_instance(metric, i1->offset, i1->offset, &atom1, type) || + !Metric_instance(metric, i2->offset, i2->offset, &atom2, type)) { + if (type == PM_TYPE_STRING) { + free(atom1.cp); + free(atom2.cp); + } + return -1; + } + + switch (type) { + case PM_TYPE_STRING: { + int cmp = SPACESHIP_NULLSTR(atom2.cp, atom1.cp); + free(atom2.cp); + free(atom1.cp); + return cmp; + } + case PM_TYPE_32: + return SPACESHIP_NUMBER(atom2.l, atom1.l); + case PM_TYPE_U32: + return SPACESHIP_NUMBER(atom2.ul, atom1.ul); + case PM_TYPE_64: + return SPACESHIP_NUMBER(atom2.ll, atom1.ll); + case PM_TYPE_U64: + return SPACESHIP_NUMBER(atom2.ull, atom1.ull); + case PM_TYPE_FLOAT: + return SPACESHIP_NUMBER(atom2.f, atom1.f); + case PM_TYPE_DOUBLE: + return SPACESHIP_NUMBER(atom2.d, atom1.d); + default: + break; + } + + return 0; +} + +static int Instance_compare(const void* v1, const void* v2) { + const Instance* i1 = (const Instance*)v1; + const Instance* i2 = (const Instance*)v2; + const ScreenSettings* ss = i1->super.host->settings->ss; + RowField key = ScreenSettings_getActiveSortKey(ss); + int result = Instance_compareByKey(v1, v2, key); + + // Implement tie-breaker (needed to make tree mode more stable) + if (!result) + return SPACESHIP_NUMBER(Instance_getId(i1), Instance_getId(i2)); + + return (ScreenSettings_getActiveDirection(ss) == 1) ? result : -result; +} + +const RowClass Instance_class = { + .super = { + .extends = Class(Row), + .display = Row_display, + .delete = Instance_delete, + .compare = Instance_compare, + }, + .sortKeyString = Instance_externalName, + .writeField = Instance_writeField, +}; diff --git a/vendor/github.com/htop-dev/htop/pcp/Instance.h b/vendor/github.com/htop-dev/htop/pcp/Instance.h new file mode 100644 index 0000000000..c7d688fcb1 --- /dev/null +++ b/vendor/github.com/htop-dev/htop/pcp/Instance.h @@ -0,0 +1,37 @@ +#ifndef HEADER_Instance +#define HEADER_Instance +/* +htop - Instance.h +(C) 2022-2023 htop dev team +(C) 2022-2023 Sohaib Mohammed +Released under the GNU GPLv2+, see the COPYING file +in the source distribution for its full text. +*/ + +#include "Hashtable.h" +#include "Object.h" +#include "Platform.h" +#include "Row.h" + + +typedef struct Instance_ { + Row super; + + char *name; /* external instance name */ + const struct InDomTable_* indom; /* instance domain */ + + /* default result offset to use for searching metrics with instances */ + unsigned int offset; +} Instance; + +#define InDom_getId(i_) ((i_)->indom->id) +#define Instance_getId(i_) ((i_)->super.id) +#define Instance_setId(i_, id_) ((i_)->super.id = (id_)) + +extern const RowClass Instance_class; + +Instance* Instance_new(const Machine* host, const struct InDomTable_* indom); + +void Instance_done(Instance* this); + +#endif diff --git a/vendor/github.com/htop-dev/htop/pcp/PCPMetric.c b/vendor/github.com/htop-dev/htop/pcp/Metric.c similarity index 75% rename from vendor/github.com/htop-dev/htop/pcp/PCPMetric.c rename to vendor/github.com/htop-dev/htop/pcp/Metric.c index 606a5df06f..ce6d90d000 100644 --- a/vendor/github.com/htop-dev/htop/pcp/PCPMetric.c +++ b/vendor/github.com/htop-dev/htop/pcp/Metric.c @@ -1,5 +1,5 @@ /* -htop - PCPMetric.c +htop - Metric.c (C) 2020-2021 htop dev team (C) 2020-2021 Red Hat, Inc. Released under the GNU GPLv2+, see the COPYING file @@ -8,8 +8,9 @@ in the source distribution for its full text. #include "config.h" // IWYU pragma: keep -#include "pcp/PCPMetric.h" +#include "pcp/Metric.h" +#include #include #include #include @@ -21,15 +22,15 @@ in the source distribution for its full text. extern Platform* pcp; -const pmDesc* PCPMetric_desc(PCPMetric metric) { +const pmDesc* Metric_desc(Metric metric) { return &pcp->descs[metric]; } -int PCPMetric_type(PCPMetric metric) { +int Metric_type(Metric metric) { return pcp->descs[metric].type; } -pmAtomValue* PCPMetric_values(PCPMetric metric, pmAtomValue* atom, int count, int type) { +pmAtomValue* Metric_values(Metric metric, pmAtomValue* atom, int count, int type) { if (pcp->result == NULL) return NULL; @@ -54,14 +55,14 @@ pmAtomValue* PCPMetric_values(PCPMetric metric, pmAtomValue* atom, int count, in return atom; } -int PCPMetric_instanceCount(PCPMetric metric) { +int Metric_instanceCount(Metric metric) { pmValueSet* vset = pcp->result->vset[metric]; if (vset) return vset->numval; return 0; } -int PCPMetric_instanceOffset(PCPMetric metric, int inst) { +int Metric_instanceOffset(Metric metric, int inst) { pmValueSet* vset = pcp->result->vset[metric]; if (!vset || vset->numval <= 0) return 0; @@ -74,7 +75,7 @@ int PCPMetric_instanceOffset(PCPMetric metric, int inst) { return 0; } -static pmAtomValue* PCPMetric_extract(PCPMetric metric, int inst, int offset, pmValueSet* vset, pmAtomValue* atom, int type) { +static pmAtomValue* Metric_extract(Metric metric, int inst, int offset, pmValueSet* vset, pmAtomValue* atom, int type) { /* extract value (using requested type) of given metric instance */ const pmDesc* desc = &pcp->descs[metric]; @@ -89,7 +90,7 @@ static pmAtomValue* PCPMetric_extract(PCPMetric metric, int inst, int offset, pm return atom; } -pmAtomValue* PCPMetric_instance(PCPMetric metric, int inst, int offset, pmAtomValue* atom, int type) { +pmAtomValue* Metric_instance(Metric metric, int inst, int offset, pmAtomValue* atom, int type) { pmValueSet* vset = pcp->result->vset[metric]; if (!vset || vset->numval <= 0) @@ -97,12 +98,12 @@ pmAtomValue* PCPMetric_instance(PCPMetric metric, int inst, int offset, pmAtomVa /* fast-path using heuristic offset based on expected location */ if (offset >= 0 && offset < vset->numval && inst == vset->vlist[offset].inst) - return PCPMetric_extract(metric, inst, offset, vset, atom, type); + return Metric_extract(metric, inst, offset, vset, atom, type); /* slow-path using a linear search for the requested instance */ for (int i = 0; i < vset->numval; i++) { if (inst == vset->vlist[i].inst) - return PCPMetric_extract(metric, inst, i, vset, atom, type); + return Metric_extract(metric, inst, i, vset, atom, type); } return NULL; } @@ -113,7 +114,7 @@ pmAtomValue* PCPMetric_instance(PCPMetric metric, int inst, int offset, pmAtomVa * * Start it off by passing offset -1 into the routine. */ -bool PCPMetric_iterate(PCPMetric metric, int* instp, int* offsetp) { +bool Metric_iterate(Metric metric, int* instp, int* offsetp) { if (!pcp->result) return false; @@ -132,15 +133,15 @@ bool PCPMetric_iterate(PCPMetric metric, int* instp, int* offsetp) { } /* Switch on/off a metric for value fetching (sampling) */ -void PCPMetric_enable(PCPMetric metric, bool enable) { +void Metric_enable(Metric metric, bool enable) { pcp->fetch[metric] = enable ? pcp->pmids[metric] : PM_ID_NULL; } -bool PCPMetric_enabled(PCPMetric metric) { +bool Metric_enabled(Metric metric) { return pcp->fetch[metric] != PM_ID_NULL; } -void PCPMetric_enableThreads(void) { +void Metric_enableThreads(void) { pmValueSet* vset = xCalloc(1, sizeof(pmValueSet)); vset->vlist[0].inst = PM_IN_NULL; vset->vlist[0].value.lval = 1; @@ -159,7 +160,7 @@ void PCPMetric_enableThreads(void) { pmFreeResult(result); } -bool PCPMetric_fetch(struct timeval* timestamp) { +bool Metric_fetch(struct timeval* timestamp) { if (pcp->result) { pmFreeResult(pcp->result); pcp->result = NULL; @@ -178,3 +179,21 @@ bool PCPMetric_fetch(struct timeval* timestamp) { *timestamp = pcp->result->timestamp; return true; } + +void Metric_externalName(Metric metric, int inst, char** externalName) { + const pmDesc* desc = &pcp->descs[metric]; + pmNameInDom(desc->indom, inst, externalName); +} + +int Metric_lookupText(const char* metric, char** desc) { + pmID pmid; + int sts; + + sts = pmLookupName(1, &metric, &pmid); + if (sts < 0) + return sts; + + if (pmLookupText(pmid, PM_TEXT_ONELINE, desc) >= 0) + (*desc)[0] = toupper((*desc)[0]); /* UI consistency */ + return 0; +} diff --git a/vendor/github.com/htop-dev/htop/pcp/PCPMetric.h b/vendor/github.com/htop-dev/htop/pcp/Metric.h similarity index 90% rename from vendor/github.com/htop-dev/htop/pcp/PCPMetric.h rename to vendor/github.com/htop-dev/htop/pcp/Metric.h index e89a0a4c77..789ef4b247 100644 --- a/vendor/github.com/htop-dev/htop/pcp/PCPMetric.h +++ b/vendor/github.com/htop-dev/htop/pcp/Metric.h @@ -1,7 +1,7 @@ -#ifndef HEADER_PCPMetric -#define HEADER_PCPMetric +#ifndef HEADER_Metric +#define HEADER_Metric /* -htop - PCPMetric.h +htop - Metric.h (C) 2020-2021 htop dev team (C) 2020-2021 Red Hat, Inc. Released under the GNU GPLv2+, see the COPYING file @@ -22,7 +22,7 @@ in the source distribution for its full text. #undef PACKAGE_BUGREPORT -typedef enum PCPMetric_ { +typedef enum Metric_ { PCP_CONTROL_THREADS, /* proc.control.perclient.threads */ PCP_HINV_NCPU, /* hinv.ncpu */ @@ -156,28 +156,32 @@ typedef enum PCPMetric_ { PCP_PROC_SMAPS_SWAPPSS, /* proc.smaps.swappss */ PCP_METRIC_COUNT /* total metric count */ -} PCPMetric; +} Metric; -void PCPMetric_enable(PCPMetric metric, bool enable); +void Metric_enable(Metric metric, bool enable); -bool PCPMetric_enabled(PCPMetric metric); +bool Metric_enabled(Metric metric); -void PCPMetric_enableThreads(void); +void Metric_enableThreads(void); -bool PCPMetric_fetch(struct timeval* timestamp); +bool Metric_fetch(struct timeval* timestamp); -bool PCPMetric_iterate(PCPMetric metric, int* instp, int* offsetp); +bool Metric_iterate(Metric metric, int* instp, int* offsetp); -pmAtomValue* PCPMetric_values(PCPMetric metric, pmAtomValue* atom, int count, int type); +pmAtomValue* Metric_values(Metric metric, pmAtomValue* atom, int count, int type); -const pmDesc* PCPMetric_desc(PCPMetric metric); +const pmDesc* Metric_desc(Metric metric); -int PCPMetric_type(PCPMetric metric); +int Metric_type(Metric metric); -int PCPMetric_instanceCount(PCPMetric metric); +int Metric_instanceCount(Metric metric); -int PCPMetric_instanceOffset(PCPMetric metric, int inst); +int Metric_instanceOffset(Metric metric, int inst); -pmAtomValue* PCPMetric_instance(PCPMetric metric, int inst, int offset, pmAtomValue* atom, int type); +pmAtomValue* Metric_instance(Metric metric, int inst, int offset, pmAtomValue* atom, int type); + +void Metric_externalName(Metric metric, int inst, char** externalName); + +int Metric_lookupText(const char* metric, char** desc); #endif diff --git a/vendor/github.com/htop-dev/htop/pcp/PCPDynamicColumn.c b/vendor/github.com/htop-dev/htop/pcp/PCPDynamicColumn.c index 23b896e6fa..02d3ab9c5d 100644 --- a/vendor/github.com/htop-dev/htop/pcp/PCPDynamicColumn.c +++ b/vendor/github.com/htop-dev/htop/pcp/PCPDynamicColumn.c @@ -1,8 +1,7 @@ /* htop - PCPDynamicColumn.c -(C) 2021 Sohaib Mohammed -(C) 2021 htop dev team -(C) 2021 Red Hat, Inc. +(C) 2021-2023 Sohaib Mohammed +(C) 2021-2023 htop dev team Released under the GNU GPLv2+, see the COPYING file in the source distribution for its full text. */ @@ -28,8 +27,9 @@ in the source distribution for its full text. #include "RichString.h" #include "XUtils.h" +#include "linux/CGroupUtils.h" +#include "pcp/Metric.h" #include "pcp/PCPProcess.h" -#include "pcp/PCPMetric.h" static bool PCPDynamicColumn_addMetric(PCPDynamicColumns* columns, PCPDynamicColumn* column) { @@ -49,6 +49,10 @@ static bool PCPDynamicColumn_addMetric(PCPDynamicColumns* columns, PCPDynamicCol } static void PCPDynamicColumn_parseMetric(PCPDynamicColumns* columns, PCPDynamicColumn* column, const char* path, unsigned int line, char* value) { + /* pmLookupText */ + if (!column->super.description) + Metric_lookupText(value, &column->super.description); + /* lookup a dynamic metric with this name, else create */ if (PCPDynamicColumn_addMetric(columns, column) == false) return; @@ -108,6 +112,10 @@ static bool PCPDynamicColumn_uniqueName(char* key, PCPDynamicColumns* columns) { static PCPDynamicColumn* PCPDynamicColumn_new(PCPDynamicColumns* columns, const char* name) { PCPDynamicColumn* column = xCalloc(1, sizeof(*column)); String_safeStrncpy(column->super.name, name, sizeof(column->super.name)); + column->super.enabled = false; + column->percent = false; + column->instances = false; + column->defaultEnabled = true; size_t id = columns->count + LAST_PROCESSFIELD; Hashtable_put(columns->table, id, column); @@ -160,6 +168,14 @@ static void PCPDynamicColumn_parseFile(PCPDynamicColumns* columns, const char* p free_and_xStrdup(&column->super.description, value); } else if (value && column && String_eq(key, "width")) { column->super.width = strtoul(value, NULL, 10); + } else if (value && column && String_eq(key, "format")) { + free_and_xStrdup(&column->format, value); + } else if (value && column && String_eq(key, "instances")) { + if (String_eq(value, "True") || String_eq(value, "true")) + column->instances = true; + } else if (value && column && (String_eq(key, "default") || String_eq(key, "enabled"))) { + if (String_eq(value, "False") || String_eq(value, "false")) + column->defaultEnabled = false; } else if (value && column && String_eq(key, "metric")) { PCPDynamicColumn_parseMetric(columns, column, path, lineno, value); } @@ -233,88 +249,238 @@ void PCPDynamicColumns_init(PCPDynamicColumns* columns) { free(path); } +void PCPDynamicColumn_done(PCPDynamicColumn* this) { + DynamicColumn_done(&this->super); + free(this->metricName); + free(this->format); +} + static void PCPDynamicColumns_free(ATTR_UNUSED ht_key_t key, void* value, ATTR_UNUSED void* data) { PCPDynamicColumn* column = (PCPDynamicColumn*) value; - free(column->metricName); - free(column->super.heading); - free(column->super.caption); - free(column->super.description); + PCPDynamicColumn_done(column); } void PCPDynamicColumns_done(Hashtable* table) { Hashtable_foreach(table, PCPDynamicColumns_free, NULL); } -void PCPDynamicColumn_writeField(PCPDynamicColumn* this, const Process* proc, RichString* str) { - const PCPProcess* pp = (const PCPProcess*) proc; - unsigned int type = PCPMetric_type(this->id); +static void PCPDynamicColumn_setupWidth(ATTR_UNUSED ht_key_t key, void* value, ATTR_UNUSED void* data) { + PCPDynamicColumn* column = (PCPDynamicColumn*) value; - pmAtomValue atom; - if (!PCPMetric_instance(this->id, proc->pid, pp->offset, &atom, type)) { - RichString_appendAscii(str, CRT_colors[METER_VALUE_ERROR], "no data"); + /* calculate column size based on config file and metric units */ + const pmDesc* desc = Metric_desc(column->id); + + if (column->instances || desc->type == PM_TYPE_STRING) { + column->super.width = column->width; + if (column->super.width == 0) + column->super.width = -16; return; } - int width = this->super.width; - if (!width || abs(width) > DYNAMIC_MAX_COLUMN_WIDTH) - width = DYNAMIC_DEFAULT_COLUMN_WIDTH; - int abswidth = abs(width); - if (abswidth > DYNAMIC_MAX_COLUMN_WIDTH) { - abswidth = DYNAMIC_MAX_COLUMN_WIDTH; - width = -abswidth; + if (column->format) { + if (strcmp(column->format, "percent") == 0) { + column->super.width = 5; + return; + } + if (strcmp(column->format, "process") == 0) { + column->super.width = Process_pidDigits; + return; + } } - char buffer[DYNAMIC_MAX_COLUMN_WIDTH + /* space */ 1 + /* null terminator */ + 1]; - int attr = CRT_colors[DEFAULT_COLOR]; + if (column->width) { + column->super.width = column->width; + return; + } + + pmUnits units = desc->units; + if (units.dimSpace && units.dimTime) + column->super.width = 11; // Row_printRate + else if (units.dimSpace) + column->super.width = 5; // Row_printBytes + else if (units.dimCount && units.dimTime) + column->super.width = 11; // Row_printCount + else if (units.dimTime) + column->super.width = 8; // Row_printTime + else + column->super.width = 11; // Row_printCount +} + +void PCPDynamicColumns_setupWidths(PCPDynamicColumns* columns) { + Hashtable_foreach(columns->table, PCPDynamicColumn_setupWidth, NULL); +} + +/* normalize output units to bytes and seconds */ +static int PCPDynamicColumn_normalize(const pmDesc* desc, const pmAtomValue* ap, double* value) { + /* form normalized units based on the original metric units */ + pmUnits units = desc->units; + if (units.dimTime) + units.scaleTime = PM_TIME_SEC; + if (units.dimSpace) + units.scaleSpace = PM_SPACE_BYTE; + if (units.dimCount) + units.scaleCount = PM_COUNT_ONE; + + pmAtomValue atom; + int sts, type = desc->type; + if ((sts = pmConvScale(type, ap, &desc->units, &atom, &units)) < 0) + return sts; + switch (type) { - case PM_TYPE_STRING: - attr = CRT_colors[PROCESS_SHADOW]; - Process_printLeftAlignedField(str, attr, atom.cp, abswidth); - free(atom.cp); - break; case PM_TYPE_32: - xSnprintf(buffer, sizeof(buffer), "%*d ", width, atom.l); - RichString_appendAscii(str, attr, buffer); + *value = (double) atom.l; break; case PM_TYPE_U32: - xSnprintf(buffer, sizeof(buffer), "%*u ", width, atom.ul); - RichString_appendAscii(str, attr, buffer); + *value = (double) atom.ul; break; case PM_TYPE_64: - xSnprintf(buffer, sizeof(buffer), "%*lld ", width, (long long) atom.ll); - RichString_appendAscii(str, attr, buffer); + *value = (double) atom.ll; break; case PM_TYPE_U64: - xSnprintf(buffer, sizeof(buffer), "%*llu ", width, (unsigned long long) atom.ull); - RichString_appendAscii(str, attr, buffer); + *value = (double) atom.ull; break; case PM_TYPE_FLOAT: - xSnprintf(buffer, sizeof(buffer), "%*.2f ", width, (double) atom.f); - RichString_appendAscii(str, attr, buffer); + *value = (double) atom.f; break; case PM_TYPE_DOUBLE: - xSnprintf(buffer, sizeof(buffer), "%*.2f ", width, atom.d); - RichString_appendAscii(str, attr, buffer); + *value = atom.d; break; default: - attr = CRT_colors[METER_VALUE_ERROR]; - RichString_appendAscii(str, attr, "no type"); - break; + return PM_ERR_CONV; + } + return 0; +} + +void PCPDynamicColumn_writeAtomValue(PCPDynamicColumn* column, RichString* str, const struct Settings_* settings, int metric, int instance, const pmDesc* desc, const void* atom) { + const pmAtomValue* atomvalue = (const pmAtomValue*) atom; + char buffer[DYNAMIC_MAX_COLUMN_WIDTH + /*space*/ 1 + /*null*/ 1]; + int attr = CRT_colors[DEFAULT_COLOR]; + int width = column->super.width; + int n; + + if (!width || abs(width) > DYNAMIC_MAX_COLUMN_WIDTH) + width = DYNAMIC_DEFAULT_COLUMN_WIDTH; + int abswidth = abs(width); + if (abswidth > DYNAMIC_MAX_COLUMN_WIDTH) { + abswidth = DYNAMIC_MAX_COLUMN_WIDTH; + width = -abswidth; + } + + if (atomvalue == NULL) { + n = xSnprintf(buffer, sizeof(buffer), "%*.*s ", width, abswidth, "N/A"); + RichString_appendnAscii(str, CRT_colors[PROCESS_SHADOW], buffer, n); + return; } + + /* deal with instance names and metrics with string values first */ + if (column->instances || desc->type == PM_TYPE_STRING) { + char* value = NULL; + char* dupd1 = NULL; + if (column->instances) { + attr = CRT_colors[DYNAMIC_GRAY]; + Metric_externalName(metric, instance, &dupd1); + value = dupd1; + } else { + attr = CRT_colors[DYNAMIC_GREEN]; + value = atomvalue->cp; + } + if (column->format && value) { + char* dupd2 = NULL; + if (strcmp(column->format, "command") == 0) + attr = CRT_colors[PROCESS_COMM]; + else if (strcmp(column->format, "process") == 0) + attr = CRT_colors[PROCESS_SHADOW]; + else if (strcmp(column->format, "device") == 0 && strncmp(value, "/dev/", 5) == 0) + value += 5; + else if (strcmp(column->format, "cgroup") == 0 && (dupd2 = CGroup_filterName(value))) + value = dupd2; + n = xSnprintf(buffer, sizeof(buffer), "%*.*s ", width, abswidth, value); + if (dupd2) + free(dupd2); + } else if (value) { + n = xSnprintf(buffer, sizeof(buffer), "%*.*s ", width, abswidth, value); + } else { + n = xSnprintf(buffer, sizeof(buffer), "%*.*s ", width, abswidth, "N/A"); + } + if (dupd1) + free(dupd1); + RichString_appendnAscii(str, attr, buffer, n); + return; + } + + /* deal with any numeric value - first, normalize units to bytes/seconds */ + double value; + if (PCPDynamicColumn_normalize(desc, atomvalue, &value) < 0) { + n = xSnprintf(buffer, sizeof(buffer), "%*.*s ", width, abswidth, "no conv"); + RichString_appendnAscii(str, CRT_colors[METER_VALUE_ERROR], buffer, n); + return; + } + + if (column->format) { + if (strcmp(column->format, "percent") == 0) { + n = Row_printPercentage(value, buffer, sizeof(buffer), width, &attr); + RichString_appendnAscii(str, attr, buffer, n); + return; + } + if (strcmp(column->format, "process") == 0) { + n = xSnprintf(buffer, sizeof(buffer), "%*d ", Row_pidDigits, (int)value); + RichString_appendnAscii(str, attr, buffer, n); + return; + } + } + + /* width overrides unit suffix and coloring; too complex for a corner case */ + if (column->width) { + if (value - (unsigned long long)value > 0) /* display floating point */ + n = xSnprintf(buffer, sizeof(buffer), "%*.2f ", width, value); + else /* display as integer */ + n = xSnprintf(buffer, sizeof(buffer), "%*llu ", width, (unsigned long long)value); + RichString_appendnAscii(str, CRT_colors[PROCESS], buffer, n); + return; + } + + bool coloring = settings->highlightMegabytes; + pmUnits units = desc->units; + if (units.dimSpace && units.dimTime) + Row_printRate(str, value, coloring); + else if (units.dimSpace) + Row_printBytes(str, value, coloring); + else if (units.dimCount) + Row_printCount(str, value, coloring); + else if (units.dimTime) + Row_printTime(str, value / 10 /* hundreds of a second */, coloring); + else + Row_printCount(str, value, 0); /* e.g. PID */ +} + +void PCPDynamicColumn_writeField(PCPDynamicColumn* this, const Process* proc, RichString* str) { + const Settings* settings = proc->super.host->settings; + const PCPProcess* pp = (const PCPProcess*) proc; + const pmDesc* desc = Metric_desc(this->id); + pid_t pid = Process_getPid(proc); + + pmAtomValue atom; + pmAtomValue *ap = &atom; + if (!Metric_instance(this->id, pid, pp->offset, ap, desc->type)) + ap = NULL; + + PCPDynamicColumn_writeAtomValue(this, str, settings, this->id, pid, desc, ap); } int PCPDynamicColumn_compareByKey(const PCPProcess* p1, const PCPProcess* p2, ProcessField key) { - const PCPDynamicColumn* column = Hashtable_get(p1->super.host->settings->dynamicColumns, key); + const Process* proc = &p1->super; + const Settings* settings = proc->super.host->settings; + const PCPDynamicColumn* column = Hashtable_get(settings->dynamicColumns, key); if (!column) return -1; size_t metric = column->id; - unsigned int type = PCPMetric_type(metric); + unsigned int type = Metric_type(metric); pmAtomValue atom1 = {0}, atom2 = {0}; - if (!PCPMetric_instance(metric, p1->super.pid, p1->offset, &atom1, type) || - !PCPMetric_instance(metric, p2->super.pid, p2->offset, &atom2, type)) { + if (!Metric_instance(metric, Process_getPid(&p1->super), p1->offset, &atom1, type) || + !Metric_instance(metric, Process_getPid(&p2->super), p2->offset, &atom2, type)) { if (type == PM_TYPE_STRING) { free(atom1.cp); free(atom2.cp); @@ -338,9 +504,9 @@ int PCPDynamicColumn_compareByKey(const PCPProcess* p1, const PCPProcess* p2, Pr case PM_TYPE_U64: return SPACESHIP_NUMBER(atom2.ull, atom1.ull); case PM_TYPE_FLOAT: - return SPACESHIP_NUMBER(atom2.f, atom1.f); + return compareRealNumbers(atom2.f, atom1.f); case PM_TYPE_DOUBLE: - return SPACESHIP_NUMBER(atom2.d, atom1.d); + return compareRealNumbers(atom2.d, atom1.d); default: break; } diff --git a/vendor/github.com/htop-dev/htop/pcp/PCPDynamicColumn.h b/vendor/github.com/htop-dev/htop/pcp/PCPDynamicColumn.h index d0ffe71921..ade782b7fb 100644 --- a/vendor/github.com/htop-dev/htop/pcp/PCPDynamicColumn.h +++ b/vendor/github.com/htop-dev/htop/pcp/PCPDynamicColumn.h @@ -1,5 +1,11 @@ #ifndef HEADER_PCPDynamicColumn #define HEADER_PCPDynamicColumn +/* +htop - PCPDynamicColumn.h +(C) 2023 htop dev team +Released under the GNU GPLv2+, see the COPYING file +in the source distribution for its full text. +*/ #include @@ -11,15 +17,22 @@ #include "pcp/PCPProcess.h" +struct pmDesc; + typedef struct PCPDynamicColumn_ { DynamicColumn super; char* metricName; + char* format; size_t id; /* identifier for metric array lookups */ + int width; /* optional width from configuration file */ + bool defaultEnabled; /* default enabled in dynamic screen */ + bool percent; + bool instances; /* an instance *names* column, not values */ } PCPDynamicColumn; typedef struct PCPDynamicColumns_ { Hashtable* table; - size_t count; /* count of dynamic meters discovered by scan */ + size_t count; /* count of dynamic columns discovered by scan */ size_t offset; /* start offset into the Platform metric array */ size_t cursor; /* identifier allocator for each new metric used */ } PCPDynamicColumns; @@ -28,8 +41,14 @@ void PCPDynamicColumns_init(PCPDynamicColumns* columns); void PCPDynamicColumns_done(Hashtable* table); +void PCPDynamicColumns_setupWidths(PCPDynamicColumns* columns); + void PCPDynamicColumn_writeField(PCPDynamicColumn* this, const Process* proc, RichString* str); +void PCPDynamicColumn_writeAtomValue(PCPDynamicColumn* column, RichString* str, const struct Settings_* settings, int metric, int instance, const struct pmDesc* desc, const void* atomvalue); + int PCPDynamicColumn_compareByKey(const PCPProcess* p1, const PCPProcess* p2, ProcessField key); +void PCPDynamicColumn_done(PCPDynamicColumn* this); + #endif diff --git a/vendor/github.com/htop-dev/htop/pcp/PCPDynamicMeter.c b/vendor/github.com/htop-dev/htop/pcp/PCPDynamicMeter.c index e899988136..87e51700ca 100644 --- a/vendor/github.com/htop-dev/htop/pcp/PCPDynamicMeter.c +++ b/vendor/github.com/htop-dev/htop/pcp/PCPDynamicMeter.c @@ -25,7 +25,7 @@ in the source distribution for its full text. #include "RichString.h" #include "XUtils.h" -#include "pcp/PCPMetric.h" +#include "pcp/Metric.h" static PCPDynamicMetric* PCPDynamicMeter_lookupMetric(PCPDynamicMeters* meters, PCPDynamicMeter* meter, const char* name) { @@ -309,7 +309,7 @@ void PCPDynamicMeters_done(Hashtable* table) { void PCPDynamicMeter_enable(PCPDynamicMeter* this) { for (size_t i = 0; i < this->totalMetrics; i++) - PCPMetric_enable(this->metrics[i].id, true); + Metric_enable(this->metrics[i].id, true); } void PCPDynamicMeter_updateValues(PCPDynamicMeter* this, Meter* meter) { @@ -322,10 +322,10 @@ void PCPDynamicMeter_updateValues(PCPDynamicMeter* this, Meter* meter) { buffer[bytes++] = '/'; /* separator */ PCPDynamicMetric* metric = &this->metrics[i]; - const pmDesc* desc = PCPMetric_desc(metric->id); + const pmDesc* desc = Metric_desc(metric->id); pmAtomValue atom, raw; - if (!PCPMetric_values(metric->id, &raw, 1, desc->type)) { + if (!Metric_values(metric->id, &raw, 1, desc->type)) { bytes--; /* clear the separator */ continue; } @@ -393,11 +393,11 @@ void PCPDynamicMeter_display(PCPDynamicMeter* this, ATTR_UNUSED const Meter* met for (size_t i = 0; i < this->totalMetrics; i++) { PCPDynamicMetric* metric = &this->metrics[i]; - const pmDesc* desc = PCPMetric_desc(metric->id); + const pmDesc* desc = Metric_desc(metric->id); pmAtomValue atom, raw; char buffer[64]; - if (!PCPMetric_values(metric->id, &raw, 1, desc->type)) + if (!Metric_values(metric->id, &raw, 1, desc->type)) continue; pmUnits conv = desc->units; /* convert to canonical units */ diff --git a/vendor/github.com/htop-dev/htop/pcp/PCPDynamicMeter.h b/vendor/github.com/htop-dev/htop/pcp/PCPDynamicMeter.h index 0e5ddd2b56..3a72d13c32 100644 --- a/vendor/github.com/htop-dev/htop/pcp/PCPDynamicMeter.h +++ b/vendor/github.com/htop-dev/htop/pcp/PCPDynamicMeter.h @@ -1,5 +1,11 @@ #ifndef HEADER_PCPDynamicMeter #define HEADER_PCPDynamicMeter +/* +htop - PCPDynamicMeter.h +(C) 2023 htop dev team +Released under the GNU GPLv2+, see the COPYING file +in the source distribution for its full text. +*/ #include diff --git a/vendor/github.com/htop-dev/htop/pcp/PCPDynamicScreen.c b/vendor/github.com/htop-dev/htop/pcp/PCPDynamicScreen.c new file mode 100644 index 0000000000..a4622e3420 --- /dev/null +++ b/vendor/github.com/htop-dev/htop/pcp/PCPDynamicScreen.c @@ -0,0 +1,405 @@ +/* +htop - PCPDynamicScreen.c +(C) 2022 Sohaib Mohammed +(C) 2022-2023 htop dev team +Released under the GNU GPLv2+, see the COPYING file +in the source distribution for its full text. +*/ + +#include "pcp/PCPDynamicScreen.h" + +#include +#include +#include +#include + +#include "AvailableColumnsPanel.h" +#include "Macros.h" +#include "Platform.h" +#include "Settings.h" +#include "XUtils.h" + +#include "pcp/InDomTable.h" +#include "pcp/PCPDynamicColumn.h" + + +static char* formatFields(PCPDynamicScreen* screen) { + char* columns = strdup(""); + + for (size_t j = 0; j < screen->totalColumns; j++) { + const PCPDynamicColumn* column = screen->columns[j]; + if (column->super.enabled == false) + continue; + char* prefix = columns; + xAsprintf(&columns, "%s Dynamic(%s)", prefix, column->super.name); + free(prefix); + } + + return columns; +} + +static void PCPDynamicScreens_appendDynamicColumns(PCPDynamicScreens* screens, PCPDynamicColumns* columns) { + for (size_t i = 0; i < screens->count; i++) { + PCPDynamicScreen *screen = Hashtable_get(screens->table, i); + if (!screen) + return; + + /* setup default fields (columns) based on configuration */ + for (size_t j = 0; j < screen->totalColumns; j++) { + PCPDynamicColumn* column = screen->columns[j]; + + column->id = columns->offset + columns->cursor; + columns->cursor++; + Platform_addMetric(column->id, column->metricName); + + size_t id = columns->count + LAST_PROCESSFIELD; + Hashtable_put(columns->table, id, column); + columns->count++; + + if (j == 0) { + const pmDesc* desc = Metric_desc(column->id); + assert(desc->indom != PM_INDOM_NULL); + screen->indom = desc->indom; + screen->key = column->id; + } + } + screen->super.columnKeys = formatFields(screen); + } +} + +static PCPDynamicColumn* PCPDynamicScreen_lookupMetric(PCPDynamicScreen* screen, const char* name) { + PCPDynamicColumn* column = NULL; + size_t bytes = strlen(name) + strlen(screen->super.name) + 1; /* colon */ + if (bytes >= sizeof(column->super.name)) + return NULL; + + bytes += 16; /* prefix, dots and terminator */ + char* metricName = xMalloc(bytes); + xSnprintf(metricName, bytes, "htop.screen.%s.%s", screen->super.name, name); + + for (size_t i = 0; i < screen->totalColumns; i++) { + column = screen->columns[i]; + if (String_eq(column->metricName, metricName)) { + free(metricName); + return column; + } + } + + /* not an existing column in this screen - create it and add to the list */ + column = xCalloc(1, sizeof(PCPDynamicColumn)); + xSnprintf(column->super.name, sizeof(column->super.name), "%s:%s", screen->super.name, name); + column->super.table = &screen->table->super; + column->metricName = metricName; + column->super.enabled = true; + + size_t n = screen->totalColumns + 1; + screen->columns = xReallocArray(screen->columns, n, sizeof(PCPDynamicColumn*)); + screen->columns[n - 1] = column; + screen->totalColumns = n; + + return column; +} + +static void PCPDynamicScreen_parseColumn(PCPDynamicScreen* screen, const char* path, unsigned int line, char* key, char* value) { + PCPDynamicColumn* column; + char* p; + + if ((p = strchr(key, '.')) == NULL) + return; + *p++ = '\0'; /* end the name, p is now the attribute, e.g. 'label' */ + + /* lookup a dynamic column with this name, else create */ + column = PCPDynamicScreen_lookupMetric(screen, key); + + if (String_eq(p, "metric")) { + char* error; + if (pmRegisterDerivedMetric(column->metricName, value, &error) < 0) { + char* note; + xAsprintf(¬e, + "%s: failed to parse expression in %s at line %u\n%s\n", + pmGetProgname(), path, line, error); + free(error); + errno = EINVAL; + CRT_fatalError(note); + free(note); + } + + /* pmLookupText - add optional metric help text */ + if (!column->super.description && !column->instances) + Metric_lookupText(value, &column->super.description); + + } else { + /* this is a property of a dynamic column - the column expression */ + /* may not have been observed yet; i.e. we allow for any ordering */ + + if (String_eq(p, "caption")) { + free_and_xStrdup(&column->super.caption, value); + } else if (String_eq(p, "heading")) { + free_and_xStrdup(&column->super.heading, value); + } else if (String_eq(p, "description")) { + free_and_xStrdup(&column->super.description, value); + } else if (String_eq(p, "width")) { + column->width = strtoul(value, NULL, 10); + } else if (String_eq(p, "format")) { + free_and_xStrdup(&column->format, value); + } else if (String_eq(p, "instances")) { + if (String_eq(value, "True") || String_eq(value, "true")) + column->instances = true; + free_and_xStrdup(&column->super.description, screen->super.caption); + } else if (String_eq(p, "default")) { /* displayed by default */ + if (String_eq(value, "False") || String_eq(value, "false")) + column->defaultEnabled = column->super.enabled = false; + } + } +} + +static bool PCPDynamicScreen_validateScreenName(char* key, const char* path, unsigned int line) { + char* p = key; + char* end = strrchr(key, ']'); + + if (end) { + *end = '\0'; + } else { + fprintf(stderr, + "%s: no closing brace on screen name at %s line %u\n\"%s\"", + pmGetProgname(), path, line, key); + return false; + } + + while (*p) { + if (p == key) { + if (!isalpha(*p) && *p != '_') + break; + } else { + if (!isalnum(*p) && *p != '_') + break; + } + p++; + } + if (*p != '\0') { /* badness */ + fprintf(stderr, + "%s: invalid screen name at %s line %u\n\"%s\"", + pmGetProgname(), path, line, key); + return false; + } + return true; +} + +/* Ensure a screen name has not been defined previously */ +static bool PCPDynamicScreen_uniqueName(char* key, PCPDynamicScreens* screens) { + return !DynamicScreen_search(screens->table, key, NULL); +} + +static PCPDynamicScreen* PCPDynamicScreen_new(PCPDynamicScreens* screens, const char* name) { + PCPDynamicScreen* screen = xCalloc(1, sizeof(*screen)); + String_safeStrncpy(screen->super.name, name, sizeof(screen->super.name)); + screen->defaultEnabled = true; + + size_t id = screens->count; + Hashtable_put(screens->table, id, screen); + screens->count++; + + return screen; +} + +static void PCPDynamicScreen_parseFile(PCPDynamicScreens* screens, const char* path) { + FILE* file = fopen(path, "r"); + if (!file) + return; + + PCPDynamicScreen* screen = NULL; + unsigned int lineno = 0; + bool ok = true; + for (;;) { + char* line = String_readLine(file); + if (!line) + break; + lineno++; + + /* cleanup whitespace, skip comment lines */ + char* trimmed = String_trim(line); + free(line); + if (!trimmed || !trimmed[0] || trimmed[0] == '#') { + free(trimmed); + continue; + } + + size_t n; + char** config = String_split(trimmed, '=', &n); + free(trimmed); + if (config == NULL) + continue; + + char* key = String_trim(config[0]); + char* value = n > 1 ? String_trim(config[1]) : NULL; + if (key[0] == '[') { /* new section name - i.e. new screen */ + ok = PCPDynamicScreen_validateScreenName(key + 1, path, lineno); + if (ok) + ok = PCPDynamicScreen_uniqueName(key + 1, screens); + if (ok) + screen = PCPDynamicScreen_new(screens, key + 1); + if (pmDebugOptions.appl0) + fprintf(stderr, "[%s] screen: %s\n", path, key+1); + } else if (!ok) { + ; /* skip this one, we're looking for a new header */ + } else if (!value || !screen) { + ; /* skip this one as we always need value strings */ + } else if (String_eq(key, "heading")) { + free_and_xStrdup(&screen->super.heading, value); + } else if (String_eq(key, "caption")) { + free_and_xStrdup(&screen->super.caption, value); + } else if (String_eq(key, "sortKey")) { + free_and_xStrdup(&screen->super.sortKey, value); + } else if (String_eq(key, "sortDirection")) { + screen->super.direction = strtoul(value, NULL, 10); + } else if (String_eq(key, "default") || String_eq(key, "enabled")) { + if (String_eq(value, "False") || String_eq(value, "false")) + screen->defaultEnabled = false; + else if (String_eq(value, "True") || String_eq(value, "true")) + screen->defaultEnabled = true; /* also default */ + } else { + PCPDynamicScreen_parseColumn(screen, path, lineno, key, value); + } + String_freeArray(config); + free(value); + free(key); + } + fclose(file); +} + +static void PCPDynamicScreen_scanDir(PCPDynamicScreens* screens, char* path) { + DIR* dir = opendir(path); + if (!dir) + return; + + struct dirent* dirent; + while ((dirent = readdir(dir)) != NULL) { + if (dirent->d_name[0] == '.') + continue; + + char* file = String_cat(path, dirent->d_name); + PCPDynamicScreen_parseFile(screens, file); + free(file); + } + closedir(dir); +} + +void PCPDynamicScreens_init(PCPDynamicScreens* screens, PCPDynamicColumns* columns) { + const char* share = pmGetConfig("PCP_SHARE_DIR"); + const char* sysconf = pmGetConfig("PCP_SYSCONF_DIR"); + const char* xdgConfigHome = getenv("XDG_CONFIG_HOME"); + const char* override = getenv("PCP_HTOP_DIR"); + const char* home = getenv("HOME"); + char* path; + + screens->table = Hashtable_new(0, true); + + /* developer paths - PCP_HTOP_DIR=./pcp ./pcp-htop */ + if (override) { + path = String_cat(override, "/screens/"); + PCPDynamicScreen_scanDir(screens, path); + free(path); + } + + /* next, search in home directory alongside htoprc */ + if (xdgConfigHome) + path = String_cat(xdgConfigHome, "/htop/screens/"); + else if (home) + path = String_cat(home, "/.config/htop/screens/"); + else + path = NULL; + if (path) { + PCPDynamicScreen_scanDir(screens, path); + free(path); + } + + /* next, search in the system screens directory */ + path = String_cat(sysconf, "/htop/screens/"); + PCPDynamicScreen_scanDir(screens, path); + free(path); + + /* next, try the readonly system screens directory */ + path = String_cat(share, "/htop/screens/"); + PCPDynamicScreen_scanDir(screens, path); + free(path); + + /* establish internal metric identifier mappings */ + PCPDynamicScreens_appendDynamicColumns(screens, columns); +} + +static void PCPDynamicScreen_done(PCPDynamicScreen* ds) { + DynamicScreen_done(&ds->super); + Object_delete(ds->table); + free(ds->columns); +} + +static void PCPDynamicScreens_free(ATTR_UNUSED ht_key_t key, void* value, ATTR_UNUSED void* data) { + PCPDynamicScreen* ds = (PCPDynamicScreen*) value; + PCPDynamicScreen_done(ds); +} + +void PCPDynamicScreens_done(Hashtable* table) { + Hashtable_foreach(table, PCPDynamicScreens_free, NULL); +} + +void PCPDynamicScreen_appendTables(PCPDynamicScreens* screens, Machine* host) { + PCPDynamicScreen* ds; + + for (size_t i = 0; i < screens->count; i++) { + if ((ds = (PCPDynamicScreen*)Hashtable_get(screens->table, i)) == NULL) + continue; + ds->table = InDomTable_new(host, ds->indom, ds->key); + } +} + +void PCPDynamicScreen_appendScreens(PCPDynamicScreens* screens, Settings* settings) { + PCPDynamicScreen* ds; + + for (size_t i = 0; i < screens->count; i++) { + if ((ds = (PCPDynamicScreen*)Hashtable_get(screens->table, i)) == NULL) + continue; + if (ds->defaultEnabled == false) + continue; + const char* tab = ds->super.heading; + Settings_newDynamicScreen(settings, tab, &ds->super, &ds->table->super); + } +} + +/* called when htoprc .dynamic line is parsed for a dynamic screen */ +void PCPDynamicScreen_addDynamicScreen(PCPDynamicScreens* screens, ScreenSettings* ss) { + PCPDynamicScreen* ds; + + for (size_t i = 0; i < screens->count; i++) { + if ((ds = (PCPDynamicScreen*)Hashtable_get(screens->table, i)) == NULL) + continue; + if (String_eq(ss->dynamic, ds->super.name) == false) + continue; + ss->table = &ds->table->super; + } +} + +void PCPDynamicScreens_addAvailableColumns(Panel* availableColumns, Hashtable* screens, const char* screen) { + Vector_prune(availableColumns->items); + + bool success; + unsigned int key; + success = DynamicScreen_search(screens, screen, &key); + if (!success) + return; + + PCPDynamicScreen* dynamicScreen = Hashtable_get(screens, key); + if (!screen) + return; + + for (unsigned int j = 0; j < dynamicScreen->totalColumns; j++) { + PCPDynamicColumn* column = dynamicScreen->columns[j]; + const char* title = column->super.heading ? column->super.heading : column->super.name; + const char* text = column->super.description ? column->super.description : column->super.caption; + char description[256]; + if (text) + xSnprintf(description, sizeof(description), "%s - %s", title, text); + else + xSnprintf(description, sizeof(description), "%s", title); + Panel_add(availableColumns, (Object*) ListItem_new(description, j)); + } +} diff --git a/vendor/github.com/htop-dev/htop/pcp/PCPDynamicScreen.h b/vendor/github.com/htop-dev/htop/pcp/PCPDynamicScreen.h new file mode 100644 index 0000000000..73535925a5 --- /dev/null +++ b/vendor/github.com/htop-dev/htop/pcp/PCPDynamicScreen.h @@ -0,0 +1,56 @@ +#ifndef HEADER_PCPDynamicScreen +#define HEADER_PCPDynamicScreen +/* +htop - PCPDynamicScreen.h +(C) 2023 htop dev team +Released under the GNU GPLv2+, see the COPYING file +in the source distribution for its full text. +*/ + +#include +#include + +#include "CRT.h" +#include "DynamicScreen.h" +#include "Hashtable.h" +#include "Machine.h" +#include "Panel.h" +#include "Settings.h" + + +struct InDomTable_; +struct PCPDynamicColumn_; +struct PCPDynamicColumns_; + +typedef struct PCPDynamicScreen_ { + DynamicScreen super; + + struct InDomTable_ *table; + struct PCPDynamicColumn_** columns; + size_t totalColumns; + + unsigned int indom; /* instance domain number */ + unsigned int key; /* PCPMetric identifier */ + + bool defaultEnabled; /* enabled setting from configuration file */ + /* at runtime enabled screens have entries in settings->screens */ +} PCPDynamicScreen; + +typedef struct PCPDynamicScreens_ { + Hashtable* table; + size_t count; /* count of dynamic screens discovered from scan */ +} PCPDynamicScreens; + +void PCPDynamicScreens_init(PCPDynamicScreens* screens, struct PCPDynamicColumns_* columns); + +void PCPDynamicScreens_done(Hashtable* table); + +void PCPDynamicScreen_appendTables(PCPDynamicScreens* screens, Machine* host); + +void PCPDynamicScreen_appendScreens(PCPDynamicScreens* screens, Settings* settings); + +void PCPDynamicScreen_addDynamicScreen(PCPDynamicScreens* screens, ScreenSettings* ss); + +void PCPDynamicScreens_addAvailableColumns(Panel* availableColumns, Hashtable* screens, const char* screen); + +#endif diff --git a/vendor/github.com/htop-dev/htop/pcp/PCPMachine.c b/vendor/github.com/htop-dev/htop/pcp/PCPMachine.c index 59e056247d..801f397849 100644 --- a/vendor/github.com/htop-dev/htop/pcp/PCPMachine.c +++ b/vendor/github.com/htop-dev/htop/pcp/PCPMachine.c @@ -25,13 +25,13 @@ in the source distribution for its full text. #include "Settings.h" #include "XUtils.h" -#include "pcp/PCPMetric.h" +#include "pcp/Metric.h" #include "pcp/PCPProcess.h" static void PCPMachine_updateCPUcount(PCPMachine* this) { Machine* super = &this->super; - super->activeCPUs = PCPMetric_instanceCount(PCP_PERCPU_SYSTEM); + super->activeCPUs = Metric_instanceCount(PCP_PERCPU_SYSTEM); unsigned int cpus = Platform_getMaxCPU(); if (cpus == super->existingCPUs) return; @@ -58,30 +58,30 @@ static void PCPMachine_updateMemoryInfo(Machine* host) { host->usedSwap = host->totalSwap = host->sharedMem = 0; pmAtomValue value; - if (PCPMetric_values(PCP_MEM_TOTAL, &value, 1, PM_TYPE_U64) != NULL) + if (Metric_values(PCP_MEM_TOTAL, &value, 1, PM_TYPE_U64) != NULL) host->totalMem = value.ull; - if (PCPMetric_values(PCP_MEM_FREE, &value, 1, PM_TYPE_U64) != NULL) + if (Metric_values(PCP_MEM_FREE, &value, 1, PM_TYPE_U64) != NULL) freeMem = value.ull; - if (PCPMetric_values(PCP_MEM_BUFFERS, &value, 1, PM_TYPE_U64) != NULL) + if (Metric_values(PCP_MEM_BUFFERS, &value, 1, PM_TYPE_U64) != NULL) host->buffersMem = value.ull; - if (PCPMetric_values(PCP_MEM_SRECLAIM, &value, 1, PM_TYPE_U64) != NULL) + if (Metric_values(PCP_MEM_SRECLAIM, &value, 1, PM_TYPE_U64) != NULL) sreclaimableMem = value.ull; - if (PCPMetric_values(PCP_MEM_SHARED, &value, 1, PM_TYPE_U64) != NULL) + if (Metric_values(PCP_MEM_SHARED, &value, 1, PM_TYPE_U64) != NULL) host->sharedMem = value.ull; - if (PCPMetric_values(PCP_MEM_CACHED, &value, 1, PM_TYPE_U64) != NULL) + if (Metric_values(PCP_MEM_CACHED, &value, 1, PM_TYPE_U64) != NULL) host->cachedMem = value.ull + sreclaimableMem - host->sharedMem; const memory_t usedDiff = freeMem + host->cachedMem + sreclaimableMem + host->buffersMem; host->usedMem = (host->totalMem >= usedDiff) ? host->totalMem - usedDiff : host->totalMem - freeMem; - if (PCPMetric_values(PCP_MEM_AVAILABLE, &value, 1, PM_TYPE_U64) != NULL) + if (Metric_values(PCP_MEM_AVAILABLE, &value, 1, PM_TYPE_U64) != NULL) host->availableMem = MINIMUM(value.ull, host->totalMem); else host->availableMem = freeMem; - if (PCPMetric_values(PCP_MEM_SWAPFREE, &value, 1, PM_TYPE_U64) != NULL) + if (Metric_values(PCP_MEM_SWAPFREE, &value, 1, PM_TYPE_U64) != NULL) swapFreeMem = value.ull; - if (PCPMetric_values(PCP_MEM_SWAPTOTAL, &value, 1, PM_TYPE_U64) != NULL) + if (Metric_values(PCP_MEM_SWAPTOTAL, &value, 1, PM_TYPE_U64) != NULL) host->totalSwap = value.ull; - if (PCPMetric_values(PCP_MEM_SWAPCACHED, &value, 1, PM_TYPE_U64) != NULL) + if (Metric_values(PCP_MEM_SWAPCACHED, &value, 1, PM_TYPE_U64) != NULL) host->cachedSwap = value.ull; host->usedSwap = host->totalSwap - swapFreeMem - host->cachedSwap; } @@ -153,26 +153,26 @@ static void PCPMachine_deriveCPUTime(pmAtomValue* values) { PCPMachine_saveCPUTimePeriod(values, CPU_TOTAL_PERIOD, totaltime); } -static void PCPMachine_updateAllCPUTime(PCPMachine* this, PCPMetric metric, CPUMetric cpumetric) +static void PCPMachine_updateAllCPUTime(PCPMachine* this, Metric metric, CPUMetric cpumetric) { pmAtomValue* value = &this->cpu[cpumetric]; - if (PCPMetric_values(metric, value, 1, PM_TYPE_U64) == NULL) + if (Metric_values(metric, value, 1, PM_TYPE_U64) == NULL) memset(value, 0, sizeof(pmAtomValue)); } -static void PCPMachine_updatePerCPUTime(PCPMachine* this, PCPMetric metric, CPUMetric cpumetric) +static void PCPMachine_updatePerCPUTime(PCPMachine* this, Metric metric, CPUMetric cpumetric) { int cpus = this->super.existingCPUs; - if (PCPMetric_values(metric, this->values, cpus, PM_TYPE_U64) == NULL) + if (Metric_values(metric, this->values, cpus, PM_TYPE_U64) == NULL) memset(this->values, 0, cpus * sizeof(pmAtomValue)); for (int i = 0; i < cpus; i++) this->percpu[i][cpumetric].ull = this->values[i].ull; } -static void PCPMachine_updatePerCPUReal(PCPMachine* this, PCPMetric metric, CPUMetric cpumetric) +static void PCPMachine_updatePerCPUReal(PCPMachine* this, Metric metric, CPUMetric cpumetric) { int cpus = this->super.existingCPUs; - if (PCPMetric_values(metric, this->values, cpus, PM_TYPE_DOUBLE) == NULL) + if (Metric_values(metric, this->values, cpus, PM_TYPE_DOUBLE) == NULL) memset(this->values, 0, cpus * sizeof(pmAtomValue)); for (int i = 0; i < cpus; i++) this->percpu[i][cpumetric].d = this->values[i].d; @@ -185,29 +185,29 @@ static inline void PCPMachine_scanZfsArcstats(PCPMachine* this) { pmAtomValue value; memset(&this->zfs, 0, sizeof(ZfsArcStats)); - if (PCPMetric_values(PCP_ZFS_ARC_ANON_SIZE, &value, 1, PM_TYPE_U64)) + if (Metric_values(PCP_ZFS_ARC_ANON_SIZE, &value, 1, PM_TYPE_U64)) this->zfs.anon = value.ull / ONE_K; - if (PCPMetric_values(PCP_ZFS_ARC_C_MIN, &value, 1, PM_TYPE_U64)) + if (Metric_values(PCP_ZFS_ARC_C_MIN, &value, 1, PM_TYPE_U64)) this->zfs.min = value.ull / ONE_K; - if (PCPMetric_values(PCP_ZFS_ARC_C_MAX, &value, 1, PM_TYPE_U64)) + if (Metric_values(PCP_ZFS_ARC_C_MAX, &value, 1, PM_TYPE_U64)) this->zfs.max = value.ull / ONE_K; - if (PCPMetric_values(PCP_ZFS_ARC_BONUS_SIZE, &value, 1, PM_TYPE_U64)) + if (Metric_values(PCP_ZFS_ARC_BONUS_SIZE, &value, 1, PM_TYPE_U64)) bonusSize = value.ull / ONE_K; - if (PCPMetric_values(PCP_ZFS_ARC_DBUF_SIZE, &value, 1, PM_TYPE_U64)) + if (Metric_values(PCP_ZFS_ARC_DBUF_SIZE, &value, 1, PM_TYPE_U64)) dbufSize = value.ull / ONE_K; - if (PCPMetric_values(PCP_ZFS_ARC_DNODE_SIZE, &value, 1, PM_TYPE_U64)) + if (Metric_values(PCP_ZFS_ARC_DNODE_SIZE, &value, 1, PM_TYPE_U64)) dnodeSize = value.ull / ONE_K; - if (PCPMetric_values(PCP_ZFS_ARC_COMPRESSED_SIZE, &value, 1, PM_TYPE_U64)) + if (Metric_values(PCP_ZFS_ARC_COMPRESSED_SIZE, &value, 1, PM_TYPE_U64)) this->zfs.compressed = value.ull / ONE_K; - if (PCPMetric_values(PCP_ZFS_ARC_UNCOMPRESSED_SIZE, &value, 1, PM_TYPE_U64)) + if (Metric_values(PCP_ZFS_ARC_UNCOMPRESSED_SIZE, &value, 1, PM_TYPE_U64)) this->zfs.uncompressed = value.ull / ONE_K; - if (PCPMetric_values(PCP_ZFS_ARC_HDR_SIZE, &value, 1, PM_TYPE_U64)) + if (Metric_values(PCP_ZFS_ARC_HDR_SIZE, &value, 1, PM_TYPE_U64)) this->zfs.header = value.ull / ONE_K; - if (PCPMetric_values(PCP_ZFS_ARC_MFU_SIZE, &value, 1, PM_TYPE_U64)) + if (Metric_values(PCP_ZFS_ARC_MFU_SIZE, &value, 1, PM_TYPE_U64)) this->zfs.MFU = value.ull / ONE_K; - if (PCPMetric_values(PCP_ZFS_ARC_MRU_SIZE, &value, 1, PM_TYPE_U64)) + if (Metric_values(PCP_ZFS_ARC_MRU_SIZE, &value, 1, PM_TYPE_U64)) this->zfs.MRU = value.ull / ONE_K; - if (PCPMetric_values(PCP_ZFS_ARC_SIZE, &value, 1, PM_TYPE_U64)) + if (Metric_values(PCP_ZFS_ARC_SIZE, &value, 1, PM_TYPE_U64)) this->zfs.size = value.ull / ONE_K; this->zfs.other = (dbufSize + dnodeSize + bonusSize) / ONE_K; @@ -260,31 +260,31 @@ void Machine_scan(Machine* super) { bool flagged; for (int metric = PCP_PROC_PID; metric < PCP_METRIC_COUNT; metric++) - PCPMetric_enable(metric, true); + Metric_enable(metric, true); flagged = settings->showCPUFrequency; - PCPMetric_enable(PCP_HINV_CPUCLOCK, flagged); + Metric_enable(PCP_HINV_CPUCLOCK, flagged); flagged = flags & PROCESS_FLAG_LINUX_CGROUP; - PCPMetric_enable(PCP_PROC_CGROUPS, flagged); + Metric_enable(PCP_PROC_CGROUPS, flagged); flagged = flags & PROCESS_FLAG_LINUX_OOM; - PCPMetric_enable(PCP_PROC_OOMSCORE, flagged); + Metric_enable(PCP_PROC_OOMSCORE, flagged); flagged = flags & PROCESS_FLAG_LINUX_CTXT; - PCPMetric_enable(PCP_PROC_VCTXSW, flagged); - PCPMetric_enable(PCP_PROC_NVCTXSW, flagged); + Metric_enable(PCP_PROC_VCTXSW, flagged); + Metric_enable(PCP_PROC_NVCTXSW, flagged); flagged = flags & PROCESS_FLAG_LINUX_SECATTR; - PCPMetric_enable(PCP_PROC_LABELS, flagged); + Metric_enable(PCP_PROC_LABELS, flagged); flagged = flags & PROCESS_FLAG_LINUX_AUTOGROUP; - PCPMetric_enable(PCP_PROC_AUTOGROUP_ID, flagged); - PCPMetric_enable(PCP_PROC_AUTOGROUP_NICE, flagged); + Metric_enable(PCP_PROC_AUTOGROUP_ID, flagged); + Metric_enable(PCP_PROC_AUTOGROUP_NICE, flagged); /* Sample smaps metrics on every second pass to improve performance */ host->smaps_flag = !!host->smaps_flag; - PCPMetric_enable(PCP_PROC_SMAPS_PSS, host->smaps_flag); - PCPMetric_enable(PCP_PROC_SMAPS_SWAP, host->smaps_flag); - PCPMetric_enable(PCP_PROC_SMAPS_SWAPPSS, host->smaps_flag); + Metric_enable(PCP_PROC_SMAPS_PSS, host->smaps_flag); + Metric_enable(PCP_PROC_SMAPS_SWAP, host->smaps_flag); + Metric_enable(PCP_PROC_SMAPS_SWAPPSS, host->smaps_flag); struct timeval timestamp; - if (PCPMetric_fetch(×tamp) != true) + if (Metric_fetch(×tamp) != true) return; double sample = host->timestamp; @@ -307,6 +307,8 @@ Machine* Machine_new(UsersTable* usersTable, uid_t userId) { this->cpu = xCalloc(CPU_METRIC_COUNT, sizeof(pmAtomValue)); PCPMachine_updateCPUcount(this); + Platform_updateTables(super); + return super; } @@ -326,7 +328,7 @@ bool Machine_isCPUonline(const Machine* host, unsigned int id) { (void) host; pmAtomValue value; - if (PCPMetric_instance(PCP_PERCPU_SYSTEM, id, id, &value, PM_TYPE_U32)) + if (Metric_instance(PCP_PERCPU_SYSTEM, id, id, &value, PM_TYPE_U32)) return true; return false; } diff --git a/vendor/github.com/htop-dev/htop/pcp/PCPProcess.c b/vendor/github.com/htop-dev/htop/pcp/PCPProcess.c index cefd0ac3a0..b54834765e 100644 --- a/vendor/github.com/htop-dev/htop/pcp/PCPProcess.c +++ b/vendor/github.com/htop-dev/htop/pcp/PCPProcess.c @@ -103,57 +103,58 @@ void Process_delete(Object* cast) { free(this); } -static void PCPProcess_printDelay(float delay_percent, char* buffer, int n) { - if (isnan(delay_percent)) { - xSnprintf(buffer, n, " N/A "); - } else { +static void PCPProcess_printDelay(float delay_percent, char* buffer, size_t n) { + if (isNonnegative(delay_percent)) { xSnprintf(buffer, n, "%4.1f ", delay_percent); + } else { + xSnprintf(buffer, n, " N/A "); } } -static void PCPProcess_writeField(const Process* this, RichString* str, ProcessField field) { - const PCPProcess* pp = (const PCPProcess*) this; - bool coloring = this->host->settings->highlightMegabytes; +static double PCPProcess_totalIORate(const PCPProcess* pp) { + double totalRate = NAN; + if (isNonnegative(pp->io_rate_read_bps)) { + totalRate = pp->io_rate_read_bps; + if (isNonnegative(pp->io_rate_write_bps)) { + totalRate += pp->io_rate_write_bps; + } + } else if (isNonnegative(pp->io_rate_write_bps)) { + totalRate = pp->io_rate_write_bps; + } + return totalRate; +} + +static void PCPProcess_rowWriteField(const Row* super, RichString* str, ProcessField field) { + const PCPProcess* pp = (const PCPProcess*) super; + bool coloring = super->host->settings->highlightMegabytes; char buffer[256]; buffer[255] = '\0'; int attr = CRT_colors[DEFAULT_COLOR]; - int n = sizeof(buffer) - 1; + size_t n = sizeof(buffer) - 1; switch ((int)field) { - case CMINFLT: Process_printCount(str, pp->cminflt, coloring); return; - case CMAJFLT: Process_printCount(str, pp->cmajflt, coloring); return; - case M_DRS: Process_printBytes(str, pp->m_drs, coloring); return; - case M_DT: Process_printBytes(str, pp->m_dt, coloring); return; - case M_LRS: Process_printBytes(str, pp->m_lrs, coloring); return; - case M_TRS: Process_printBytes(str, pp->m_trs, coloring); return; - case M_SHARE: Process_printBytes(str, pp->m_share, coloring); return; - case M_PSS: Process_printKBytes(str, pp->m_pss, coloring); return; - case M_SWAP: Process_printKBytes(str, pp->m_swap, coloring); return; - case M_PSSWP: Process_printKBytes(str, pp->m_psswp, coloring); return; - case UTIME: Process_printTime(str, pp->utime, coloring); return; - case STIME: Process_printTime(str, pp->stime, coloring); return; - case CUTIME: Process_printTime(str, pp->cutime, coloring); return; - case CSTIME: Process_printTime(str, pp->cstime, coloring); return; - case RCHAR: Process_printBytes(str, pp->io_rchar, coloring); return; - case WCHAR: Process_printBytes(str, pp->io_wchar, coloring); return; - case SYSCR: Process_printCount(str, pp->io_syscr, coloring); return; - case SYSCW: Process_printCount(str, pp->io_syscw, coloring); return; - case RBYTES: Process_printBytes(str, pp->io_read_bytes, coloring); return; - case WBYTES: Process_printBytes(str, pp->io_write_bytes, coloring); return; - case CNCLWB: Process_printBytes(str, pp->io_cancelled_write_bytes, coloring); return; - case IO_READ_RATE: Process_printRate(str, pp->io_rate_read_bps, coloring); return; - case IO_WRITE_RATE: Process_printRate(str, pp->io_rate_write_bps, coloring); return; - case IO_RATE: { - double totalRate = NAN; - if (!isnan(pp->io_rate_read_bps) && !isnan(pp->io_rate_write_bps)) - totalRate = pp->io_rate_read_bps + pp->io_rate_write_bps; - else if (!isnan(pp->io_rate_read_bps)) - totalRate = pp->io_rate_read_bps; - else if (!isnan(pp->io_rate_write_bps)) - totalRate = pp->io_rate_write_bps; - else - totalRate = NAN; - Process_printRate(str, totalRate, coloring); - return; - } + case CMINFLT: Row_printCount(str, pp->cminflt, coloring); return; + case CMAJFLT: Row_printCount(str, pp->cmajflt, coloring); return; + case M_DRS: Row_printBytes(str, pp->m_drs, coloring); return; + case M_DT: Row_printBytes(str, pp->m_dt, coloring); return; + case M_LRS: Row_printBytes(str, pp->m_lrs, coloring); return; + case M_TRS: Row_printBytes(str, pp->m_trs, coloring); return; + case M_SHARE: Row_printBytes(str, pp->m_share, coloring); return; + case M_PSS: Row_printKBytes(str, pp->m_pss, coloring); return; + case M_SWAP: Row_printKBytes(str, pp->m_swap, coloring); return; + case M_PSSWP: Row_printKBytes(str, pp->m_psswp, coloring); return; + case UTIME: Row_printTime(str, pp->utime, coloring); return; + case STIME: Row_printTime(str, pp->stime, coloring); return; + case CUTIME: Row_printTime(str, pp->cutime, coloring); return; + case CSTIME: Row_printTime(str, pp->cstime, coloring); return; + case RCHAR: Row_printBytes(str, pp->io_rchar, coloring); return; + case WCHAR: Row_printBytes(str, pp->io_wchar, coloring); return; + case SYSCR: Row_printCount(str, pp->io_syscr, coloring); return; + case SYSCW: Row_printCount(str, pp->io_syscw, coloring); return; + case RBYTES: Row_printBytes(str, pp->io_read_bytes, coloring); return; + case WBYTES: Row_printBytes(str, pp->io_write_bytes, coloring); return; + case CNCLWB: Row_printBytes(str, pp->io_cancelled_write_bytes, coloring); return; + case IO_READ_RATE: Row_printRate(str, pp->io_rate_read_bps, coloring); return; + case IO_WRITE_RATE: Row_printRate(str, pp->io_rate_write_bps, coloring); return; + case IO_RATE: Row_printRate(str, PCPProcess_totalIORate(pp), coloring); return; case CGROUP: xSnprintf(buffer, n, "%-10s ", pp->cgroup ? pp->cgroup : ""); break; case OOM: xSnprintf(buffer, n, "%4u ", pp->oom); break; case PERCENT_CPU_DELAY: @@ -192,19 +193,12 @@ static void PCPProcess_writeField(const Process* this, RichString* str, ProcessF } break; default: - Process_writeField(this, str, field); + Process_writeField(&pp->super, str, field); return; } RichString_appendWide(str, attr, buffer); } -static double adjustNaN(double num) { - if (isnan(num)) - return -0.0005; - - return num; -} - static int PCPProcess_compareByKey(const Process* v1, const Process* v2, ProcessField key) { const PCPProcess* p1 = (const PCPProcess*)v1; const PCPProcess* p2 = (const PCPProcess*)v2; @@ -249,21 +243,21 @@ static int PCPProcess_compareByKey(const Process* v1, const Process* v2, Process case CNCLWB: return SPACESHIP_NUMBER(p1->io_cancelled_write_bytes, p2->io_cancelled_write_bytes); case IO_READ_RATE: - return SPACESHIP_NUMBER(adjustNaN(p1->io_rate_read_bps), adjustNaN(p2->io_rate_read_bps)); + return compareRealNumbers(p1->io_rate_read_bps, p2->io_rate_read_bps); case IO_WRITE_RATE: - return SPACESHIP_NUMBER(adjustNaN(p1->io_rate_write_bps), adjustNaN(p2->io_rate_write_bps)); + return compareRealNumbers(p1->io_rate_write_bps, p2->io_rate_write_bps); case IO_RATE: - return SPACESHIP_NUMBER(adjustNaN(p1->io_rate_read_bps) + adjustNaN(p1->io_rate_write_bps), adjustNaN(p2->io_rate_read_bps) + adjustNaN(p2->io_rate_write_bps)); + return compareRealNumbers(PCPProcess_totalIORate(p1), PCPProcess_totalIORate(p2)); case CGROUP: return SPACESHIP_NULLSTR(p1->cgroup, p2->cgroup); case OOM: return SPACESHIP_NUMBER(p1->oom, p2->oom); case PERCENT_CPU_DELAY: - return SPACESHIP_NUMBER(p1->cpu_delay_percent, p2->cpu_delay_percent); + return compareRealNumbers(p1->cpu_delay_percent, p2->cpu_delay_percent); case PERCENT_IO_DELAY: - return SPACESHIP_NUMBER(p1->blkio_delay_percent, p2->blkio_delay_percent); + return compareRealNumbers(p1->blkio_delay_percent, p2->blkio_delay_percent); case PERCENT_SWAP_DELAY: - return SPACESHIP_NUMBER(p1->swapin_delay_percent, p2->swapin_delay_percent); + return compareRealNumbers(p1->swapin_delay_percent, p2->swapin_delay_percent); case CTXT: return SPACESHIP_NUMBER(p1->ctxt_diff, p2->ctxt_diff); case SECATTR: @@ -281,11 +275,18 @@ static int PCPProcess_compareByKey(const Process* v1, const Process* v2, Process const ProcessClass PCPProcess_class = { .super = { - .extends = Class(Process), - .display = Process_display, - .delete = Process_delete, - .compare = Process_compare + .super = { + .extends = Class(Process), + .display = Row_display, + .delete = Process_delete, + .compare = Process_compare + }, + .isHighlighted = Process_rowIsHighlighted, + .isVisible = Process_rowIsVisible, + .matchesFilter = Process_rowMatchesFilter, + .compareByParent = Process_compareByParent, + .sortKeyString = Process_rowGetSortKey, + .writeField = PCPProcess_rowWriteField, }, - .writeField = PCPProcess_writeField, - .compareByKey = PCPProcess_compareByKey + .compareByKey = PCPProcess_compareByKey, }; diff --git a/vendor/github.com/htop-dev/htop/pcp/PCPProcessList.c b/vendor/github.com/htop-dev/htop/pcp/PCPProcessList.c index c18d74be93..69c04e2213 100644 --- a/vendor/github.com/htop-dev/htop/pcp/PCPProcessList.c +++ b/vendor/github.com/htop-dev/htop/pcp/PCPProcessList.c @@ -26,71 +26,72 @@ in the source distribution for its full text. #include "Settings.h" #include "XUtils.h" +#include "pcp/Metric.h" #include "pcp/PCPMachine.h" -#include "pcp/PCPMetric.h" #include "pcp/PCPProcess.h" ProcessList* ProcessList_new(Machine* host, Hashtable* pidMatchList) { PCPProcessList* this = xCalloc(1, sizeof(PCPProcessList)); - ProcessList* super = &(this->super); + Object_setClass(this, Class(ProcessList)); + ProcessList* super = &this->super; ProcessList_init(super, Class(PCPProcess), host, pidMatchList); return super; } -void ProcessList_delete(ProcessList* super) { - PCPProcessList* this = (PCPProcessList*) super; - ProcessList_done(super); +void ProcessList_delete(Object* cast) { + PCPProcessList* this = (PCPProcessList*) cast; + ProcessList_done(&this->super); free(this); } static inline long Metric_instance_s32(int metric, int pid, int offset, long fallback) { pmAtomValue value; - if (PCPMetric_instance(metric, pid, offset, &value, PM_TYPE_32)) + if (Metric_instance(metric, pid, offset, &value, PM_TYPE_32)) return value.l; return fallback; } static inline long long Metric_instance_s64(int metric, int pid, int offset, long long fallback) { pmAtomValue value; - if (PCPMetric_instance(metric, pid, offset, &value, PM_TYPE_64)) + if (Metric_instance(metric, pid, offset, &value, PM_TYPE_64)) return value.l; return fallback; } static inline unsigned long Metric_instance_u32(int metric, int pid, int offset, unsigned long fallback) { pmAtomValue value; - if (PCPMetric_instance(metric, pid, offset, &value, PM_TYPE_U32)) + if (Metric_instance(metric, pid, offset, &value, PM_TYPE_U32)) return value.ul; return fallback; } static inline unsigned long long Metric_instance_u64(int metric, int pid, int offset, unsigned long long fallback) { pmAtomValue value; - if (PCPMetric_instance(metric, pid, offset, &value, PM_TYPE_U64)) + if (Metric_instance(metric, pid, offset, &value, PM_TYPE_U64)) return value.ull; return fallback; } static inline unsigned long long Metric_instance_time(int metric, int pid, int offset) { pmAtomValue value; - if (PCPMetric_instance(metric, pid, offset, &value, PM_TYPE_U64)) + if (Metric_instance(metric, pid, offset, &value, PM_TYPE_U64)) return value.ull / 10; return 0; } static inline unsigned long long Metric_instance_ONE_K(int metric, int pid, int offset) { pmAtomValue value; - if (PCPMetric_instance(metric, pid, offset, &value, PM_TYPE_U64)) + if (Metric_instance(metric, pid, offset, &value, PM_TYPE_U64)) return value.ull / ONE_K; return ULLONG_MAX; } static inline char Metric_instance_char(int metric, int pid, int offset, char fallback) { pmAtomValue value; - if (PCPMetric_instance(metric, pid, offset, &value, PM_TYPE_STRING)) { + if (Metric_instance(metric, pid, offset, &value, PM_TYPE_STRING)) { char uchar = value.cp[0]; free(value.cp); return uchar; @@ -104,7 +105,7 @@ static char* setUser(UsersTable* this, unsigned int uid, int pid, int offset) { return name; pmAtomValue value; - if (PCPMetric_instance(PCP_PROC_ID_USER, pid, offset, &value, PM_TYPE_STRING)) { + if (Metric_instance(PCP_PROC_ID_USER, pid, offset, &value, PM_TYPE_STRING)) { Hashtable_put(this->users, uid, value.cp); name = value.cp; } @@ -129,16 +130,16 @@ static inline ProcessState PCPProcessList_getProcessState(char state) { } static void PCPProcessList_updateID(Process* process, int pid, int offset) { - process->tgid = Metric_instance_u32(PCP_PROC_TGID, pid, offset, 1); - process->ppid = Metric_instance_u32(PCP_PROC_PPID, pid, offset, 1); + Process_setThreadGroup(process, Metric_instance_u32(PCP_PROC_TGID, pid, offset, 1)); + Process_setParent(process, Metric_instance_u32(PCP_PROC_PPID, pid, offset, 1)); process->state = PCPProcessList_getProcessState(Metric_instance_char(PCP_PROC_STATE, pid, offset, '?')); } -static void PCPProcessList_updateInfo(Process* process, int pid, int offset, char* command, size_t commLen) { - PCPProcess* pp = (PCPProcess*) process; +static void PCPProcessList_updateInfo(PCPProcess* pp, int pid, int offset, char* command, size_t commLen) { + Process* process = &pp->super; pmAtomValue value; - if (!PCPMetric_instance(PCP_PROC_CMD, pid, offset, &value, PM_TYPE_STRING)) + if (!Metric_instance(PCP_PROC_CMD, pid, offset, &value, PM_TYPE_STRING)) value.cp = xStrdup(""); String_safeStrncpy(command, value.cp, commLen); free(value.cp); @@ -173,7 +174,7 @@ static void PCPProcessList_updateIO(PCPProcess* pp, int pid, int offset, unsigne pp->io_syscw = Metric_instance_u64(PCP_PROC_IO_SYSCW, pid, offset, ULLONG_MAX); pp->io_cancelled_write_bytes = Metric_instance_ONE_K(PCP_PROC_IO_CANCELLED, pid, offset); - if (PCPMetric_instance(PCP_PROC_IO_READB, pid, offset, &value, PM_TYPE_U64)) { + if (Metric_instance(PCP_PROC_IO_READB, pid, offset, &value, PM_TYPE_U64)) { unsigned long long last_read = pp->io_read_bytes; pp->io_read_bytes = value.ull / ONE_K; pp->io_rate_read_bps = ONE_K * (pp->io_read_bytes - last_read) / @@ -183,7 +184,7 @@ static void PCPProcessList_updateIO(PCPProcess* pp, int pid, int offset, unsigne pp->io_rate_read_bps = NAN; } - if (PCPMetric_instance(PCP_PROC_IO_WRITEB, pid, offset, &value, PM_TYPE_U64)) { + if (Metric_instance(PCP_PROC_IO_WRITEB, pid, offset, &value, PM_TYPE_U64)) { unsigned long long last_write = pp->io_write_bytes; pp->io_write_bytes = value.ull; pp->io_rate_write_bps = ONE_K * (pp->io_write_bytes - last_write) / @@ -225,20 +226,20 @@ static void PCPProcessList_readCtxtData(PCPProcess* pp, int pid, int offset) { pmAtomValue value; unsigned long ctxt = 0; - if (PCPMetric_instance(PCP_PROC_VCTXSW, pid, offset, &value, PM_TYPE_U32)) + if (Metric_instance(PCP_PROC_VCTXSW, pid, offset, &value, PM_TYPE_U32)) ctxt += value.ul; - if (PCPMetric_instance(PCP_PROC_NVCTXSW, pid, offset, &value, PM_TYPE_U32)) + if (Metric_instance(PCP_PROC_NVCTXSW, pid, offset, &value, PM_TYPE_U32)) ctxt += value.ul; pp->ctxt_diff = ctxt > pp->ctxt_total ? ctxt - pp->ctxt_total : 0; pp->ctxt_total = ctxt; } -static char* setString(PCPMetric metric, int pid, int offset, char* string) { +static char* setString(Metric metric, int pid, int offset, char* string) { if (string) free(string); pmAtomValue value; - if (PCPMetric_instance(metric, pid, offset, &value, PM_TYPE_STRING)) + if (Metric_instance(metric, pid, offset, &value, PM_TYPE_STRING)) string = value.cp; else string = NULL; @@ -268,7 +269,7 @@ static void PCPProcessList_updateUsername(Process* process, int pid, int offset, static void PCPProcessList_updateCmdline(Process* process, int pid, int offset, const char* comm) { pmAtomValue value; - if (!PCPMetric_instance(PCP_PROC_PSARGS, pid, offset, &value, PM_TYPE_STRING)) { + if (!Metric_instance(PCP_PROC_PSARGS, pid, offset, &value, PM_TYPE_STRING)) { if (process->state != ZOMBIE) process->isKernelThread = true; Process_updateCmdline(process, NULL, 0, 0); @@ -287,22 +288,30 @@ static void PCPProcessList_updateCmdline(Process* process, int pid, int offset, process->isKernelThread = true; } + int tokenEnd = 0; int tokenStart = 0; + bool argSepSpace = false; + for (int i = 0; i < length; i++) { /* htop considers the next character after the last / that is before * basenameOffset, as the start of the basename in cmdline - see * Process_writeCommand */ if (command[i] == '/') tokenStart = i + 1; + /* special-case arguments for problematic situations like "find /" */ + if (command[i] <= ' ') + argSepSpace = true; } - int tokenEnd = length; + tokenEnd = length; + if (argSepSpace) + tokenStart = 0; Process_updateCmdline(process, command, tokenStart, tokenEnd); free(value.cp); Process_updateComm(process, comm); - if (PCPMetric_instance(PCP_PROC_EXE, pid, offset, &value, PM_TYPE_STRING)) { + if (Metric_instance(PCP_PROC_EXE, pid, offset, &value, PM_TYPE_STRING)) { Process_updateExe(process, value.cp[0] ? value.cp : NULL); free(value.cp); } @@ -310,7 +319,7 @@ static void PCPProcessList_updateCmdline(Process* process, int pid, int offset, static bool PCPProcessList_updateProcesses(PCPProcessList* this) { ProcessList* pl = (ProcessList*) this; - Machine* host = pl->host; + Machine* host = pl->super.host; PCPMachine* phost = (PCPMachine*) host; const Settings* settings = host->settings; @@ -322,13 +331,13 @@ static bool PCPProcessList_updateProcesses(PCPProcessList* this) { int pid = -1, offset = -1; /* for every process ... */ - while (PCPMetric_iterate(PCP_PROC_PID, &pid, &offset)) { + while (Metric_iterate(PCP_PROC_PID, &pid, &offset)) { bool preExisting; Process* proc = ProcessList_getProcess(pl, pid, &preExisting, PCPProcess_new); PCPProcess* pp = (PCPProcess*) proc; PCPProcessList_updateID(proc, pid, offset); - proc->isUserlandThread = proc->pid != proc->tgid; + proc->isUserlandThread = Process_getPid(proc) != Process_getThreadGroup(proc); pp->offset = offset >= 0 ? offset : 0; /* @@ -338,8 +347,8 @@ static bool PCPProcessList_updateProcesses(PCPProcessList* this) { * But it will short-circuit subsequent scans. */ if (preExisting && hideKernelThreads && Process_isKernelThread(proc)) { - proc->updated = true; - proc->show = false; + proc->super.updated = true; + proc->super.show = false; if (proc->state == RUNNING) pl->runningTasks++; pl->kernelThreads++; @@ -347,8 +356,8 @@ static bool PCPProcessList_updateProcesses(PCPProcessList* this) { continue; } if (preExisting && hideUserlandThreads && Process_isUserlandThread(proc)) { - proc->updated = true; - proc->show = false; + proc->super.updated = true; + proc->super.show = false; if (proc->state == RUNNING) pl->runningTasks++; pl->userlandThreads++; @@ -363,7 +372,7 @@ static bool PCPProcessList_updateProcesses(PCPProcessList* this) { if ((flags & PROCESS_FLAG_LINUX_SMAPS) && (Process_isKernelThread(proc) == false)) { - if (PCPMetric_enabled(PCP_PROC_SMAPS_PSS)) + if (Metric_enabled(PCP_PROC_SMAPS_PSS)) PCPProcessList_updateSmaps(pp, pid, offset); } @@ -371,14 +380,16 @@ static bool PCPProcessList_updateProcesses(PCPProcessList* this) { unsigned int tty_nr = proc->tty_nr; unsigned long long int lasttimes = pp->utime + pp->stime; - PCPProcessList_updateInfo(proc, pid, offset, command, sizeof(command)); + PCPProcessList_updateInfo(pp, pid, offset, command, sizeof(command)); proc->starttime_ctime += Platform_getBootTime(); if (tty_nr != proc->tty_nr) PCPProcessList_updateTTY(proc, pid, offset); - float percent_cpu = (pp->utime + pp->stime - lasttimes) / phost->period * 100.0; - proc->percent_cpu = isnan(percent_cpu) ? - 0.0 : CLAMP(percent_cpu, 0.0, host->activeCPUs * 100.0); + proc->percent_cpu = NAN; + if (phost->period > 0.0) { + float percent_cpu = saturatingSub(pp->utime + pp->stime, lasttimes) / phost->period * 100.0; + proc->percent_cpu = MINIMUM(percent_cpu, host->activeCPUs * 100.0F); + } proc->percent_mem = proc->m_resident / (double) host->totalMem * 100.0; Process_updateCPUFieldWidths(proc->percent_cpu); @@ -425,13 +436,13 @@ static bool PCPProcessList_updateProcesses(PCPProcessList* this) { } /* Set at the end when we know if a new entry is a thread */ - proc->show = ! ((hideKernelThreads && Process_isKernelThread(proc)) || + proc->super.show = ! ((hideKernelThreads && Process_isKernelThread(proc)) || (hideUserlandThreads && Process_isUserlandThread(proc))); pl->totalTasks++; if (proc->state == RUNNING) pl->runningTasks++; - proc->updated = true; + proc->super.updated = true; } return true; } diff --git a/vendor/github.com/htop-dev/htop/pcp/Platform.c b/vendor/github.com/htop-dev/htop/pcp/Platform.c index 12e0f4d780..cfcd36c6c2 100644 --- a/vendor/github.com/htop-dev/htop/pcp/Platform.c +++ b/vendor/github.com/htop-dev/htop/pcp/Platform.c @@ -25,6 +25,7 @@ in the source distribution for its full text. #include "DiskIOMeter.h" #include "DynamicColumn.h" #include "DynamicMeter.h" +#include "DynamicScreen.h" #include "FileDescriptorMeter.h" #include "HostnameMeter.h" #include "LoadAverageMeter.h" @@ -44,10 +45,11 @@ in the source distribution for its full text. #include "linux/PressureStallMeter.h" #include "linux/ZramMeter.h" #include "linux/ZramStats.h" +#include "pcp/Metric.h" #include "pcp/PCPDynamicColumn.h" #include "pcp/PCPDynamicMeter.h" +#include "pcp/PCPDynamicScreen.h" #include "pcp/PCPMachine.h" -#include "pcp/PCPMetric.h" #include "pcp/PCPProcessList.h" #include "zfs/ZfsArcMeter.h" #include "zfs/ZfsArcStats.h" @@ -286,7 +288,7 @@ int pmLookupDescs(int numpmid, pmID* pmids, pmDesc* descs) { } #endif -size_t Platform_addMetric(PCPMetric id, const char* name) { +size_t Platform_addMetric(Metric id, const char* name) { unsigned int i = (unsigned int)id; if (i >= PCP_METRIC_COUNT && i >= pcp->totalMetrics) { @@ -355,6 +357,7 @@ bool Platform_init(void) { pcp->columns.offset = PCP_METRIC_COUNT + pcp->meters.cursor; PCPDynamicColumns_init(&pcp->columns); + PCPDynamicScreens_init(&pcp->screens, &pcp->columns); sts = pmLookupName(pcp->totalMetrics, pcp->names, pcp->pmids); if (sts < 0) { @@ -374,31 +377,32 @@ bool Platform_init(void) { } /* set proc.control.perclient.threads to 1 for live contexts */ - PCPMetric_enableThreads(); + Metric_enableThreads(); /* extract values needed for setup - e.g. cpu count, pid_max */ - PCPMetric_enable(PCP_PID_MAX, true); - PCPMetric_enable(PCP_BOOTTIME, true); - PCPMetric_enable(PCP_HINV_NCPU, true); - PCPMetric_enable(PCP_PERCPU_SYSTEM, true); - PCPMetric_enable(PCP_UNAME_SYSNAME, true); - PCPMetric_enable(PCP_UNAME_RELEASE, true); - PCPMetric_enable(PCP_UNAME_MACHINE, true); - PCPMetric_enable(PCP_UNAME_DISTRO, true); - + Metric_enable(PCP_PID_MAX, true); + Metric_enable(PCP_BOOTTIME, true); + Metric_enable(PCP_HINV_NCPU, true); + Metric_enable(PCP_PERCPU_SYSTEM, true); + Metric_enable(PCP_UNAME_SYSNAME, true); + Metric_enable(PCP_UNAME_RELEASE, true); + Metric_enable(PCP_UNAME_MACHINE, true); + Metric_enable(PCP_UNAME_DISTRO, true); + + /* enable metrics for all dynamic columns (including those from dynamic screens) */ for (size_t i = pcp->columns.offset; i < pcp->columns.offset + pcp->columns.count; i++) - PCPMetric_enable(i, true); + Metric_enable(i, true); - PCPMetric_fetch(NULL); + Metric_fetch(NULL); - for (PCPMetric metric = 0; metric < PCP_PROC_PID; metric++) - PCPMetric_enable(metric, true); - PCPMetric_enable(PCP_PID_MAX, false); /* needed one time only */ - PCPMetric_enable(PCP_BOOTTIME, false); - PCPMetric_enable(PCP_UNAME_SYSNAME, false); - PCPMetric_enable(PCP_UNAME_RELEASE, false); - PCPMetric_enable(PCP_UNAME_MACHINE, false); - PCPMetric_enable(PCP_UNAME_DISTRO, false); + for (Metric metric = 0; metric < PCP_PROC_PID; metric++) + Metric_enable(metric, true); + Metric_enable(PCP_PID_MAX, false); /* needed one time only */ + Metric_enable(PCP_BOOTTIME, false); + Metric_enable(PCP_UNAME_SYSNAME, false); + Metric_enable(PCP_UNAME_RELEASE, false); + Metric_enable(PCP_UNAME_MACHINE, false); + Metric_enable(PCP_UNAME_DISTRO, false); /* first sample (fetch) performed above, save constants */ Platform_getBootTime(); @@ -417,6 +421,10 @@ void Platform_dynamicMetersDone(Hashtable* meters) { PCPDynamicMeters_done(meters); } +void Platform_dynamicScreensDone(Hashtable* screens) { + PCPDynamicScreens_done(screens); +} + void Platform_done(void) { pmDestroyContext(pcp->context); if (pcp->result) @@ -436,7 +444,7 @@ void Platform_setBindings(Htop_Action* keys) { int Platform_getUptime(void) { pmAtomValue value; - if (PCPMetric_values(PCP_UPTIME, &value, 1, PM_TYPE_32) == NULL) + if (Metric_values(PCP_UPTIME, &value, 1, PM_TYPE_32) == NULL) return 0; return value.l; } @@ -445,7 +453,7 @@ void Platform_getLoadAverage(double* one, double* five, double* fifteen) { *one = *five = *fifteen = 0.0; pmAtomValue values[3] = {0}; - if (PCPMetric_values(PCP_LOAD_AVERAGE, values, 3, PM_TYPE_DOUBLE) != NULL) { + if (Metric_values(PCP_LOAD_AVERAGE, values, 3, PM_TYPE_DOUBLE) != NULL) { *one = values[0].d; *five = values[1].d; *fifteen = values[2].d; @@ -457,7 +465,7 @@ unsigned int Platform_getMaxCPU(void) { return pcp->ncpu; pmAtomValue value; - if (PCPMetric_values(PCP_HINV_NCPU, &value, 1, PM_TYPE_U32) != NULL) + if (Metric_values(PCP_HINV_NCPU, &value, 1, PM_TYPE_U32) != NULL) pcp->ncpu = value.ul; else pcp->ncpu = 1; @@ -469,7 +477,7 @@ int Platform_getMaxPid(void) { return pcp->pidmax; pmAtomValue value; - if (PCPMetric_values(PCP_PID_MAX, &value, 1, PM_TYPE_32) == NULL) + if (Metric_values(PCP_PID_MAX, &value, 1, PM_TYPE_32) == NULL) return -1; pcp->pidmax = value.l; return pcp->pidmax; @@ -480,7 +488,7 @@ long long Platform_getBootTime(void) { return pcp->btime; pmAtomValue value; - if (PCPMetric_values(PCP_BOOTTIME, &value, 1, PM_TYPE_64) != NULL) + if (Metric_values(PCP_BOOTTIME, &value, 1, PM_TYPE_64) != NULL) pcp->btime = value.ll; return pcp->btime; } @@ -497,24 +505,28 @@ static double Platform_setOneCPUValues(Meter* this, const Settings* settings, pm v[CPU_METER_KERNEL] = values[CPU_SYSTEM_PERIOD].ull / total * 100.0; v[CPU_METER_IRQ] = values[CPU_IRQ_PERIOD].ull / total * 100.0; v[CPU_METER_SOFTIRQ] = values[CPU_SOFTIRQ_PERIOD].ull / total * 100.0; + this->curItems = 5; + v[CPU_METER_STEAL] = values[CPU_STEAL_PERIOD].ull / total * 100.0; v[CPU_METER_GUEST] = values[CPU_GUEST_PERIOD].ull / total * 100.0; - v[CPU_METER_IOWAIT] = values[CPU_IOWAIT_PERIOD].ull / total * 100.0; - this->curItems = 8; - percent = v[CPU_METER_NICE] + v[CPU_METER_NORMAL] + v[CPU_METER_KERNEL] + v[CPU_METER_IRQ] + v[CPU_METER_SOFTIRQ]; if (settings->accountGuestInCPUMeter) { - percent += v[CPU_METER_STEAL] + v[CPU_METER_GUEST]; + this->curItems = 7; } + + v[CPU_METER_IOWAIT] = values[CPU_IOWAIT_PERIOD].ull / total * 100.0; } else { v[CPU_METER_KERNEL] = values[CPU_SYSTEM_ALL_PERIOD].ull / total * 100.0; value = values[CPU_STEAL_PERIOD].ull + values[CPU_GUEST_PERIOD].ull; v[CPU_METER_IRQ] = value / total * 100.0; this->curItems = 4; - percent = v[CPU_METER_NICE] + v[CPU_METER_NORMAL] + v[CPU_METER_KERNEL] + v[CPU_METER_IRQ]; } - percent = CLAMP(percent, 0.0, 100.0); - if (isnan(percent)) - percent = 0.0; + + percent = sumPositiveValues(v, this->curItems); + percent = MINIMUM(percent, 100.0); + + if (settings->detailedCPUTime) { + this->curItems = 8; + } v[CPU_METER_FREQUENCY] = values[CPU_FREQUENCY].d; v[CPU_METER_TEMPERATURE] = NAN; @@ -563,7 +575,7 @@ void Platform_setSwapValues(Meter* this) { } void Platform_setZramValues(Meter* this) { - int i, count = PCPMetric_instanceCount(PCP_ZRAM_CAPACITY); + int i, count = Metric_instanceCount(PCP_ZRAM_CAPACITY); if (!count) { this->total = 0; this->values[0] = 0; @@ -574,24 +586,28 @@ void Platform_setZramValues(Meter* this) { pmAtomValue* values = xCalloc(count, sizeof(pmAtomValue)); ZramStats stats = {0}; - if (PCPMetric_values(PCP_ZRAM_CAPACITY, values, count, PM_TYPE_U64)) { + if (Metric_values(PCP_ZRAM_CAPACITY, values, count, PM_TYPE_U64)) { for (i = 0; i < count; i++) stats.totalZram += values[i].ull; } - if (PCPMetric_values(PCP_ZRAM_ORIGINAL, values, count, PM_TYPE_U64)) { + if (Metric_values(PCP_ZRAM_ORIGINAL, values, count, PM_TYPE_U64)) { for (i = 0; i < count; i++) stats.usedZramOrig += values[i].ull; } - if (PCPMetric_values(PCP_ZRAM_COMPRESSED, values, count, PM_TYPE_U64)) { + if (Metric_values(PCP_ZRAM_COMPRESSED, values, count, PM_TYPE_U64)) { for (i = 0; i < count; i++) stats.usedZramComp += values[i].ull; } free(values); + if (stats.usedZramComp > stats.usedZramOrig) { + stats.usedZramComp = stats.usedZramOrig; + } + this->total = stats.totalZram; this->values[0] = stats.usedZramComp; - this->values[1] = stats.usedZramOrig; + this->values[1] = stats.usedZramOrig - stats.usedZramComp; } void Platform_setZfsArcValues(Meter* this) { @@ -620,13 +636,13 @@ void Platform_getRelease(char** string) { /* first call, extract just-sampled values */ pmAtomValue sysname, release, machine, distro; - if (!PCPMetric_values(PCP_UNAME_SYSNAME, &sysname, 1, PM_TYPE_STRING)) + if (!Metric_values(PCP_UNAME_SYSNAME, &sysname, 1, PM_TYPE_STRING)) sysname.cp = NULL; - if (!PCPMetric_values(PCP_UNAME_RELEASE, &release, 1, PM_TYPE_STRING)) + if (!Metric_values(PCP_UNAME_RELEASE, &release, 1, PM_TYPE_STRING)) release.cp = NULL; - if (!PCPMetric_values(PCP_UNAME_MACHINE, &machine, 1, PM_TYPE_STRING)) + if (!Metric_values(PCP_UNAME_MACHINE, &machine, 1, PM_TYPE_STRING)) machine.cp = NULL; - if (!PCPMetric_values(PCP_UNAME_DISTRO, &distro, 1, PM_TYPE_STRING)) + if (!Metric_values(PCP_UNAME_DISTRO, &distro, 1, PM_TYPE_STRING)) distro.cp = NULL; size_t length = 16; /* padded for formatting characters */ @@ -674,7 +690,7 @@ void Platform_getRelease(char** string) { char* Platform_getProcessEnv(pid_t pid) { pmAtomValue value; - if (!PCPMetric_instance(PCP_PROC_ENVIRON, pid, 0, &value, PM_TYPE_STRING)) + if (!Metric_instance(PCP_PROC_ENVIRON, pid, 0, &value, PM_TYPE_STRING)) return NULL; return value.cp; } @@ -687,7 +703,7 @@ FileLocks_ProcessData* Platform_getProcessLocks(pid_t pid) { void Platform_getPressureStall(const char* file, bool some, double* ten, double* sixty, double* threehundred) { *ten = *sixty = *threehundred = 0; - PCPMetric metric; + Metric metric; if (String_eq(file, "cpu")) metric = PCP_PSI_CPUSOME; else if (String_eq(file, "io")) @@ -700,7 +716,7 @@ void Platform_getPressureStall(const char* file, bool some, double* ten, double* return; pmAtomValue values[3] = {0}; - if (PCPMetric_values(metric, values, 3, PM_TYPE_DOUBLE) != NULL) { + if (Metric_values(metric, values, 3, PM_TYPE_DOUBLE) != NULL) { *ten = values[0].d; *sixty = values[1].d; *threehundred = values[2].d; @@ -711,11 +727,11 @@ bool Platform_getDiskIO(DiskIOData* data) { memset(data, 0, sizeof(*data)); pmAtomValue value; - if (PCPMetric_values(PCP_DISK_READB, &value, 1, PM_TYPE_U64) != NULL) + if (Metric_values(PCP_DISK_READB, &value, 1, PM_TYPE_U64) != NULL) data->totalBytesRead = value.ull; - if (PCPMetric_values(PCP_DISK_WRITEB, &value, 1, PM_TYPE_U64) != NULL) + if (Metric_values(PCP_DISK_WRITEB, &value, 1, PM_TYPE_U64) != NULL) data->totalBytesWritten = value.ull; - if (PCPMetric_values(PCP_DISK_ACTIVE, &value, 1, PM_TYPE_U64) != NULL) + if (Metric_values(PCP_DISK_ACTIVE, &value, 1, PM_TYPE_U64) != NULL) data->totalMsTimeSpend = value.ull; return true; } @@ -724,13 +740,13 @@ bool Platform_getNetworkIO(NetworkIOData* data) { memset(data, 0, sizeof(*data)); pmAtomValue value; - if (PCPMetric_values(PCP_NET_RECVB, &value, 1, PM_TYPE_U64) != NULL) + if (Metric_values(PCP_NET_RECVB, &value, 1, PM_TYPE_U64) != NULL) data->bytesReceived = value.ull; - if (PCPMetric_values(PCP_NET_SENDB, &value, 1, PM_TYPE_U64) != NULL) + if (Metric_values(PCP_NET_SENDB, &value, 1, PM_TYPE_U64) != NULL) data->bytesTransmitted = value.ull; - if (PCPMetric_values(PCP_NET_RECVP, &value, 1, PM_TYPE_U64) != NULL) + if (Metric_values(PCP_NET_RECVP, &value, 1, PM_TYPE_U64) != NULL) data->packetsReceived = value.ull; - if (PCPMetric_values(PCP_NET_SENDP, &value, 1, PM_TYPE_U64) != NULL) + if (Metric_values(PCP_NET_SENDP, &value, 1, PM_TYPE_U64) != NULL) data->packetsTransmitted = value.ull; return true; } @@ -740,9 +756,9 @@ void Platform_getFileDescriptors(double* used, double* max) { *max = 65536; pmAtomValue value; - if (PCPMetric_values(PCP_VFS_FILES_COUNT, &value, 1, PM_TYPE_32) != NULL) + if (Metric_values(PCP_VFS_FILES_COUNT, &value, 1, PM_TYPE_32) != NULL) *used = value.l; - if (PCPMetric_values(PCP_VFS_FILES_MAX, &value, 1, PM_TYPE_32) != NULL) + if (Metric_values(PCP_VFS_FILES_MAX, &value, 1, PM_TYPE_32) != NULL) *max = value.l; } @@ -842,10 +858,10 @@ Hashtable* Platform_dynamicColumns(void) { return pcp->columns.table; } -const char* Platform_dynamicColumnInit(unsigned int key) { +const char* Platform_dynamicColumnName(unsigned int key) { PCPDynamicColumn* this = Hashtable_get(pcp->columns.table, key); if (this) { - PCPMetric_enable(this->id, true); + Metric_enable(this->id, true); if (this->super.caption) return this->super.caption; if (this->super.heading) @@ -863,3 +879,25 @@ bool Platform_dynamicColumnWriteField(const Process* proc, RichString* str, unsi } return false; } + +Hashtable* Platform_dynamicScreens(void) { + return pcp->screens.table; +} + +void Platform_defaultDynamicScreens(Settings* settings) { + PCPDynamicScreen_appendScreens(&pcp->screens, settings); +} + +void Platform_addDynamicScreen(ScreenSettings* ss) { + PCPDynamicScreen_addDynamicScreen(&pcp->screens, ss); +} + +void Platform_addDynamicScreenAvailableColumns(Panel* availableColumns, const char* screen) { + Hashtable* screens = pcp->screens.table; + PCPDynamicScreens_addAvailableColumns(availableColumns, screens, screen); +} + +void Platform_updateTables(Machine* host) { + PCPDynamicScreen_appendTables(&pcp->screens, host); + PCPDynamicColumns_setupWidths(&pcp->columns); +} diff --git a/vendor/github.com/htop-dev/htop/pcp/Platform.h b/vendor/github.com/htop-dev/htop/pcp/Platform.h index f90e28135d..ce21f845b7 100644 --- a/vendor/github.com/htop-dev/htop/pcp/Platform.h +++ b/vendor/github.com/htop-dev/htop/pcp/Platform.h @@ -36,9 +36,10 @@ in the source distribution for its full text. #include "SignalsPanel.h" #include "CommandLine.h" +#include "pcp/Metric.h" #include "pcp/PCPDynamicColumn.h" #include "pcp/PCPDynamicMeter.h" -#include "pcp/PCPMetric.h" +#include "pcp/PCPDynamicScreen.h" typedef struct Platform_ { @@ -51,6 +52,7 @@ typedef struct Platform_ { pmResult* result; /* sample values result indexed by Metric */ PCPDynamicMeters meters; /* dynamic meters via configuration files */ PCPDynamicColumns columns; /* dynamic columns via configuration files */ + PCPDynamicScreens screens; /* dynamic screens via configuration files */ struct timeval offset; /* time offset used in archive mode only */ long long btime; /* boottime in seconds since the epoch */ char* release; /* uname and distro from this context */ @@ -129,7 +131,7 @@ CommandLineStatus Platform_getLongOption(int opt, int argc, char** argv); extern pmOptions opts; -size_t Platform_addMetric(PCPMetric id, const char* name); +size_t Platform_addMetric(Metric id, const char* name); void Platform_getFileDescriptors(double* used, double* max); @@ -151,8 +153,20 @@ Hashtable* Platform_dynamicColumns(void); void Platform_dynamicColumnsDone(Hashtable* columns); -const char* Platform_dynamicColumnInit(unsigned int key); +const char* Platform_dynamicColumnName(unsigned int key); bool Platform_dynamicColumnWriteField(const Process* proc, RichString* str, unsigned int key); +Hashtable* Platform_dynamicScreens(void); + +void Platform_defaultDynamicScreens(Settings* settings); + +void Platform_addDynamicScreen(ScreenSettings* ss); + +void Platform_addDynamicScreenAvailableColumns(Panel* availableColumns, const char* screen); + +void Platform_dynamicScreensDone(Hashtable* screens); + +void Platform_updateTables(Machine* host); + #endif diff --git a/vendor/github.com/htop-dev/htop/pcp/screens/biosnoop b/vendor/github.com/htop-dev/htop/pcp/screens/biosnoop new file mode 100644 index 0000000000..e6cdf89452 --- /dev/null +++ b/vendor/github.com/htop-dev/htop/pcp/screens/biosnoop @@ -0,0 +1,41 @@ +# +# pcp-htop(1) configuration file - see pcp-htop(5) +# + +[biosnoop] +heading = BioSnoop +caption = BPF block I/O snoop +default = false + +pid.heading = PID +pid.caption = Process identifier +pid.metric = bpf.biosnoop.pid +pid.format = process + +disk.heading = DISK +disk.caption = Device name +disk.width = -7 +disk.metric = bpf.biosnoop.disk + +rwbs.heading = TYPE +rwbs.caption = I/O type string +rwbs.width = -4 +rwbs.metric = bpf.biosnoop.rwbs + +bytes.heading = BYTES +bytes.caption = I/O size in bytes +bytes.metric = bpf.biosnoop.bytes + +lat.heading = LAT +lat.caption = I/O latency +lat.metric = bpf.biosnoop.lat + +sector.heading = SECTOR +sector.caption = Device sector +sector.metric = bpf.biosnoop.sector + +comm.heading = Command +comm.caption = Process command name +comm.width = -16 +comm.metric = bpf.biosnoop.comm +comm.format = process diff --git a/vendor/github.com/htop-dev/htop/pcp/screens/cgroups b/vendor/github.com/htop-dev/htop/pcp/screens/cgroups new file mode 100644 index 0000000000..0ddc65c4a7 --- /dev/null +++ b/vendor/github.com/htop-dev/htop/pcp/screens/cgroups @@ -0,0 +1,45 @@ +# +# pcp-htop(1) configuration file - see pcp-htop(5) +# + +[cgroups] +heading = CGroups +caption = Control Groups +default = true + +user_cpu.heading = UTIME +user_cpu.caption = User CPU Time +user_cpu.metric = 1000 * rate(cgroup.cpu.stat.user) +user_cpu.width = 6 + +system_cpu.heading = STIME +system_cpu.caption = Kernel CPU Time +system_cpu.metric = 1000 * rate(cgroup.cpu.stat.system) +system_cpu.width = 6 + +cpu_usage.heading = CPU% +cpu_usage.caption = CPU Utilization +cpu_usage.metric = 100 * (rate(cgroup.cpu.stat.usage) / hinv.ncpu) +cpu_usage.format = percent + +cpu_psi.heading = CPU-PSI +cpu_psi.caption = CPU Pressure Stall Information +cpu_psi.metric = 1000 * rate(cgroup.pressure.cpu.some.total) +cpu_psi.width = 7 + +mem_psi.heading = MEM-PSI +mem_psi.caption = Memory Pressure Stall Information +mem_psi.metric = 1000 * rate(cgroup.pressure.memory.some.total) +mem_psi.width = 7 + +io_psi.heading = I/O-PSI +io_psi.caption = I/O Pressure Stall Information +io_psi.metric = 1000 * rate(cgroup.pressure.io.some.total) +io_psi.width = 7 + +name.heading = Control group +name.caption = Control group name +name.width = -64 +name.metric = cgroup.cpu.stat.system +name.instances = true +name.format = cgroup diff --git a/vendor/github.com/htop-dev/htop/pcp/screens/cgroupsio b/vendor/github.com/htop-dev/htop/pcp/screens/cgroupsio new file mode 100644 index 0000000000..3a431db5a4 --- /dev/null +++ b/vendor/github.com/htop-dev/htop/pcp/screens/cgroupsio @@ -0,0 +1,49 @@ +# +# pcp-htop(1) configuration file - see pcp-htop(5) +# + +[cgroupsio] +heading = CGroupsIO +caption = Control Groups I/O +default = false + +iops.heading = IOPS +iops.caption = I/O operations +iops.metric = rate(cgroup.io.stat.rios) + rate(cgroup.io.stat.wios) + rate(cgroup.io.stat.dios) + +readops.heading = RDIO +readops.caption = Read operations +readops.metric = rate(cgroup.io.stat.rios) +readops.default = false + +writeops.heading = WRIO +writeops.caption = Write operations +writeops.metric = rate(cgroup.io.stat.wios) +writeops.default = false + +directops.heading = DIO +directops.caption = Direct I/O operations +directops.metric = rate(cgroup.io.stat.dios) +directops.default = false + +totalbytes.heading = R/W/D +totalbytes.caption = Disk throughput +totalbytes.metric = rate(cgroup.io.stat.rbytes) + rate(cgroup.io.stat.wbytes) + rate(cgroup.io.stat.dbytes) + +readbytes.heading = RBYTE +readbytes.caption = Disk read throughput +readbytes.metric = rate(cgroup.io.stat.rbytes) + +writebytes.heading = WBYTE +writebytes.caption = Disk throughput +writebytes.metric = rate(cgroup.io.stat.wbytes) + +directio.heading = DBYTE +directio.caption = Direct I/O throughput +directio.metric = rate(cgroup.io.stat.dbytes) + +name.heading = Control group device +name.caption = Control group device +name.width = -64 +name.metric = cgroup.io.stat.rbytes +name.instances = true diff --git a/vendor/github.com/htop-dev/htop/pcp/screens/cgroupsmem b/vendor/github.com/htop-dev/htop/pcp/screens/cgroupsmem new file mode 100644 index 0000000000..17bc1e38f9 --- /dev/null +++ b/vendor/github.com/htop-dev/htop/pcp/screens/cgroupsmem @@ -0,0 +1,48 @@ +# +# pcp-htop(1) configuration file - see pcp-htop(5) +# + +[cgroupsmem] +heading = CGroupsMem +caption = Control Groups Memory +default = false + +current.heading = MEM +current.caption = Current memory +current.metric = cgroup.memory.current + +usage.heading = USAGE +usage.caption = Memory usage +usage.metric = cgroup.memory.usage + +container.heading = CONTAINER +container.caption = Container Name +container.metric = cgroup.memory.id.container + +resident.heading = RSS +resident.metric = cgroup.memory.stat.rss + +cresident.heading = CRSS +cresident.metric = cgroup.memory.stat.total.rss + +anonmem.heading = ANON +anonmem.metric = cgroup.memory.stat.anon + +filemem.heading = FILE +filemem.metric = cgroup.memory.stat.file + +shared.heading = SHMEM +shared.metric = cgroup.memory.stat.shmem + +swap.heading = SWAP +swap.metric = cgroup.memory.stat.swap + +pgfault.heading = FAULTS +pgfault.metric = cgroup.memory.stat.pgfaults + +name.heading = Control group +name.caption = Control group name +name.width = -64 +name.metric = cgroup.memory.current +name.instances = true +name.format = cgroup diff --git a/vendor/github.com/htop-dev/htop/pcp/screens/devices b/vendor/github.com/htop-dev/htop/pcp/screens/devices new file mode 100644 index 0000000000..f9f6bc0c13 --- /dev/null +++ b/vendor/github.com/htop-dev/htop/pcp/screens/devices @@ -0,0 +1,114 @@ +# +# pcp-htop(1) configuration file - see pcp-htop(5) +# + +[disks] +heading = Disks +caption = Disk devices + +diskdev.heading = Device +diskdev.metric = disk.dev.read +diskdev.instances = true +diskdev.format = device +diskdev.width = -8 + +total.heading = TPS +total.metric = rate(disk.dev.read) + rate(disk.dev.write) + rate(disk.dev.discard) +total.caption = Rate of read requests + +read.heading = RR/S +read.metric = rate(disk.dev.read) +read.caption = Rate of read requests + +read_bytes.heading = RRB/S +read_bytes.metric = rate(disk.dev.read_bytes) +read_bytes.caption = Read throughput from the device + +read_merge.heading = RRQM/S +read_merge.metric = rate(disk.dev.read_merge) +read_merge.caption = Rate reads merged before queued +read_merge.default = false + +read_merge_pct.heading = RRQM% +read_merge_pct.metric = 100 * rate(disk.dev.read_merge) / rate(disk.dev.read) +read_merge_pct.caption = Percentage reads merged before queued +read_merge_pct.format = percent + +read_await.heading = RAWAIT +read_await.metric = disk.dev.r_await +read_await.default = false + +read_avqsz.heading = RARQSZ +read_avqsz.metric = disk.dev.r_avg_rqsz +read_avqsz.default = false + +write.heading = WR/S +write.metric = rate(disk.dev.write) +write.caption = Rate of write requests + +write_bytes.heading = WRB/S +write_bytes.metric = rate(disk.dev.write_bytes) +write_bytes.caption = Write throughput to the device + +write_merge.heading = WRQM/S +write_merge.metric = rate(disk.dev.write_merge) +write_merge.caption = Rate writes merged before queued +write_merge.default = false + +write_merge_pct.heading = WRQM% +write_merge_pct.metric = 100 * rate(disk.dev.write_merge) / rate(disk.dev.write) +write_merge_pct.caption = Percentage writes merged before queued +write_merge_pct.format = percent + +write_await.heading = WAWAIT +write_await.metric = disk.dev.w_await +write_await.default = false + +write_avqsz.heading = WARQSZ +write_avqsz.metric = disk.dev.w_avg_rqsz +write_avqsz.default = false + +discard.heading = DR/S +discard.metric = rate(disk.dev.discard) +discard.caption = Rate of discard requests + +discard_bytes.heading = DRB/S +discard_bytes.metric = rate(disk.dev.discard_bytes) +discard_bytes.caption = Discard request throughput +discard_bytes.default = false + +discard_merge.heading = DRQM/S +discard_merge.metric = rate(disk.dev.discard_merge) +discard_merge.caption = Rate discards merged before queued +discard_merge.default = false + +discard_merge_pct.heading = DRQM% +discard_merge_pct.metric = 100 * rate(disk.dev.discard_merge) / rate(disk.dev.discard) +discard_merge_pct.caption = Percentage discards merged before queued +discard_merge_pct.format = percent +discard_merge_pct.default = false + +discard_await.heading = DAWAIT +discard_await.metric = disk.dev.d_await +discard_await.default = false + +discard_avqsz.heading = DARQSZ +discard_avqsz.metric = disk.dev.d_avg_rqsz +discard_avqsz.default = false + +flush.heading = F/S +flush.metric = rate(disk.dev.flush) +flush.default = false +flush.caption = Flushes per second + +flush_await.heading = FAWAIT +flush_await.metric = disk.dev.f_await +flush_await.default = false + +qlen.heading = AQU-SZ +qlen.metric = disk.dev.avg_qlen + +util.heading = UTIL% +util.metric = 100 * disk.dev.util +util.caption = Perentage device utilitization +util.format = percent diff --git a/vendor/github.com/htop-dev/htop/pcp/screens/execsnoop b/vendor/github.com/htop-dev/htop/pcp/screens/execsnoop new file mode 100644 index 0000000000..d706e76405 --- /dev/null +++ b/vendor/github.com/htop-dev/htop/pcp/screens/execsnoop @@ -0,0 +1,37 @@ +# +# pcp-htop(1) configuration file - see pcp-htop(5) +# + +[execsnoop] +heading = ExecSnoop +caption = BPF exec(2) syscall snoop +default = false + +pid.heading = PID +pid.caption = Process Identifier +pid.metric = bpf.execsnoop.pid +pid.format = process + +ppid.heading = PPID +ppid.caption = Parent Process +ppid.metric = bpf.execsnoop.ppid +ppid.format = process + +uid.heading = UID +uid.caption = User Identifier +uid.metric = bpf.execsnoop.uid + +comm.heading = COMM +comm.caption = Command +comm.width = -16 +comm.metric = bpf.execsnoop.comm +comm.format = command + +ret.heading = RET +ret.caption = Return Code +ret.metric = bpf.execsnoop.ret + +path.heading = Arguments +path.caption = Arguments +path.width = -12 +path.metric = bpf.execsnoop.args diff --git a/vendor/github.com/htop-dev/htop/pcp/screens/exitsnoop b/vendor/github.com/htop-dev/htop/pcp/screens/exitsnoop new file mode 100644 index 0000000000..6c6b867c0e --- /dev/null +++ b/vendor/github.com/htop-dev/htop/pcp/screens/exitsnoop @@ -0,0 +1,48 @@ +# +# pcp-htop(1) configuration file - see pcp-htop(5) +# + +[exitsnoop] +heading = ExitSnoop +caption = BPF process exit(2) snoop +default = false + +pid.heading = PID +pid.caption = Process Identifier +pid.metric = bpf.exitsnoop.pid +pid.format = process + +ppid.heading = PPID +ppid.caption = Parent Process +ppid.metric = bpf.exitsnoop.ppid +ppid.format = process + +tid.heading = TID +tid.caption = Task Identifier +tid.metric = bpf.exitsnoop.tid +tid.format = process +tid.default = false + +signal.heading = SIG +signal.caption = Signal number +signal.metric = bpf.exitsnoop.sig + +exit.heading = EXIT +exit.caption = Exit Code +exit.metric = bpf.exitsnoop.exit_code + +core.heading = CORE +core.caption = Dumped core +core.metric = bpf.exitsnoop.coredump +core.default = false + +age.heading = AGE +age.caption = Process age +age.metric = bpf.exitsnoop.age +age.default = false + +comm.heading = Command +comm.caption = COMM +comm.width = -16 +comm.metric = bpf.exitsnoop.comm +comm.format = command diff --git a/vendor/github.com/htop-dev/htop/pcp/screens/filesystems b/vendor/github.com/htop-dev/htop/pcp/screens/filesystems new file mode 100644 index 0000000000..06f3bf2369 --- /dev/null +++ b/vendor/github.com/htop-dev/htop/pcp/screens/filesystems @@ -0,0 +1,50 @@ +# +# pcp-htop(1) configuration file - see pcp-htop(5) +# + +[filesystems] +heading = Filesystems +caption = Mounted block device filesystems + +blockdev.heading = Device +blockdev.metric = filesys.mountdir +blockdev.instances = true +blockdev.width = -14 + +blocksize.heading = BSIZE +blocksize.metric = filesys.blocksize +blocksize.default = false + +capacity.heading = SIZE +capacity.metric = filesys.capacity + +used.heading = USED +used.metric = filesys.used + +free.heading = FREE +free.metric = filesys.free +free.default = false + +avail.heading = AVAIL +avail.metric = filesys.avail + +full.heading = USE% +full.metric = filesys.full +full.format = percent + +usedfiles.heading = USEDF +usedfiles.metric = filesys.usedfiles +usedfiles.default = false + +freefiles.heading = FREEF +freefiles.metric = filesys.freefiles +freefiles.default = false + +maxfiles.heading = MAXF +maxfiles.metric = filesys.maxfiles +maxfiles.default = false + +mountdir.heading = Mount point +mountdir.metric = filesys.mountdir +mountdir.format = path +mountdir.width = -33 diff --git a/vendor/github.com/htop-dev/htop/pcp/screens/opensnoop b/vendor/github.com/htop-dev/htop/pcp/screens/opensnoop new file mode 100644 index 0000000000..ec209b03f3 --- /dev/null +++ b/vendor/github.com/htop-dev/htop/pcp/screens/opensnoop @@ -0,0 +1,27 @@ +# +# pcp-htop(1) configuration file - see pcp-htop(5) +# + +[opensnoop] +heading = OpenSnoop +caption = BPF open(2) syscall snoop +default = false + +pid.heading = PID +pid.metric = bpf.opensnoop.pid +pid.format = process + +comm.heading = COMM +comm.metric = bpf.opensnoop.comm +comm.format = command + +fd.heading = FD +fd.metric = bpf.opensnoop.fd + +err.heading = ERR +err.metric = bpf.opensnoop.err + +file.heading = File name +file.width = -32 +file.metric = bpf.opensnoop.fname +file.format = path diff --git a/vendor/github.com/htop-dev/htop/solaris/Platform.c b/vendor/github.com/htop-dev/htop/solaris/Platform.c index 95c50b4d74..f14ae2e921 100644 --- a/vendor/github.com/htop-dev/htop/solaris/Platform.c +++ b/vendor/github.com/htop-dev/htop/solaris/Platform.c @@ -34,6 +34,7 @@ in the source distribution for its full text. #include "HostnameMeter.h" #include "SysArchMeter.h" #include "UptimeMeter.h" +#include "XUtils.h" #include "solaris/SolarisMachine.h" @@ -221,14 +222,13 @@ double Platform_setCPUValues(Meter* this, unsigned int cpu) { v[CPU_METER_KERNEL] = cpuData->systemPercent; v[CPU_METER_IRQ] = cpuData->irqPercent; this->curItems = 4; - percent = v[CPU_METER_NICE] + v[CPU_METER_NORMAL] + v[CPU_METER_KERNEL] + v[CPU_METER_IRQ]; } else { v[CPU_METER_KERNEL] = cpuData->systemAllPercent; this->curItems = 3; - percent = v[CPU_METER_NICE] + v[CPU_METER_NORMAL] + v[CPU_METER_KERNEL]; } - percent = isnan(percent) ? 0.0 : CLAMP(percent, 0.0, 100.0); + percent = sumPositiveValues(v, this->curItems); + percent = MINIMUM(percent, 100.0); v[CPU_METER_FREQUENCY] = cpuData->frequency; v[CPU_METER_TEMPERATURE] = NAN; diff --git a/vendor/github.com/htop-dev/htop/solaris/Platform.h b/vendor/github.com/htop-dev/htop/solaris/Platform.h index 3dc6e3b593..00bc5832c1 100644 --- a/vendor/github.com/htop-dev/htop/solaris/Platform.h +++ b/vendor/github.com/htop-dev/htop/solaris/Platform.h @@ -150,7 +150,7 @@ static inline Hashtable* Platform_dynamicColumns(void) { static inline void Platform_dynamicColumnsDone(ATTR_UNUSED Hashtable* table) { } -static inline const char* Platform_dynamicColumnInit(ATTR_UNUSED unsigned int key) { +static inline const char* Platform_dynamicColumnName(ATTR_UNUSED unsigned int key) { return NULL; } @@ -158,4 +158,16 @@ static inline bool Platform_dynamicColumnWriteField(ATTR_UNUSED const Process* p return false; } +static inline Hashtable* Platform_dynamicScreens(void) { + return NULL; +} + +static inline void Platform_defaultDynamicScreens(ATTR_UNUSED Settings* settings) { } + +static inline void Platform_addDynamicScreen(ATTR_UNUSED ScreenSettings* ss) { } + +static inline void Platform_addDynamicScreenAvailableColumns(ATTR_UNUSED Panel* availableColumns, ATTR_UNUSED const char* screen) { } + +static inline void Platform_dynamicScreensDone(ATTR_UNUSED Hashtable* screens) { } + #endif diff --git a/vendor/github.com/htop-dev/htop/solaris/SolarisProcess.c b/vendor/github.com/htop-dev/htop/solaris/SolarisProcess.c index 3b5ea1ae5c..2ec3c1d528 100644 --- a/vendor/github.com/htop-dev/htop/solaris/SolarisProcess.c +++ b/vendor/github.com/htop-dev/htop/solaris/SolarisProcess.c @@ -73,8 +73,8 @@ void Process_delete(Object* cast) { free(sp); } -static void SolarisProcess_writeField(const Process* this, RichString* str, ProcessField field) { - const SolarisProcess* sp = (const SolarisProcess*) this; +static void SolarisProcess_rowWriteField(const Row* super, RichString* str, ProcessField field) { + const SolarisProcess* sp = (const SolarisProcess*) super; char buffer[256]; buffer[255] = '\0'; int attr = CRT_colors[DEFAULT_COLOR]; int n = sizeof(buffer) - 1; @@ -85,13 +85,13 @@ static void SolarisProcess_writeField(const Process* this, RichString* str, Proc case TASKID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, sp->taskid); break; case POOLID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, sp->poolid); break; case CONTID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, sp->contid); break; - case ZONE: Process_printLeftAlignedField(str, attr, sp->zname ? sp->zname : "global", ZONENAME_MAX/4); return; + case ZONE: Row_printLeftAlignedField(str, attr, sp->zname ? sp->zname : "global", ZONENAME_MAX/4); return; case PID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, sp->realpid); break; case PPID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, sp->realppid); break; case TGID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, sp->realtgid); break; case LWPID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, sp->lwpid); break; default: - Process_writeField(this, str, field); + Process_writeField(&sp->super, str, field); return; } RichString_appendWide(str, attr, buffer); @@ -127,11 +127,18 @@ static int SolarisProcess_compareByKey(const Process* v1, const Process* v2, Pro const ProcessClass SolarisProcess_class = { .super = { - .extends = Class(Process), - .display = Process_display, - .delete = Process_delete, - .compare = Process_compare + .super = { + .extends = Class(Process), + .display = Row_display, + .delete = Process_delete, + .compare = Process_compare + }, + .isHighlighted = Process_rowIsHighlighted, + .isVisible = Process_rowIsVisible, + .matchesFilter = Process_rowMatchesFilter, + .compareByParent = Process_compareByParent, + .sortKeyString = Process_rowGetSortKey, + .writeField = SolarisProcess_rowWriteField }, - .writeField = SolarisProcess_writeField, .compareByKey = SolarisProcess_compareByKey }; diff --git a/vendor/github.com/htop-dev/htop/solaris/SolarisProcessList.c b/vendor/github.com/htop-dev/htop/solaris/SolarisProcessList.c index e759b18772..46067a7bad 100644 --- a/vendor/github.com/htop-dev/htop/solaris/SolarisProcessList.c +++ b/vendor/github.com/htop-dev/htop/solaris/SolarisProcessList.c @@ -45,18 +45,19 @@ static char* SolarisProcessList_readZoneName(kstat_ctl_t* kd, SolarisProcess* sp } ProcessList* ProcessList_new(Machine* host, Hashtable* pidMatchList) { - SolarisProcessList* spl = xCalloc(1, sizeof(SolarisProcessList)); - ProcessList* pl = (ProcessList*) spl; + SolarisProcessList* this = xCalloc(1, sizeof(SolarisProcessList)); + Object_setClass(this, Class(ProcessList)); - ProcessList_init(pl, Class(SolarisProcess), host, pidMatchList); + ProcessList* super = &this->super; + ProcessList_init(super, Class(SolarisProcess), host, pidMatchList); - return pl; + return super; } -void ProcessList_delete(ProcessList* pl) { - SolarisProcessList* spl = (SolarisProcessList*) pl; - ProcessList_done(pl); - free(spl); +void ProcessList_delete(Object* cast) { + SolarisProcessList* this = (SolarisProcessList*) cast; + ProcessList_done(&this->super); + free(this); } static void SolarisProcessList_updateExe(pid_t pid, Process* proc) { @@ -183,8 +184,8 @@ static int SolarisProcessList_walkproc(psinfo_t* _psinfo, lwpsinfo_t* _lwpsinfo, // End common code pass 1 if (onMasterLWP) { // Are we on the representative LWP? - proc->ppid = (_psinfo->pr_ppid * 1024); - proc->tgid = (_psinfo->pr_ppid * 1024); + Process_setParent(proc, (_psinfo->pr_ppid * 1024)); + Process_setThreadGroup(proc, (_psinfo->pr_ppid * 1024)); sproc->realppid = _psinfo->pr_ppid; sproc->realtgid = _psinfo->pr_ppid; @@ -224,8 +225,8 @@ static int SolarisProcessList_walkproc(psinfo_t* _psinfo, lwpsinfo_t* _lwpsinfo, proc->time = _lwpsinfo->pr_time.tv_sec * 100 + _lwpsinfo->pr_time.tv_nsec / 10000000; if (!preExisting) { // Tasks done only for NEW LWPs proc->isUserlandThread = true; - proc->ppid = _psinfo->pr_pid * 1024; - proc->tgid = _psinfo->pr_pid * 1024; + Process_setParent(proc, _psinfo->pr_pid * 1024); + Process_setThreadGroup(proc, _psinfo->pr_pid * 1024); sproc->realppid = _psinfo->pr_pid; sproc->realtgid = _psinfo->pr_pid; proc->starttime_ctime = _lwpsinfo->pr_start.tv_sec; @@ -233,10 +234,10 @@ static int SolarisProcessList_walkproc(psinfo_t* _psinfo, lwpsinfo_t* _lwpsinfo, // Top-level process only gets this for the representative LWP if (proc->isKernelThread && !settings->hideKernelThreads) { - proc->show = true; + proc->super.show = true; } if (!proc->isKernelThread && !settings->hideUserlandThreads) { - proc->show = true; + proc->super.show = true; } } // Top-level LWP or subordinate LWP @@ -253,7 +254,7 @@ static int SolarisProcessList_walkproc(psinfo_t* _psinfo, lwpsinfo_t* _lwpsinfo, ProcessList_add(pl, proc); } - proc->updated = true; + proc->super.updated = true; // End common code pass 2 diff --git a/vendor/github.com/htop-dev/htop/unsupported/Platform.h b/vendor/github.com/htop-dev/htop/unsupported/Platform.h index a718ca09ed..8e08dc238d 100644 --- a/vendor/github.com/htop-dev/htop/unsupported/Platform.h +++ b/vendor/github.com/htop-dev/htop/unsupported/Platform.h @@ -98,7 +98,7 @@ static inline Hashtable* Platform_dynamicColumns(void) { static inline void Platform_dynamicColumnsDone(ATTR_UNUSED Hashtable* table) { } -static inline const char* Platform_dynamicColumnInit(ATTR_UNUSED unsigned int key) { +static inline const char* Platform_dynamicColumnName(ATTR_UNUSED unsigned int key) { return NULL; } @@ -106,4 +106,16 @@ static inline bool Platform_dynamicColumnWriteField(ATTR_UNUSED const Process* p return false; } +static inline Hashtable* Platform_dynamicScreens(void) { + return NULL; +} + +static inline void Platform_defaultDynamicScreens(ATTR_UNUSED Settings* settings) { } + +static inline void Platform_addDynamicScreen(ATTR_UNUSED ScreenSettings* ss) { } + +static inline void Platform_addDynamicScreenAvailableColumns(ATTR_UNUSED Panel* availableColumns, ATTR_UNUSED const char* screen) { } + +static inline void Platform_dynamicScreensDone(ATTR_UNUSED Hashtable* screens) { } + #endif diff --git a/vendor/github.com/htop-dev/htop/unsupported/UnsupportedProcess.c b/vendor/github.com/htop-dev/htop/unsupported/UnsupportedProcess.c index 4d8cb08036..6df2e36a40 100644 --- a/vendor/github.com/htop-dev/htop/unsupported/UnsupportedProcess.c +++ b/vendor/github.com/htop-dev/htop/unsupported/UnsupportedProcess.c @@ -58,21 +58,20 @@ void Process_delete(Object* cast) { free(cast); } -static void UnsupportedProcess_writeField(const Process* this, RichString* str, ProcessField field) { - const UnsupportedProcess* up = (const UnsupportedProcess*) this; - bool coloring = this->host->settings->highlightMegabytes; +static void UnsupportedProcess_rowWriteField(const Row* super, RichString* str, ProcessField field) { + const UnsupportedProcess* up = (const UnsupportedProcess*) super; + bool coloring = super->host->settings->highlightMegabytes; char buffer[256]; buffer[255] = '\0'; int attr = CRT_colors[DEFAULT_COLOR]; size_t n = sizeof(buffer) - 1; - (void) up; (void) coloring; (void) n; switch (field) { /* Add platform specific fields */ default: - Process_writeField(this, str, field); + Process_writeField(&up->super, str, field); return; } RichString_appendWide(str, attr, buffer); @@ -94,11 +93,18 @@ static int UnsupportedProcess_compareByKey(const Process* v1, const Process* v2, const ProcessClass UnsupportedProcess_class = { .super = { - .extends = Class(Process), - .display = Process_display, - .delete = Process_delete, - .compare = Process_compare + .super = { + .extends = Class(Process), + .display = Row_display, + .delete = Process_delete, + .compare = Process_compare + }, + .isHighlighted = Process_rowIsHighlighted, + .isVisible = Process_rowIsVisible, + .matchesFilter = Process_rowMatchesFilter, + .compareByParent = Process_compareByParent, + .sortKeyString = Process_rowGetSortKey, + .writeField = UnsupportedProcess_rowWriteField }, - .writeField = UnsupportedProcess_writeField, .compareByKey = UnsupportedProcess_compareByKey }; diff --git a/vendor/github.com/htop-dev/htop/unsupported/UnsupportedProcessList.c b/vendor/github.com/htop-dev/htop/unsupported/UnsupportedProcessList.c index e56f49782f..1e29c17a1a 100644 --- a/vendor/github.com/htop-dev/htop/unsupported/UnsupportedProcessList.c +++ b/vendor/github.com/htop-dev/htop/unsupported/UnsupportedProcessList.c @@ -15,15 +15,18 @@ in the source distribution for its full text. ProcessList* ProcessList_new(Machine* host, Hashtable* pidMatchList) { - ProcessList* this = xCalloc(1, sizeof(ProcessList)); + UnsupportedProcessList* this = xCalloc(1, sizeof(UnsupportedProcessList)); + Object_setClass(this, Class(ProcessList)); - ProcessList_init(this, Class(Process), host, pidMatchList); + ProcessList* super = &this->super; + ProcessList_init(super, Class(Process), host, pidMatchList); return this; } -void ProcessList_delete(ProcessList* this) { - ProcessList_done(this); +void ProcessList_delete(Object* cast) { + UnsupportedProcessList* this = (UnsupportedProcessList*) cast; + ProcessList_done(&this->super); free(this); } @@ -35,9 +38,9 @@ void ProcessList_goThroughEntries(ProcessList* super) { /* Empty values */ proc->time = proc->time + 10; - proc->pid = 1; - proc->ppid = 1; - proc->tgid = 0; + Process_setPid(proc, 1); + Process_setParent(proc, 1); + Process_setThreadGroup(proc, 0); Process_updateComm(proc, "commof16char"); Process_updateCmdline(proc, "", 0, 0); @@ -48,12 +51,12 @@ void ProcessList_goThroughEntries(ProcessList* super) { free_and_xStrdup(&proc->procCwd, "/current/working/directory"); } - proc->updated = true; + proc->super.updated = true; proc->state = RUNNING; proc->isKernelThread = false; proc->isUserlandThread = false; - proc->show = true; /* Reflected in settings-> "hideXXX" really */ + proc->super.show = true; /* Reflected in settings-> "hideXXX" really */ proc->pgrp = 0; proc->session = 0; proc->tty_nr = 0;