.editorconfig
.editorconfig
file: .editorconfig
# EditorConfig configuration for htop
# http://EditorConfig.org
# top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file, utf-8 charset
[*]
end_of_line = lf
insert_final_newline = true
charset = utf-8
# match C source and header files, set indent to three spaces
[*.{c,h}]
indent_style = space
indent_size = 3
trim_trailing_whitespace = true
dependabot.yml
.github/dependabot.yml
file: dependabot.yml
---
version: 2
updates:
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
FUNDING.yml
.github/FUNDING.yml
file: FUNDING.yml
custom: ["https://hcb.hackclub.com/donations/start/htop"]
build_release.yml
.github/workflows/build_release.yml
file: build_release.yml
name: Build Source Release
# Trigger whenever a release is created
on:
release:
types:
- created
jobs:
build:
name: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: archive
id: archive
run: |
VERSION=${{ github.event.release.tag_name }}
PKGNAME="htop-$VERSION"
SHASUM=$PKGNAME.tar.xz.sha256
autoreconf -i
mkdir -p /tmp/$PKGNAME
mv * /tmp/$PKGNAME
mv /tmp/$PKGNAME .
TARBALL=$PKGNAME.tar.xz
tar cJf $TARBALL $PKGNAME
sha256sum $TARBALL > $SHASUM
echo "::set-output name=tarball::$TARBALL"
echo "::set-output name=shasum::$SHASUM"
- name: upload tarball
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ github.event.release.upload_url }}
asset_path: ./${{ steps.archive.outputs.tarball }}
asset_name: ${{ steps.archive.outputs.tarball }}
asset_content_type: application/gzip
- name: upload shasum
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ github.event.release.upload_url }}
asset_path: ./${{ steps.archive.outputs.shasum }}
asset_name: ${{ steps.archive.outputs.shasum }}
asset_content_type: text/plain
ci.yml
.github/workflows/ci.yml
file: ci.yml
codeql-analysis.yml
.github/workflows/codeql-analysis.yml
file: codeql-analysis.yml
name: "CodeQL"
on:
push:
branches: [main]
pull_request:
branches: [main]
schedule:
- cron: '0 1 * * 0'
permissions:
contents: read
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
security-events: write
env:
# Enable format attributes in ncurses headers
# Enable fortified memory/string handling
CPPFLAGS: -DGCC_PRINTF -DGCC_SCANF -D_FORTIFY_SOURCE=2
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: cpp
- name: Install Dependencies
run: sudo apt-get install --no-install-recommends libncursesw5-dev libhwloc-dev libnl-3-dev libnl-genl-3-dev libsensors-dev libcap-dev
- name: Bootstrap
run: ./autogen.sh
- name: Configure
run: ./configure --enable-werror --enable-openvz --enable-vserver --enable-ancient-vserver --enable-unicode --enable-hwloc --enable-delayacct --enable-sensors --enable-capabilities
- name: Build
run: make
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
htoprc
.github/workflows/htoprc
file: htoprc
.gitignore
.gitignore
file: .gitignore
# the binaries: htop pcp-htop # all object files *.o # skip all backups *.bak *~ .*.sw? # skip coverage files *.gcda */*.gcda *.gcno */*.gcno *.h.gch */.dirstamp # automake/autoconf related files .deps/ Makefile Makefile.in INSTALL aclocal.m4 autom4te.cache/ compile conf*/ config.guess config.h config.h.in config.log config.status config.cache config.sub configure depcomp htop.1 pcp-htop.5 install-sh libtool ltmain.sh m4/ missing stamp-h1 # files related to valgrind/callgrind callgrind.out.* # IDE workspace configurations /.idea/ /.vscode/ # Language Servers /.cache/clangd/
.travis.yml
.travis.yml
file: .travis.yml
language: c compiler: - clang - gcc os: - freebsd script: - ./autogen.sh - ./configure --enable-werror - make -k - make distcheck DISTCHECK_CONFIGURE_FLAGS=--enable-werror - sudo make install - make installcheck
Action.c
Action.c
file: Action.c
Action.h
Action.h
enum: Htop_Reaction
typedef enum {
HTOP_OK = 0x00,
HTOP_REFRESH = 0x01,
HTOP_RECALCULATE = 0x02 | HTOP_REFRESH,
HTOP_SAVE_SETTINGS = 0x04,
HTOP_KEEP_FOLLOWING = 0x08,
HTOP_QUIT = 0x10,
HTOP_REDRAW_BAR = 0x20,
HTOP_UPDATE_PANELHDR = 0x40 | HTOP_REFRESH,
HTOP_RESIZE = 0x80 | HTOP_REFRESH | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR,
} Htop_Reaction;function: Action_follow
Htop_Reaction Action_follow(State* st);
function: Action_pickFromVector
Object* Action_pickFromVector(State* st, Panel* list, int x, bool follow);
function: Action_setBindings
void Action_setBindings(Htop_Action* keys);
function: Action_setScreenTab
Htop_Reaction Action_setScreenTab(State* st, int x);
function: Action_setSortKey
Htop_Reaction Action_setSortKey(Settings* settings, ProcessField sortKey);
function: Action_setUserOnly
bool Action_setUserOnly(const char* userName, uid_t* userId);
function: State_hideFunctionBar
static inline bool State_hideFunctionBar(const State* st) {
const Settings* settings = st->host->settings;
return settings->hideFunctionBar == 2 || (settings->hideFunctionBar == 1 && st->hideSelection);
}struct: MainPanel_
struct MainPanel_;
struct: State
typedef struct State_ {
Machine* host;
struct MainPanel_* mainPanel;
Header* header;
bool pauseUpdate;
bool hideSelection;
bool hideMeters;
} State;typedef: Htop_Action
typedef Htop_Reaction (*Htop_Action)(State* st);
Affinity.c
Affinity.c
function: Affinity_add
void Affinity_add(Affinity* this, unsigned int id) {
if (this->used == this->size) {
this->size *= 2;
this->cpus = xRealloc(this->cpus, sizeof(unsigned int) * this->size);
}
this->cpus[this->used] = id;
this->used++;
}function: Affinity_delete
void Affinity_delete(Affinity* this) {
free(this->cpus);
free(this);
}function: Affinity_get (hwloc implementation)
static Affinity* Affinity_get(const Process* p, Machine* host) {
hwloc_cpuset_t cpuset = hwloc_bitmap_alloc();
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);
if (hwloc_bitmap_last(cpuset) == -1) {
for (unsigned int i = 0; i < host->existingCPUs; i++) {
Affinity_add(affinity, i);
}
} else {
int id;
hwloc_bitmap_foreach_begin(id, cpuset)
Affinity_add(affinity, (unsigned)id);
hwloc_bitmap_foreach_end();
}
}
hwloc_bitmap_free(cpuset);
return affinity;
}function: Affinity_get (sched.h implementation)
static Affinity* Affinity_get(const Process* p, Machine* host) {
cpu_set_t cpuset;
bool ok = (sched_getaffinity(Process_getPid(p), sizeof(cpu_set_t), &cpuset) == 0);
if (!ok)
return NULL;
Affinity* affinity = Affinity_new(host);
for (unsigned int i = 0; i < host->existingCPUs; i++) {
if (CPU_ISSET(i, &cpuset)) {
Affinity_add(affinity, i);
}
}
return affinity;
}function: Affinity_new
Affinity* Affinity_new(Machine* host) {
Affinity* this = xCalloc(1, sizeof(Affinity));
this->size = 8;
this->cpus = xCalloc(this->size, sizeof(unsigned int));
this->host = host;
return this;
}function: Affinity_rowGet
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);
}function: Affinity_rowSet
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);
}function: Affinity_set (hwloc implementation)
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, Process_getPid(p), cpuset, HTOP_HWLOC_CPUBIND_FLAG) == 0);
hwloc_bitmap_free(cpuset);
return ok;
}function: Affinity_set (sched.h implementation)
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(Process_getPid(p), sizeof(unsigned long), &cpuset) == 0);
return ok;
}Affinity.h
Affinity.h
function: Affinity_add
void Affinity_add(Affinity* this, unsigned int id);
function: Affinity_delete
void Affinity_delete(Affinity* this);
function: Affinity_new
Affinity* Affinity_new(Machine* host);
function: Affinity_rowGet
#if defined(HAVE_LIBHWLOC) || defined(HAVE_AFFINITY) Affinity* Affinity_rowGet(const Row* row, Machine* host); #endif /* HAVE_LIBHWLOC || HAVE_AFFINITY */
function: Affinity_rowSet
#if defined(HAVE_LIBHWLOC) || defined(HAVE_AFFINITY) bool Affinity_rowSet(Row* row, Arg arg); #endif /* HAVE_LIBHWLOC || HAVE_AFFINITY */
struct: Affinity_
typedef struct Affinity_ {
Machine* host;
unsigned int size;
unsigned int used;
unsigned int* cpus;
} Affinity;AffinityPanel.c
AffinityPanel.c
array: AffinityPanelEvents
static const int AffinityPanelEvents[] = {13, 27, KEY_F(1), KEY_F(2), KEY_F(3)};array: AffinityPanelFunctions
static const char* const AffinityPanelFunctions[] = {
"Set ",
"Cancel ",
#ifdef HAVE_LIBHWLOC
"All",
"Topology",
" ",
#endif
NULL
};array: AffinityPanelKeys
static const char* const AffinityPanelKeys[] = {"Enter", "Esc", "F1", "F2", "F3"};class: AffinityPanel_class
const PanelClass AffinityPanel_class = {
.super = {
.extends = Class(Panel),
.delete = AffinityPanel_delete
},
.eventHandler = AffinityPanel_eventHandler
};class: MaskItem_class
static const ObjectClass MaskItem_class = {
.display = MaskItem_display,
.delete = MaskItem_delete
};function: AffinityPanel_addObject
function: AffinityPanel_buildTopology
#ifdef HAVE_LIBHWLOC
static MaskItem* AffinityPanel_buildTopology(AffinityPanel* this, hwloc_obj_t obj, unsigned indent, MaskItem* parent) {
MaskItem* item = AffinityPanel_addObject(this, obj, indent, parent);
if (obj->next_sibling) {
indent |= (1U << obj->depth);
} else {
indent &= ~(1U << obj->depth);
}
for (unsigned i = 0; i < obj->arity; i++) {
AffinityPanel_buildTopology(this, obj->children[i], indent, item);
}
return parent == NULL ? item : NULL;
}
#endiffunction: AffinityPanel_delete
static void AffinityPanel_delete(Object* cast) {
AffinityPanel* this = (AffinityPanel*) cast;
Vector_delete(this->cpuids);
#ifdef HAVE_LIBHWLOC
hwloc_bitmap_free(this->workCpuset);
MaskItem_delete((Object*) this->topoRoot);
#endif
Panel_done(&this->super);
free(this);
}function: AffinityPanel_eventHandler
static HandlerResult AffinityPanel_eventHandler(Panel* super, int ch) {
AffinityPanel* this = (AffinityPanel*) super;
HandlerResult result = IGNORED;
MaskItem* selected = (MaskItem*) Panel_getSelected(super);
bool keepSelected = true;
switch (ch) {
case KEY_MOUSE:
case KEY_RECLICK:
case ' ':
if (!selected) {
return result;
}
#ifdef HAVE_LIBHWLOC
if (selected->value == 2) {
/* Item was selected, so remove this mask from the top cpuset. */
hwloc_bitmap_andnot(this->workCpuset, this->workCpuset, selected->cpuset);
selected->value = 0;
} else {
/* Item was not or only partial selected, so set all bits from this object
in the top cpuset. */
hwloc_bitmap_or(this->workCpuset, this->workCpuset, selected->cpuset);
selected->value = 2;
}
#else
selected->value = selected->value ? 0 : 2; /* toggle between 0 and 2 */
#endif
result = HANDLED;
break;
#ifdef HAVE_LIBHWLOC
case KEY_F(1):
hwloc_bitmap_copy(this->workCpuset, this->allCpuset);
result = HANDLED;
break;
case KEY_F(2):
this->topoView = !this->topoView;
keepSelected = false;
result = HANDLED;
break;
case KEY_F(3):
case '-':
case '+':
if (!selected) {
break;
}
if (selected->sub_tree) {
selected->sub_tree = 1 + !(selected->sub_tree - 1); /* toggle between 1 and 2 */
}
result = HANDLED;
break;
#endif
case 0x0a:
case 0x0d:
case KEY_ENTER:
result = BREAK_LOOP;
break;
}
if (HANDLED == result)
AffinityPanel_update(this, keepSelected);
return result;
}function: AffinityPanel_getAffinity
Affinity* AffinityPanel_getAffinity(Panel* super, Machine* host) {
const AffinityPanel* this = (AffinityPanel*) super;
Affinity* affinity = Affinity_new(host);
#ifdef HAVE_LIBHWLOC
int i;
hwloc_bitmap_foreach_begin(i, this->workCpuset)
Affinity_add(affinity, (unsigned)i);
hwloc_bitmap_foreach_end();
#else
for (int i = 0; i < Vector_size(this->cpuids); i++) {
const MaskItem* item = (const MaskItem*)Vector_get(this->cpuids, i);
if (item->value) {
Affinity_add(affinity, item->cpu);
}
}
#endif
return affinity;
}function: AffinityPanel_new
Panel* AffinityPanel_new(Machine* host, const Affinity* affinity, int* width) {
AffinityPanel* this = AllocThis(AffinityPanel);
Panel* super = &this->super;
Panel_init(super, 1, 1, 1, 1, Class(MaskItem), false, FunctionBar_new(AffinityPanelFunctions, AffinityPanelKeys, AffinityPanelEvents));
this->host = host;
/* defaults to 15, this also includes the gap between the panels,
* but this will be added by the caller */
this->width = 14;
this->cpuids = Vector_new(Class(MaskItem), true, DEFAULT_SIZE);
#ifdef HAVE_LIBHWLOC
this->topoView = host->settings->topologyAffinity;
#else
this->topoView = false;
#endif
#ifdef HAVE_LIBHWLOC
this->allCpuset = hwloc_topology_get_complete_cpuset(host->topology);
this->workCpuset = hwloc_bitmap_alloc();
#endif
Panel_setHeader(super, "Use CPUs:");
unsigned int curCpu = 0;
for (unsigned int i = 0; i < host->existingCPUs; i++) {
if (!Machine_isCPUonline(host, i))
continue;
char number[16];
xSnprintf(number, 9, "CPU %d", Settings_cpuId(host->settings, i));
unsigned cpu_width = 4 + strlen(number);
if (cpu_width > this->width) {
this->width = cpu_width;
}
bool isSet = false;
if (curCpu < affinity->used && affinity->cpus[curCpu] == i) {
#ifdef HAVE_LIBHWLOC
hwloc_bitmap_set(this->workCpuset, i);
#endif
isSet = true;
curCpu++;
}
MaskItem* cpuItem = MaskItem_newSingleton(number, i, isSet);
Vector_add(this->cpuids, (Object*) cpuItem);
}
#ifdef HAVE_LIBHWLOC
this->topoRoot = AffinityPanel_buildTopology(this, hwloc_get_root_obj(host->topology), 0, NULL);
#endif
if (width) {
*width = this->width;
}
AffinityPanel_update(this, false);
return super;
}function: AffinityPanel_update
static void AffinityPanel_update(AffinityPanel* this, bool keepSelected) {
Panel* super = &this->super;
FunctionBar_setLabel(super->currentBar, KEY_F(3), this->topoView ? "Collapse/Expand" : "");
int oldSelected = Panel_getSelectedIndex(super);
Panel_prune(super);
#ifdef HAVE_LIBHWLOC
if (this->topoView) {
AffinityPanel_updateTopo(this, this->topoRoot);
} else {
for (int i = 0; i < Vector_size(this->cpuids); i++) {
AffinityPanel_updateItem(this, (MaskItem*) Vector_get(this->cpuids, i));
}
}
#else
Panel_splice(super, this->cpuids);
#endif
if (keepSelected)
Panel_setSelected(super, oldSelected);
super->needsRedraw = true;
}function: AffinityPanel_updateItem
#ifdef HAVE_LIBHWLOC
static void AffinityPanel_updateItem(AffinityPanel* this, MaskItem* item) {
Panel* super = &this->super;
item->value = hwloc_bitmap_isincluded(item->cpuset, this->workCpuset) ? 2 :
hwloc_bitmap_intersects(item->cpuset, this->workCpuset) ? 1 : 0;
Panel_add(super, (Object*) item);
}
#endiffunction: AffinityPanel_updateTopo
#ifdef HAVE_LIBHWLOC
static void AffinityPanel_updateTopo(AffinityPanel* this, MaskItem* item) {
AffinityPanel_updateItem(this, item);
if (item->sub_tree == 2)
return;
for (int i = 0; i < Vector_size(item->children); i++)
AffinityPanel_updateTopo(this, (MaskItem*) Vector_get(item->children, i));
}
#endiffunction: MaskItem_delete
static void MaskItem_delete(Object* cast) {
MaskItem* this = (MaskItem*) cast;
free(this->text);
free(this->indent);
Vector_delete(this->children);
#ifdef HAVE_LIBHWLOC
if (this->ownCpuset)
hwloc_bitmap_free(this->cpuset);
#endif
free(this);
}function: MaskItem_display
static void MaskItem_display(const Object* cast, RichString* out) {
const MaskItem* this = (const MaskItem*)cast;
assert (this != NULL);
RichString_appendAscii(out, CRT_colors[CHECK_BOX], "[");
if (this->value == 2) {
RichString_appendAscii(out, CRT_colors[CHECK_MARK], "x");
} else if (this->value == 1) {
RichString_appendAscii(out, CRT_colors[CHECK_MARK], "o");
} else {
RichString_appendAscii(out, CRT_colors[CHECK_MARK], " ");
}
RichString_appendAscii(out, CRT_colors[CHECK_BOX], "]");
RichString_appendAscii(out, CRT_colors[CHECK_TEXT], " ");
if (this->indent) {
RichString_appendWide(out, CRT_colors[PROCESS_TREE], this->indent);
RichString_appendWide(out, CRT_colors[PROCESS_TREE],
this->sub_tree == 2
? CRT_treeStr[TREE_STR_OPEN]
: CRT_treeStr[TREE_STR_SHUT]);
RichString_appendAscii(out, CRT_colors[CHECK_TEXT], " ");
}
RichString_appendWide(out, CRT_colors[CHECK_TEXT], this->text);
}function: MaskItem_newMask
#ifdef HAVE_LIBHWLOC
static MaskItem* MaskItem_newMask(const char* text, const char* indent, hwloc_bitmap_t cpuset, bool owner) {
MaskItem* this = AllocThis(MaskItem);
this->text = xStrdup(text);
this->indent = xStrdup(indent); /* nonnull for tree node */
this->value = 0;
this->ownCpuset = owner;
this->cpuset = cpuset;
this->sub_tree = hwloc_bitmap_weight(cpuset) > 1 ? 1 : 0;
this->children = Vector_new(Class(MaskItem), true, DEFAULT_SIZE);
return this;
}
#endiffunction: MaskItem_newSingleton
static MaskItem* MaskItem_newSingleton(const char* text, int cpu, bool isSet) {
MaskItem* this = AllocThis(MaskItem);
this->text = xStrdup(text);
this->indent = NULL; /* not a tree node */
this->sub_tree = 0;
this->children = Vector_new(Class(MaskItem), true, DEFAULT_SIZE);
#ifdef HAVE_LIBHWLOC
this->ownCpuset = true;
this->cpuset = hwloc_bitmap_alloc();
hwloc_bitmap_set(this->cpuset, cpu);
#else
this->cpu = cpu;
#endif
this->value = isSet ? 2 : 0;
return this;
}struct: AffinityPanel_
typedef struct AffinityPanel_ {
Panel super;
Machine* host;
bool topoView;
Vector* cpuids;
unsigned width;
#ifdef HAVE_LIBHWLOC
MaskItem* topoRoot;
hwloc_const_cpuset_t allCpuset;
hwloc_bitmap_t workCpuset;
#endif
} AffinityPanel;struct: MaskItem_
typedef struct MaskItem_ {
Object super;
char* text;
char* indent; /* used also as an condition whether this is a tree node */
int value; /* tri-state: 0 - off, 1 - some set, 2 - all set */
int sub_tree; /* tri-state: 0 - no sub-tree, 1 - open sub-tree, 2 - closed sub-tree */
Vector* children;
#ifdef HAVE_LIBHWLOC
bool ownCpuset;
hwloc_bitmap_t cpuset;
#else
int cpu;
#endif
} MaskItem;AffinityPanel.h
AffinityPanel.h
function declaration: AffinityPanel_getAffinity
Affinity* AffinityPanel_getAffinity(Panel* super, Machine* host);
function declaration: AffinityPanel_new
Panel* AffinityPanel_new(Machine* host, const Affinity* affinity, int* width);
global constant declaration: AffinityPanel_class
extern const PanelClass AffinityPanel_class;
AUTHORS
AUTHORS
file: AUTHORS
Originally authored by: Hisham H. Muhammad Currently maintained by the htop dev team: Benny Baumann Christian Göttsche Daniel Lange Nathan Scott For the full list of contributors see: git log --format="%aN" | sort -u
autogen.sh
autogen.sh
script: autogen.sh
#!/bin/sh autoreconf --force --install --verbose -Wall
AvailableColumnsPanel.c
AvailableColumnsPanel.c
data structure: AvailableColumnsFunctions
static const char* const AvailableColumnsFunctions[] = {" ", " ", " ", " ", "Add ", " ", " ", " ", " ", "Done ", NULL};function: AvailableColumnsPanel_addDynamicColumn
static void AvailableColumnsPanel_addDynamicColumn(ht_key_t key, void* value, void* data) {
const DynamicColumn* column = (const DynamicColumn*) value;
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];
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));
}function: AvailableColumnsPanel_addDynamicColumns
static void AvailableColumnsPanel_addDynamicColumns(AvailableColumnsPanel* this, Hashtable* dynamicColumns) {
assert(dynamicColumns);
Hashtable_foreach(dynamicColumns, AvailableColumnsPanel_addDynamicColumn, this);
}function: AvailableColumnsPanel_addDynamicScreens
static void AvailableColumnsPanel_addDynamicScreens(AvailableColumnsPanel* this, const char* screen) {
Platform_addDynamicScreenAvailableColumns(&this->super, screen);
}function: AvailableColumnsPanel_addPlatformColumns
static void AvailableColumnsPanel_addPlatformColumns(AvailableColumnsPanel* this) {
for (int i = 1; i < LAST_PROCESSFIELD; i++) {
if (Process_fields[i].description) {
char description[256];
xSnprintf(description, sizeof(description), "%s - %s", Process_fields[i].name, Process_fields[i].description);
Panel_add(&this->super, (Object*) ListItem_new(description, i));
}
}
}function: AvailableColumnsPanel_delete
static void AvailableColumnsPanel_delete(Object* object) {
AvailableColumnsPanel* this = (AvailableColumnsPanel*) object;
Panel_done(&this->super);
free(this);
}function: AvailableColumnsPanel_eventHandler
static HandlerResult AvailableColumnsPanel_eventHandler(Panel* super, int ch) {
AvailableColumnsPanel* this = (AvailableColumnsPanel*) super;
HandlerResult result = IGNORED;
switch (ch) {
case 13:
case KEY_ENTER:
case KEY_F(5): {
const ListItem* selected = (ListItem*) Panel_getSelected(super);
if (!selected)
break;
int at = Panel_getSelectedIndex(this->columns);
AvailableColumnsPanel_insert(this, at, selected->key);
Panel_setSelected(this->columns, at + 1);
ColumnsPanel_update(this->columns);
result = HANDLED;
break;
}
default:
if (0 < ch && ch < 255 && isgraph((unsigned char)ch))
result = Panel_selectByTyping(super, ch);
break;
}
return result;
}function: AvailableColumnsPanel_fill
void AvailableColumnsPanel_fill(AvailableColumnsPanel* this, const char* dynamicScreen, Hashtable* dynamicColumns) {
Panel_prune(&this->super);
if (dynamicScreen) {
AvailableColumnsPanel_addDynamicScreens(this, dynamicScreen);
} else {
AvailableColumnsPanel_addPlatformColumns(this);
AvailableColumnsPanel_addDynamicColumns(this, dynamicColumns);
}
}function: AvailableColumnsPanel_insert
static void AvailableColumnsPanel_insert(AvailableColumnsPanel* this, int at, int key) {
const char* name;
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));
}function: AvailableColumnsPanel_new
AvailableColumnsPanel* AvailableColumnsPanel_new(Panel* columns, Hashtable* dynamicColumns) {
AvailableColumnsPanel* this = AllocThis(AvailableColumnsPanel);
Panel* super = &this->super;
FunctionBar* fuBar = FunctionBar_new(AvailableColumnsFunctions, NULL, NULL);
Panel_init(super, 1, 1, 1, 1, Class(ListItem), true, fuBar);
Panel_setHeader(super, "Available Columns");
this->columns = columns;
AvailableColumnsPanel_fill(this, NULL, dynamicColumns);
return this;
}struct: AvailableColumnsPanel
/* Implied structure based on usage in AvailableColumnsPanel.c */
typedef struct AvailableColumnsPanel_ {
Panel super; /* Inherits from Panel */
Panel* columns; /* Pointer to the target ColumnsPanel where selected columns are added */
} AvailableColumnsPanel;struct instance: AvailableColumnsPanel_class
const PanelClass AvailableColumnsPanel_class = {
.super = {
.extends = Class(Panel),
.delete = AvailableColumnsPanel_delete
},
.eventHandler = AvailableColumnsPanel_eventHandler
};AvailableColumnsPanel.h
AvailableColumnsPanel.h
extern const: AvailableColumnsPanel_class
extern const PanelClass AvailableColumnsPanel_class;
function: AvailableColumnsPanel_fill
void AvailableColumnsPanel_fill(AvailableColumnsPanel* this, const char* dynamicScreen, Hashtable* dynamicColumns);
function: AvailableColumnsPanel_new
AvailableColumnsPanel* AvailableColumnsPanel_new(Panel* columns, Hashtable* dynamicColumns);
struct: AvailableColumnsPanel_
typedef struct AvailableColumnsPanel_ {
Panel super;
Panel* columns;
} AvailableColumnsPanel;AvailableMetersPanel.c
AvailableMetersPanel.c
function: AvailableMetersPanel_addCPUMeters
static void AvailableMetersPanel_addCPUMeters(Panel* super, const MeterClass* type, const Machine* host) {
if (host->existingCPUs > 1) {
Panel_add(super, (Object*) ListItem_new("CPU average", 0));
for (unsigned int i = 1; i <= host->existingCPUs; i++) {
char buffer[50];
xSnprintf(buffer, sizeof(buffer), "%s %d", type->uiName, Settings_cpuId(host->settings, i - 1));
Panel_add(super, (Object*) ListItem_new(buffer, i));
}
} else {
Panel_add(super, (Object*) ListItem_new(type->uiName, 1));
}
}function: AvailableMetersPanel_addDynamicMeter
static void AvailableMetersPanel_addDynamicMeter(ATTR_UNUSED ht_key_t key, void* value, void* data) {
const DynamicMeter* meter = (const DynamicMeter*)value;
DynamicIterator* iter = (DynamicIterator*)data;
unsigned int identifier = (iter->offset << 16) | iter->id;
const char* label = meter->description ? meter->description : meter->caption;
if (!label)
label = meter->name; /* last fallback to name, guaranteed set */
Panel_add(iter->super, (Object*) ListItem_new(label, identifier));
iter->id++;
}function: AvailableMetersPanel_addDynamicMeters
static void AvailableMetersPanel_addDynamicMeters(Panel* super, const Settings* settings, unsigned int offset) {
DynamicIterator iter = { .super = super, .id = 1, .offset = offset };
Hashtable* dynamicMeters = settings->dynamicMeters;
assert(dynamicMeters != NULL);
Hashtable_foreach(dynamicMeters, AvailableMetersPanel_addDynamicMeter, &iter);
}function: AvailableMetersPanel_addMeter
static inline void AvailableMetersPanel_addMeter(Header* header, MetersPanel* panel, const MeterClass* type, unsigned int param, size_t column) {
const Meter* meter = Header_addMeterByClass(header, type, param, column);
Panel_add((Panel*)panel, (Object*) Meter_toListItem(meter, false));
Panel_setSelected((Panel*)panel, Panel_size((Panel*)panel) - 1);
MetersPanel_setMoving(panel, true);
}function: AvailableMetersPanel_addPlatformMeter
static void AvailableMetersPanel_addPlatformMeter(Panel* super, const MeterClass* type, unsigned int offset) {
const char* label = type->description ? type->description : type->uiName;
Panel_add(super, (Object*) ListItem_new(label, offset << 16));
}function: AvailableMetersPanel_delete
static void AvailableMetersPanel_delete(Object* object) {
AvailableMetersPanel* this = (AvailableMetersPanel*) object;
free(this->meterPanels);
Panel_done(&this->super);
free(this);
}function: AvailableMetersPanel_eventHandler
static HandlerResult AvailableMetersPanel_eventHandler(Panel* super, int ch) {
AvailableMetersPanel* this = (AvailableMetersPanel*) super;
Header* header = this->header;
const ListItem* selected = (ListItem*) Panel_getSelected(super);
if (!selected)
return IGNORED;
unsigned int param = selected->key & 0xffff;
int type = selected->key >> 16;
HandlerResult result = IGNORED;
bool update = false;
switch (ch) {
case KEY_F(5):
case 'l':
case 'L':
AvailableMetersPanel_addMeter(header, this->meterPanels[0], Platform_meterTypes[type], param, 0);
result = HANDLED;
update = true;
break;
case 0x0a:
case 0x0d:
case KEY_ENTER:
case KEY_F(6):
case 'r':
case 'R':
AvailableMetersPanel_addMeter(header, this->meterPanels[this->columns - 1], Platform_meterTypes[type], param, this->columns - 1);
result = (KEY_LEFT << 16) | SYNTH_KEY;
update = true;
break;
}
if (update) {
Settings* settings = this->host->settings;
settings->changed = true;
settings->lastUpdate++;
Header_calculateHeight(header);
Header_updateData(header);
Header_draw(header);
ScreenManager_resize(this->scr);
}
return result;
}function: AvailableMetersPanel_new
AvailableMetersPanel* AvailableMetersPanel_new(Machine* host, Header* header, size_t columns, MetersPanel** meterPanels, ScreenManager* scr) {
AvailableMetersPanel* this = AllocThis(AvailableMetersPanel);
Panel* super = &this->super;
FunctionBar* fuBar = FunctionBar_newEnterEsc("Add ", "Done ");
Panel_init(super, 1, 1, 1, 1, Class(ListItem), true, fuBar);
this->host = host;
this->header = header;
this->columns = columns;
this->meterPanels = meterPanels;
this->scr = scr;
Panel_setHeader(super, "Available meters");
// Platform_meterTypes[0] should be always (&CPUMeter_class) which we will
// handle separately in the code below. Likewise, identifiers for Dynamic
// Meters are handled separately - similar to CPUs, this allows generation
// of multiple different Meters (also using 'param' to distinguish them).
for (unsigned int i = 1; Platform_meterTypes[i]; i++) {
const MeterClass* type = Platform_meterTypes[i];
assert(type != &CPUMeter_class);
if (type == &DynamicMeter_class)
AvailableMetersPanel_addDynamicMeters(super, host->settings, i);
else
AvailableMetersPanel_addPlatformMeter(super, type, i);
}
AvailableMetersPanel_addCPUMeters(super, &CPUMeter_class, host);
return this;
}struct: AvailableMetersPanel_class
const PanelClass AvailableMetersPanel_class = {
.super = {
.extends = Class(Panel),
.delete = AvailableMetersPanel_delete
},
.eventHandler = AvailableMetersPanel_eventHandler
};struct: DynamicIterator
typedef struct {
Panel* super;
unsigned int id;
unsigned int offset;
} DynamicIterator;AvailableMetersPanel.h
AvailableMetersPanel.h
function: AvailableMetersPanel_new
AvailableMetersPanel* AvailableMetersPanel_new(Machine* host, Header* header, size_t columns, MetersPanel** meterPanels, ScreenManager* scr);
struct: AvailableMetersPanel_
typedef struct AvailableMetersPanel_ {
Panel super;
ScreenManager* scr;
Machine* host;
Header* header;
size_t columns;
MetersPanel** meterPanels;
} AvailableMetersPanel;variable: AvailableMetersPanel_class
extern const PanelClass AvailableMetersPanel_class;
BatteryMeter.c
BatteryMeter.c
function: BatteryMeter_updateValues
static void BatteryMeter_updateValues(Meter* this) {
ACPresence isOnAC;
double percent;
Platform_getBattery(&percent, &isOnAC);
if (!isNonnegative(percent)) {
this->values[0] = NAN;
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "N/A");
return;
}
this->values[0] = percent;
const char* text;
switch (isOnAC) {
case AC_PRESENT:
text = this->mode == TEXT_METERMODE ? " (Running on A/C)" : "(A/C)";
break;
case AC_ABSENT:
text = this->mode == TEXT_METERMODE ? " (Running on battery)" : "(bat)";
break;
case AC_ERROR:
default:
text = "";
break;
}
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "%.1f%%%s", percent, text);
}struct: BatteryMeter_class
const MeterClass BatteryMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete
},
.updateValues = BatteryMeter_updateValues,
.defaultMode = TEXT_METERMODE,
.supportedModes = METERMODE_DEFAULT_SUPPORTED,
.maxItems = 1,
.total = 100.0,
.attributes = BatteryMeter_attributes,
.name = "Battery",
.uiName = "Battery",
.caption = "Battery: "
};variable: BatteryMeter_attributes
static const int BatteryMeter_attributes[] = {
BATTERY
};BatteryMeter.h
BatteryMeter.h
struct: ACPresence
typedef enum ACPresence_ {
AC_ABSENT,
AC_PRESENT,
AC_ERROR
} ACPresence;struct: BatteryMeter_class
extern const MeterClass BatteryMeter_class;
CategoriesPanel.c
CategoriesPanel.c
function: CategoriesPanel_delete
static void CategoriesPanel_delete(Object* object) {
CategoriesPanel* this = (CategoriesPanel*) object;
Panel_done(&this->super);
free(this);
}function: CategoriesPanel_eventHandler
static HandlerResult CategoriesPanel_eventHandler(Panel* super, int ch) {
CategoriesPanel* this = (CategoriesPanel*) super;
HandlerResult result = IGNORED;
int selected = Panel_getSelectedIndex(super);
switch (ch) {
case EVENT_SET_SELECTED:
result = HANDLED;
break;
case KEY_UP:
case KEY_CTRL('P'):
case KEY_DOWN:
case KEY_CTRL('N'):
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 (0 < ch && ch < 255 && isgraph((unsigned char)ch))
result = Panel_selectByTyping(super, ch);
if (result == BREAK_LOOP)
result = IGNORED;
break;
}
if (result == HANDLED) {
int size = ScreenManager_size(this->scr);
for (int i = 1; i < size; i++)
ScreenManager_remove(this->scr, 1);
if (selected >= 0 && (size_t)selected < ARRAYSIZE(categoriesPanelPages)) {
categoriesPanelPages[selected].ctor(this);
}
}
return result;
}function: CategoriesPanel_makeColorsPage
static void CategoriesPanel_makeColorsPage(CategoriesPanel* this) {
Settings* settings = this->host->settings;
Panel* colors = (Panel*) ColorsPanel_new(settings);
ScreenManager_add(this->scr, colors, -1);
}function: CategoriesPanel_makeDisplayOptionsPage
static void CategoriesPanel_makeDisplayOptionsPage(CategoriesPanel* this) {
Settings* settings = this->host->settings;
Panel* displayOptions = (Panel*) DisplayOptionsPanel_new(settings, this->scr);
ScreenManager_add(this->scr, displayOptions, -1);
}function: CategoriesPanel_makeHeaderOptionsPage
static void CategoriesPanel_makeHeaderOptionsPage(CategoriesPanel* this) {
Settings* settings = this->host->settings;
Panel* colors = (Panel*) HeaderOptionsPanel_new(settings, this->scr);
ScreenManager_add(this->scr, colors, -1);
}function: CategoriesPanel_makeMetersPage
static void CategoriesPanel_makeMetersPage(CategoriesPanel* this) {
size_t columns = HeaderLayout_getColumns(this->scr->header->headerLayout);
MetersPanel** meterPanels = xMallocArray(columns, sizeof(MetersPanel*));
Settings* settings = this->host->settings;
for (size_t i = 0; i < columns; i++) {
char titleBuffer[32];
xSnprintf(titleBuffer, sizeof(titleBuffer), "Column %zu", i + 1);
meterPanels[i] = MetersPanel_new(settings, titleBuffer, this->header->columns[i], this->scr);
if (i != 0) {
meterPanels[i]->leftNeighbor = meterPanels[i - 1];
meterPanels[i - 1]->rightNeighbor = meterPanels[i];
}
ScreenManager_add(this->scr, (Panel*) meterPanels[i], 20);
}
Panel* availableMeters = (Panel*) AvailableMetersPanel_new(this->host, this->header, columns, meterPanels, this->scr);
ScreenManager_add(this->scr, availableMeters, -1);
}function: CategoriesPanel_makeScreensPage
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*) ((ScreensPanel*)screens)->availableColumns;
ScreenManager_add(this->scr, screens, 20);
ScreenManager_add(this->scr, columns, 20);
ScreenManager_add(this->scr, availableColumns, -1);
}function: CategoriesPanel_makeScreenTabsPage
#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);
}
#endiffunction: CategoriesPanel_new
CategoriesPanel* CategoriesPanel_new(ScreenManager* scr, Header* header, Machine* host) {
CategoriesPanel* this = AllocThis(CategoriesPanel);
Panel* super = &this->super;
FunctionBar* fuBar = FunctionBar_new(CategoriesFunctions, NULL, NULL);
Panel_init(super, 1, 1, 1, 1, Class(ListItem), true, fuBar);
this->scr = scr;
this->host = host;
this->header = header;
Panel_setHeader(super, "Categories");
for (size_t i = 0; i < ARRAYSIZE(categoriesPanelPages); i++)
Panel_add(super, (Object*) ListItem_new(categoriesPanelPages[i].name, 0));
ScreenManager_add(scr, super, 16);
categoriesPanelPages[0].ctor(this);
return this;
}global constant array: CategoriesFunctions
static const char* const CategoriesFunctions[] = {" ", " ", " ", " ", " ", " ", " ", " ", " ", "Done ", NULL};global constant array: 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 },
};struct: CategoriesPanelPage
typedef struct CategoriesPanelPage_ {
const char* name;
CategoriesPanel_makePageFunc ctor;
} CategoriesPanelPage;struct instance: CategoriesPanel_class
const PanelClass CategoriesPanel_class = {
.super = {
.extends = Class(Panel),
.delete = CategoriesPanel_delete
},
.eventHandler = CategoriesPanel_eventHandler
};typedef: CategoriesPanel_makePageFunc
typedef void (* CategoriesPanel_makePageFunc)(CategoriesPanel* ref);
CategoriesPanel.h
CategoriesPanel.h
function: CategoriesPanel_new
CategoriesPanel* CategoriesPanel_new(ScreenManager* scr, Header* header, Machine* host);
struct: CategoriesPanel_
typedef struct CategoriesPanel_ {
Panel super;
ScreenManager* scr;
Machine* host;
Header* header;
} CategoriesPanel;struct: CategoriesPanel_class
extern const PanelClass CategoriesPanel_class;
ChangeLog
ChangeLog
file: ChangeLog
check-pcp-style.sh
check-pcp-style.sh
function: check_file
method: check_section
function check_section() {
missing = ""
for (i in required_names) {
rname = required_names[i]
if (rname ~ /\?$/) {
continue
}
if (rname ~ /^\*\./) {
rname = substr(rname, 3, length(rname) - 2)
for (g in groups) {
if (g == "") {
continue
}
if (!(g rname in seen)) {
missing = missing g rname " "
}
}
continue
}
if (!(rname in seen)) {
missing = missing rname " "
}
}
if (missing != "") {
print "Error: Missing " missing "in section " section
exit 1
}
}method: trim
function trim(s) {
gsub(/^[ \t]+|[ \t]+$/, "", s)
return s
}structure: Awk Validation Script
ClockMeter.c
ClockMeter.c
function: ClockMeter_updateValues
static void ClockMeter_updateValues(Meter* this) {
const Machine* host = this->host;
struct tm result;
const struct tm* lt = localtime_r(&host->realtime.tv_sec, &result);
strftime(this->txtBuffer, sizeof(this->txtBuffer), "%H:%M:%S", lt);
}global variable: ClockMeter_attributes
static const int ClockMeter_attributes[] = {
CLOCK
};struct instance (class definition): ClockMeter_class
const MeterClass ClockMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete
},
.updateValues = ClockMeter_updateValues,
.defaultMode = TEXT_METERMODE,
.supportedModes = (1 << TEXT_METERMODE) | (1 << LED_METERMODE),
.maxItems = 0,
.total = 0.0,
.attributes = ClockMeter_attributes,
.name = "Clock",
.uiName = "Clock",
.caption = "Time: ",
};ClockMeter.h
ClockMeter.h
variable: ClockMeter_class
extern const MeterClass ClockMeter_class;
ColorsPanel.c
ColorsPanel.c
function: ColorsPanel_delete
static void ColorsPanel_delete(Object* object) {
ColorsPanel* this = (ColorsPanel*) object;
Panel_done(&this->super);
free(this);
}function: ColorsPanel_eventHandler
static HandlerResult ColorsPanel_eventHandler(Panel* super, int ch) {
ColorsPanel* this = (ColorsPanel*) super;
HandlerResult result = IGNORED;
switch (ch) {
case 0x0a:
case 0x0d:
case KEY_ENTER:
case KEY_MOUSE:
case KEY_RECLICK:
case ' ': {
int mark = Panel_getSelectedIndex(super);
assert(mark >= 0);
assert(mark < LAST_COLORSCHEME);
for (int i = 0; ColorSchemeNames[i] != NULL; i++)
CheckItem_set((CheckItem*)Panel_get(super, i), false);
CheckItem_set((CheckItem*)Panel_get(super, mark), true);
this->settings->colorScheme = mark;
this->settings->changed = true;
this->settings->lastUpdate++;
CRT_setColors(mark);
clear();
result = HANDLED | REDRAW;
}
}
return result;
}function: ColorsPanel_new
ColorsPanel* ColorsPanel_new(Settings* settings) {
ColorsPanel* this = AllocThis(ColorsPanel);
Panel* super = &this->super;
FunctionBar* fuBar = FunctionBar_new(ColorsFunctions, NULL, NULL);
Panel_init(super, 1, 1, 1, 1, Class(CheckItem), true, fuBar);
this->settings = settings;
assert(ARRAYSIZE(ColorSchemeNames) == LAST_COLORSCHEME + 1);
Panel_setHeader(super, "Colors");
for (int i = 0; ColorSchemeNames[i] != NULL; i++) {
Panel_add(super, (Object*) CheckItem_newByVal(ColorSchemeNames[i], false));
}
CheckItem_set((CheckItem*)Panel_get(super, settings->colorScheme), true);
return this;
}struct instance: ColorsPanel_class
const PanelClass ColorsPanel_class = {
.super = {
.extends = Class(Panel),
.delete = ColorsPanel_delete
},
.eventHandler = ColorsPanel_eventHandler
};ColorsPanel.h
ColorsPanel.h
function: ColorsPanel_new
ColorsPanel* ColorsPanel_new(Settings* settings);
struct: ColorsPanel
typedef struct ColorsPanel_ {
Panel super;
Settings* settings;
} ColorsPanel;variable: ColorsPanel_class
extern const PanelClass ColorsPanel_class;
ColumnsPanel.c
ColumnsPanel.c
class: ColumnsPanel_class
const PanelClass ColumnsPanel_class = {
.super = {
.extends = Class(Panel),
.delete = ColumnsPanel_delete
},
.eventHandler = ColumnsPanel_eventHandler
};function: ColumnsPanel_add
static void ColumnsPanel_add(Panel* super, unsigned int key, Hashtable* columns) {
const char* name;
if (key < LAST_PROCESSFIELD) {
name = Process_fields[key].name;
} else {
const DynamicColumn* column = Hashtable_get(columns, key);
assert(column);
if (!column) {
name = NULL;
} else {
/* heading preferred here but name is always available */
name = column->heading ? column->heading : column->name;
}
}
if (name == NULL)
name = "- ";
Panel_add(super, (Object*) ListItem_new(name, key));
}function: ColumnsPanel_delete
static void ColumnsPanel_delete(Object* object) {
ColumnsPanel* this = (ColumnsPanel*) object;
Panel_done(&this->super);
free(this);
}function: ColumnsPanel_eventHandler
static HandlerResult ColumnsPanel_eventHandler(Panel* super, int ch) {
ColumnsPanel* const this = (ColumnsPanel*) super;
int selected = Panel_getSelectedIndex(super);
HandlerResult result = IGNORED;
int size = Panel_size(super);
switch (ch) {
case 0x0a:
case 0x0d:
case KEY_ENTER:
case KEY_MOUSE:
case KEY_RECLICK:
if (selected < size) {
this->moving = !(this->moving);
Panel_setSelectionColor(super, this->moving ? PANEL_SELECTION_FOLLOW : PANEL_SELECTION_FOCUS);
ListItem* selectedItem = (ListItem*) Panel_getSelected(super);
if (selectedItem)
selectedItem->moving = this->moving;
result = HANDLED;
}
break;
case KEY_UP:
if (!this->moving)
break;
/* else fallthrough */
case KEY_F(7):
case '[':
case '-':
if (selected < size)
Panel_moveSelectedUp(super);
result = HANDLED;
break;
case KEY_DOWN:
if (!this->moving)
break;
/* else fallthrough */
case KEY_F(8):
case ']':
case '+':
if (selected < size - 1)
Panel_moveSelectedDown(super);
result = HANDLED;
break;
case KEY_F(9):
case KEY_DC:
case KEY_DEL_MAC:
if (size > 1 && selected < size)
Panel_remove(super, selected);
result = HANDLED;
break;
default:
if (0 < ch && ch < 255 && isgraph((unsigned char)ch))
result = Panel_selectByTyping(super, ch);
if (result == BREAK_LOOP)
result = IGNORED;
break;
}
if (result == HANDLED)
ColumnsPanel_update(super);
return result;
}function: ColumnsPanel_fill
void ColumnsPanel_fill(ColumnsPanel* this, ScreenSettings* ss, Hashtable* columns) {
Panel* super = &this->super;
Panel_prune(super);
for (const RowField* fields = ss->fields; *fields; fields++)
ColumnsPanel_add(super, *fields, columns);
this->ss = ss;
}function: ColumnsPanel_new
ColumnsPanel* ColumnsPanel_new(ScreenSettings* ss, Hashtable* columns, bool* changed) {
ColumnsPanel* this = AllocThis(ColumnsPanel);
Panel* super = &this->super;
FunctionBar* fuBar = FunctionBar_new(ColumnsFunctions, NULL, NULL);
Panel_init(super, 1, 1, 1, 1, Class(ListItem), true, fuBar);
this->ss = ss;
this->changed = changed;
this->moving = false;
Panel_setHeader(super, "Active Columns");
ColumnsPanel_fill(this, ss, columns);
return this;
}function: ColumnsPanel_update
void ColumnsPanel_update(Panel* super) {
ColumnsPanel* this = (ColumnsPanel*) super;
int size = Panel_size(super);
*(this->changed) = true;
this->ss->fields = xRealloc(this->ss->fields, sizeof(ProcessField) * (size + 1));
this->ss->flags = 0;
for (int i = 0; i < size; i++) {
int key = ((ListItem*) Panel_get(super, i))->key;
this->ss->fields[i] = key;
if (key < LAST_PROCESSFIELD)
this->ss->flags |= Process_fields[key].flags;
}
this->ss->fields[size] = 0;
}global variable: ColumnsFunctions
static const char* const ColumnsFunctions[] = {" ", " ", " ", " ", " ", " ", "MoveUp", "MoveDn", "Remove", "Done ", NULL};ColumnsPanel.h
ColumnsPanel.h
function: ColumnsPanel_fill
void ColumnsPanel_fill(ColumnsPanel* this, ScreenSettings* ss, Hashtable* columns);
function: ColumnsPanel_new
ColumnsPanel* ColumnsPanel_new(ScreenSettings* ss, Hashtable* columns, bool* changed);
function: ColumnsPanel_update
void ColumnsPanel_update(Panel* super);
struct: ColumnsPanel
typedef struct ColumnsPanel_ {
Panel super;
ScreenSettings* ss;
bool* changed;
bool moving;
} ColumnsPanel;variable declaration: ColumnsPanel_class
extern const PanelClass ColumnsPanel_class;
CommandLine.c
CommandLine.c
function: CommandLine_delay
static void CommandLine_delay(Machine* host, unsigned long millisec) {
struct timespec req = {
.tv_sec = 0,
.tv_nsec = millisec * 1000000L
};
while (nanosleep(&req, &req) == -1)
continue;
Platform_gettime_realtime(&host->realtime, &host->realtimeMs);
}function: CommandLine_run
function: parseArguments
function: printHelpFlag
static void printHelpFlag(const char* name) {
printf("%s " VERSION "\n"
COPYRIGHT "\n"
"Released under the GNU GPLv2+.\n\n"
"-C --no-color Use a monochrome color scheme\n"
"-d --delay=DELAY Set the delay between updates, in tenths of seconds\n"
"-F --filter=FILTER Show only the commands matching the given filter\n"
"-h --help Print this help screen\n"
"-H --highlight-changes[=DELAY] Highlight new and old processes\n", name);
#ifdef HAVE_GETMOUSE
printf("-M --no-mouse Disable the mouse\n");
#endif
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"
"-u --user[=USERNAME] Show only processes for a given user (or $USER)\n"
"-U --no-unicode Do not use unicode but plain ASCII\n"
"-V --version Print version info\n");
Platform_longOptionsUsage(name);
printf("\n"
"Press F1 inside %s for online help.\n"
"See 'man %s' for more information.\n", name, name);
}function: printVersionFlag
static void printVersionFlag(const char* name) {
printf("%s " VERSION "\n", name);
}function: setCommFilter
static void setCommFilter(State* state, char** commFilter) {
Table* table = state->host->activeTable;
IncSet* inc = state->mainPanel->inc;
IncSet_setFilter(inc, *commFilter);
table->incFilter = IncSet_filter(inc);
free(*commFilter);
*commFilter = NULL;
}struct: CommandLineSettings_
typedef struct CommandLineSettings_ {
Hashtable* pidMatchList;
char* commFilter;
uid_t userId;
int sortKey;
int delay;
int iterationsRemaining;
bool useColors;
#ifdef HAVE_GETMOUSE
bool enableMouse;
#endif
bool treeView;
bool allowUnicode;
bool highlightChanges;
int highlightDelaySecs;
bool readonly;
} CommandLineSettings;CommandLine.h
CommandLine.h
enum: CommandLineStatus
typedef enum {
STATUS_OK,
STATUS_ERROR_EXIT,
STATUS_OK_EXIT
} CommandLineStatus;function: CommandLine_run
int CommandLine_run(int argc, char** argv);
variable: program
extern const char* program;
CommandScreen.c
CommandScreen.c
function: CommandScreen_delete
void CommandScreen_delete(Object* this) {
free(InfoScreen_done((InfoScreen*)this));
}function: CommandScreen_draw
static void CommandScreen_draw(InfoScreen* this) {
InfoScreen_drawTitled(this, "Command of process %d - %s", Process_getPid(this->process), Process_getCommand(this->process));
}function: CommandScreen_new
CommandScreen* CommandScreen_new(Process* process) {
CommandScreen* this = AllocThis(CommandScreen);
return (CommandScreen*) InfoScreen_init(&this->super, process, NULL, LINES - 2, " ");
}function: CommandScreen_scan
static void CommandScreen_scan(InfoScreen* this) {
Panel* panel = this->display;
int idx = MAXIMUM(Panel_getSelectedIndex(panel), 0);
Panel_prune(panel);
const char* p = Process_getCommand(this->process);
char line[COLS + 1];
int line_offset = 0, last_spc = -1, len;
for (; *p != '\0'; p++, line_offset++) {
assert(line_offset >= 0 && (size_t)line_offset < sizeof(line));
line[line_offset] = *p;
if (*p == ' ') {
last_spc = line_offset;
}
if (line_offset == COLS) {
len = (last_spc == -1) ? line_offset : last_spc;
line[len] = '\0';
InfoScreen_addLine(this, line);
line_offset -= len;
last_spc = -1;
memcpy(line, p - line_offset, line_offset + 1);
}
}
if (line_offset > 0) {
line[line_offset] = '\0';
InfoScreen_addLine(this, line);
}
Panel_setSelected(panel, idx);
}struct: CommandScreen_class
const InfoScreenClass CommandScreen_class = {
.super = {
.extends = Class(Object),
.delete = CommandScreen_delete
},
.scan = CommandScreen_scan,
.draw = CommandScreen_draw
};CommandScreen.h
CommandScreen.h
function: CommandScreen_delete
void CommandScreen_delete(Object* this);
function: CommandScreen_new
CommandScreen* CommandScreen_new(Process* process);
struct: CommandScreen_
typedef struct CommandScreen_ {
InfoScreen super;
} CommandScreen;typedef: CommandScreen
typedef struct CommandScreen_ {
InfoScreen super;
} CommandScreen;variable: CommandScreen_class
extern const InfoScreenClass CommandScreen_class;
Compat.c
Compat.c
function: Compat_faccessat
int Compat_faccessat(int dirfd,
const char* pathname,
int mode,
int flags) {
int ret;
#ifdef HAVE_FACCESSAT
// Implementation note: AT_SYMLINK_NOFOLLOW unsupported on FreeBSD, fallback to lstat in that case
errno = 0;
ret = faccessat(dirfd, pathname, mode, flags);
if (!ret || errno != EINVAL)
return ret;
#endif
// Error out on unsupported configurations
if (dirfd != (int)AT_FDCWD || mode != F_OK) {
errno = EINVAL;
return -1;
}
// Fallback to stat(2)/lstat(2) depending on flags
struct stat sb;
if (flags) {
ret = lstat(pathname, &sb);
} else {
ret = stat(pathname, &sb);
}
return ret;
}function: Compat_fstatat
int Compat_fstatat(int dirfd,
const char* dirpath,
const char* pathname,
struct stat* statbuf,
int flags) {
#ifdef HAVE_FSTATAT
(void)dirpath;
return fstatat(dirfd, pathname, statbuf, flags);
#else
(void)dirfd;
char path[4096];
xSnprintf(path, sizeof(path), "%s/%s", dirpath, pathname);
if (flags & AT_SYMLINK_NOFOLLOW)
return lstat(path, statbuf);
return stat(path, statbuf);
#endif
}function: Compat_openat
int Compat_openat(const char* dirpath,
const char* pathname,
int flags) {
char path[4096];
xSnprintf(path, sizeof(path), "%s/%s", dirpath, pathname);
return open(path, flags);
}function: Compat_readlink
ssize_t Compat_readlink(openat_arg_t dirfd,
const char* pathname,
char* buf,
size_t bufsize) {
#ifdef HAVE_OPENAT
char fdPath[32];
xSnprintf(fdPath, sizeof(fdPath), "/proc/self/fd/%d", dirfd);
char dirPath[PATH_MAX + 1];
ssize_t r = readlink(fdPath, dirPath, sizeof(dirPath) - 1);
if (r < 0)
return r;
dirPath[r] = '\0';
char linkPath[PATH_MAX + 1];
xSnprintf(linkPath, sizeof(linkPath), "%s/%s", dirPath, pathname);
#else
char linkPath[PATH_MAX + 1];
xSnprintf(linkPath, sizeof(linkPath), "%s/%s", dirfd, pathname);
#endif /* HAVE_OPENAT */
return readlink(linkPath, buf, bufsize);
}function: Compat_readlinkat
ssize_t Compat_readlinkat(int dirfd,
const char* dirpath,
const char* pathname,
char* buf,
size_t bufsize) {
#ifdef HAVE_READLINKAT
(void)dirpath;
return readlinkat(dirfd, pathname, buf, bufsize);
#else
(void)dirfd;
char path[4096];
xSnprintf(path, sizeof(path), "%s/%s", dirpath, pathname);
return readlink(path, buf, bufsize);
#endif
}Compat.h
Compat.h
function: Compat_faccessat
int Compat_faccessat(int dirfd,
const char* pathname,
int mode,
int flags);function: Compat_fstatat
int Compat_fstatat(int dirfd,
const char* dirpath,
const char* pathname,
struct stat* statbuf,
int flags);function: Compat_openat (!HAVE_OPENAT)
int Compat_openat(openat_arg_t dirpath, const char* pathname, int flags);
function: Compat_openat (HAVE_OPENAT)
static inline int Compat_openat(openat_arg_t dirfd, const char* pathname, int flags) {
return openat(dirfd, pathname, flags);
}function: Compat_openatArgClose (!HAVE_OPENAT)
static inline void Compat_openatArgClose(openat_arg_t dirpath) {
(void)dirpath;
}function: Compat_openatArgClose (HAVE_OPENAT)
static inline void Compat_openatArgClose(openat_arg_t dirfd) {
close(dirfd);
}function: Compat_readlink
ssize_t Compat_readlink(openat_arg_t dirfd,
const char* pathname,
char* buf,
size_t bufsize);function: Compat_readlinkat
ssize_t Compat_readlinkat(int dirfd,
const char* dirpath,
const char* pathname,
char* buf,
size_t bufsize);type: openat_arg_t (!HAVE_OPENAT)
typedef const char* openat_arg_t;
type: openat_arg_t (HAVE_OPENAT)
typedef int openat_arg_t;
configure.ac
configure.ac
file: configure.ac
CONTRIBUTING.md
CONTRIBUTING.md
file: CONTRIBUTING.md
Contributing Guide ================== Thank you so much for taking the time to contribute in to htop! Bug Reports ----------- Bug reports should be posted in the [Github issue tracker](https://github.com/htop-dev/htop/issues). Bug reports are extremely important since it's impossible for us to test htop in every possible system, distribution and scenario. Your feedback is what keeps the tool stable and always improving! Thank you! Pull Requests ------------- Code contributions are most welcome! Just [fork the repo](https://github.com/htop-dev/htop) and send a [pull request](https://github.com/htop-dev/htop/pulls). Help is especially appreciated for support of platforms other than Linux. If proposing new features, please be mindful that htop is a system tool that needs to keep a small footprint and perform well on systems under stress -- so unfortunately we can't accept every new feature proposed, as we need to keep the tool slim and maintainable. Great ideas backed by a PR are always carefully considered for inclusion though! Also, PRs containing bug fixes and portability tweaks are always included, please send those in! Feature Requests ---------------- Please label Github issues that are feature requests with one of the `feature request` labels. If you can't do this yourself, don't worry. The friendly folks from the core team will distribute and fixup Github labels as part of the regular reviews. Style Guide ----------- To make working with the code easier a set of guidelines have evolved in the past that new contributions should try to follow. While they are not set in stone and always up for changes should the need arise they still provide a first orientation to go by when contributing to this repository. The details of the coding style as well as what to take care about with your contributions can be found in our [style guide](docs/styleguide.md).
COPYING
COPYING
file: COPYING
CPUMeter.c
CPUMeter.c
function: AllCPUsMeter_done
static void AllCPUsMeter_done(Meter* this) {
CPUMeterData* data = this->meterData;
Meter** meters = data->meters;
int start, count;
AllCPUsMeter_getRange(this, &start, &count);
for (int i = 0; i < count; i++)
Meter_delete((Object*)meters[i]);
free(data->meters);
free(data);
}function: AllCPUsMeter_getRange
static void AllCPUsMeter_getRange(const Meter* this, int* start, int* count) {
unsigned int cpus = this->host->existingCPUs;
switch (Meter_name(this)[0]) {
default:
case 'A': // All
*start = 0;
*count = cpus;
break;
case 'L': // First Half
*start = 0;
*count = (cpus + 1) / 2;
break;
case 'R': // Second Half
*start = (cpus + 1) / 2;
*count = cpus - *start;
break;
}
}function: AllCPUsMeter_updateValues
static void AllCPUsMeter_updateValues(Meter* this) {
CPUMeterData* data = this->meterData;
Meter** meters = data->meters;
int start, count;
AllCPUsMeter_getRange(this, &start, &count);
for (int i = 0; i < count; i++)
Meter_updateValues(meters[i]);
}function: CPUMeter_display
function: CPUMeter_getUiName
static void CPUMeter_getUiName(const Meter* this, char* buffer, size_t length) {
assert(length > 0);
if (this->param > 0)
xSnprintf(buffer, length, "%s %u", Meter_uiName(this), this->param);
else
xSnprintf(buffer, length, "%s", Meter_uiName(this));
}function: CPUMeter_init
static void CPUMeter_init(Meter* this) {
unsigned int cpu = this->param;
const Machine* host = this->host;
if (cpu == 0) {
Meter_setCaption(this, "Avg");
} else if (host->activeCPUs > 1) {
char caption[10];
xSnprintf(caption, sizeof(caption), "%3u", Settings_cpuId(host->settings, cpu - 1));
Meter_setCaption(this, caption);
}
}function: CPUMeter_updateValues
function: CPUMeterCommonDraw
static void CPUMeterCommonDraw(Meter* this, int x, int y, int w, int ncol) {
CPUMeterData* data = this->meterData;
Meter** meters = data->meters;
int start, count;
AllCPUsMeter_getRange(this, &start, &count);
int colwidth = (w - ncol) / ncol + 1;
int diff = (w - (colwidth * ncol));
int nrows = (count + ncol - 1) / ncol;
for (int i = 0; i < count; i++) {
int d = (i / nrows) > diff ? diff : (i / nrows); // dynamic spacer
int xpos = x + ((i / nrows) * colwidth) + d;
int ypos = y + ((i % nrows) * meters[0]->h);
meters[i]->draw(meters[i], xpos, ypos, colwidth);
}
}function: CPUMeterCommonInit
static void CPUMeterCommonInit(Meter* this) {
int start, count;
AllCPUsMeter_getRange(this, &start, &count);
CPUMeterData* data = this->meterData;
if (!data) {
data = this->meterData = xMalloc(sizeof(CPUMeterData));
data->cpus = this->host->existingCPUs;
data->meters = count ? xCalloc(count, sizeof(Meter*)) : NULL;
}
Meter** meters = data->meters;
for (int i = 0; i < count; i++) {
if (!meters[i])
meters[i] = Meter_new(this->host, start + i + 1, (const MeterClass*) Class(CPUMeter));
Meter_init(meters[i]);
}
}function: CPUMeterCommonUpdateMode
static void CPUMeterCommonUpdateMode(Meter* this, MeterModeId mode, int ncol) {
CPUMeterData* data = this->meterData;
Meter** meters = data->meters;
this->mode = mode;
int start, count;
AllCPUsMeter_getRange(this, &start, &count);
if (!count) {
this->h = 1;
return;
}
for (int i = 0; i < count; i++) {
Meter_setMode(meters[i], mode);
}
int h = meters[0]->h;
assert(h > 0);
this->h = h * ((count + ncol - 1) / ncol);
}function: DualColCPUsMeter_draw
static void DualColCPUsMeter_draw(Meter* this, int x, int y, int w) {
CPUMeterCommonDraw(this, x, y, w, 2);
}function: DualColCPUsMeter_updateMode
static void DualColCPUsMeter_updateMode(Meter* this, MeterModeId mode) {
CPUMeterCommonUpdateMode(this, mode, 2);
}function: OctoColCPUsMeter_draw
static void OctoColCPUsMeter_draw(Meter* this, int x, int y, int w) {
CPUMeterCommonDraw(this, x, y, w, 8);
}function: OctoColCPUsMeter_updateMode
static void OctoColCPUsMeter_updateMode(Meter* this, MeterModeId mode) {
CPUMeterCommonUpdateMode(this, mode, 8);
}function: QuadColCPUsMeter_draw
static void QuadColCPUsMeter_draw(Meter* this, int x, int y, int w) {
CPUMeterCommonDraw(this, x, y, w, 4);
}function: QuadColCPUsMeter_updateMode
static void QuadColCPUsMeter_updateMode(Meter* this, MeterModeId mode) {
CPUMeterCommonUpdateMode(this, mode, 4);
}function: SingleColCPUsMeter_draw
static void SingleColCPUsMeter_draw(Meter* this, int x, int y, int w) {
CPUMeterData* data = this->meterData;
Meter** meters = data->meters;
int start, count;
AllCPUsMeter_getRange(this, &start, &count);
for (int i = 0; i < count; i++) {
meters[i]->draw(meters[i], x, y, w);
y += meters[i]->h;
}
}function: SingleColCPUsMeter_updateMode
static void SingleColCPUsMeter_updateMode(Meter* this, MeterModeId mode) {
CPUMeterCommonUpdateMode(this, mode, 1);
}global variable: AllCPUs2Meter_class
const MeterClass AllCPUs2Meter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = CPUMeter_display
},
.updateValues = AllCPUsMeter_updateValues,
.defaultMode = BAR_METERMODE,
.supportedModes = METERMODE_DEFAULT_SUPPORTED,
.isMultiColumn = true,
.total = 100.0,
.attributes = CPUMeter_attributes,
.name = "AllCPUs2",
.uiName = "CPUs (1&2/2)",
.description = "CPUs (1&2/2): all CPUs in 2 shorter columns",
.caption = "CPU",
.draw = DualColCPUsMeter_draw,
.init = CPUMeterCommonInit,
.updateMode = DualColCPUsMeter_updateMode,
.done = AllCPUsMeter_done
};global variable: AllCPUs4Meter_class
const MeterClass AllCPUs4Meter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = CPUMeter_display
},
.updateValues = AllCPUsMeter_updateValues,
.defaultMode = BAR_METERMODE,
.supportedModes = METERMODE_DEFAULT_SUPPORTED,
.isMultiColumn = true,
.total = 100.0,
.attributes = CPUMeter_attributes,
.name = "AllCPUs4",
.uiName = "CPUs (1&2&3&4/4)",
.description = "CPUs (1&2&3&4/4): all CPUs in 4 shorter columns",
.caption = "CPU",
.draw = QuadColCPUsMeter_draw,
.init = CPUMeterCommonInit,
.updateMode = QuadColCPUsMeter_updateMode,
.done = AllCPUsMeter_done
};global variable: AllCPUs8Meter_class
const MeterClass AllCPUs8Meter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = CPUMeter_display
},
.updateValues = AllCPUsMeter_updateValues,
.defaultMode = BAR_METERMODE,
.supportedModes = METERMODE_DEFAULT_SUPPORTED,
.isMultiColumn = true,
.total = 100.0,
.attributes = CPUMeter_attributes,
.name = "AllCPUs8",
.uiName = "CPUs (1-8/8)",
.description = "CPUs (1-8/8): all CPUs in 8 shorter columns",
.caption = "CPU",
.draw = OctoColCPUsMeter_draw,
.init = CPUMeterCommonInit,
.updateMode = OctoColCPUsMeter_updateMode,
.done = AllCPUsMeter_done
};global variable: AllCPUsMeter_class
const MeterClass AllCPUsMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = CPUMeter_display
},
.updateValues = AllCPUsMeter_updateValues,
.defaultMode = BAR_METERMODE,
.supportedModes = METERMODE_DEFAULT_SUPPORTED,
.total = 100.0,
.attributes = CPUMeter_attributes,
.name = "AllCPUs",
.uiName = "CPUs (1/1)",
.description = "CPUs (1/1): all CPUs",
.caption = "CPU",
.draw = SingleColCPUsMeter_draw,
.init = CPUMeterCommonInit,
.updateMode = SingleColCPUsMeter_updateMode,
.done = AllCPUsMeter_done
};global variable: CPUMeter_attributes
static const int CPUMeter_attributes[] = {
CPU_NICE,
CPU_NORMAL,
CPU_SYSTEM,
CPU_IRQ,
CPU_SOFTIRQ,
CPU_STEAL,
CPU_GUEST,
CPU_IOWAIT
};global variable: CPUMeter_class
const MeterClass CPUMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = CPUMeter_display
},
.updateValues = CPUMeter_updateValues,
.getUiName = CPUMeter_getUiName,
.defaultMode = BAR_METERMODE,
.supportedModes = METERMODE_DEFAULT_SUPPORTED,
.maxItems = CPU_METER_ITEMCOUNT,
.total = 100.0,
.attributes = CPUMeter_attributes,
.name = "CPU",
.uiName = "CPU",
.caption = "CPU",
.init = CPUMeter_init
};global variable: LeftCPUs2Meter_class
const MeterClass LeftCPUs2Meter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = CPUMeter_display
},
.updateValues = AllCPUsMeter_updateValues,
.defaultMode = BAR_METERMODE,
.supportedModes = METERMODE_DEFAULT_SUPPORTED,
.isMultiColumn = true,
.total = 100.0,
.attributes = CPUMeter_attributes,
.name = "LeftCPUs2",
.uiName = "CPUs (1&2/4)",
.description = "CPUs (1&2/4): first half in 2 shorter columns",
.caption = "CPU",
.draw = DualColCPUsMeter_draw,
.init = CPUMeterCommonInit,
.updateMode = DualColCPUsMeter_updateMode,
.done = AllCPUsMeter_done
};global variable: LeftCPUs4Meter_class
const MeterClass LeftCPUs4Meter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = CPUMeter_display
},
.updateValues = AllCPUsMeter_updateValues,
.defaultMode = BAR_METERMODE,
.supportedModes = METERMODE_DEFAULT_SUPPORTED,
.isMultiColumn = true,
.total = 100.0,
.attributes = CPUMeter_attributes,
.name = "LeftCPUs4",
.uiName = "CPUs (1-4/8)",
.description = "CPUs (1-4/8): first half in 4 shorter columns",
.caption = "CPU",
.draw = QuadColCPUsMeter_draw,
.init = CPUMeterCommonInit,
.updateMode = QuadColCPUsMeter_updateMode,
.done = AllCPUsMeter_done
};global variable: LeftCPUs8Meter_class
const MeterClass LeftCPUs8Meter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = CPUMeter_display
},
.updateValues = AllCPUsMeter_updateValues,
.defaultMode = BAR_METERMODE,
.supportedModes = METERMODE_DEFAULT_SUPPORTED,
.isMultiColumn = true,
.total = 100.0,
.attributes = CPUMeter_attributes,
.name = "LeftCPUs8",
.uiName = "CPUs (1-8/16)",
.description = "CPUs (1-8/16): first half in 8 shorter columns",
.caption = "CPU",
.draw = OctoColCPUsMeter_draw,
.init = CPUMeterCommonInit,
.updateMode = OctoColCPUsMeter_updateMode,
.done = AllCPUsMeter_done
};global variable: LeftCPUsMeter_class
const MeterClass LeftCPUsMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = CPUMeter_display
},
.updateValues = AllCPUsMeter_updateValues,
.defaultMode = BAR_METERMODE,
.supportedModes = METERMODE_DEFAULT_SUPPORTED,
.isMultiColumn = true,
.total = 100.0,
.attributes = CPUMeter_attributes,
.name = "LeftCPUs",
.uiName = "CPUs (1/2)",
.description = "CPUs (1/2): first half of list",
.caption = "CPU",
.draw = SingleColCPUsMeter_draw,
.init = CPUMeterCommonInit,
.updateMode = SingleColCPUsMeter_updateMode,
.done = AllCPUsMeter_done
};global variable: RightCPUs2Meter_class
const MeterClass RightCPUs2Meter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = CPUMeter_display
},
.updateValues = AllCPUsMeter_updateValues,
.defaultMode = BAR_METERMODE,
.supportedModes = METERMODE_DEFAULT_SUPPORTED,
.isMultiColumn = true,
.total = 100.0,
.attributes = CPUMeter_attributes,
.name = "RightCPUs2",
.uiName = "CPUs (3&4/4)",
.description = "CPUs (3&4/4): second half in 2 shorter columns",
.caption = "CPU",
.draw = DualColCPUsMeter_draw,
.init = CPUMeterCommonInit,
.updateMode = DualColCPUsMeter_updateMode,
.done = AllCPUsMeter_done
};global variable: RightCPUs4Meter_class
const MeterClass RightCPUs4Meter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = CPUMeter_display
},
.updateValues = AllCPUsMeter_updateValues,
.defaultMode = BAR_METERMODE,
.supportedModes = METERMODE_DEFAULT_SUPPORTED,
.isMultiColumn = true,
.total = 100.0,
.attributes = CPUMeter_attributes,
.name = "RightCPUs4",
.uiName = "CPUs (5-8/8)",
.description = "CPUs (5-8/8): second half in 4 shorter columns",
.caption = "CPU",
.draw = QuadColCPUsMeter_draw,
.init = CPUMeterCommonInit,
.updateMode = QuadColCPUsMeter_updateMode,
.done = AllCPUsMeter_done
};global variable: RightCPUs8Meter_class
const MeterClass RightCPUs8Meter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = CPUMeter_display
},
.updateValues = AllCPUsMeter_updateValues,
.defaultMode = BAR_METERMODE,
.supportedModes = METERMODE_DEFAULT_SUPPORTED,
.isMultiColumn = true,
.total = 100.0,
.attributes = CPUMeter_attributes,
.name = "RightCPUs8",
.uiName = "CPUs (9-16/16)",
.description = "CPUs (9-16/16): second half in 8 shorter columns",
.caption = "CPU",
.draw = OctoColCPUsMeter_draw,
.init = CPUMeterCommonInit,
.updateMode = OctoColCPUsMeter_updateMode,
.done = AllCPUsMeter_done
};global variable: RightCPUsMeter_class
const MeterClass RightCPUsMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = CPUMeter_display
},
.updateValues = AllCPUsMeter_updateValues,
.defaultMode = BAR_METERMODE,
.supportedModes = METERMODE_DEFAULT_SUPPORTED,
.isMultiColumn = true,
.total = 100.0,
.attributes = CPUMeter_attributes,
.name = "RightCPUs",
.uiName = "CPUs (2/2)",
.description = "CPUs (2/2): second half of list",
.caption = "CPU",
.draw = SingleColCPUsMeter_draw,
.init = CPUMeterCommonInit,
.updateMode = SingleColCPUsMeter_updateMode,
.done = AllCPUsMeter_done
};struct: CPUMeterData_
typedef struct CPUMeterData_ {
unsigned int cpus;
Meter** meters;
} CPUMeterData;CPUMeter.h
CPUMeter.h
enum: CPUMeterValues
typedef enum {
CPU_METER_NICE = 0,
CPU_METER_NORMAL = 1,
CPU_METER_KERNEL = 2,
CPU_METER_IRQ = 3,
CPU_METER_SOFTIRQ = 4,
CPU_METER_STEAL = 5,
CPU_METER_GUEST = 6,
CPU_METER_IOWAIT = 7,
CPU_METER_FREQUENCY = 8,
CPU_METER_TEMPERATURE = 9,
CPU_METER_ITEMCOUNT = 10 // number of entries in this enum
} CPUMeterValues;variable: AllCPUs2Meter_class
extern const MeterClass AllCPUs2Meter_class;
variable: AllCPUs4Meter_class
extern const MeterClass AllCPUs4Meter_class;
variable: AllCPUs8Meter_class
extern const MeterClass AllCPUs8Meter_class;
variable: AllCPUsMeter_class
extern const MeterClass AllCPUsMeter_class;
variable: CPUMeter_class
extern const MeterClass CPUMeter_class;
variable: LeftCPUs2Meter_class
extern const MeterClass LeftCPUs2Meter_class;
variable: LeftCPUs4Meter_class
extern const MeterClass LeftCPUs4Meter_class;
variable: LeftCPUs8Meter_class
extern const MeterClass LeftCPUs8Meter_class;
variable: LeftCPUsMeter_class
extern const MeterClass LeftCPUsMeter_class;
variable: RightCPUs2Meter_class
extern const MeterClass RightCPUs2Meter_class;
variable: RightCPUs4Meter_class
extern const MeterClass RightCPUs4Meter_class;
variable: RightCPUs8Meter_class
extern const MeterClass RightCPUs8Meter_class;
variable: RightCPUsMeter_class
extern const MeterClass RightCPUsMeter_class;
CRT.c
CRT.c
file: CRT.c
CRT.h
CRT.h
enum: ColorElements
enum: ColorScheme
typedef enum ColorScheme_ {
COLORSCHEME_DEFAULT,
COLORSCHEME_MONOCHROME,
COLORSCHEME_BLACKONWHITE,
COLORSCHEME_LIGHTTERMINAL,
COLORSCHEME_MIDNIGHT,
COLORSCHEME_BLACKNIGHT,
COLORSCHEME_BROKENGRAY,
LAST_COLORSCHEME
} ColorScheme;enum: TreeStr
typedef enum TreeStr_ {
TREE_STR_VERT,
TREE_STR_RTEE,
TREE_STR_BEND,
TREE_STR_TEND,
TREE_STR_OPEN,
TREE_STR_SHUT,
TREE_STR_ASC,
TREE_STR_DESC,
LAST_TREE_STR
} TreeStr;function: CRT_debug_impl
void CRT_debug_impl(const char* file, size_t lineno, const char* func, const char* fmt, ...) ATTR_FORMAT(printf, 4, 5);
function: CRT_disableDelay
void CRT_disableDelay(void);
function: CRT_done
void CRT_done(void);
function: CRT_enableDelay
void CRT_enableDelay(void);
function: CRT_fatalError
void CRT_fatalError(const char* note) ATTR_NORETURN;
function: CRT_handleSIGSEGV
void CRT_handleSIGSEGV(int signal) ATTR_NORETURN;
function: CRT_init
void CRT_init(const Settings* settings, bool allowUnicode, bool retainScreenOnExit);
function: CRT_readKey
int CRT_readKey(void);
function: CRT_resetSignalHandlers
void CRT_resetSignalHandlers(void);
function: CRT_setColors
void CRT_setColors(int colorScheme);
function: CRT_setMouse
#ifdef HAVE_GETMOUSE void CRT_setMouse(bool enabled); #else #define CRT_setMouse(enabled) #endif
function: CRT_updateDelay
static inline void CRT_updateDelay(void) {
CRT_enableDelay(); // pushes new delay setting into halfdelay(3X)
}global_variable: CRT_colors
extern const int* CRT_colors;
global_variable: CRT_colorScheme
extern ColorScheme CRT_colorScheme;
global_variable: CRT_cursorX
extern int CRT_cursorX;
global_variable: CRT_degreeSign
extern const char* CRT_degreeSign;
global_variable: CRT_scrollHAmount
extern int CRT_scrollHAmount;
global_variable: CRT_scrollWheelVAmount
extern int CRT_scrollWheelVAmount;
global_variable: CRT_treeStr
extern const char* const* CRT_treeStr;
global_variable: CRT_utf8
extern bool CRT_utf8;
macro: CRT_debug
#ifdef NDEBUG # define CRT_debug(...) #else void CRT_debug_impl(const char* file, size_t lineno, const char* func, const char* fmt, ...) ATTR_FORMAT(printf, 4, 5); # define CRT_debug(...) CRT_debug_impl(__FILE__, __LINE__, __func__, __VA_ARGS__) #endif
macro: KEY_ALT
#define KEY_ALT(x) (KEY_F(64 - 26) + ((x) - 'A'))
macro: KEY_DEL_MAC
#define KEY_DEL_MAC 127
macro: KEY_FOCUS_IN
#define KEY_FOCUS_IN (KEY_MAX + 'I')
macro: KEY_FOCUS_OUT
#define KEY_FOCUS_OUT (KEY_MAX + 'O')
macro: KEY_RECLICK
#define KEY_RECLICK KEY_F(32)
macro: KEY_SHIFT_TAB
#define KEY_SHIFT_TAB KEY_F(33)
macro: KEY_WHEELDOWN
#define KEY_WHEELDOWN KEY_F(31)
macro: KEY_WHEELUP
#define KEY_WHEELUP KEY_F(30)
macro: SCREEN_TAB_COLUMN_GAP
#define SCREEN_TAB_COLUMN_GAP 1
macro: SCREEN_TAB_MARGIN_LEFT
#define SCREEN_TAB_MARGIN_LEFT 2
DarwinMachine.c
darwin/DarwinMachine.c
function: DarwinMachine_allocateCPULoadInfo
static unsigned DarwinMachine_allocateCPULoadInfo(processor_cpu_load_info_t* p) {
mach_msg_type_number_t info_size = sizeof(processor_cpu_load_info_t);
unsigned cpu_count;
// TODO Improving the accuracy of the load counts would help a lot.
if (0 != host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &cpu_count, (processor_info_array_t*)p, &info_size)) {
CRT_fatalError("Unable to retrieve CPU info");
}
return cpu_count;
}function: DarwinMachine_freeCPULoadInfo
static void DarwinMachine_freeCPULoadInfo(processor_cpu_load_info_t* p) {
if (!p)
return;
if (!*p)
return;
if (0 != munmap(*p, vm_page_size)) {
CRT_fatalError("Unable to free old CPU load information");
}
*p = NULL;
}function: DarwinMachine_getHostInfo
static void DarwinMachine_getHostInfo(host_basic_info_data_t* p) {
mach_msg_type_number_t info_size = HOST_BASIC_INFO_COUNT;
if (0 != host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t)p, &info_size)) {
CRT_fatalError("Unable to retrieve host info");
}
}function: DarwinMachine_getVMStats
static void DarwinMachine_getVMStats(DarwinMachine* this) {
#ifdef HAVE_STRUCT_VM_STATISTICS64
mach_msg_type_number_t info_size = HOST_VM_INFO64_COUNT;
if (host_statistics64(mach_host_self(), HOST_VM_INFO64, (host_info_t)&this->vm_stats, &info_size) != 0) {
CRT_fatalError("Unable to retrieve VM statistics64");
}
#else
mach_msg_type_number_t info_size = HOST_VM_INFO_COUNT;
if (host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)&this->vm_stats, &info_size) != 0) {
CRT_fatalError("Unable to retrieve VM statistics");
}
#endif
}function: Machine_delete
void Machine_delete(Machine* super) {
DarwinMachine* this = (DarwinMachine*) super;
DarwinMachine_freeCPULoadInfo(&this->prev_load);
Machine_done(super);
free(this);
}function: Machine_isCPUonline
bool Machine_isCPUonline(const Machine* host, unsigned int id) {
assert(id < host->existingCPUs);
// TODO: support offline CPUs and hot swapping
(void) host; (void) id;
return true;
}function: Machine_new
Machine* Machine_new(UsersTable* usersTable, uid_t userId) {
DarwinMachine* this = xCalloc(1, sizeof(DarwinMachine));
Machine* super = &this->super;
Machine_init(super, usersTable, userId);
/* Initialize the CPU information */
super->activeCPUs = DarwinMachine_allocateCPULoadInfo(&this->prev_load);
super->existingCPUs = super->activeCPUs;
DarwinMachine_getHostInfo(&this->host_info);
DarwinMachine_allocateCPULoadInfo(&this->curr_load);
/* Initialize the VM statistics */
DarwinMachine_getVMStats(this);
/* Initialize the ZFS kstats, if zfs.kext loaded */
openzfs_sysctl_init(&this->zfs);
openzfs_sysctl_updateArcStats(&this->zfs);
return super;
}function: Machine_scan
void Machine_scan(Machine* super) {
DarwinMachine* host = (DarwinMachine*) super;
/* Update the global data (CPU times and VM stats) */
DarwinMachine_freeCPULoadInfo(&host->prev_load);
host->prev_load = host->curr_load;
DarwinMachine_allocateCPULoadInfo(&host->curr_load);
DarwinMachine_getVMStats(host);
openzfs_sysctl_updateArcStats(&host->zfs);
}DarwinMachine.h
darwin/DarwinMachine.h
struct: DarwinMachine
typedef struct DarwinMachine_ {
Machine super;
host_basic_info_data_t host_info;
#ifdef HAVE_STRUCT_VM_STATISTICS64
vm_statistics64_data_t vm_stats;
#else
vm_statistics_data_t vm_stats;
#endif
processor_cpu_load_info_t prev_load;
processor_cpu_load_info_t curr_load;
ZfsArcStats zfs;
} DarwinMachine;DarwinProcess.c
darwin/DarwinProcess.c
function: DarwinProcess_compareByKey
static int DarwinProcess_compareByKey(const Process* v1, const Process* v2, ProcessField key) {
const DarwinProcess* p1 = (const DarwinProcess*)v1;
const DarwinProcess* p2 = (const DarwinProcess*)v2;
switch (key) {
// add Platform-specific fields here
case TRANSLATED:
return SPACESHIP_NUMBER(p1->translated, p2->translated);
default:
return Process_compareByKey_Base(v1, v2, key);
}
}function: DarwinProcess_getDevname
static char* DarwinProcess_getDevname(dev_t dev) {
if (dev == NODEV) {
return NULL;
}
char buf[sizeof("/dev/") + MAXNAMLEN];
char* name = devname_r(dev, S_IFCHR, buf, MAXNAMLEN);
if (name) {
return xStrdup(name);
}
return NULL;
}function: DarwinProcess_new
Process* DarwinProcess_new(const Machine* host) {
DarwinProcess* this = xCalloc(1, sizeof(DarwinProcess));
Object_setClass(this, Class(DarwinProcess));
Process_init(&this->super, host);
this->utime = 0;
this->stime = 0;
this->taskAccess = true;
this->translated = false;
this->super.state = UNKNOWN;
return (Process*)this;
}function: DarwinProcess_rowWriteField
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];
size_t n = sizeof(buffer) - 1;
switch (field) {
// add Platform-specific fields here
case TRANSLATED: xSnprintf(buffer, n, "%c ", dp->translated ? 'T' : 'N'); break;
default:
Process_writeField(&dp->super, str, field);
return;
}
RichString_appendWide(str, attr, buffer);
}function: DarwinProcess_scanThreads
function: DarwinProcess_setFromKInfoProc
function: DarwinProcess_setFromLibprocPidinfo
void DarwinProcess_setFromLibprocPidinfo(DarwinProcess* proc, DarwinProcessTable* dpt, double timeIntervalNS) {
struct proc_taskinfo pti;
if (PROC_PIDTASKINFO_SIZE != proc_pidinfo(Process_getPid(&proc->super), PROC_PIDTASKINFO, 0, &pti, PROC_PIDTASKINFO_SIZE)) {
proc->taskAccess = false;
return;
}
const DarwinMachine* dhost = (const DarwinMachine*) proc->super.super.host;
uint64_t total_existing_time_ns = proc->stime + proc->utime;
uint64_t user_time_ns = pti.pti_total_user;
uint64_t system_time_ns = pti.pti_total_system;
uint64_t total_current_time_ns = user_time_ns + system_time_ns;
if (total_existing_time_ns < total_current_time_ns) {
const uint64_t total_time_diff_ns = total_current_time_ns - total_existing_time_ns;
proc->super.percent_cpu = ((double)total_time_diff_ns / timeIntervalNS) * 100.0;
} else {
proc->super.percent_cpu = 0.0;
}
Process_updateCPUFieldWidths(proc->super.percent_cpu);
proc->super.state = pti.pti_numrunning > 0 ? RUNNING : SLEEPING;
// Convert from nanoseconds to hundredths of seconds
proc->super.time = total_current_time_ns / 10000000ULL;
proc->super.nlwp = pti.pti_threadnum;
proc->super.m_virt = pti.pti_virtual_size / ONE_K;
proc->super.m_resident = pti.pti_resident_size / ONE_K;
proc->super.majflt = pti.pti_faults;
proc->super.percent_mem = (double)pti.pti_resident_size * 100.0 / (double)dhost->host_info.max_mem;
proc->stime = system_time_ns;
proc->utime = user_time_ns;
dpt->super.kernelThreads += 0; /*pti.pti_threads_system;*/
dpt->super.userlandThreads += pti.pti_threadnum; /*pti.pti_threads_user;*/
dpt->super.totalTasks += pti.pti_threadnum;
dpt->super.runningTasks += pti.pti_numrunning;
}function: DarwinProcess_updateCmdLine
function: DarwinProcess_updateCwd
static void DarwinProcess_updateCwd(pid_t pid, Process* proc) {
struct proc_vnodepathinfo vpi;
int r = proc_pidinfo(pid, PROC_PIDVNODEPATHINFO, 0, &vpi, sizeof(vpi));
if (r <= 0) {
free(proc->procCwd);
proc->procCwd = NULL;
return;
}
if (!vpi.pvi_cdir.vip_path[0]) {
free(proc->procCwd);
proc->procCwd = NULL;
return;
}
free_and_xStrdup(&proc->procCwd, vpi.pvi_cdir.vip_path);
}function: DarwinProcess_updateExe
static void DarwinProcess_updateExe(pid_t pid, Process* proc) {
char path[PROC_PIDPATHINFO_MAXSIZE];
int r = proc_pidpath(pid, path, sizeof(path));
if (r <= 0)
return;
Process_updateExe(proc, path);
}function: Process_delete
void Process_delete(Object* cast) {
DarwinProcess* this = (DarwinProcess*) cast;
Process_done(&this->super);
// free platform-specific fields here
free(this);
}global_constant: DarwinProcess_class
const ProcessClass DarwinProcess_class = {
.super = {
.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
},
.compareByKey = DarwinProcess_compareByKey
};global_constant: Process_fields
DarwinProcess.h
darwin/DarwinProcess.h
extern const: DarwinProcess_class
extern const ProcessClass DarwinProcess_class;
extern const: Process_fields
extern const ProcessFieldData Process_fields[LAST_PROCESSFIELD];
function: DarwinProcess_new
Process* DarwinProcess_new(const Machine* settings);
function: DarwinProcess_scanThreads
void DarwinProcess_scanThreads(DarwinProcess* dp, DarwinProcessTable* dpt);
function: DarwinProcess_setFromKInfoProc
void DarwinProcess_setFromKInfoProc(Process* proc, const struct kinfo_proc* ps, bool exists);
function: DarwinProcess_setFromLibprocPidinfo
void DarwinProcess_setFromLibprocPidinfo(DarwinProcess* proc, DarwinProcessTable* dpt, double timeIntervalNS);
function: Process_delete
void Process_delete(Object* cast);
macro: PROCESS_FLAG_TTY
#define PROCESS_FLAG_TTY 0x00000100
struct: DarwinProcess_
typedef struct DarwinProcess_ {
Process super;
uint64_t utime;
uint64_t stime;
bool taskAccess;
bool translated;
} DarwinProcess;DarwinProcessTable.c
darwin/DarwinProcessTable.c
function: ProcessTable_delete
void ProcessTable_delete(Object* cast) {
DarwinProcessTable* this = (DarwinProcessTable*) cast;
ProcessTable_done(&this->super);
free(this);
}function: ProcessTable_getKInfoProcs
static struct kinfo_proc* ProcessTable_getKInfoProcs(size_t* count) {
int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 };
struct kinfo_proc* processes = NULL;
for (unsigned int retry = 0; retry < 4; retry++) {
size_t size = 0;
if (sysctl(mib, 4, NULL, &size, NULL, 0) < 0 || size == 0) {
CRT_fatalError("Unable to get size of kproc_infos");
}
size += 16 * retry * retry * sizeof(struct kinfo_proc);
processes = xRealloc(processes, size);
if (sysctl(mib, 4, processes, &size, NULL, 0) == 0) {
*count = size / sizeof(struct kinfo_proc);
return processes;
}
if (errno != ENOMEM)
break;
}
CRT_fatalError("Unable to get kinfo_procs");
}function: ProcessTable_goThroughEntries
function: ProcessTable_new
ProcessTable* ProcessTable_new(Machine* host, Hashtable* pidMatchList) {
DarwinProcessTable* this = xCalloc(1, sizeof(DarwinProcessTable));
Object_setClass(this, Class(ProcessTable));
ProcessTable* super = &this->super;
ProcessTable_init(super, Class(DarwinProcess), host, pidMatchList);
return super;
}DarwinProcessTable.h
darwin/DarwinProcessTable.h
struct: DarwinProcessTable_
typedef struct DarwinProcessTable_ {
ProcessTable super;
uint64_t global_diff;
} DarwinProcessTable;Platform.c
darwin/Platform.c
file: Platform.c
Platform.h
darwin/Platform.h
function: Platform_addDynamicScreen
static inline void Platform_addDynamicScreen(ATTR_UNUSED ScreenSettings* ss) { }function: Platform_addDynamicScreenAvailableColumns
static inline void Platform_addDynamicScreenAvailableColumns(ATTR_UNUSED Panel* availableColumns, ATTR_UNUSED const char* screen) { }function: Platform_defaultDynamicScreens
static inline void Platform_defaultDynamicScreens(ATTR_UNUSED Settings* settings) { }function: Platform_done
void Platform_done(void);
function: Platform_dynamicColumnName
static inline const char* Platform_dynamicColumnName(ATTR_UNUSED unsigned int key) {
return NULL;
}function: Platform_dynamicColumns
static inline Hashtable* Platform_dynamicColumns(void) {
return NULL;
}function: Platform_dynamicColumnsDone
static inline void Platform_dynamicColumnsDone(ATTR_UNUSED Hashtable* table) { }function: Platform_dynamicColumnWriteField
static inline bool Platform_dynamicColumnWriteField(ATTR_UNUSED const Process* proc, ATTR_UNUSED RichString* str, ATTR_UNUSED unsigned int key) {
return false;
}function: Platform_dynamicMeterDisplay
static inline void Platform_dynamicMeterDisplay(ATTR_UNUSED const Meter* meter, ATTR_UNUSED RichString* out) { }function: Platform_dynamicMeterInit
static inline void Platform_dynamicMeterInit(ATTR_UNUSED Meter* meter) { }function: Platform_dynamicMeters
static inline Hashtable* Platform_dynamicMeters(void) {
return NULL;
}function: Platform_dynamicMetersDone
static inline void Platform_dynamicMetersDone(ATTR_UNUSED Hashtable* table) { }function: Platform_dynamicMeterUpdateValues
static inline void Platform_dynamicMeterUpdateValues(ATTR_UNUSED Meter* meter) { }function: Platform_dynamicScreens
static inline Hashtable* Platform_dynamicScreens(void) {
return NULL;
}function: Platform_dynamicScreensDone
static inline void Platform_dynamicScreensDone(ATTR_UNUSED Hashtable* screens) { }function: Platform_getBattery
void Platform_getBattery(double* percent, ACPresence* isOnAC);
function: Platform_getDiskIO
bool Platform_getDiskIO(DiskIOData* data);
function: Platform_getFileDescriptors
void Platform_getFileDescriptors(double* used, double* max);
function: Platform_getHostname
static inline void Platform_getHostname(char* buffer, size_t size) {
Generic_hostname(buffer, size);
}function: Platform_getLoadAverage
void Platform_getLoadAverage(double* one, double* five, double* fifteen);
function: Platform_getLongOption
static inline CommandLineStatus Platform_getLongOption(ATTR_UNUSED int opt, ATTR_UNUSED int argc, ATTR_UNUSED char** argv) {
return STATUS_ERROR_EXIT;
}function: Platform_getMaxPid
pid_t Platform_getMaxPid(void);
function: Platform_getNetworkIO
bool Platform_getNetworkIO(NetworkIOData* data);
function: Platform_getProcessEnv
char* Platform_getProcessEnv(pid_t pid);
function: Platform_getProcessLocks
FileLocks_ProcessData* Platform_getProcessLocks(pid_t pid);
function: Platform_getRelease
static inline void Platform_getRelease(char** string) {
*string = Generic_uname();
}function: Platform_gettime_monotonic
void Platform_gettime_monotonic(uint64_t* msec);
function: Platform_gettime_realtime
static inline void Platform_gettime_realtime(struct timeval* tv, uint64_t* msec) {
Generic_gettime_realtime(tv, msec);
}function: Platform_getUptime
int Platform_getUptime(void);
function: Platform_init
bool Platform_init(void);
function: Platform_longOptionsUsage
static inline void Platform_longOptionsUsage(ATTR_UNUSED const char* name) { }function: Platform_schedulerTicksToNanoseconds
double Platform_schedulerTicksToNanoseconds(const double scheduler_ticks);
function: Platform_setBindings
void Platform_setBindings(Htop_Action* keys);
function: Platform_setCPUValues
double Platform_setCPUValues(Meter* mtr, unsigned int cpu);
function: Platform_setMemoryValues
void Platform_setMemoryValues(Meter* mtr);
function: Platform_setSwapValues
void Platform_setSwapValues(Meter* mtr);
function: Platform_setZfsArcValues
void Platform_setZfsArcValues(Meter* this);
function: Platform_setZfsCompressedArcValues
void Platform_setZfsCompressedArcValues(Meter* this);
macro: PLATFORM_LONG_OPTIONS
#define PLATFORM_LONG_OPTIONS
variable: Platform_defaultScreens
extern const ScreenDefaults Platform_defaultScreens[];
variable: Platform_meterTypes
extern const MeterClass* const Platform_meterTypes[];
variable: Platform_numberOfDefaultScreens
extern const unsigned int Platform_numberOfDefaultScreens;
variable: Platform_numberOfSignals
extern const unsigned int Platform_numberOfSignals;
variable: Platform_signals
extern const SignalItem Platform_signals[];
PlatformHelpers.c
darwin/PlatformHelpers.c
function: Platform_CompareKernelVersion
int Platform_CompareKernelVersion(KernelVersion v) {
struct KernelVersion actualVersion;
Platform_GetKernelVersion(&actualVersion);
if (actualVersion.major != v.major) {
return actualVersion.major - v.major;
}
if (actualVersion.minor != v.minor) {
return actualVersion.minor - v.minor;
}
if (actualVersion.patch != v.patch) {
return actualVersion.patch - v.patch;
}
return 0;
}function: Platform_getCPUBrandString
void Platform_getCPUBrandString(char* cpuBrandString, size_t cpuBrandStringSize) {
if (sysctlbyname("machdep.cpu.brand_string", cpuBrandString, &cpuBrandStringSize, NULL, 0) == -1) {
fprintf(stderr,
"WARN: Unable to determine the CPU brand string.\n"
"errno: %i, %s\n", errno, strerror(errno));
String_safeStrncpy(cpuBrandString, "UNKNOWN!", cpuBrandStringSize);
}
}function: Platform_GetKernelVersion
void Platform_GetKernelVersion(KernelVersion* k) {
static KernelVersion cachedKernelVersion;
if (!cachedKernelVersion.major) {
// just in case it fails someday
cachedKernelVersion = (KernelVersion) { -1, -1, -1 };
char str[256] = {0};
size_t size = sizeof(str);
int ret = sysctlbyname("kern.osrelease", str, &size, NULL, 0);
if (ret == 0) {
sscanf(str, "%hd.%hd.%hd", &cachedKernelVersion.major, &cachedKernelVersion.minor, &cachedKernelVersion.patch);
}
}
memcpy(k, &cachedKernelVersion, sizeof(cachedKernelVersion));
}function: Platform_isRunningTranslated
bool Platform_isRunningTranslated(void) {
int ret = 0;
size_t size = sizeof(ret);
errno = 0;
if (sysctlbyname("sysctl.proc_translated", &ret, &size, NULL, 0) == -1) {
if (errno == ENOENT)
return false;
fprintf(stderr,
"WARN: Could not determine if this process was running in a translation environment like Rosetta 2.\n"
"Assuming that we're not.\n"
"errno: %i, %s\n", errno, strerror(errno));
return false;
}
return ret;
}function: Platform_KernelVersionIsBetween
bool Platform_KernelVersionIsBetween(KernelVersion lowerBound, KernelVersion upperBound) {
return 0 <= Platform_CompareKernelVersion(lowerBound)
&& Platform_CompareKernelVersion(upperBound) < 0;
}PlatformHelpers.h
darwin/PlatformHelpers.h
function: Platform_CompareKernelVersion
int Platform_CompareKernelVersion(KernelVersion v);
function: Platform_getCPUBrandString
void Platform_getCPUBrandString(char* cpuBrandString, size_t cpuBrandStringSize);
function: Platform_GetKernelVersion
void Platform_GetKernelVersion(KernelVersion* k);
function: Platform_isRunningTranslated
bool Platform_isRunningTranslated(void);
function: Platform_KernelVersionIsBetween
bool Platform_KernelVersionIsBetween(KernelVersion lowerBound, KernelVersion upperBound);
struct: KernelVersion
typedef struct KernelVersion {
short int major;
short int minor;
short int patch;
} KernelVersion;ProcessField.h
darwin/ProcessField.h
macro: PLATFORM_PROCESS_FIELDS
#define PLATFORM_PROCESS_FIELDS \
TRANSLATED = 100, \
\
DUMMY_BUMP_FIELD = CWD, \
// End of listDateMeter.c
DateMeter.c
function: DateMeter_updateValues
static void DateMeter_updateValues(Meter* this) {
const Machine* host = this->host;
struct tm result;
const struct tm* lt = localtime_r(&host->realtime.tv_sec, &result);
strftime(this->txtBuffer, sizeof(this->txtBuffer), "%F", lt);
}global variable: DateMeter_attributes
static const int DateMeter_attributes[] = {
DATE
};global variable (struct instance): DateMeter_class
const MeterClass DateMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete
},
.updateValues = DateMeter_updateValues,
.defaultMode = TEXT_METERMODE,
.supportedModes = (1 << TEXT_METERMODE) | (1 << LED_METERMODE),
.maxItems = 0,
.total = 0.0,
.attributes = DateMeter_attributes,
.name = "Date",
.uiName = "Date",
.caption = "Date: ",
};DateMeter.h
DateMeter.h
variable: DateMeter_class
extern const MeterClass DateMeter_class;
DateTimeMeter.c
DateTimeMeter.c
function: DateTimeMeter_updateValues
static void DateTimeMeter_updateValues(Meter* this) {
const Machine* host = this->host;
struct tm result;
const struct tm* lt = localtime_r(&host->realtime.tv_sec, &result);
strftime(this->txtBuffer, sizeof(this->txtBuffer), "%F %H:%M:%S", lt);
}struct: DateTimeMeter_class
const MeterClass DateTimeMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete
},
.updateValues = DateTimeMeter_updateValues,
.defaultMode = TEXT_METERMODE,
.supportedModes = (1 << TEXT_METERMODE) | (1 << LED_METERMODE),
.maxItems = 0,
.total = 0.0,
.attributes = DateTimeMeter_attributes,
.name = "DateTime",
.uiName = "Date and Time",
.caption = "Date & Time: ",
};variable: DateTimeMeter_attributes
static const int DateTimeMeter_attributes[] = {
DATETIME
};DateTimeMeter.h
DateTimeMeter.h
struct: DateTimeMeter_class
extern const MeterClass DateTimeMeter_class;
DiskIOMeter.c
DiskIOMeter.c
function: DiskIOMeter_display
static void DiskIOMeter_display(ATTR_UNUSED const Object* cast, RichString* out) {
switch (status) {
case RATESTATUS_NODATA:
RichString_writeAscii(out, CRT_colors[METER_VALUE_ERROR], "no data");
return;
case RATESTATUS_INIT:
RichString_writeAscii(out, CRT_colors[METER_VALUE], "initializing...");
return;
case RATESTATUS_STALE:
RichString_writeAscii(out, CRT_colors[METER_VALUE_WARN], "stale data");
return;
case RATESTATUS_DATA:
break;
}
char buffer[16];
int color = cached_utilisation_diff > 40.0 ? METER_VALUE_NOTICE : METER_VALUE;
int len = xSnprintf(buffer, sizeof(buffer), "%.1f%%", cached_utilisation_diff);
RichString_appendnAscii(out, CRT_colors[color], buffer, len);
RichString_appendAscii(out, CRT_colors[METER_TEXT], " read: ");
RichString_appendAscii(out, CRT_colors[METER_VALUE_IOREAD], cached_read_diff_str);
RichString_appendAscii(out, CRT_colors[METER_VALUE_IOREAD], "iB/s");
RichString_appendAscii(out, CRT_colors[METER_TEXT], " write: ");
RichString_appendAscii(out, CRT_colors[METER_VALUE_IOWRITE], cached_write_diff_str);
RichString_appendAscii(out, CRT_colors[METER_VALUE_IOWRITE], "iB/s");
}function: DiskIOMeter_updateValues
global variable: cached_read_diff_str
static char cached_read_diff_str[6];
global variable: cached_utilisation_diff
static double cached_utilisation_diff;
global variable: cached_utilisation_norm
static double cached_utilisation_norm;
global variable: cached_write_diff_str
static char cached_write_diff_str[6];
global variable: DiskIOMeter_attributes
static const int DiskIOMeter_attributes[] = {
METER_VALUE_NOTICE,
METER_VALUE_IOREAD,
METER_VALUE_IOWRITE,
};global variable: status
static MeterRateStatus status = RATESTATUS_INIT;
struct: DiskIOMeter_class
const MeterClass DiskIOMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = DiskIOMeter_display
},
.updateValues = DiskIOMeter_updateValues,
.defaultMode = TEXT_METERMODE,
.supportedModes = METERMODE_DEFAULT_SUPPORTED,
.maxItems = 1,
.total = 1.0,
.attributes = DiskIOMeter_attributes,
.name = "DiskIO",
.uiName = "Disk IO",
.caption = "Disk IO: "
};DiskIOMeter.h
DiskIOMeter.h
extern declaration: DiskIOMeter_class
extern const MeterClass DiskIOMeter_class;
struct: DiskIOData
typedef struct DiskIOData_ {
uint64_t totalBytesRead;
uint64_t totalBytesWritten;
uint64_t totalMsTimeSpend;
uint64_t numDisks;
} DiskIOData;DisplayOptionsPanel.c
DisplayOptionsPanel.c
constant array: DisplayOptionsDecIncEvents
static const int DisplayOptionsDecIncEvents[] = {'-', KEY_F(7), '+', KEY_F(8), ERR, KEY_F(10)};constant array: DisplayOptionsDecIncFunctions
static const char* const DisplayOptionsDecIncFunctions[] = {" ", " ", " ", " ", " ", " ", "Dec ", "Inc ", " ", "Done ", NULL};constant array: DisplayOptionsDecIncKeys
static const char* const DisplayOptionsDecIncKeys[] = {" " , " " , " " , " " , " " , " " , "F7" , "F8" , " " , "F10" , NULL};constant array: DisplayOptionsFunctions
static const char* const DisplayOptionsFunctions[] = {" ", " ", " ", " ", " ", " ", " ", " ", " ", "Done ", NULL};function: DisplayOptionsPanel_delete
static void DisplayOptionsPanel_delete(Object* object) {
DisplayOptionsPanel* this = (DisplayOptionsPanel*) object;
FunctionBar_delete(this->decIncBar);
Panel_done(&this->super);
free(this);
}function: DisplayOptionsPanel_eventHandler
function: DisplayOptionsPanel_new
struct: DisplayOptionsPanel
/* (Struct definition is typically in DisplayOptionsPanel.h) */
typedef struct DisplayOptionsPanel_ {
Panel super;
FunctionBar* decIncBar;
Settings* settings;
ScreenManager* scr;
} DisplayOptionsPanel;struct instance: DisplayOptionsPanel_class
const PanelClass DisplayOptionsPanel_class = {
.super = {
.extends = Class(Panel),
.delete = DisplayOptionsPanel_delete
},
.eventHandler = DisplayOptionsPanel_eventHandler
};DisplayOptionsPanel.h
DisplayOptionsPanel.h
extern const: DisplayOptionsPanel_class
extern const PanelClass DisplayOptionsPanel_class;
function: DisplayOptionsPanel_new
DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager* scr);
struct: DisplayOptionsPanel_
typedef struct DisplayOptionsPanel_ {
Panel super;
Settings* settings;
ScreenManager* scr;
FunctionBar* decIncBar;
} DisplayOptionsPanel;type alias: DisplayOptionsPanel
typedef struct DisplayOptionsPanel_ {
Panel super;
Settings* settings;
ScreenManager* scr;
FunctionBar* decIncBar;
} DisplayOptionsPanel;styleguide.md
docs/styleguide.md
function: BlankLinesInFunctionExample
int stuff = 0;
// If asked for gives only half the answer ...
if (param)
stuff = 21;
// Compute the answer
stuff %= 2;
stuff *= 4;
stuff *= 5;
stuff += !!stuff;
stuff *= 2;
return stuff;
function: ComplexIfStatementWithBracesExample
if ((fd = open(filename, O_RDONLY)) >= 0 &&
(amtRead = read(buffer, sizeof(buffer))) > 0) {
// Parse the information further ...
metric = handleBufferContent(buffer, amtRead);
} else {
metric = -1;
}
if (fd >= 0)
close(fd);
function: ControlFlowNewLinesNoBracesExample
if (answer) return 42; else if (again) continue; else break;
function: MultiLineIfStatementIndentationExample
if (very_long_condition &&
another_very_complex_expression &&
something_else_to_check) {
// Code follows as normal ...
} else {
}
function: SimpleIfStatementNoBracesExample
if (answer) return 42;
struct: HeaderGuardExample
#ifndef HEADER_FILENAME #define HEADER_FILENAME /* htop - Filename.h (C) 2021 htop dev team Released under the GNU GPLv2+, see the COPYING file in the source distribution for its full text. */
DragonFlyBSDMachine.c
dragonflybsd/DragonFlyBSDMachine.c
function: DragonFlyBSDMachine_readJailName
char* DragonFlyBSDMachine_readJailName(const DragonFlyBSDMachine* host, int jailid) {
char* hostname;
char* jname;
if (jailid != 0 && host->jails && (hostname = (char*)Hashtable_get(host->jails, jailid))) {
jname = xStrdup(hostname);
} else {
jname = xStrdup("-");
}
return jname;
}function: DragonFlyBSDMachine_scanCPUTime
function: DragonFlyBSDMachine_scanJails
static void DragonFlyBSDMachine_scanJails(DragonFlyBSDMachine* this) {
size_t len;
char* jails; /* Jail list */
char* curpos;
char* nextpos;
if (sysctlbyname("jail.list", NULL, &len, NULL, 0) == -1) {
CRT_fatalError("initial sysctlbyname / jail.list failed");
}
retry:
if (len == 0)
return;
jails = xMalloc(len);
if (sysctlbyname("jail.list", jails, &len, NULL, 0) == -1) {
if (errno == ENOMEM) {
free(jails);
goto retry;
}
CRT_fatalError("sysctlbyname / jail.list failed");
}
if (this->jails) {
Hashtable_delete(this->jails);
}
this->jails = Hashtable_new(20, true);
curpos = jails;
while (curpos) {
int jailid;
char* str_hostname;
nextpos = strchr(curpos, '\n');
if (nextpos) {
*nextpos++ = 0;
}
jailid = atoi(strtok(curpos, " "));
str_hostname = strtok(NULL, " ");
char* jname = (char*) (Hashtable_get(this->jails, jailid));
if (jname == NULL) {
jname = xStrdup(str_hostname);
Hashtable_put(this->jails, jailid, jname);
}
curpos = nextpos;
}
free(jails);
}function: DragonFlyBSDMachine_scanMemoryInfo
static void DragonFlyBSDMachine_scanMemoryInfo(Machine* super) {
DragonFlyBSDMachine* this = (DragonFlyBSDMachine*) super;
// @etosan:
// memory counter relationships seem to be these:
// total = active + wired + inactive + cache + free
// htop_used (unavail to anybody) = active + wired
// htop_cache (for cache meter) = buffers + cache
// user_free (avail to procs) = buffers + inactive + cache + free
size_t len = sizeof(super->totalMem);
//disabled for now, as it is always smaller than phycal amount of memory...
//...to avoid "where is my memory?" questions
//sysctl(MIB_vm_stats_vm_v_page_count, 4, &(this->totalMem), &len, NULL, 0);
//this->totalMem *= pageSizeKb;
sysctl(MIB_hw_physmem, 2, &(super->totalMem), &len, NULL, 0);
super->totalMem /= 1024;
unsigned long long int memActive = 0;
sysctl(MIB_vm_stats_vm_v_active_count, 4, &memActive, &len, NULL, 0);
memActive *= this->pageSizeKb;
unsigned long long int memWire = 0;
sysctl(MIB_vm_stats_vm_v_wire_count, 4, &memWire, &len, NULL, 0);
memWire *= this->pageSizeKb;
sysctl(MIB_vfs_bufspace, 2, &(super->buffersMem), &len, NULL, 0);
super->buffersMem /= 1024;
sysctl(MIB_vm_stats_vm_v_cache_count, 4, &(super->cachedMem), &len, NULL, 0);
super->cachedMem *= this->pageSizeKb;
super->usedMem = memActive + memWire;
struct kvm_swap swap[16];
int nswap = kvm_getswapinfo(this->kd, swap, ARRAYSIZE(swap), 0);
super->totalSwap = 0;
super->usedSwap = 0;
for (int i = 0; i < nswap; i++) {
super->totalSwap += swap[i].ksw_total;
super->usedSwap += swap[i].ksw_used;
}
super->totalSwap *= this->pageSizeKb;
super->usedSwap *= this->pageSizeKb;
}function: Machine_delete
void Machine_delete(Machine* super) {
DragonFlyBSDMachine* this = (DragonFlyBSDMachine*) super;
Machine_done(super);
if (this->kd) {
kvm_close(this->kd);
}
if (this->jails) {
Hashtable_delete(this->jails);
}
free(this->cp_time_o);
free(this->cp_time_n);
free(this->cp_times_o);
free(this->cp_times_n);
free(this->cpus);
free(this);
}function: Machine_isCPUonline
bool Machine_isCPUonline(const Machine* host, unsigned int id) {
assert(id < host->existingCPUs);
(void)host; (void)id;
// TODO: Support detecting online / offline CPUs.
return true;
}function: Machine_new
function: Machine_scan
void Machine_scan(Machine* super) {
DragonFlyBSDMachine* this = (DragonFlyBSDMachine*) super;
DragonFlyBSDMachine_scanMemoryInfo(super);
DragonFlyBSDMachine_scanCPUTime(super);
DragonFlyBSDMachine_scanJails(this);
}DragonFlyBSDMachine.h
dragonflybsd/DragonFlyBSDMachine.h
function: DragonFlyBSDMachine_readJailName
char* DragonFlyBSDMachine_readJailName(const DragonFlyBSDMachine* host, int jailid);
struct: CPUData
typedef struct CPUData_ {
double userPercent;
double nicePercent;
double systemPercent;
double irqPercent;
double idlePercent;
double systemAllPercent;
} CPUData;struct: DragonFlyBSDMachine
typedef struct DragonFlyBSDMachine_ {
Machine super;
kvm_t* kd;
Hashtable* jails;
int pageSize;
int pageSizeKb;
int kernelFScale;
CPUData* cpus;
unsigned long* cp_time_o;
unsigned long* cp_time_n;
unsigned long* cp_times_o;
unsigned long* cp_times_n;
} DragonFlyBSDMachine;DragonFlyBSDProcess.c
dragonflybsd/DragonFlyBSDProcess.c
function: DragonFlyBSDProcess_new
Process* DragonFlyBSDProcess_new(const Machine* host) {
DragonFlyBSDProcess* this = xCalloc(1, sizeof(DragonFlyBSDProcess));
Object_setClass(this, Class(DragonFlyBSDProcess));
Process_init(&this->super, host);
return (Process*)this;
}method: DragonFlyBSDProcess_compareByKey
static int DragonFlyBSDProcess_compareByKey(const Process* v1, const Process* v2, ProcessField key) {
const DragonFlyBSDProcess* p1 = (const DragonFlyBSDProcess*)v1;
const DragonFlyBSDProcess* p2 = (const DragonFlyBSDProcess*)v2;
switch (key) {
// add Platform-specific fields here
case JID:
return SPACESHIP_NUMBER(p1->jid, p2->jid);
case JAIL:
return SPACESHIP_NULLSTR(p1->jname, p2->jname);
default:
return Process_compareByKey_Base(v1, v2, key);
}
}method: DragonFlyBSDProcess_rowWriteField
static void DragonFlyBSDProcess_rowWriteField(const Row* super, RichString* str, ProcessField field) {
const Process* this = (const Process*) super;
const DragonFlyBSDProcess* fp = (const DragonFlyBSDProcess*) super;
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 : Process_getPid(this)); break;
case JID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, fp->jid); break;
case JAIL: Row_printLeftAlignedField(str, attr, fp->jname, 11); return;
default:
Process_writeField(&fp->super, str, field);
return;
}
RichString_appendWide(str, attr, buffer);
}method: Process_delete
void Process_delete(Object* cast) {
DragonFlyBSDProcess* this = (DragonFlyBSDProcess*) cast;
Process_done((Process*)cast);
free(this->jname);
free(this);
}structure: DragonFlyBSDProcess_class
const ProcessClass DragonFlyBSDProcess_class = {
.super = {
.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
},
.compareByKey = DragonFlyBSDProcess_compareByKey
};structure: Process_fields
DragonFlyBSDProcess.h
dragonflybsd/DragonFlyBSDProcess.h
function: DragonFlyBSDProcess_new
Process* DragonFlyBSDProcess_new(const Machine* host);
function: Process_delete
void Process_delete(Object* cast);
struct: DragonFlyBSDProcess_
typedef struct DragonFlyBSDProcess_ {
Process super;
int jid;
char* jname;
} DragonFlyBSDProcess;variable: DragonFlyBSDProcess_class
extern const ProcessClass DragonFlyBSDProcess_class;
variable: Process_fields
extern const ProcessFieldData Process_fields[LAST_PROCESSFIELD];
DragonFlyBSDProcessTable.c
dragonflybsd/DragonFlyBSDProcessTable.c
function: DragonFlyBSDProcessTable_updateCwd
static void DragonFlyBSDProcessTable_updateCwd(const struct kinfo_proc* kproc, Process* proc) {
const int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_CWD, kproc->kp_pid };
char buffer[2048];
size_t size = sizeof(buffer);
if (sysctl(mib, 4, buffer, &size, NULL, 0) != 0) {
free(proc->procCwd);
proc->procCwd = NULL;
return;
}
/* Kernel threads return an empty buffer */
if (buffer[0] == '\0') {
free(proc->procCwd);
proc->procCwd = NULL;
return;
}
free_and_xStrdup(&proc->procCwd, buffer);
}function: DragonFlyBSDProcessTable_updateExe
static void DragonFlyBSDProcessTable_updateExe(const struct kinfo_proc* kproc, Process* proc) {
if (Process_isKernelThread(proc))
return;
char path[32];
xSnprintf(path, sizeof(path), "/proc/%d/file", kproc->kp_pid);
char target[PATH_MAX];
ssize_t ret = readlink(path, target, sizeof(target) - 1);
if (ret <= 0)
return;
target[ret] = '\0';
Process_updateExe(proc, target);
}function: DragonFlyBSDProcessTable_updateProcessName
static void DragonFlyBSDProcessTable_updateProcessName(kvm_t* kd, const struct kinfo_proc* kproc, Process* proc) {
Process_updateComm(proc, kproc->kp_comm);
char** argv = kvm_getargv(kd, kproc, 0);
if (!argv || !argv[0]) {
Process_updateCmdline(proc, kproc->kp_comm, 0, strlen(kproc->kp_comm));
return;
}
size_t len = 0;
for (int i = 0; argv[i]; i++) {
len += strlen(argv[i]) + 1;
}
char* cmdline = xMalloc(len);
char* at = cmdline;
int end = 0;
for (int i = 0; argv[i]; i++) {
at = stpcpy(at, argv[i]);
if (end == 0) {
end = at - cmdline;
}
*at++ = ' ';
}
at--;
*at = '\0';
Process_updateCmdline(proc, cmdline, 0, end);
free(cmdline);
}function: ProcessTable_delete
void ProcessTable_delete(Object* cast) {
DragonFlyBSDProcessTable* this = (DragonFlyBSDProcessTable*) cast;
ProcessTable_done(&this->super);
free(this);
}function: ProcessTable_goThroughEntries
function: ProcessTable_new
ProcessTable* ProcessTable_new(Machine* host, Hashtable* pidMatchList) {
DragonFlyBSDProcessTable* this = xCalloc(1, sizeof(DragonFlyBSDProcessTable));
Object_setClass(this, Class(ProcessTable));
ProcessTable* super = (ProcessTable*) this;
ProcessTable_init(super, Class(DragonFlyBSDProcess), host, pidMatchList);
return super;
}DragonFlyBSDProcessTable.h
dragonflybsd/DragonFlyBSDProcessTable.h
struct: DragonFlyBSDProcessTable
typedef struct DragonFlyBSDProcessTable_ {
ProcessTable super;
} DragonFlyBSDProcessTable;Platform.c
dragonflybsd/Platform.c
file: Platform.c
Platform.h
dragonflybsd/Platform.h
function: Platform_addDynamicScreen
static inline void Platform_addDynamicScreen(ATTR_UNUSED ScreenSettings* ss) { }function: Platform_addDynamicScreenAvailableColumns
static inline void Platform_addDynamicScreenAvailableColumns(ATTR_UNUSED Panel* availableColumns, ATTR_UNUSED const char* screen) { }function: Platform_defaultDynamicScreens
static inline void Platform_defaultDynamicScreens(ATTR_UNUSED Settings* settings) { }function: Platform_done
void Platform_done(void);
function: Platform_dynamicColumnName
static inline const char* Platform_dynamicColumnName(ATTR_UNUSED unsigned int key) {
return NULL;
}function: Platform_dynamicColumns
static inline Hashtable* Platform_dynamicColumns(void) {
return NULL;
}function: Platform_dynamicColumnsDone
static inline void Platform_dynamicColumnsDone(ATTR_UNUSED Hashtable* table) { }function: Platform_dynamicColumnWriteField
static inline bool Platform_dynamicColumnWriteField(ATTR_UNUSED const Process* proc, ATTR_UNUSED RichString* str, ATTR_UNUSED unsigned int key) {
return false;
}function: Platform_dynamicMeterDisplay
static inline void Platform_dynamicMeterDisplay(ATTR_UNUSED const Meter* meter, ATTR_UNUSED RichString* out) { }function: Platform_dynamicMeterInit
static inline void Platform_dynamicMeterInit(ATTR_UNUSED Meter* meter) { }function: Platform_dynamicMeters
static inline Hashtable* Platform_dynamicMeters(void) {
return NULL;
}function: Platform_dynamicMetersDone
static inline void Platform_dynamicMetersDone(ATTR_UNUSED Hashtable* table) { }function: Platform_dynamicMeterUpdateValues
static inline void Platform_dynamicMeterUpdateValues(ATTR_UNUSED Meter* meter) { }function: Platform_dynamicScreens
static inline Hashtable* Platform_dynamicScreens(void) {
return NULL;
}function: Platform_dynamicScreensDone
static inline void Platform_dynamicScreensDone(ATTR_UNUSED Hashtable* screens) { }function: Platform_getBattery
void Platform_getBattery(double* percent, ACPresence* isOnAC);
function: Platform_getDiskIO
bool Platform_getDiskIO(DiskIOData* data);
function: Platform_getFileDescriptors
void Platform_getFileDescriptors(double* used, double* max);
function: Platform_getHostname
static inline void Platform_getHostname(char* buffer, size_t size) {
Generic_hostname(buffer, size);
}function: Platform_getLoadAverage
void Platform_getLoadAverage(double* one, double* five, double* fifteen);
function: Platform_getLongOption
static inline CommandLineStatus Platform_getLongOption(ATTR_UNUSED int opt, ATTR_UNUSED int argc, ATTR_UNUSED char** argv) {
return STATUS_ERROR_EXIT;
}function: Platform_getMaxPid
pid_t Platform_getMaxPid(void);
function: Platform_getNetworkIO
bool Platform_getNetworkIO(NetworkIOData* data);
function: Platform_getProcessEnv
char* Platform_getProcessEnv(pid_t pid);
function: Platform_getProcessLocks
FileLocks_ProcessData* Platform_getProcessLocks(pid_t pid);
function: Platform_getRelease
static inline void Platform_getRelease(char** string) {
*string = Generic_uname();
}function: Platform_gettime_monotonic
static inline void Platform_gettime_monotonic(uint64_t* msec) {
Generic_gettime_monotonic(msec);
}function: Platform_gettime_realtime
static inline void Platform_gettime_realtime(struct timeval* tv, uint64_t* msec) {
Generic_gettime_realtime(tv, msec);
}function: Platform_getUptime
int Platform_getUptime(void);
function: Platform_init
bool Platform_init(void);
function: Platform_longOptionsUsage
static inline void Platform_longOptionsUsage(ATTR_UNUSED const char* name) { }function: Platform_setBindings
void Platform_setBindings(Htop_Action* keys);
function: Platform_setCPUValues
double Platform_setCPUValues(Meter* this, unsigned int cpu);
function: Platform_setMemoryValues
void Platform_setMemoryValues(Meter* this);
function: Platform_setSwapValues
void Platform_setSwapValues(Meter* this);
macro: PLATFORM_LONG_OPTIONS
#define PLATFORM_LONG_OPTIONS
variable: Platform_defaultScreens
extern const ScreenDefaults Platform_defaultScreens[];
variable: Platform_meterTypes
extern const MeterClass* const Platform_meterTypes[];
variable: Platform_numberOfDefaultScreens
extern const unsigned int Platform_numberOfDefaultScreens;
variable: Platform_numberOfSignals
extern const unsigned int Platform_numberOfSignals;
variable: Platform_signals
extern const SignalItem Platform_signals[];
ProcessField.h
dragonflybsd/ProcessField.h
macro: PLATFORM_PROCESS_FIELDS
#define PLATFORM_PROCESS_FIELDS \
JID = 100, \
JAIL = 101, \
\
DUMMY_BUMP_FIELD = CWD, \
// End of listDynamicColumn.c
DynamicColumn.c
function: DynamicColumn_compare
static void DynamicColumn_compare(ht_key_t key, void* value, void* data) {
const DynamicColumn* column = (const DynamicColumn*)value;
DynamicIterator* iter = (DynamicIterator*)data;
if (String_eq(iter->name, column->name)) {
iter->data = column;
iter->key = key;
}
}function: DynamicColumn_done
void DynamicColumn_done(DynamicColumn* this) {
free(this->heading);
free(this->caption);
free(this->description);
}function: DynamicColumn_lookup
const DynamicColumn* DynamicColumn_lookup(Hashtable* dynamics, unsigned int key) {
return (const DynamicColumn*) Hashtable_get(dynamics, key);
}function: DynamicColumn_name
const char* DynamicColumn_name(unsigned int key) {
return Platform_dynamicColumnName(key);
}function: DynamicColumn_search
const DynamicColumn* DynamicColumn_search(Hashtable* dynamics, const char* name, unsigned int* key) {
DynamicIterator iter = { .key = 0, .data = NULL, .name = name };
if (dynamics)
Hashtable_foreach(dynamics, DynamicColumn_compare, &iter);
if (key)
*key = iter.key;
return iter.data;
}function: DynamicColumn_writeField
bool DynamicColumn_writeField(const Process* proc, RichString* str, unsigned int key) {
return Platform_dynamicColumnWriteField(proc, str, key);
}function: DynamicColumns_delete
void DynamicColumns_delete(Hashtable* dynamics) {
if (dynamics) {
Platform_dynamicColumnsDone(dynamics);
Hashtable_delete(dynamics);
}
}function: DynamicColumns_new
Hashtable* DynamicColumns_new(void) {
Hashtable* dynamics = Platform_dynamicColumns();
if (!dynamics)
dynamics = Hashtable_new(0, true);
return dynamics;
}struct: DynamicIterator
typedef struct {
const char* name;
const DynamicColumn* data;
unsigned int key;
} DynamicIterator;DynamicColumn.h
DynamicColumn.h
function: DynamicColumn_done
void DynamicColumn_done(DynamicColumn* this);
function: DynamicColumn_lookup
const DynamicColumn* DynamicColumn_lookup(Hashtable* dynamics, unsigned int key);
function: DynamicColumn_name
const char* DynamicColumn_name(unsigned int key);
function: DynamicColumn_search
const DynamicColumn* DynamicColumn_search(Hashtable* dynamics, const char* name, unsigned int* key);
function: DynamicColumn_writeField
bool DynamicColumn_writeField(const Process* proc, RichString* str, unsigned int key);
function: DynamicColumns_delete
void DynamicColumns_delete(Hashtable* dynamics);
function: DynamicColumns_new
Hashtable* DynamicColumns_new(void);
macro: DYNAMIC_DEFAULT_COLUMN_WIDTH
#define DYNAMIC_DEFAULT_COLUMN_WIDTH -5
macro: DYNAMIC_MAX_COLUMN_WIDTH
#define DYNAMIC_MAX_COLUMN_WIDTH 64
struct: DynamicColumn
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 */
bool enabled; /* false == ignore this column (until enabled) */
Table* table; /* pointer to DynamicScreen or ProcessTable */
} DynamicColumn;DynamicMeter.c
DynamicMeter.c
function: DynamicMeter_compare
static void DynamicMeter_compare(ht_key_t key, void* value, void* data) {
const DynamicMeter* meter = (const DynamicMeter*)value;
DynamicIterator* iter = (DynamicIterator*)data;
if (String_eq(iter->name, meter->name)) {
iter->found = true;
iter->key = key;
}
}function: DynamicMeter_display
static void DynamicMeter_display(const Object* cast, RichString* out) {
const Meter* meter = (const Meter*)cast;
Platform_dynamicMeterDisplay(meter, out);
}function: DynamicMeter_getCaption
static const char* DynamicMeter_getCaption(const Meter* this) {
const Settings* settings = this->host->settings;
const DynamicMeter* meter = Hashtable_get(settings->dynamicMeters, this->param);
if (meter)
return meter->caption ? meter->caption : meter->name;
return this->caption;
}function: DynamicMeter_getUiName
static void DynamicMeter_getUiName(const Meter* this, char* name, size_t length) {
assert(length > 0);
const Settings* settings = this->host->settings;
const DynamicMeter* meter = Hashtable_get(settings->dynamicMeters, this->param);
if (meter) {
const char* uiName = meter->caption;
if (uiName) {
size_t uiNameLen = strlen(uiName);
if (uiNameLen > 2 && uiName[uiNameLen - 2] == ':')
uiNameLen -= 2;
String_safeStrncpy(name, uiName, MINIMUM(length, uiNameLen + 1));
} else {
String_safeStrncpy(name, meter->name, length);
}
}
}function: DynamicMeter_init
static void DynamicMeter_init(Meter* meter) {
Platform_dynamicMeterInit(meter);
}function: DynamicMeter_lookup
const char* DynamicMeter_lookup(Hashtable* dynamics, unsigned int key) {
const DynamicMeter* meter = Hashtable_get(dynamics, key);
return meter ? meter->name : NULL;
}function: DynamicMeter_search
bool DynamicMeter_search(Hashtable* dynamics, const char* name, unsigned int* key) {
DynamicIterator iter = { .key = 0, .name = name, .found = false };
if (dynamics)
Hashtable_foreach(dynamics, DynamicMeter_compare, &iter);
if (key)
*key = iter.key;
return iter.found;
}function: DynamicMeter_updateValues
static void DynamicMeter_updateValues(Meter* meter) {
Platform_dynamicMeterUpdateValues(meter);
}function: DynamicMeters_delete
void DynamicMeters_delete(Hashtable* dynamics) {
if (dynamics) {
Platform_dynamicMetersDone(dynamics);
Hashtable_delete(dynamics);
}
}function: DynamicMeters_new
Hashtable* DynamicMeters_new(void) {
return Platform_dynamicMeters();
}global variable: DynamicMeter_attributes
static const int DynamicMeter_attributes[] = {
DYNAMIC_GRAY,
DYNAMIC_DARKGRAY,
DYNAMIC_RED,
DYNAMIC_GREEN,
DYNAMIC_BLUE,
DYNAMIC_CYAN,
DYNAMIC_MAGENTA,
DYNAMIC_YELLOW,
DYNAMIC_WHITE
};global variable: DynamicMeter_class
const MeterClass DynamicMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = DynamicMeter_display
},
.init = DynamicMeter_init,
.updateValues = DynamicMeter_updateValues,
.getCaption = DynamicMeter_getCaption,
.getUiName = DynamicMeter_getUiName,
.defaultMode = TEXT_METERMODE,
.supportedModes = METERMODE_DEFAULT_SUPPORTED,
.maxItems = 0,
.total = 100.0,
.attributes = DynamicMeter_attributes,
.name = "Dynamic",
.uiName = "Dynamic",
.caption = "",
};struct: DynamicIterator
typedef struct {
unsigned int key;
const char* name;
bool found;
} DynamicIterator;DynamicMeter.h
DynamicMeter.h
function: DynamicMeter_lookup
const char* DynamicMeter_lookup(Hashtable* dynamics, unsigned int key);
function: DynamicMeter_search
bool DynamicMeter_search(Hashtable* dynamics, const char* name, unsigned int* key);
function: DynamicMeters_delete
void DynamicMeters_delete(Hashtable* dynamics);
function: DynamicMeters_new
Hashtable* DynamicMeters_new(void);
struct: DynamicMeter
typedef struct DynamicMeter_ {
char name[32]; /* unique name, cannot contain spaces */
char* caption;
char* description;
unsigned int type;
double maximum;
} DynamicMeter;variable: DynamicMeter_class
extern const MeterClass DynamicMeter_class;
DynamicScreen.c
DynamicScreen.c
function: DynamicScreen_compare
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;
}
}function: DynamicScreen_done
void DynamicScreen_done(DynamicScreen* this) {
free(this->caption);
free(this->fields);
free(this->heading);
free(this->sortKey);
free(this->columnKeys);
}function: DynamicScreen_lookup
const char* DynamicScreen_lookup(Hashtable* screens, ht_key_t key) {
const DynamicScreen* screen = Hashtable_get(screens, key);
return screen ? screen->name : NULL;
}function: DynamicScreen_search
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;
}function: DynamicScreens_delete
void DynamicScreens_delete(Hashtable* screens) {
if (screens) {
Platform_dynamicScreensDone(screens);
Hashtable_delete(screens);
}
}function: DynamicScreens_new
Hashtable* DynamicScreens_new(void) {
return Platform_dynamicScreens();
}struct: DynamicIterator
typedef struct {
ht_key_t key;
const char* name;
bool found;
} DynamicIterator;DynamicScreen.h
DynamicScreen.h
function: DynamicScreen_done
void DynamicScreen_done(DynamicScreen* this);
function: DynamicScreen_lookup
const char* DynamicScreen_lookup(Hashtable* screens, unsigned int key);
function: DynamicScreen_search
bool DynamicScreen_search(Hashtable* screens, const char* name, unsigned int* key);
function: DynamicScreens_addAvailableColumns
void DynamicScreens_addAvailableColumns(Panel* availableColumns, char* screen);
function: DynamicScreens_delete
void DynamicScreens_delete(Hashtable* screens);
function: DynamicScreens_new
Hashtable* DynamicScreens_new(void);
struct: DynamicScreen_
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;EnvScreen.c
EnvScreen.c
function: EnvScreen_delete
void EnvScreen_delete(Object* this) {
free(InfoScreen_done((InfoScreen*)this));
}function: EnvScreen_draw
static void EnvScreen_draw(InfoScreen* this) {
InfoScreen_drawTitled(this, "Environment of process %d - %s", Process_getPid(this->process), Process_getCommand(this->process));
}function: EnvScreen_new
EnvScreen* EnvScreen_new(Process* process) {
EnvScreen* this = xMalloc(sizeof(EnvScreen));
Object_setClass(this, Class(EnvScreen));
return (EnvScreen*) InfoScreen_init(&this->super, process, NULL, LINES - 2, " ");
}function: EnvScreen_scan
static void EnvScreen_scan(InfoScreen* this) {
Panel* panel = this->display;
int idx = MAXIMUM(Panel_getSelectedIndex(panel), 0);
Panel_prune(panel);
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);
free(env);
}
else {
InfoScreen_addLine(this, "Could not read process environment.");
}
Vector_insertionSort(this->lines);
Vector_insertionSort(panel->items);
Panel_setSelected(panel, idx);
}struct: EnvScreen_class
const InfoScreenClass EnvScreen_class = {
.super = {
.extends = Class(Object),
.delete = EnvScreen_delete
},
.scan = EnvScreen_scan,
.draw = EnvScreen_draw
};EnvScreen.h
EnvScreen.h
extern const: EnvScreen_class
extern const InfoScreenClass EnvScreen_class;
function: EnvScreen_delete
void EnvScreen_delete(Object* this);
function: EnvScreen_new
EnvScreen* EnvScreen_new(Process* process);
struct: EnvScreen_
typedef struct EnvScreen_ {
InfoScreen super;
} EnvScreen;type alias: EnvScreen
typedef struct EnvScreen_ {
InfoScreen super;
} EnvScreen;FileDescriptorMeter.c
FileDescriptorMeter.c
file: FileDescriptorMeter.c
FileDescriptorMeter.h
FileDescriptorMeter.h
struct: FileDescriptorMeter_class
extern const MeterClass FileDescriptorMeter_class;
FreeBSDMachine.c
freebsd/FreeBSDMachine.c
function: FreeBSDMachine_scanCPU
function: FreeBSDMachine_scanMemoryInfo
function: Machine_delete
void Machine_delete(Machine* super) {
FreeBSDMachine* this = (FreeBSDMachine*) super;
Machine_done(super);
if (this->kd) {
kvm_close(this->kd);
}
free(this->cp_time_o);
free(this->cp_time_n);
free(this->cp_times_o);
free(this->cp_times_n);
free(this->cpus);
free(this);
}function: Machine_isCPUonline
bool Machine_isCPUonline(const Machine* host, unsigned int id) {
assert(id < host->existingCPUs);
// TODO: support offline CPUs and hot swapping
(void) host; (void) id;
return true;
}function: Machine_new
function: Machine_scan
void Machine_scan(Machine* super) {
FreeBSDMachine* this = (FreeBSDMachine*) super;
openzfs_sysctl_updateArcStats(&this->zfs);
FreeBSDMachine_scanMemoryInfo(super);
FreeBSDMachine_scanCPU(super);
}FreeBSDMachine.h
freebsd/FreeBSDMachine.h
struct: CPUData
typedef struct CPUData_ {
double userPercent;
double nicePercent;
double systemPercent;
double irqPercent;
double systemAllPercent;
double frequency;
double temperature;
} CPUData;struct: FreeBSDMachine
typedef struct FreeBSDMachine_ {
Machine super;
kvm_t* kd;
int pageSize;
int pageSizeKb;
int kernelFScale;
ZfsArcStats zfs;
CPUData* cpus;
unsigned long* cp_time_o;
unsigned long* cp_time_n;
unsigned long* cp_times_o;
unsigned long* cp_times_n;
} FreeBSDMachine;FreeBSDProcess.c
freebsd/FreeBSDProcess.c
function: FreeBSDProcess_compareByKey
static int FreeBSDProcess_compareByKey(const Process* v1, const Process* v2, ProcessField key) {
const FreeBSDProcess* p1 = (const FreeBSDProcess*)v1;
const FreeBSDProcess* p2 = (const FreeBSDProcess*)v2;
switch (key) {
// add FreeBSD-specific fields here
case JID:
return SPACESHIP_NUMBER(p1->jid, p2->jid);
case JAIL:
return SPACESHIP_NULLSTR(p1->jname, p2->jname);
case EMULATION:
return SPACESHIP_NULLSTR(p1->emul, p2->emul);
case SCHEDCLASS:
return SPACESHIP_NUMBER(p1->sched_class, p2->sched_class);
default:
return Process_compareByKey_Base(v1, v2, key);
}
}function: FreeBSDProcess_new
Process* FreeBSDProcess_new(const Machine* machine) {
FreeBSDProcess* this = xCalloc(1, sizeof(FreeBSDProcess));
Object_setClass(this, Class(FreeBSDProcess));
Process_init(&this->super, machine);
return (Process*)this;
}function: FreeBSDProcess_rowWriteField
static void FreeBSDProcess_rowWriteField(const Row* super, RichString* str, ProcessField field) {
const FreeBSDProcess* fp = (const FreeBSDProcess*) super;
char buffer[256]; buffer[255] = '\0';
char sched_class;
int attr = CRT_colors[DEFAULT_COLOR];
size_t n = sizeof(buffer) - 1;
switch (field) {
// add FreeBSD-specific fields here
case JID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, fp->jid); break;
case JAIL:
Row_printLeftAlignedField(str, attr, fp->jname ? fp->jname : "N/A", 11);
return;
case EMULATION:
Row_printLeftAlignedField(str, attr, fp->emul ? fp->emul : "N/A", 16);
return;
case SCHEDCLASS:
assert(0 <= fp->sched_class && fp->sched_class < ARRAYSIZE(FreeBSD_schedclassChars));
sched_class = FreeBSD_schedclassChars[fp->sched_class];
assert(sched_class);
xSnprintf(buffer, n, " %c", sched_class);
break;
default:
Process_writeField(&fp->super, str, field);
return;
}
RichString_appendWide(str, attr, buffer);
}function: Process_delete
void Process_delete(Object* cast) {
FreeBSDProcess* this = (FreeBSDProcess*) cast;
Process_done((Process*)cast);
free(this->emul);
free(this->jname);
free(this);
}global variable: FreeBSD_schedclassChars
static const char FreeBSD_schedclassChars[MAX_SCHEDCLASS] = {
[SCHEDCLASS_UNKNOWN] = '?', // Something went wrong or the base system has a new scheduling class
[SCHEDCLASS_INTR_THREAD] = '-', // interrupt thread, these have special handling of priority
[SCHEDCLASS_IDLE] = 'i', // idletime scheduling
[SCHEDCLASS_TIMESHARE] = ' ', // timesharing process scheduling (regular processes are timeshared)
[SCHEDCLASS_REALTIME] = 'r', // realtime scheduling
};global variable: FreeBSDProcess_class
const ProcessClass FreeBSDProcess_class = {
.super = {
.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
},
.compareByKey = FreeBSDProcess_compareByKey
};global variable: nodevStr
const char* const nodevStr = "nodev";
global variable: Process_fields
FreeBSDProcess.h
freebsd/FreeBSDProcess.h
enum: FreeBSDSchedClass
typedef enum {
SCHEDCLASS_UNKNOWN = 0,
SCHEDCLASS_INTR_THREAD, /* interrupt thread */
SCHEDCLASS_REALTIME,
SCHEDCLASS_TIMESHARE, /* Regular scheduling */
SCHEDCLASS_IDLE,
MAX_SCHEDCLASS,
} FreeBSDSchedClass;function: FreeBSDProcess_new
Process* FreeBSDProcess_new(const Machine* host);
function: Process_delete
void Process_delete(Object* cast);
global constant: FreeBSDProcess_class
extern const ProcessClass FreeBSDProcess_class;
global constant: Process_fields
extern const ProcessFieldData Process_fields[LAST_PROCESSFIELD];
struct: FreeBSDProcess_
typedef struct FreeBSDProcess_ {
Process super;
int jid;
char* jname;
char* emul;
FreeBSDSchedClass sched_class;
} FreeBSDProcess;type alias: FreeBSDProcess
typedef struct FreeBSDProcess_ {
Process super;
int jid;
char* jname;
char* emul;
FreeBSDSchedClass sched_class;
} FreeBSDProcess;FreeBSDProcessTable.c
freebsd/FreeBSDProcessTable.c
file: FreeBSDProcessTable.c
FreeBSDProcessTable.h
freebsd/FreeBSDProcessTable.h
struct: FreeBSDProcessTable
typedef struct FreeBSDProcessTable_ {
ProcessTable super;
} FreeBSDProcessTable;Platform.c
freebsd/Platform.c
function: Platform_done
void Platform_done(void) {
/* no platform-specific cleanup needed */
}function: Platform_getBattery
void Platform_getBattery(double* percent, ACPresence* isOnAC) {
int life;
size_t life_len = sizeof(life);
if (sysctlbyname("hw.acpi.battery.life", &life, &life_len, NULL, 0) == -1)
*percent = NAN;
else
*percent = life;
int acline;
size_t acline_len = sizeof(acline);
if (sysctlbyname("hw.acpi.acline", &acline, &acline_len, NULL, 0) == -1)
*isOnAC = AC_ERROR;
else
*isOnAC = acline == 0 ? AC_ABSENT : AC_PRESENT;
}function: Platform_getDiskIO
bool Platform_getDiskIO(DiskIOData* data) {
if (devstat_checkversion(NULL) < 0)
return false;
// use static to plug memory leak; see #841
static struct devinfo info = { 0 };
struct statinfo current = { .dinfo = &info };
// get number of devices
if (devstat_getdevs(NULL, ¤t) < 0)
return false;
int count = current.dinfo->numdevs;
uint64_t bytesReadSum = 0, bytesWriteSum = 0, timeSpendSum = 0;
uint64_t numDisks = 0;
// get data
for (int i = 0; i < count; i++) {
uint64_t bytes_read, bytes_write;
long double busy_time;
devstat_compute_statistics(¤t.dinfo->devices[i],
NULL,
1.0,
DSM_TOTAL_BYTES_READ, &bytes_read,
DSM_TOTAL_BYTES_WRITE, &bytes_write,
DSM_TOTAL_BUSY_TIME, &busy_time,
DSM_NONE);
bytesReadSum += bytes_read;
bytesWriteSum += bytes_write;
timeSpendSum += 1000 * busy_time;
numDisks++;
}
data->totalBytesRead = bytesReadSum;
data->totalBytesWritten = bytesWriteSum;
data->totalMsTimeSpend = timeSpendSum;
data->numDisks = numDisks;
return true;
}function: Platform_getFileDescriptors
void Platform_getFileDescriptors(double* used, double* max) {
Generic_getFileDescriptors_sysctl(used, max);
}function: Platform_getLoadAverage
void Platform_getLoadAverage(double* one, double* five, double* fifteen) {
struct loadavg loadAverage;
const int mib[2] = { CTL_VM, VM_LOADAVG };
size_t size = sizeof(loadAverage);
int err = sysctl(mib, 2, &loadAverage, &size, NULL, 0);
if (err) {
*one = 0;
*five = 0;
*fifteen = 0;
return;
}
*one = (double) loadAverage.ldavg[0] / loadAverage.fscale;
*five = (double) loadAverage.ldavg[1] / loadAverage.fscale;
*fifteen = (double) loadAverage.ldavg[2] / loadAverage.fscale;
}function: Platform_getMaxPid
pid_t Platform_getMaxPid(void) {
int maxPid;
size_t size = sizeof(maxPid);
int err = sysctlbyname("kern.pid_max", &maxPid, &size, NULL, 0);
if (err) {
return 99999;
}
return maxPid;
}function: Platform_getNetworkIO
bool Platform_getNetworkIO(NetworkIOData* data) {
// get number of interfaces
int count;
size_t countLen = sizeof(count);
const int countMib[] = { CTL_NET, PF_LINK, NETLINK_GENERIC, IFMIB_SYSTEM, IFMIB_IFCOUNT };
int r = sysctl(countMib, ARRAYSIZE(countMib), &count, &countLen, NULL, 0);
if (r < 0)
return false;
for (int i = 1; i <= count; i++) {
struct ifmibdata ifmd;
size_t ifmdLen = sizeof(ifmd);
const int dataMib[] = { CTL_NET, PF_LINK, NETLINK_GENERIC, IFMIB_IFDATA, i, IFDATA_GENERAL };
r = sysctl(dataMib, ARRAYSIZE(dataMib), &ifmd, &ifmdLen, NULL, 0);
if (r < 0)
continue;
if (ifmd.ifmd_flags & IFF_LOOPBACK)
continue;
data->bytesReceived += ifmd.ifmd_data.ifi_ibytes;
data->packetsReceived += ifmd.ifmd_data.ifi_ipackets;
data->bytesTransmitted += ifmd.ifmd_data.ifi_obytes;
data->packetsTransmitted += ifmd.ifmd_data.ifi_opackets;
}
return true;
}function: Platform_getProcessEnv
char* Platform_getProcessEnv(pid_t pid) {
const int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_ENV, pid };
size_t capacity = ARG_MAX;
char* env = xMalloc(capacity);
int err = sysctl(mib, 4, env, &capacity, NULL, 0);
if (err || capacity == 0) {
free(env);
return NULL;
}
if (env[capacity - 1] || env[capacity - 2]) {
env = xRealloc(env, capacity + 2);
env[capacity] = 0;
env[capacity + 1] = 0;
}
return env;
}function: Platform_getProcessLocks
FileLocks_ProcessData* Platform_getProcessLocks(pid_t pid) {
(void)pid;
return NULL;
}function: Platform_getUptime
int Platform_getUptime(void) {
struct timeval bootTime, currTime;
const int mib[2] = { CTL_KERN, KERN_BOOTTIME };
size_t size = sizeof(bootTime);
int err = sysctl(mib, 2, &bootTime, &size, NULL, 0);
if (err) {
return -1;
}
gettimeofday(&currTime, NULL);
return (int) difftime(currTime.tv_sec, bootTime.tv_sec);
}function: Platform_init
bool Platform_init(void) {
/* no platform-specific setup needed */
return true;
}function: Platform_setBindings
void Platform_setBindings(Htop_Action* keys) {
/* no platform-specific key bindings */
(void) keys;
}function: Platform_setCPUValues
double Platform_setCPUValues(Meter* this, unsigned int cpu) {
const Machine* host = this->host;
const FreeBSDMachine* fhost = (const FreeBSDMachine*) host;
unsigned int cpus = host->activeCPUs;
// single CPU box has everything in fhost->cpus[0]
const CPUData* cpuData = cpus == 1 ? &fhost->cpus[0] : &fhost->cpus[cpu];
double percent;
double* v = this->values;
v[CPU_METER_NICE] = cpuData->nicePercent;
v[CPU_METER_NORMAL] = cpuData->userPercent;
if (host->settings->detailedCPUTime) {
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 = CLAMP(percent, 0.0, 100.0);
v[CPU_METER_FREQUENCY] = cpuData->frequency;
v[CPU_METER_TEMPERATURE] = cpuData->temperature;
return percent;
}function: Platform_setMemoryValues
void Platform_setMemoryValues(Meter* this) {
const Machine* host = this->host;
const FreeBSDMachine* fhost = (const FreeBSDMachine*) host;
this->total = host->totalMem;
this->values[MEMORY_METER_USED] = host->usedMem;
this->values[MEMORY_METER_SHARED] = host->sharedMem;
// this->values[MEMORY_METER_COMPRESSED] = "compressed memory, like zswap on linux"
this->values[MEMORY_METER_BUFFERS] = host->buffersMem;
this->values[MEMORY_METER_CACHE] = host->cachedMem;
// this->values[MEMORY_METER_AVAILABLE] = "available memory"
if (fhost->zfs.enabled) {
// ZFS does not shrink below the value of zfs_arc_min.
unsigned long long int shrinkableSize = 0;
if (fhost->zfs.size > fhost->zfs.min)
shrinkableSize = fhost->zfs.size - fhost->zfs.min;
this->values[MEMORY_METER_USED] -= shrinkableSize;
this->values[MEMORY_METER_CACHE] += shrinkableSize;
// this->values[MEMORY_METER_AVAILABLE] += shrinkableSize;
}
}function: Platform_setSwapValues
void Platform_setSwapValues(Meter* this) {
const Machine* host = this->host;
this->total = host->totalSwap;
this->values[SWAP_METER_USED] = host->usedSwap;
// this->values[SWAP_METER_CACHE] = "pages that are both in swap and RAM, like SwapCached on linux"
// this->values[SWAP_METER_FRONTSWAP] = "pages that are accounted to swap but stored elsewhere, like frontswap on linux"
}function: Platform_setZfsArcValues
void Platform_setZfsArcValues(Meter* this) {
const FreeBSDMachine* fhost = (const FreeBSDMachine*) this->host;
ZfsArcMeter_readStats(this, &fhost->zfs);
}function: Platform_setZfsCompressedArcValues
void Platform_setZfsCompressedArcValues(Meter* this) {
const FreeBSDMachine* fhost = (const FreeBSDMachine*) this->host;
ZfsCompressedArcMeter_readStats(this, &fhost->zfs);
}global variable: Platform_defaultScreens
const ScreenDefaults Platform_defaultScreens[] = {
{
.name = "Main",
.columns = "PID USER PRIORITY NICE M_VIRT M_RESIDENT STATE PERCENT_CPU PERCENT_MEM TIME Command",
.sortKey = "PERCENT_CPU",
},
};global variable: Platform_meterTypes
const MeterClass* const Platform_meterTypes[] = {
&CPUMeter_class,
&ClockMeter_class,
&DateMeter_class,
&DateTimeMeter_class,
&LoadAverageMeter_class,
&LoadMeter_class,
&MemoryMeter_class,
&SwapMeter_class,
&MemorySwapMeter_class,
&TasksMeter_class,
&UptimeMeter_class,
&BatteryMeter_class,
&HostnameMeter_class,
&SysArchMeter_class,
&AllCPUsMeter_class,
&AllCPUs2Meter_class,
&AllCPUs4Meter_class,
&AllCPUs8Meter_class,
&LeftCPUsMeter_class,
&RightCPUsMeter_class,
&LeftCPUs2Meter_class,
&RightCPUs2Meter_class,
&LeftCPUs4Meter_class,
&RightCPUs4Meter_class,
&LeftCPUs8Meter_class,
&RightCPUs8Meter_class,
&BlankMeter_class,
&ZfsArcMeter_class,
&ZfsCompressedArcMeter_class,
&DiskIOMeter_class,
&FileDescriptorMeter_class,
&NetworkIOMeter_class,
NULL
};global variable: Platform_numberOfDefaultScreens
const unsigned int Platform_numberOfDefaultScreens = ARRAYSIZE(Platform_defaultScreens);
global variable: Platform_numberOfSignals
const unsigned int Platform_numberOfSignals = ARRAYSIZE(Platform_signals);
global variable: Platform_signals
const SignalItem Platform_signals[] = {
{ .name = " 0 Cancel", .number = 0 },
{ .name = " 1 SIGHUP", .number = 1 },
{ .name = " 2 SIGINT", .number = 2 },
{ .name = " 3 SIGQUIT", .number = 3 },
{ .name = " 4 SIGILL", .number = 4 },
{ .name = " 5 SIGTRAP", .number = 5 },
{ .name = " 6 SIGABRT", .number = 6 },
{ .name = " 7 SIGEMT", .number = 7 },
{ .name = " 8 SIGFPE", .number = 8 },
{ .name = " 9 SIGKILL", .number = 9 },
{ .name = "10 SIGBUS", .number = 10 },
{ .name = "11 SIGSEGV", .number = 11 },
{ .name = "12 SIGSYS", .number = 12 },
{ .name = "13 SIGPIPE", .number = 13 },
{ .name = "14 SIGALRM", .number = 14 },
{ .name = "15 SIGTERM", .number = 15 },
{ .name = "16 SIGURG", .number = 16 },
{ .name = "17 SIGSTOP", .number = 17 },
{ .name = "18 SIGTSTP", .number = 18 },
{ .name = "19 SIGCONT", .number = 19 },
{ .name = "20 SIGCHLD", .number = 20 },
{ .name = "21 SIGTTIN", .number = 21 },
{ .name = "22 SIGTTOU", .number = 22 },
{ .name = "23 SIGIO", .number = 23 },
{ .name = "24 SIGXCPU", .number = 24 },
{ .name = "25 SIGXFSZ", .number = 25 },
{ .name = "26 SIGVTALRM", .number = 26 },
{ .name = "27 SIGPROF", .number = 27 },
{ .name = "28 SIGWINCH", .number = 28 },
{ .name = "29 SIGINFO", .number = 29 },
{ .name = "30 SIGUSR1", .number = 30 },
{ .name = "31 SIGUSR2", .number = 31 },
{ .name = "32 SIGTHR", .number = 32 },
{ .name = "33 SIGLIBRT", .number = 33 },
};Platform.h
freebsd/Platform.h
function: Platform_addDynamicScreen
static inline void Platform_addDynamicScreen(ATTR_UNUSED ScreenSettings* ss) { }function: Platform_addDynamicScreenAvailableColumns
static inline void Platform_addDynamicScreenAvailableColumns(ATTR_UNUSED Panel* availableColumns, ATTR_UNUSED const char* screen) { }function: Platform_defaultDynamicScreens
static inline void Platform_defaultDynamicScreens(ATTR_UNUSED Settings* settings) { }function: Platform_done
void Platform_done(void);
function: Platform_dynamicColumnName
static inline const char* Platform_dynamicColumnName(ATTR_UNUSED unsigned int key) {
return NULL;
}function: Platform_dynamicColumns
static inline Hashtable* Platform_dynamicColumns(void) {
return NULL;
}function: Platform_dynamicColumnsDone
static inline void Platform_dynamicColumnsDone(ATTR_UNUSED Hashtable* table) { }function: Platform_dynamicColumnWriteField
static inline bool Platform_dynamicColumnWriteField(ATTR_UNUSED const Process* proc, ATTR_UNUSED RichString* str, ATTR_UNUSED unsigned int key) {
return false;
}function: Platform_dynamicMeterDisplay
static inline void Platform_dynamicMeterDisplay(ATTR_UNUSED const Meter* meter, ATTR_UNUSED RichString* out) { }function: Platform_dynamicMeterInit
static inline void Platform_dynamicMeterInit(ATTR_UNUSED Meter* meter) { }function: Platform_dynamicMeters
static inline Hashtable* Platform_dynamicMeters(void) {
return NULL;
}function: Platform_dynamicMetersDone
static inline void Platform_dynamicMetersDone(ATTR_UNUSED Hashtable* table) { }function: Platform_dynamicMeterUpdateValues
static inline void Platform_dynamicMeterUpdateValues(ATTR_UNUSED Meter* meter) { }function: Platform_dynamicScreens
static inline Hashtable* Platform_dynamicScreens(void) {
return NULL;
}function: Platform_dynamicScreensDone
static inline void Platform_dynamicScreensDone(ATTR_UNUSED Hashtable* screens) { }function: Platform_getBattery
void Platform_getBattery(double* percent, ACPresence* isOnAC);
function: Platform_getDiskIO
bool Platform_getDiskIO(DiskIOData* data);
function: Platform_getFileDescriptors
void Platform_getFileDescriptors(double* used, double* max);
function: Platform_getHostname
static inline void Platform_getHostname(char* buffer, size_t size) {
Generic_hostname(buffer, size);
}function: Platform_getLoadAverage
void Platform_getLoadAverage(double* one, double* five, double* fifteen);
function: Platform_getLongOption
static inline CommandLineStatus Platform_getLongOption(ATTR_UNUSED int opt, ATTR_UNUSED int argc, ATTR_UNUSED char** argv) {
return STATUS_ERROR_EXIT;
}function: Platform_getMaxPid
pid_t Platform_getMaxPid(void);
function: Platform_getNetworkIO
bool Platform_getNetworkIO(NetworkIOData* data);
function: Platform_getProcessEnv
char* Platform_getProcessEnv(pid_t pid);
function: Platform_getProcessLocks
FileLocks_ProcessData* Platform_getProcessLocks(pid_t pid);
function: Platform_getRelease
static inline void Platform_getRelease(char** string) {
*string = Generic_uname();
}function: Platform_gettime_monotonic
static inline void Platform_gettime_monotonic(uint64_t* msec) {
Generic_gettime_monotonic(msec);
}function: Platform_gettime_realtime
static inline void Platform_gettime_realtime(struct timeval* tv, uint64_t* msec) {
Generic_gettime_realtime(tv, msec);
}function: Platform_getUptime
int Platform_getUptime(void);
function: Platform_init
bool Platform_init(void);
function: Platform_longOptionsUsage
static inline void Platform_longOptionsUsage(ATTR_UNUSED const char* name) { }function: Platform_setBindings
void Platform_setBindings(Htop_Action* keys);
function: Platform_setCPUValues
double Platform_setCPUValues(Meter* this, unsigned int cpu);
function: Platform_setMemoryValues
void Platform_setMemoryValues(Meter* this);
function: Platform_setSwapValues
void Platform_setSwapValues(Meter* this);
function: Platform_setZfsArcValues
void Platform_setZfsArcValues(Meter* this);
function: Platform_setZfsCompressedArcValues
void Platform_setZfsCompressedArcValues(Meter* this);
global variable: Platform_defaultScreens
extern const ScreenDefaults Platform_defaultScreens[];
global variable: Platform_meterTypes
extern const MeterClass* const Platform_meterTypes[];
global variable: Platform_numberOfDefaultScreens
extern const unsigned int Platform_numberOfDefaultScreens;
global variable: Platform_numberOfSignals
extern const unsigned int Platform_numberOfSignals;
global variable: Platform_signals
extern const SignalItem Platform_signals[];
macro: PLATFORM_LONG_OPTIONS
#define PLATFORM_LONG_OPTIONS
ProcessField.h
freebsd/ProcessField.h
macro: PLATFORM_PROCESS_FIELDS
#define PLATFORM_PROCESS_FIELDS \
JID = 100, \
JAIL = 101, \
EMULATION = 102, \
SCHEDCLASS = 103, \
\
DUMMY_BUMP_FIELD = CWD, \
// End of listFunctionBar.c
FunctionBar.c
function: FunctionBar_append
void FunctionBar_append(const char* buffer, int attr) {
if (attr == -1) {
attrset(CRT_colors[FUNCTION_BAR]);
} else {
attrset(attr);
}
mvaddstr(LINES - 1, currentLen + 1, buffer);
attrset(CRT_colors[RESET_COLOR]);
currentLen += strlen(buffer) + 1;
}function: FunctionBar_delete
void FunctionBar_delete(FunctionBar* this) {
for (int i = 0; i < FUNCTIONBAR_MAXEVENTS && this->functions[i]; i++) {
free(this->functions[i]);
}
free(this->functions);
if (!this->staticData) {
for (int i = 0; i < this->size; i++) {
free(this->keys.keys[i]);
}
free(this->keys.keys);
free(this->events);
}
free(this);
}function: FunctionBar_draw
int FunctionBar_draw(const FunctionBar* this) {
return FunctionBar_drawExtra(this, NULL, -1, false);
}function: FunctionBar_drawExtra
int FunctionBar_drawExtra(const FunctionBar* this, const char* buffer, int attr, bool setCursor) {
int cursorX = 0;
attrset(CRT_colors[FUNCTION_BAR]);
mvhline(LINES - 1, 0, ' ', COLS);
int x = 0;
for (int i = 0; i < this->size; i++) {
attrset(CRT_colors[FUNCTION_KEY]);
mvaddstr(LINES - 1, x, this->keys.constKeys[i]);
x += strlen(this->keys.constKeys[i]);
attrset(CRT_colors[FUNCTION_BAR]);
mvaddstr(LINES - 1, x, this->functions[i]);
x += strlen(this->functions[i]);
}
if (buffer) {
if (attr == -1) {
attrset(CRT_colors[FUNCTION_BAR]);
} else {
attrset(attr);
} {
mvaddstr(LINES - 1, x, buffer);
x += strlen(buffer);
cursorX = x;
}
attrset(CRT_colors[RESET_COLOR]);
if (setCursor) {
curs_set(1);
} else {
curs_set(0);
}
currentLen = x;
return cursorX;
}function: FunctionBar_new
FunctionBar* FunctionBar_new(const char* const* functions, const char* const* keys, const int* events) {
FunctionBar* this = xCalloc(1, sizeof(FunctionBar));
this->functions = xCalloc(FUNCTIONBAR_MAXEVENTS + 1, sizeof(char*));
if (!functions) {
functions = FunctionBar_FLabels;
}
for (int i = 0; i < FUNCTIONBAR_MAXEVENTS && functions[i]; i++) {
this->functions[i] = xStrdup(functions[i]);
}
if (keys && events) {
this->staticData = false;
this->keys.keys = xCalloc(FUNCTIONBAR_MAXEVENTS, sizeof(char*));
this->events = xCalloc(FUNCTIONBAR_MAXEVENTS, sizeof(int));
int i = 0;
while (i < FUNCTIONBAR_MAXEVENTS && functions[i]) {
this->keys.keys[i] = xStrdup(keys[i]);
this->events[i] = events[i];
i++;
}
this->size = i;
} else {
this->staticData = true;
this->keys.constKeys = FunctionBar_FKeys;
this->events = FunctionBar_FEvents;
this->size = ARRAYSIZE(FunctionBar_FEvents);
}
return this;
}function: FunctionBar_newEnterEsc
FunctionBar* FunctionBar_newEnterEsc(const char* enter, const char* esc) {
const char* functions[FUNCTIONBAR_MAXEVENTS + 1] = {enter, esc, NULL};
return FunctionBar_new(functions, FunctionBar_EnterEscKeys, FunctionBar_EnterEscEvents);
}function: FunctionBar_setLabel
void FunctionBar_setLabel(FunctionBar* this, int event, const char* text) {
for (int i = 0; i < this->size; i++) {
if (this->events[i] == event) {
free(this->functions[i]);
this->functions[i] = xStrdup(text);
break;
}
}
}function: FunctionBar_synthesizeEvent
int FunctionBar_synthesizeEvent(const FunctionBar* this, int pos) {
int x = 0;
for (int i = 0; i < this->size; i++) {
x += strlen(this->keys.constKeys[i]);
x += strlen(this->functions[i]);
if (pos < x) {
return this->events[i];
}
}
return ERR;
}global_variable: currentLen
static int currentLen = 0;
global_variable: FunctionBar_EnterEscEvents
static const int FunctionBar_EnterEscEvents[] = {13, 27};global_variable: FunctionBar_EnterEscKeys
static const char* const FunctionBar_EnterEscKeys[] = {"Enter", "Esc", NULL};global_variable: FunctionBar_FEvents
static int FunctionBar_FEvents[] = {KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5), KEY_F(6), KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10)};global_variable: FunctionBar_FKeys
static const char* const FunctionBar_FKeys[] = {"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", NULL};global_variable: FunctionBar_FLabels
static const char* const FunctionBar_FLabels[] = {" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", NULL};FunctionBar.h
FunctionBar.h
function: FunctionBar_append
void FunctionBar_append(const char* buffer, int attr);
function: FunctionBar_new
FunctionBar* FunctionBar_new(const char* const* functions, const char* const* keys, const int* events);
function: FunctionBar_newEnterEsc
FunctionBar* FunctionBar_newEnterEsc(const char* enter, const char* esc);
method: FunctionBar_delete
void FunctionBar_delete(FunctionBar* this);
method: FunctionBar_draw
int FunctionBar_draw(const FunctionBar* this);
method: FunctionBar_drawExtra
int FunctionBar_drawExtra(const FunctionBar* this, const char* buffer, int attr, bool setCursor);
method: FunctionBar_setLabel
void FunctionBar_setLabel(FunctionBar* this, int event, const char* text);
method: FunctionBar_synthesizeEvent
int FunctionBar_synthesizeEvent(const FunctionBar* this, int pos);
struct: FunctionBar
typedef struct FunctionBar_ {
int size;
char** functions;
union {
char** keys;
const char* const* constKeys;
} keys;
int* events;
bool staticData;
} FunctionBar;fdstat_sysctl.c
generic/fdstat_sysctl.c
function: Generic_getFileDescriptors_sysctl
void Generic_getFileDescriptors_sysctl(double* used, double* max) {
#if defined(HTOP_DARWIN)
Generic_getFileDescriptors_sysctl_internal(
"kern.maxfiles", "kern.num_files", 0, 0, used, max);
#elif defined(HTOP_DRAGONFLYBSD)
Generic_getFileDescriptors_sysctl_internal(
"kern.maxfiles", "kern.openfiles", 0, 0, used, max);
#elif defined(HTOP_FREEBSD)
Generic_getFileDescriptors_sysctl_internal(
"kern.maxfiles", "kern.openfiles", 0, 0, used, max);
#elif defined(HTOP_NETBSD)
Generic_getFileDescriptors_sysctl_internal(
"kern.maxfiles", NULL, 0, sizeof(struct kinfo_file), used, max);
#else
#error Unknown platform: Please implement proper way to query open/max file information
#endif
}function: Generic_getFileDescriptors_sysctl_internal
static void Generic_getFileDescriptors_sysctl_internal(
const char* sysctlname_maxfiles,
const char* sysctlname_numfiles,
size_t size_header,
size_t size_entry,
double* used,
double* max
) {
*used = NAN;
*max = 65536;
int max_fd, open_fd;
size_t len;
len = sizeof(max_fd);
if (sysctlname_maxfiles && sysctlbyname(sysctlname_maxfiles, &max_fd, &len, NULL, 0) == 0) {
if (max_fd) {
*max = max_fd;
} else {
*max = NAN;
}
}
len = sizeof(open_fd);
if (sysctlname_numfiles && sysctlbyname(sysctlname_numfiles, &open_fd, &len, NULL, 0) == 0) {
*used = open_fd;
return;
}
// If no sysctl arc available, try to guess from the file table size at kern.file
// The size per entry differs per OS, thus skip if we don't know:
if (!size_entry)
return;
len = 0;
if (sysctlbyname("kern.file", NULL, &len, NULL, 0) < 0)
return;
if (len < size_header)
return;
*used = (len - size_header) / size_entry;
}fdstat_sysctl.h
generic/fdstat_sysctl.h
function: Generic_getFileDescriptors_sysctl
void Generic_getFileDescriptors_sysctl(double* used, double* max);
gettime.c
generic/gettime.c
function: Generic_gettime_monotonic
void Generic_gettime_monotonic(uint64_t* msec) {
#if defined(HAVE_CLOCK_GETTIME)
struct timespec ts;
if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
*msec = ((uint64_t)ts.tv_sec * 1000) + ((uint64_t)ts.tv_nsec / 1000000);
else
*msec = 0;
#else /* lower resolution gettimeofday() should be always available */
struct timeval tv;
if (gettimeofday(&tv, NULL) == 0)
*msec = ((uint64_t)tv.tv_sec * 1000) + ((uint64_t)tv.tv_usec / 1000);
else
*msec = 0;
#endif
}function: Generic_gettime_realtime
void Generic_gettime_realtime(struct timeval* tvp, uint64_t* msec) {
#if defined(HAVE_CLOCK_GETTIME)
struct timespec ts;
if (clock_gettime(CLOCK_REALTIME, &ts) == 0) {
tvp->tv_sec = ts.tv_sec;
tvp->tv_usec = ts.tv_nsec / 1000;
*msec = ((uint64_t)ts.tv_sec * 1000) + ((uint64_t)ts.tv_nsec / 1000000);
} else {
memset(tvp, 0, sizeof(struct timeval));
*msec = 0;
}
#else /* lower resolution gettimeofday(2) is always available */
struct timeval tv;
if (gettimeofday(&tv, NULL) == 0) {
*tvp = tv; /* struct copy */
*msec = ((uint64_t)tv.tv_sec * 1000) + ((uint64_t)tv.tv_usec / 1000);
} else {
memset(tvp, 0, sizeof(struct timeval));
*msec = 0;
}
#endif
}gettime.h
generic/gettime.h
function: Generic_gettime_monotonic
void Generic_gettime_monotonic(uint64_t* msec);
function: Generic_gettime_realtime
void Generic_gettime_realtime(struct timeval* tvp, uint64_t* msec);
hostname.c
generic/hostname.c
function: Generic_hostname
void Generic_hostname(char* buffer, size_t size) {
gethostname(buffer, size - 1);
buffer[size - 1] = '\0';
}hostname.h
generic/hostname.h
function: Generic_hostname
void Generic_hostname(char* buffer, size_t size);
openzfs_sysctl.c
generic/openzfs_sysctl.c
function: openzfs_sysctl_init
void openzfs_sysctl_init(ZfsArcStats* stats) {
size_t len;
unsigned long long int arcSize;
len = sizeof(arcSize);
if (sysctlbyname("kstat.zfs.misc.arcstats.size", &arcSize, &len, NULL, 0) == 0 && arcSize != 0) {
stats->enabled = 1;
len = 5;
sysctlnametomib("kstat.zfs.misc.arcstats.size", MIB_kstat_zfs_misc_arcstats_size, &len);
sysctlnametomib("kstat.zfs.misc.arcstats.c_min", MIB_kstat_zfs_misc_arcstats_c_min, &len);
sysctlnametomib("kstat.zfs.misc.arcstats.c_max", MIB_kstat_zfs_misc_arcstats_c_max, &len);
sysctlnametomib("kstat.zfs.misc.arcstats.mfu_size", MIB_kstat_zfs_misc_arcstats_mfu_size, &len);
sysctlnametomib("kstat.zfs.misc.arcstats.mru_size", MIB_kstat_zfs_misc_arcstats_mru_size, &len);
sysctlnametomib("kstat.zfs.misc.arcstats.anon_size", MIB_kstat_zfs_misc_arcstats_anon_size, &len);
sysctlnametomib("kstat.zfs.misc.arcstats.hdr_size", MIB_kstat_zfs_misc_arcstats_hdr_size, &len);
sysctlnametomib("kstat.zfs.misc.arcstats.other_size", MIB_kstat_zfs_misc_arcstats_other_size, &len);
if (sysctlnametomib("kstat.zfs.misc.arcstats.compressed_size", MIB_kstat_zfs_misc_arcstats_compressed_size, &len) == 0) {
stats->isCompressed = 1;
sysctlnametomib("kstat.zfs.misc.arcstats.uncompressed_size", MIB_kstat_zfs_misc_arcstats_uncompressed_size, &len);
} else {
stats->isCompressed = 0;
}
} else {
stats->enabled = 0;
}
}function: openzfs_sysctl_updateArcStats
void openzfs_sysctl_updateArcStats(ZfsArcStats* stats) {
size_t len;
if (stats->enabled) {
len = sizeof(stats->size);
sysctl(MIB_kstat_zfs_misc_arcstats_size, 5, &(stats->size), &len, NULL, 0);
stats->size /= 1024;
len = sizeof(stats->min);
sysctl(MIB_kstat_zfs_misc_arcstats_c_min, 5, &(stats->min), &len, NULL, 0);
stats->min /= 1024;
len = sizeof(stats->max);
sysctl(MIB_kstat_zfs_misc_arcstats_c_max, 5, &(stats->max), &len, NULL, 0);
stats->max /= 1024;
len = sizeof(stats->MFU);
sysctl(MIB_kstat_zfs_misc_arcstats_mfu_size, 5, &(stats->MFU), &len, NULL, 0);
stats->MFU /= 1024;
len = sizeof(stats->MRU);
sysctl(MIB_kstat_zfs_misc_arcstats_mru_size, 5, &(stats->MRU), &len, NULL, 0);
stats->MRU /= 1024;
len = sizeof(stats->anon);
sysctl(MIB_kstat_zfs_misc_arcstats_anon_size, 5, &(stats->anon), &len, NULL, 0);
stats->anon /= 1024;
len = sizeof(stats->header);
sysctl(MIB_kstat_zfs_misc_arcstats_hdr_size, 5, &(stats->header), &len, NULL, 0);
stats->header /= 1024;
len = sizeof(stats->other);
sysctl(MIB_kstat_zfs_misc_arcstats_other_size, 5, &(stats->other), &len, NULL, 0);
stats->other /= 1024;
if (stats->isCompressed) {
len = sizeof(stats->compressed);
sysctl(MIB_kstat_zfs_misc_arcstats_compressed_size, 5, &(stats->compressed), &len, NULL, 0);
stats->compressed /= 1024;
len = sizeof(stats->uncompressed);
sysctl(MIB_kstat_zfs_misc_arcstats_uncompressed_size, 5, &(stats->uncompressed), &len, NULL, 0);
stats->uncompressed /= 1024;
}
}
}variable: MIB_kstat_zfs_misc_arcstats_anon_size
static int MIB_kstat_zfs_misc_arcstats_anon_size[5];
variable: MIB_kstat_zfs_misc_arcstats_c_max
static int MIB_kstat_zfs_misc_arcstats_c_max[5];
variable: MIB_kstat_zfs_misc_arcstats_c_min
static int MIB_kstat_zfs_misc_arcstats_c_min[5];
variable: MIB_kstat_zfs_misc_arcstats_compressed_size
static int MIB_kstat_zfs_misc_arcstats_compressed_size[5];
variable: MIB_kstat_zfs_misc_arcstats_hdr_size
static int MIB_kstat_zfs_misc_arcstats_hdr_size[5];
variable: MIB_kstat_zfs_misc_arcstats_mfu_size
static int MIB_kstat_zfs_misc_arcstats_mfu_size[5];
variable: MIB_kstat_zfs_misc_arcstats_mru_size
static int MIB_kstat_zfs_misc_arcstats_mru_size[5];
variable: MIB_kstat_zfs_misc_arcstats_other_size
static int MIB_kstat_zfs_misc_arcstats_other_size[5];
variable: MIB_kstat_zfs_misc_arcstats_size
static int MIB_kstat_zfs_misc_arcstats_size[5];
variable: MIB_kstat_zfs_misc_arcstats_uncompressed_size
static int MIB_kstat_zfs_misc_arcstats_uncompressed_size[5];
openzfs_sysctl.h
generic/openzfs_sysctl.h
function: openzfs_sysctl_init
void openzfs_sysctl_init(ZfsArcStats* stats);
function: openzfs_sysctl_updateArcStats
void openzfs_sysctl_updateArcStats(ZfsArcStats* stats);
uname.c
generic/uname.c
function: Generic_uname
char* Generic_uname(void) {
static char savedString[
/* uname structure fields - manpages recommend sizeof */
sizeof(((struct utsname*)0)->sysname) +
sizeof(((struct utsname*)0)->release) +
sizeof(((struct utsname*)0)->machine) +
16/*markup*/ +
128/*distro*/] = {'\0'};
static bool loaded_data = false;
if (!loaded_data) {
struct utsname uname_info;
int uname_result = uname(&uname_info);
char distro[128];
parseOSRelease(distro, sizeof(distro));
if (uname_result == 0) {
size_t written = xSnprintf(savedString, sizeof(savedString), "%s %s [%s]", uname_info.sysname, uname_info.release, uname_info.machine);
if (!String_contains_i(savedString, distro, false) && sizeof(savedString) > written)
snprintf(savedString + written, sizeof(savedString) - written, " @ %s", distro);
} else {
snprintf(savedString, sizeof(savedString), "%s", distro);
}
loaded_data = true;
}
return savedString;
}function: parseOSRelease
static void parseOSRelease(char* buffer, size_t bufferLen) {
FILE* fp = fopen(OSRELEASEFILE, "r");
if (!fp) {
xSnprintf(buffer, bufferLen, "No OS Release");
return;
}
char name[64] = {'\0'};
char version[64] = {'\0'};
char lineBuffer[256];
while (fgets(lineBuffer, sizeof(lineBuffer), fp)) {
if (String_startsWith(lineBuffer, "PRETTY_NAME=\"")) {
const char* start = lineBuffer + strlen("PRETTY_NAME=\"");
const char* stop = strrchr(lineBuffer, '"');
if (!stop || stop <= start)
continue;
String_safeStrncpy(buffer, start, MINIMUM(bufferLen, (size_t)(stop - start + 1)));
fclose(fp);
return;
}
if (String_startsWith(lineBuffer, "NAME=\"")) {
const char* start = lineBuffer + strlen("NAME=\"");
const char* stop = strrchr(lineBuffer, '"');
if (!stop || stop <= start)
continue;
String_safeStrncpy(name, start, MINIMUM(sizeof(name), (size_t)(stop - start + 1)));
continue;
}
if (String_startsWith(lineBuffer, "VERSION=\"")) {
const char* start = lineBuffer + strlen("VERSION=\"");
const char* stop = strrchr(lineBuffer, '"');
if (!stop || stop <= start)
continue;
String_safeStrncpy(version, start, MINIMUM(sizeof(version), (size_t)(stop - start + 1)));
continue;
}
}
fclose(fp);
snprintf(buffer, bufferLen, "%s%s%s", name[0] ? name : "", name[0] && version[0] ? " " : "", version);
}uname.h
generic/uname.h
function: Generic_uname
char* Generic_uname(void);
Hashtable.c
Hashtable.c
function: Hashtable_clear
void Hashtable_clear(Hashtable* this) {
assert(Hashtable_isConsistent(this));
if (this->owner)
for (size_t i = 0; i < this->size; i++)
free(this->buckets[i].value);
memset(this->buckets, 0, this->size * sizeof(HashtableItem));
this->items = 0;
assert(Hashtable_isConsistent(this));
}function: Hashtable_count
size_t Hashtable_count(const Hashtable* this) {
size_t items = 0;
for (size_t i = 0; i < this->size; i++) {
if (this->buckets[i].value)
items++;
}
assert(items == this->items);
return items;
}function: Hashtable_delete
void Hashtable_delete(Hashtable* this) {
Hashtable_clear(this);
free(this->buckets);
free(this);
}function: Hashtable_dump
static void Hashtable_dump(const Hashtable* this) {
fprintf(stderr, "Hashtable %p: size=%zu items=%zu owner=%s\n",
(const void*)this,
this->size,
this->items,
this->owner ? "yes" : "no");
size_t items = 0;
for (size_t i = 0; i < this->size; i++) {
fprintf(stderr, " item %5zu: key = %5u probe = %2zu value = %p\n",
i,
this->buckets[i].key,
this->buckets[i].probe,
this->buckets[i].value);
if (this->buckets[i].value)
items++;
}
fprintf(stderr, "Hashtable %p: items=%zu counted=%zu\n",
(const void*)this,
this->items,
items);
}function: Hashtable_foreach
void Hashtable_foreach(Hashtable* this, Hashtable_PairFunction f, void* userData) {
assert(Hashtable_isConsistent(this));
for (size_t i = 0; i < this->size; i++) {
HashtableItem* walk = &this->buckets[i];
if (walk->value)
f(walk->key, walk->value, userData);
}
assert(Hashtable_isConsistent(this));
}function: Hashtable_get
void* Hashtable_get(Hashtable* this, ht_key_t key) {
size_t index = key % this->size;
size_t probe = 0;
void* res = NULL;
#ifndef NDEBUG
size_t origIndex = index;
#endif
assert(Hashtable_isConsistent(this));
while (this->buckets[index].value) {
if (this->buckets[index].key == key) {
res = this->buckets[index].value;
break;
}
if (this->buckets[index].probe < probe)
break;
index = (index + 1) != this->size ? (index + 1) : 0;
probe++;
assert(index != origIndex);
}
return res;
}function: Hashtable_isConsistent
static bool Hashtable_isConsistent(const Hashtable* this) {
size_t items = 0;
for (size_t i = 0; i < this->size; i++) {
if (this->buckets[i].value)
items++;
}
bool res = items == this->items;
if (!res)
Hashtable_dump(this);
return res;
}function: Hashtable_new
Hashtable* Hashtable_new(size_t size, bool owner) {
size = size ? nextPrime(size) : 13;
Hashtable* this = xMalloc(sizeof(Hashtable));
*this = (Hashtable) {
.items = 0,
.size = size,
.buckets = xCalloc(size, sizeof(HashtableItem)),
.owner = owner,
};
assert(Hashtable_isConsistent(this));
return this;
}function: Hashtable_put
void Hashtable_put(Hashtable* this, ht_key_t key, void* value) {
assert(Hashtable_isConsistent(this));
assert(this->size > 0);
assert(value);
/* grow on load-factor > 0.7 */
if (10 * this->items > 7 * this->size) {
if (SIZE_MAX / 2 < this->size)
CRT_fatalError("Hashtable: size overflow");
Hashtable_setSize(this, 2 * this->size);
}
insert(this, key, value);
assert(Hashtable_isConsistent(this));
assert(Hashtable_get(this, key) != NULL);
assert(this->size > this->items);
}function: Hashtable_remove
void* Hashtable_remove(Hashtable* this, ht_key_t key) {
size_t index = key % this->size;
size_t probe = 0;
#ifndef NDEBUG
size_t origIndex = index;
#endif
assert(Hashtable_isConsistent(this));
void* res = NULL;
while (this->buckets[index].value) {
if (this->buckets[index].key == key) {
if (this->owner) {
free(this->buckets[index].value);
} else {
res = this->buckets[index].value;
}
size_t next = (index + 1) % this->size;
while (this->buckets[next].value && this->buckets[next].probe > 0) {
this->buckets[index] = this->buckets[next];
this->buckets[index].probe -= 1;
index = next;
next = (index + 1) % this->size;
}
/* set empty after backward shifting */
this->buckets[index].value = NULL;
this->items--;
break;
}
if (this->buckets[index].probe < probe)
break;
index = (index + 1) % this->size;
probe++;
assert(index != origIndex);
}
assert(Hashtable_isConsistent(this));
assert(Hashtable_get(this, key) == NULL);
/* shrink on load-factor < 0.125 */
if (8 * this->items < this->size)
Hashtable_setSize(this, this->size / 3); /* account for nextPrime rounding up */
return res;
}function: Hashtable_setSize
void Hashtable_setSize(Hashtable* this, size_t size) {
assert(Hashtable_isConsistent(this));
if (size <= this->items)
return;
size_t newSize = nextPrime(size);
if (newSize == this->size)
return;
HashtableItem* oldBuckets = this->buckets;
size_t oldSize = this->size;
this->size = newSize;
this->buckets = (HashtableItem*) xCalloc(this->size, sizeof(HashtableItem));
this->items = 0;
/* rehash */
for (size_t i = 0; i < oldSize; i++) {
if (!oldBuckets[i].value)
continue;
insert(this, oldBuckets[i].key, oldBuckets[i].value);
}
free(oldBuckets);
assert(Hashtable_isConsistent(this));
}function: insert
static void insert(Hashtable* this, ht_key_t key, void* value) {
size_t index = key % this->size;
size_t probe = 0;
#ifndef NDEBUG
size_t origIndex = index;
#endif
for (;;) {
if (!this->buckets[index].value) {
this->items++;
this->buckets[index].key = key;
this->buckets[index].probe = probe;
this->buckets[index].value = value;
return;
}
if (this->buckets[index].key == key) {
if (this->owner && this->buckets[index].value != value)
free(this->buckets[index].value);
this->buckets[index].value = value;
return;
}
/* Robin Hood swap */
if (probe > this->buckets[index].probe) {
HashtableItem tmp = this->buckets[index];
this->buckets[index].key = key;
this->buckets[index].probe = probe;
this->buckets[index].value = value;
key = tmp.key;
probe = tmp.probe;
value = tmp.value;
}
index = (index + 1) % this->size;
probe++;
assert(index != origIndex);
}
}function: nextPrime
static size_t nextPrime(size_t n) {
/* on 32-bit make sure we do not return primes not fitting in size_t */
for (size_t i = 0; i < ARRAYSIZE(OEISprimes) && OEISprimes[i] < SIZE_MAX; i++) {
if (n <= OEISprimes[i])
return OEISprimes[i];
}
CRT_fatalError("Hashtable: no prime found");
}struct: Hashtable
struct Hashtable_ {
size_t size;
HashtableItem* buckets;
size_t items;
bool owner;
};struct: HashtableItem
typedef struct HashtableItem_ {
ht_key_t key;
size_t probe;
void* value;
} HashtableItem;Hashtable.h
Hashtable.h
function: Hashtable_clear
void Hashtable_clear(Hashtable* this);
function: Hashtable_count
size_t Hashtable_count(const Hashtable* this);
function: Hashtable_delete
void Hashtable_delete(Hashtable* this);
function: Hashtable_foreach
void Hashtable_foreach(Hashtable* this, Hashtable_PairFunction f, void* userData);
function: Hashtable_get
void* Hashtable_get(Hashtable* this, ht_key_t key);
function: Hashtable_new
Hashtable* Hashtable_new(size_t size, bool owner);
function: Hashtable_put
void Hashtable_put(Hashtable* this, ht_key_t key, void* value);
function: Hashtable_remove
void* Hashtable_remove(Hashtable* this, ht_key_t key);
function: Hashtable_setSize
void Hashtable_setSize(Hashtable* this, size_t size);
struct: Hashtable
typedef struct Hashtable_ Hashtable;
typedef: Hashtable_PairFunction
typedef void(*Hashtable_PairFunction)(ht_key_t key, void* value, void* userdata);
typedef: ht_key_t
typedef unsigned int ht_key_t;
Header.c
Header.c
function: calcColumnWidthCount
static int calcColumnWidthCount(const Header* this, const Meter* curMeter, const int pad, const unsigned int curColumn, const int curHeight) {
for (size_t i = curColumn + 1; i < HeaderLayout_getColumns(this->headerLayout); i++) {
const Vector* meters = this->columns[i];
int height = pad;
for (int j = 0; j < Vector_size(meters); j++) {
const Meter* meter = (const Meter*) Vector_get(meters, j);
if (height >= curHeight + curMeter->h)
break;
height += meter->h;
if (height <= curHeight)
continue;
if (!Object_isA((const Object*) meter, (const ObjectClass*) &BlankMeter_class))
return i - curColumn;
}
}
return HeaderLayout_getColumns(this->headerLayout) - curColumn;
}function: Header_addMeterByClass
Meter* Header_addMeterByClass(Header* this, const MeterClass* type, unsigned int param, unsigned int column) {
assert(column < HeaderLayout_getColumns(this->headerLayout));
Vector* meters = this->columns[column];
Meter* meter = Meter_new(this->host, param, type);
Vector_add(meters, meter);
return meter;
}function: Header_addMeterByName
static void Header_addMeterByName(Header* this, const char* name, MeterModeId mode, unsigned int column) {
assert(column < HeaderLayout_getColumns(this->headerLayout));
Vector* meters = this->columns[column];
const char* paren = strchr(name, '(');
unsigned int param = 0;
size_t nameLen;
if (paren) {
if (sscanf(paren, "(%10u)", ¶m) != 1) { // not CPUMeter
char dynamic[32] = {0};
if (sscanf(paren, "(%30s)", dynamic) == 1) { // DynamicMeter
char* end;
if ((end = strrchr(dynamic, ')')) == NULL)
return; // htoprc parse failure
*end = '\0';
const Settings* settings = this->host->settings;
if (!DynamicMeter_search(settings->dynamicMeters, dynamic, ¶m))
return; // name lookup failure
} else {
param = 0;
}
}
nameLen = paren - name;
} else {
nameLen = strlen(name);
}
for (const MeterClass* const* type = Platform_meterTypes; *type; type++) {
if (0 == strncmp(name, (*type)->name, nameLen) && (*type)->name[nameLen] == '\0') {
Meter* meter = Meter_new(this->host, param, *type);
if (mode != 0) {
Meter_setMode(meter, mode);
}
Vector_add(meters, meter);
break;
}
}
}function: Header_calculateHeight
int Header_calculateHeight(Header* this) {
const Settings* settings = this->host->settings;
const int pad = settings->headerMargin ? 2 : 0;
int maxHeight = pad;
Header_forEachColumn(this, col) {
const Vector* meters = this->columns[col];
int height = pad;
for (int i = 0; i < Vector_size(meters); i++) {
Meter* meter = (Meter*) Vector_get(meters, i);
meter->columnWidthCount = calcColumnWidthCount(this, meter, pad, col, height);
height += meter->h;
}
maxHeight = MAXIMUM(maxHeight, height);
}
if (maxHeight == pad) {
maxHeight = 0;
this->pad = 0;
} else {
this->pad = pad;
}
if (settings->screenTabs) {
maxHeight++;
}
this->height = maxHeight;
return maxHeight;
}function: Header_delete
void Header_delete(Header* this) {
Header_forEachColumn(this, i) {
Vector_delete(this->columns[i]);
}
free(this->columns);
free(this);
}function: Header_draw
void Header_draw(const Header* this) {
const int height = this->height;
const int pad = this->pad;
attrset(CRT_colors[RESET_COLOR]);
for (int y = 0; y < height; y++) {
mvhline(y, 0, ' ', COLS);
}
const int numCols = HeaderLayout_getColumns(this->headerLayout);
const int width = COLS - 2 * pad - (numCols - 1);
int x = pad;
float roundingLoss = 0.0F;
Header_forEachColumn(this, col) {
Vector* meters = this->columns[col];
float colWidth = (float)width * HeaderLayout_layouts[this->headerLayout].widths[col] / 100.0F;
roundingLoss += colWidth - floorf(colWidth);
if (roundingLoss >= 1.0F) {
colWidth += 1.0F;
roundingLoss -= 1.0F;
}
for (int y = (pad / 2), i = 0; i < Vector_size(meters); i++) {
Meter* meter = (Meter*) Vector_get(meters, i);
float actualWidth = colWidth;
/* Let meters in text mode expand to the right on empty neighbors;
except for multi column meters. */
if (meter->mode == TEXT_METERMODE && !Meter_isMultiColumn(meter)) {
for (int j = 1; j < meter->columnWidthCount; j++) {
actualWidth++; /* separator column */
actualWidth += (float)width * HeaderLayout_layouts[this->headerLayout].widths[col + j] / 100.0F;
}
}
assert(meter->draw);
meter->draw(meter, x, y, floorf(actualWidth));
y += meter->h;
}
x += floorf(colWidth);
x++; /* separator column */
}
}function: Header_new
Header* Header_new(Machine* host, HeaderLayout hLayout) {
Header* this = xCalloc(1, sizeof(Header));
this->columns = xMallocArray(HeaderLayout_getColumns(hLayout), sizeof(Vector*));
this->headerLayout = hLayout;
this->host = host;
Header_forEachColumn(this, i) {
this->columns[i] = Vector_new(Class(Meter), true, DEFAULT_SIZE);
}
return this;
}function: Header_populateFromSettings
void Header_populateFromSettings(Header* this) {
const Settings* settings = this->host->settings;
Header_setLayout(this, settings->hLayout);
Header_forEachColumn(this, col) {
const MeterColumnSetting* colSettings = &settings->hColumns[col];
Vector_prune(this->columns[col]);
for (size_t i = 0; i < colSettings->len; i++) {
Header_addMeterByName(this, colSettings->names[i], colSettings->modes[i], col);
}
}
Header_calculateHeight(this);
}function: Header_reinit
void Header_reinit(Header* this) {
Header_forEachColumn(this, col) {
for (int i = 0; i < Vector_size(this->columns[col]); i++) {
Meter* meter = (Meter*) Vector_get(this->columns[col], i);
if (Meter_initFn(meter)) {
Meter_init(meter);
}
}
}
}function: Header_setLayout
void Header_setLayout(Header* this, HeaderLayout hLayout) {
size_t oldColumns = HeaderLayout_getColumns(this->headerLayout);
size_t newColumns = HeaderLayout_getColumns(hLayout);
this->headerLayout = hLayout;
if (newColumns == oldColumns)
return;
if (newColumns > oldColumns) {
this->columns = xReallocArray(this->columns, newColumns, sizeof(Vector*));
for (size_t i = oldColumns; i < newColumns; i++)
this->columns[i] = Vector_new(Class(Meter), true, DEFAULT_SIZE);
} else {
// move meters from to-be-deleted columns into last one
for (size_t i = newColumns; i < oldColumns; i++) {
for (int j = this->columns[i]->items - 1; j >= 0; j--) {
Vector_add(this->columns[newColumns - 1], Vector_take(this->columns[i], j));
}
Vector_delete(this->columns[i]);
}
this->columns = xReallocArray(this->columns, newColumns, sizeof(Vector*));
}
Header_calculateHeight(this);
}function: Header_updateData
void Header_updateData(Header* this) {
Header_forEachColumn(this, col) {
Vector* meters = this->columns[col];
int items = Vector_size(meters);
for (int i = 0; i < items; i++) {
Meter* meter = (Meter*) Vector_get(meters, i);
Meter_updateValues(meter);
}
}
}function: Header_writeBackToSettings
void Header_writeBackToSettings(const Header* this) {
Settings* settings = this->host->settings;
Settings_setHeaderLayout(settings, this->headerLayout);
Header_forEachColumn(this, col) {
MeterColumnSetting* colSettings = &settings->hColumns[col];
if (colSettings->names) {
for (size_t j = 0; j < colSettings->len; j++)
free(colSettings->names[j]);
free(colSettings->names);
}
free(colSettings->modes);
const Vector* vec = this->columns[col];
int len = Vector_size(vec);
colSettings->names = len ? xCalloc(len + 1, sizeof(*colSettings->names)) : NULL;
colSettings->modes = len ? xCalloc(len, sizeof(*colSettings->modes)) : NULL;
colSettings->len = len;
for (int i = 0; i < len; i++) {
const Meter* meter = (Meter*) Vector_get(vec, i);
char* name;
if (meter->param && As_Meter(meter) == &DynamicMeter_class) {
const char* dynamic = DynamicMeter_lookup(settings->dynamicMeters, meter->param);
xAsprintf(&name, "%s(%s)", As_Meter(meter)->name, dynamic);
} else if (meter->param && As_Meter(meter) == &CPUMeter_class) {
xAsprintf(&name, "%s(%u)", As_Meter(meter)->name, meter->param);
} else {
xAsprintf(&name, "%s", As_Meter(meter)->name);
}
colSettings->names[i] = name;
colSettings->modes[i] = meter->mode;
}
}
}Header.h
Header.h
function: Header_addMeterByClass
Meter* Header_addMeterByClass(Header* this, const MeterClass* type, unsigned int param, unsigned int column);
function: Header_calculateHeight
int Header_calculateHeight(Header* this);
function: Header_delete
void Header_delete(Header* this);
function: Header_draw
void Header_draw(const Header* this);
function: Header_new
Header* Header_new(Machine* host, HeaderLayout hLayout);
function: Header_populateFromSettings
void Header_populateFromSettings(Header* this);
function: Header_reinit
void Header_reinit(Header* this);
function: Header_setLayout
void Header_setLayout(Header* this, HeaderLayout hLayout);
function: Header_updateData
void Header_updateData(Header* this);
function: Header_writeBackToSettings
void Header_writeBackToSettings(const Header* this);
macro: Header_forEachColumn
#define Header_forEachColumn(this_, i_) for (size_t (i_)=0, H_fEC_numColumns_ = HeaderLayout_getColumns((this_)->headerLayout); (i_) < H_fEC_numColumns_; ++(i_))
struct: Header
typedef struct Header_ {
Vector** columns;
Machine* host;
HeaderLayout headerLayout;
int pad;
int height;
} Header;HeaderLayout.h
HeaderLayout.h
enum: HeaderLayout
typedef enum HeaderLayout_ {
HF_INVALID = -1,
HF_ONE_100,
HF_TWO_50_50,
HF_TWO_33_67,
HF_TWO_67_33,
HF_THREE_33_34_33,
HF_THREE_25_25_50,
HF_THREE_25_50_25,
HF_THREE_50_25_25,
HF_THREE_40_30_30,
HF_THREE_30_40_30,
HF_THREE_30_30_40,
HF_THREE_40_20_40,
HF_FOUR_25_25_25_25,
LAST_HEADER_LAYOUT
} HeaderLayout;function: HeaderLayout_fromName
static inline HeaderLayout HeaderLayout_fromName(const char* name) {
for (size_t i = 0; i < LAST_HEADER_LAYOUT; i++) {
if (String_eq(HeaderLayout_layouts[i].name, name))
return (HeaderLayout) i;
}
return LAST_HEADER_LAYOUT;
}function: HeaderLayout_getColumns
static inline size_t HeaderLayout_getColumns(HeaderLayout hLayout) {
/* assert the layout is initialized */
assert(0 <= hLayout);
assert(hLayout < LAST_HEADER_LAYOUT);
assert(HeaderLayout_layouts[hLayout].name[0]);
assert(HeaderLayout_layouts[hLayout].description[0]);
return HeaderLayout_layouts[hLayout].columns;
}function: HeaderLayout_getName
static inline const char* HeaderLayout_getName(HeaderLayout hLayout) {
/* assert the layout is initialized */
assert(0 <= hLayout);
assert(hLayout < LAST_HEADER_LAYOUT);
assert(HeaderLayout_layouts[hLayout].name[0]);
assert(HeaderLayout_layouts[hLayout].description[0]);
return HeaderLayout_layouts[hLayout].name;
}global variable: HeaderLayout_layouts
static const struct {
uint8_t columns;
const uint8_t widths[4];
const char* name;
const char* description;
} HeaderLayout_layouts[LAST_HEADER_LAYOUT] = {
[HF_ONE_100] = { 1, { 100, 0, 0, 0 }, "one_100", "1 column - full width", },
[HF_TWO_50_50] = { 2, { 50, 50, 0, 0 }, "two_50_50", "2 columns - 50/50 (default)", },
[HF_TWO_33_67] = { 2, { 33, 67, 0, 0 }, "two_33_67", "2 columns - 33/67", },
[HF_TWO_67_33] = { 2, { 67, 33, 0, 0 }, "two_67_33", "2 columns - 67/33", },
[HF_THREE_33_34_33] = { 3, { 33, 34, 33, 0 }, "three_33_34_33", "3 columns - 33/34/33", },
[HF_THREE_25_25_50] = { 3, { 25, 25, 50, 0 }, "three_25_25_50", "3 columns - 25/25/50", },
[HF_THREE_25_50_25] = { 3, { 25, 50, 25, 0 }, "three_25_50_25", "3 columns - 25/50/25", },
[HF_THREE_50_25_25] = { 3, { 50, 25, 25, 0 }, "three_50_25_25", "3 columns - 50/25/25", },
[HF_THREE_40_30_30] = { 3, { 40, 30, 30, 0 }, "three_40_30_30", "3 columns - 40/30/30", },
[HF_THREE_30_40_30] = { 3, { 30, 40, 30, 0 }, "three_30_40_30", "3 columns - 30/40/30", },
[HF_THREE_30_30_40] = { 3, { 30, 30, 40, 0 }, "three_30_30_40", "3 columns - 30/30/40", },
[HF_THREE_40_20_40] = { 3, { 40, 20, 40, 0 }, "three_40_20_40", "3 columns - 40/20/40", },
[HF_FOUR_25_25_25_25] = { 4, { 25, 25, 25, 25 }, "four_25_25_25_25", "4 columns - 25/25/25/25", },
};HeaderOptionsPanel.c
HeaderOptionsPanel.c
class definition: HeaderOptionsPanel_class
const PanelClass HeaderOptionsPanel_class = {
.super = {
.extends = Class(Panel),
.delete = HeaderOptionsPanel_delete
},
.eventHandler = HeaderOptionsPanel_eventHandler
};function: HeaderOptionsPanel_delete
static void HeaderOptionsPanel_delete(Object* object) {
HeaderOptionsPanel* this = (HeaderOptionsPanel*) object;
Panel_done(&this->super);
free(this);
}function: HeaderOptionsPanel_eventHandler
static HandlerResult HeaderOptionsPanel_eventHandler(Panel* super, int ch) {
HeaderOptionsPanel* this = (HeaderOptionsPanel*) super;
HandlerResult result = IGNORED;
switch (ch) {
case 0x0a:
case 0x0d:
case KEY_ENTER:
case KEY_MOUSE:
case KEY_RECLICK:
case ' ': {
int mark = Panel_getSelectedIndex(super);
assert(mark >= 0);
assert(mark < LAST_HEADER_LAYOUT);
for (int i = 0; i < LAST_HEADER_LAYOUT; i++)
CheckItem_set((CheckItem*)Panel_get(super, i), false);
CheckItem_set((CheckItem*)Panel_get(super, mark), true);
Header_setLayout(this->scr->header, mark);
this->settings->changed = true;
this->settings->lastUpdate++;
ScreenManager_resize(this->scr);
result = HANDLED;
}
}
return result;
}function: HeaderOptionsPanel_new
HeaderOptionsPanel* HeaderOptionsPanel_new(Settings* settings, ScreenManager* scr) {
HeaderOptionsPanel* this = AllocThis(HeaderOptionsPanel);
Panel* super = &this->super;
FunctionBar* fuBar = FunctionBar_new(HeaderOptionsFunctions, NULL, NULL);
Panel_init(super, 1, 1, 1, 1, Class(CheckItem), true, fuBar);
this->scr = scr;
this->settings = settings;
Panel_setHeader(super, "Header Layout");
for (int i = 0; i < LAST_HEADER_LAYOUT; i++) {
Panel_add(super, (Object*) CheckItem_newByVal(HeaderLayout_layouts[i].description, false));
}
CheckItem_set((CheckItem*)Panel_get(super, scr->header->headerLayout), true);
return this;
}static variable: HeaderOptionsFunctions
static const char* const HeaderOptionsFunctions[] = {" ", " ", " ", " ", " ", " ", " ", " ", " ", "Done ", NULL};HeaderOptionsPanel.h
HeaderOptionsPanel.h
extern const: HeaderOptionsPanel_class
extern const PanelClass HeaderOptionsPanel_class;
function: HeaderOptionsPanel_new
HeaderOptionsPanel* HeaderOptionsPanel_new(Settings* settings, ScreenManager* scr);
struct: HeaderOptionsPanel_
typedef struct HeaderOptionsPanel_ {
Panel super;
ScreenManager* scr;
Settings* settings;
} HeaderOptionsPanel;HostnameMeter.c
HostnameMeter.c
function: HostnameMeter_updateValues
static void HostnameMeter_updateValues(Meter* this) {
Platform_getHostname(this->txtBuffer, sizeof(this->txtBuffer));
}struct: HostnameMeter_class
const MeterClass HostnameMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete
},
.updateValues = HostnameMeter_updateValues,
.defaultMode = TEXT_METERMODE,
.supportedModes = (1 << TEXT_METERMODE),
.maxItems = 0,
.total = 0.0,
.attributes = HostnameMeter_attributes,
.name = "Hostname",
.uiName = "Hostname",
.caption = "Hostname: ",
};structure: HostnameMeter_attributes
static const int HostnameMeter_attributes[] = {
HOSTNAME
};HostnameMeter.h
HostnameMeter.h
struct: HostnameMeter_class
extern const MeterClass HostnameMeter_class;
htop.1.in
htop.1.in
file: htop.1.in
htop.c
htop.c
function: main
int main(int argc, char** argv) {
return CommandLine_run(argc, argv);
}global variable: program
const char* program = PACKAGE;
htop.desktop
htop.desktop
file: htop.desktop
htop.svg
htop.svg
file: htop.svg
IncSet.c
IncSet.c
function: IncMode_done
static inline void IncMode_done(IncMode* mode) {
FunctionBar_delete(mode->bar);
}function: IncMode_find
static bool IncMode_find(const IncMode* mode, Panel* panel, IncMode_GetPanelValue getPanelValue, int step) {
int size = Panel_size(panel);
int here = Panel_getSelectedIndex(panel);
int i = here;
for (;;) {
i += step;
if (i == size) {
i = 0;
}
if (i == -1) {
i = size - 1;
}
if (i == here) {
return false;
}
if (String_contains_i(getPanelValue(panel, i), mode->buffer, true)) {
Panel_setSelected(panel, i);
return true;
}
}
}function: IncMode_initFilter
static inline void IncMode_initFilter(IncMode* filter) {
memset(filter, 0, sizeof(IncMode));
filter->bar = FunctionBar_new(filterFunctions, filterKeys, filterEvents);
filter->isFilter = true;
}function: IncMode_initSearch
static inline void IncMode_initSearch(IncMode* search) {
memset(search, 0, sizeof(IncMode));
search->bar = FunctionBar_new(searchFunctions, searchKeys, searchEvents);
search->isFilter = false;
}function: IncMode_reset
static void IncMode_reset(IncMode* mode) {
mode->index = 0;
mode->buffer[0] = 0;
}function: IncSet_activate
void IncSet_activate(IncSet* this, IncType type, Panel* panel) {
this->active = &(this->modes[type]);
panel->currentBar = this->active->bar;
panel->cursorOn = true;
this->panel = panel;
IncSet_drawBar(this, CRT_colors[FUNCTION_BAR]);
}function: IncSet_deactivate
static void IncSet_deactivate(IncSet* this, Panel* panel) {
this->active = NULL;
Panel_setDefaultBar(panel);
panel->cursorOn = false;
FunctionBar_draw(this->defaultBar);
}function: IncSet_delete
void IncSet_delete(IncSet* this) {
IncMode_done(&(this->modes[0]));
IncMode_done(&(this->modes[1]));
free(this);
}function: IncSet_drawBar
void IncSet_drawBar(const IncSet* this, int attr) {
if (this->active) {
if (!this->active->isFilter && !this->found)
attr = CRT_colors[FAILED_SEARCH];
int cursorX = FunctionBar_drawExtra(this->active->bar, this->active->buffer, attr, true);
this->panel->cursorY = LINES - 1;
this->panel->cursorX = cursorX;
} else {
FunctionBar_draw(this->defaultBar);
}
}function: IncSet_getListItemValue
const char* IncSet_getListItemValue(Panel* panel, int i) {
const ListItem* l = (const ListItem*) Panel_get(panel, i);
return l ? l->value : "";
}function: IncSet_handleKey
bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue getPanelValue, Vector* lines) {
if (ch == ERR)
return true;
IncMode* mode = this->active;
int size = Panel_size(panel);
bool filterChanged = false;
bool doSearch = true;
if (ch == KEY_F(3) || ch == KEY_F(15)) {
if (size == 0)
return true;
IncMode_find(mode, panel, getPanelValue, ch == KEY_F(3) ? 1 : -1);
doSearch = false;
} else if (0 < ch && ch < 255 && isprint((unsigned char)ch)) {
if (mode->index < INCMODE_MAX) {
mode->buffer[mode->index] = (char) ch;
mode->index++;
mode->buffer[mode->index] = 0;
if (mode->isFilter) {
filterChanged = true;
if (mode->index == 1) {
this->filtering = true;
}
}
}
} else if (ch == KEY_BACKSPACE || ch == 127) {
if (mode->index > 0) {
mode->index--;
mode->buffer[mode->index] = 0;
if (mode->isFilter) {
filterChanged = true;
if (mode->index == 0) {
this->filtering = false;
IncMode_reset(mode);
}
}
} else {
doSearch = false;
}
} else if (ch == KEY_RESIZE) {
doSearch = (mode->index > 0);
} else {
if (mode->isFilter) {
filterChanged = true;
if (ch == 27) {
this->filtering = false;
IncMode_reset(mode);
}
} else {
if (ch == 27) {
IncMode_reset(mode);
}
}
IncSet_deactivate(this, panel);
doSearch = false;
}
if (doSearch) {
this->found = search(this, panel, getPanelValue);
}
if (filterChanged && lines) {
updateWeakPanel(this, panel, lines);
}
return filterChanged;
}function: IncSet_new
IncSet* IncSet_new(FunctionBar* bar) {
IncSet* this = xMalloc(sizeof(IncSet));
IncMode_initSearch(&(this->modes[INC_SEARCH]));
IncMode_initFilter(&(this->modes[INC_FILTER]));
this->active = NULL;
this->defaultBar = bar;
this->filtering = false;
this->found = false;
return this;
}function: IncSet_reset
void IncSet_reset(IncSet* this, IncType type) {
IncMode_reset(&this->modes[type]);
}function: IncSet_setFilter
void IncSet_setFilter(IncSet* this, const char* filter) {
IncMode* mode = &this->modes[INC_FILTER];
size_t len = String_safeStrncpy(mode->buffer, filter, sizeof(mode->buffer));
mode->index = len;
this->filtering = true;
}function: IncSet_synthesizeEvent
int IncSet_synthesizeEvent(IncSet* this, int x) {
if (this->active) {
return FunctionBar_synthesizeEvent(this->active->bar, x);
} else {
return FunctionBar_synthesizeEvent(this->defaultBar, x);
}
}function: search
static bool search(const IncSet* this, Panel* panel, IncMode_GetPanelValue getPanelValue) {
int size = Panel_size(panel);
for (int i = 0; i < size; i++) {
if (String_contains_i(getPanelValue(panel, i), this->active->buffer, true)) {
Panel_setSelected(panel, i);
return true;
}
}
return false;
}function: updateWeakPanel
static void updateWeakPanel(const IncSet* this, Panel* panel, Vector* lines) {
const Object* selected = Panel_getSelected(panel);
Panel_prune(panel);
if (this->filtering) {
int n = 0;
const char* incFilter = this->modes[INC_FILTER].buffer;
for (int i = 0; i < Vector_size(lines); i++) {
ListItem* line = (ListItem*)Vector_get(lines, i);
if (String_contains_i(line->value, incFilter, true)) {
Panel_add(panel, (Object*)line);
if (selected == (Object*)line) {
Panel_setSelected(panel, n);
}
n++;
}
}
} else {
for (int i = 0; i < Vector_size(lines); i++) {
Object* line = Vector_get(lines, i);
Panel_add(panel, line);
if (selected == line) {
Panel_setSelected(panel, i);
}
}
}
}IncSet.h
IncSet.h
enum: IncType
typedef enum {
INC_SEARCH = 0,
INC_FILTER = 1
} IncType;function: IncSet_activate
void IncSet_activate(IncSet* this, IncType type, Panel* panel);
function: IncSet_delete
void IncSet_delete(IncSet* this);
function: IncSet_drawBar
void IncSet_drawBar(const IncSet* this, int attr);
function: IncSet_filter
static inline const char* IncSet_filter(const IncSet* this) {
return this->filtering ? this->modes[INC_FILTER].buffer : NULL;
}function: IncSet_getListItemValue
const char* IncSet_getListItemValue(Panel* panel, int i);
function: IncSet_handleKey
bool IncSet_handleKey(IncSet* this, int ch, Panel* panel, IncMode_GetPanelValue getPanelValue, Vector* lines);
function: IncSet_new
IncSet* IncSet_new(FunctionBar* bar);
function: IncSet_reset
void IncSet_reset(IncSet* this, IncType type);
function: IncSet_setFilter
void IncSet_setFilter(IncSet* this, const char* filter);
function: IncSet_synthesizeEvent
int IncSet_synthesizeEvent(IncSet* this, int x);
macro: INCMODE_MAX
#define INCMODE_MAX 128
struct: IncMode
typedef struct IncMode_ {
char buffer[INCMODE_MAX + 1];
int index;
FunctionBar* bar;
bool isFilter;
} IncMode;struct: IncSet
typedef struct IncSet_ {
IncMode modes[2];
IncMode* active;
Panel* panel;
FunctionBar* defaultBar;
bool filtering;
bool found;
} IncSet;typedef: IncMode_GetPanelValue
typedef const char* (*IncMode_GetPanelValue)(Panel*, int);
InfoScreen.c
InfoScreen.c
function: InfoScreen_addLine
void InfoScreen_addLine(InfoScreen* this, const char* line) {
Vector_add(this->lines, (Object*) ListItem_new(line, 0));
const char* incFilter = IncSet_filter(this->inc);
if (!incFilter || String_contains_i(line, incFilter, true)) {
Panel_add(this->display, Vector_get(this->lines, Vector_size(this->lines) - 1));
}
}function: InfoScreen_appendLine
void InfoScreen_appendLine(InfoScreen* this, const char* line) {
ListItem* last = (ListItem*)Vector_get(this->lines, Vector_size(this->lines) - 1);
ListItem_append(last, line);
const char* incFilter = IncSet_filter(this->inc);
if (incFilter && Panel_get(this->display, Panel_size(this->display) - 1) != (Object*)last && String_contains_i(line, incFilter, true)) {
Panel_add(this->display, (Object*)last);
}
}function: InfoScreen_done
InfoScreen* InfoScreen_done(InfoScreen* this) {
Panel_delete((Object*)this->display);
IncSet_delete(this->inc);
Vector_delete(this->lines);
return this;
}function: InfoScreen_drawTitled
void InfoScreen_drawTitled(InfoScreen* this, const char* fmt, ...) {
va_list ap;
va_start(ap, fmt);
char title[COLS + 1];
int len = vsnprintf(title, sizeof(title), fmt, ap);
va_end(ap);
if (len > COLS) {
memset(&title[COLS - 3], '.', 3);
}
attrset(CRT_colors[METER_TEXT]);
mvhline(0, 0, ' ', COLS);
mvaddstr(0, 0, title);
attrset(CRT_colors[DEFAULT_COLOR]);
Panel_draw(this->display, true, true, true, false);
IncSet_drawBar(this->inc, CRT_colors[FUNCTION_BAR]);
}function: InfoScreen_init
InfoScreen* InfoScreen_init(InfoScreen* this, const Process* process, FunctionBar* bar, int height, const char* panelHeader) {
this->process = process;
if (!bar) {
bar = FunctionBar_new(InfoScreenFunctions, InfoScreenKeys, InfoScreenEvents);
}
this->display = Panel_new(0, 1, COLS, height, Class(ListItem), false, bar);
this->inc = IncSet_new(bar);
this->lines = Vector_new(Vector_type(this->display->items), true, DEFAULT_SIZE);
Panel_setHeader(this->display, panelHeader);
return this;
}function: InfoScreen_run
global variable: InfoScreenEvents
static const int InfoScreenEvents[] = {KEY_F(3), KEY_F(4), KEY_F(5), 27};global variable: InfoScreenFunctions
static const char* const InfoScreenFunctions[] = {"Search ", "Filter ", "Refresh", "Done ", NULL};global variable: InfoScreenKeys
static const char* const InfoScreenKeys[] = {"F3", "F4", "F5", "Esc"};InfoScreen.h
InfoScreen.h
function: InfoScreen_addLine
void InfoScreen_addLine(InfoScreen* this, const char* line);
function: InfoScreen_appendLine
void InfoScreen_appendLine(InfoScreen* this, const char* line);
function: InfoScreen_done
InfoScreen* InfoScreen_done(InfoScreen* this);
function: InfoScreen_drawTitled
ATTR_FORMAT(printf, 2, 3) void InfoScreen_drawTitled(InfoScreen* this, const char* fmt, ...);
function: InfoScreen_init
InfoScreen* InfoScreen_init(InfoScreen* this, const Process* process, FunctionBar* bar, int height, const char* panelHeader);
function: InfoScreen_run
void InfoScreen_run(InfoScreen* this);
macro: As_InfoScreen
#define As_InfoScreen(this_) ((const InfoScreenClass*)(((InfoScreen*)(this_))->super.klass))
macro: InfoScreen_draw
#define InfoScreen_draw(this_) As_InfoScreen(this_)->draw((InfoScreen*)(this_))
macro: InfoScreen_onErr
#define InfoScreen_onErr(this_) As_InfoScreen(this_)->onErr((InfoScreen*)(this_))
macro: InfoScreen_onKey
#define InfoScreen_onKey(this_, ch_) As_InfoScreen(this_)->onKey((InfoScreen*)(this_), ch_)
macro: InfoScreen_scan
#define InfoScreen_scan(this_) As_InfoScreen(this_)->scan((InfoScreen*)(this_))
struct: InfoScreen
typedef struct InfoScreen_ {
Object super;
const Process* process;
Panel* display;
IncSet* inc;
Vector* lines;
} InfoScreen;struct: InfoScreenClass
typedef struct InfoScreenClass_ {
const ObjectClass super;
const InfoScreen_Scan scan;
const InfoScreen_Draw draw;
const InfoScreen_OnErr onErr;
const InfoScreen_OnKey onKey;
} InfoScreenClass;typedef: InfoScreen_Draw
typedef void(*InfoScreen_Draw)(InfoScreen*);
typedef: InfoScreen_OnErr
typedef void(*InfoScreen_OnErr)(InfoScreen*);
typedef: InfoScreen_OnKey
typedef bool(*InfoScreen_OnKey)(InfoScreen*, int);
typedef: InfoScreen_Scan
typedef void(*InfoScreen_Scan)(InfoScreen*);
htop.imp
iwyu/htop.imp
file: htop.imp
[
{ include: ["<curses.h>", "private", "\"ProvideCurses.h\"", "public"] },
{ include: ["<ncurses.h>", "private", "\"ProvideCurses.h\"", "public"] },
{ include: ["<ncurses/curses.h>", "private", "\"ProvideCurses.h\"", "public"] },
{ include: ["<ncurses/ncurses.h>", "private", "\"ProvideCurses.h\"", "public"] },
{ include: ["<term.h>", "private", "\"ProvideTerm.h\"", "public"] },
{ include: ["<ncurses/term.h>", "private", "\"ProvideTerm.h\"", "public"] },
{ include: ["<ncursesw/term.h>", "private", "\"ProvideTerm.h\"", "public"] },
{ include: ["<libunwind-x86_64.h>", "private", "<libunwind.h>", "public"] },
{ include: ["\"ibunwind-x86_64.h\"", "private", "<libunwind.h>", "public"] },
{ include: ["<bits/types/struct_tm.h>", "private", "<time.h>", "public"] },
{ include: ["<bits/getopt_core.h>", "private", "<unistd.h>", "public"] },
{ include: ["<sys/dirent.h>", "private", "<dirent.h>", "public"] },
{ include: ["<sys/signal.h>", "private", "<signal.h>", "public"] },
{ include: ["<sys/_stdarg.h>", "private", "<stdarg.h>", "public"] },
{ include: ["<sys/limits.h>", "private", "<limits.h>", "public"] },
{ include: ["<x86/_inttypes.h>", "private", "<inttypes.h>", "public"] },
{ include: ["<linux/capability.h>", "private", "<sys/capability.h>", "public"] },
{ include: ["<bits/mman-shared.h>", "private", "<sys/mman.h>", "public"] },
{ include: ["<bits/types/struct_sched_param.h>", "private", "<sched.h>", "public"] },
]
run_iwyu.sh
iwyu/run_iwyu.sh
script: run_iwyu.sh
#!/bin/sh
SCRIPT=$(readlink -f "$0")
SCRIPTDIR=$(dirname "$SCRIPT")
SOURCEDIR="$SCRIPTDIR/.."
PKG_NL3=$(pkg-config --cflags libnl-3.0)
IWYU=${IWYU:-iwyu}
cd "$SOURCEDIR" || exit
./configure CC=clang CXX=clang++ --enable-silent-rules
make clean
make -k -s CC="$IWYU" CFLAGS="-Xiwyu --no_comments -Xiwyu --no_fwd_decl -Xiwyu --mapping_file='$SCRIPTDIR/htop.imp' $PKG_NL3"CGroupUtils.c
linux/CGroupUtils.c
function: CGroup_filterContainer
char* CGroup_filterContainer(const char* cgroup) {
StrBuf_state s = {
.buf = NULL,
.size = 0,
.pos = 0,
};
if (!CGroup_filterContainer_internal(cgroup, &s, StrBuf_putc_count)) {
return NULL;
}
if (!s.pos) {
return xStrdup("/");
}
s.buf = xCalloc(s.pos + 1, sizeof(char));
s.size = s.pos;
s.pos = 0;
if (!CGroup_filterContainer_internal(cgroup, &s, StrBuf_putc_write)) {
free(s.buf);
return NULL;
}
s.buf[s.size] = '\0';
return s.buf;
}function: CGroup_filterContainer_internal
function: CGroup_filterName
char* CGroup_filterName(const char* cgroup) {
StrBuf_state s = {
.buf = NULL,
.size = 0,
.pos = 0,
};
if (!CGroup_filterName_internal(cgroup, &s, StrBuf_putc_count)) {
return NULL;
}
s.buf = xCalloc(s.pos + 1, sizeof(char));
s.size = s.pos;
s.pos = 0;
if (!CGroup_filterName_internal(cgroup, &s, StrBuf_putc_write)) {
free(s.buf);
return NULL;
}
s.buf[s.size] = '\0';
return s.buf;
}function: CGroup_filterName_internal
function: Label_checkEqual
static bool Label_checkEqual(const char* labelStart, size_t labelLen, const char* expected) {
return labelLen == strlen(expected) && String_startsWith(labelStart, expected);
}function: Label_checkPrefix
static bool Label_checkPrefix(const char* labelStart, size_t labelLen, const char* expected) {
return labelLen > strlen(expected) && String_startsWith(labelStart, expected);
}function: Label_checkSuffix
static bool Label_checkSuffix(const char* labelStart, size_t labelLen, const char* expected) {
return labelLen > strlen(expected) && String_startsWith(labelStart + labelLen - strlen(expected), expected);
}function: StrBuf_putc_count
static bool StrBuf_putc_count(StrBuf_state* p, ATTR_UNUSED char c) {
p->pos++;
return true;
}function: StrBuf_putc_write
static bool StrBuf_putc_write(StrBuf_state* p, char c) {
if (p->pos >= p->size)
return false;
p->buf[p->pos] = c;
p->pos++;
return true;
}function: StrBuf_putsn
static bool StrBuf_putsn(StrBuf_state* p, StrBuf_putc_t w, const char* s, size_t count) {
for (; count; count--)
if (!w(p, *s++))
return false;
return true;
}function: StrBuf_putsz
static bool StrBuf_putsz(StrBuf_state* p, StrBuf_putc_t w, const char* s) {
while (*s)
if (!w(p, *s++))
return false;
return true;
}struct: StrBuf_state
typedef struct StrBuf_state {
char* buf;
size_t size;
size_t pos;
} StrBuf_state;typedef: StrBuf_putc_t
typedef bool (*StrBuf_putc_t)(StrBuf_state* p, char c);
CGroupUtils.h
linux/CGroupUtils.h
function: CGroup_filterContainer
char* CGroup_filterContainer(const char* cgroup);
function: CGroup_filterName
char* CGroup_filterName(const char* cgroup);
GPU.c
linux/GPU.c
file: GPU.c
GPU.h
linux/GPU.h
function: GPU_readProcessData
void GPU_readProcessData(LinuxProcessTable* lpt, LinuxProcess* lp, openat_arg_t procFd);
GPUMeter.c
linux/GPUMeter.c
file: GPUMeter.c
GPUMeter.h
linux/GPUMeter.h
function: GPUMeter_active
bool GPUMeter_active(void);
variable: GPUMeter_class
extern const MeterClass GPUMeter_class;
HugePageMeter.c
linux/HugePageMeter.c
function: HugePageMeter_display
static void HugePageMeter_display(const Object* cast, RichString* out) {
char buffer[50];
const Meter* this = (const Meter*)cast;
RichString_writeAscii(out, CRT_colors[METER_TEXT], ":");
Meter_humanUnit(buffer, this->total, sizeof(buffer));
RichString_appendAscii(out, CRT_colors[METER_VALUE], buffer);
for (unsigned i = 0; i < ARRAYSIZE(HugePageMeter_active_labels); i++) {
if (!HugePageMeter_active_labels[i]) {
break;
}
RichString_appendAscii(out, CRT_colors[METER_TEXT], HugePageMeter_active_labels[i]);
Meter_humanUnit(buffer, this->values[i], sizeof(buffer));
RichString_appendAscii(out, CRT_colors[HUGEPAGE_1 + i], buffer);
}
}function: HugePageMeter_updateValues
static void HugePageMeter_updateValues(Meter* this) {
assert(ARRAYSIZE(HugePageMeter_labels) == HTOP_HUGEPAGE_COUNT);
char* buffer = this->txtBuffer;
size_t size = sizeof(this->txtBuffer);
int written;
memory_t usedTotal = 0;
unsigned nextUsed = 0;
const LinuxMachine* host = (const LinuxMachine*) this->host;
this->total = host->totalHugePageMem;
this->values[0] = 0;
HugePageMeter_active_labels[0] = " used:";
for (unsigned i = 1; i < ARRAYSIZE(HugePageMeter_active_labels); i++) {
this->values[i] = NAN;
HugePageMeter_active_labels[i] = NULL;
}
for (unsigned i = 0; i < HTOP_HUGEPAGE_COUNT; i++) {
memory_t value = host->usedHugePageMem[i];
if (value != MEMORY_MAX) {
this->values[nextUsed] = value;
usedTotal += value;
HugePageMeter_active_labels[nextUsed] = HugePageMeter_labels[i];
if (++nextUsed == ARRAYSIZE(HugePageMeter_active_labels)) {
break;
}
}
}
written = Meter_humanUnit(buffer, usedTotal, size);
METER_BUFFER_CHECK(buffer, size, written);
METER_BUFFER_APPEND_CHR(buffer, size, '/');
Meter_humanUnit(buffer, this->total, size);
}struct: HugePageMeter_class
const MeterClass HugePageMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = HugePageMeter_display,
},
.updateValues = HugePageMeter_updateValues,
.defaultMode = BAR_METERMODE,
.supportedModes = METERMODE_DEFAULT_SUPPORTED,
.maxItems = ARRAYSIZE(HugePageMeter_active_labels),
.total = 100.0,
.attributes = HugePageMeter_attributes,
.name = "HugePages",
.uiName = "HugePages",
.caption = "HP"
};HugePageMeter.h
linux/HugePageMeter.h
variable: HugePageMeter_class
extern const MeterClass HugePageMeter_class;
IOPriority.h
linux/IOPriority.h
enum: (anonymous enum)
enum {
IOPRIO_CLASS_NONE,
IOPRIO_CLASS_RT,
IOPRIO_CLASS_BE,
IOPRIO_CLASS_IDLE,
};macro: IOPRIO_CLASS_SHIFT
#define IOPRIO_CLASS_SHIFT (13)
macro: IOPRIO_PRIO_MASK
#define IOPRIO_PRIO_MASK ((1UL << IOPRIO_CLASS_SHIFT) - 1)
macro: IOPRIO_WHO_PROCESS
#define IOPRIO_WHO_PROCESS 1
macro: IOPriority_class
#define IOPriority_class(ioprio_) ((int) ((ioprio_) >> IOPRIO_CLASS_SHIFT) )
macro: IOPriority_data
#define IOPriority_data(ioprio_) ((int) ((ioprio_) & IOPRIO_PRIO_MASK) )
macro: IOPriority_Idle
#define IOPriority_Idle IOPriority_tuple(IOPRIO_CLASS_IDLE, 7)
macro: IOPriority_None
#define IOPriority_None IOPriority_tuple(IOPRIO_CLASS_NONE, 0)
macro: IOPriority_tuple
#define IOPriority_tuple(class_, data_) (((class_) << IOPRIO_CLASS_SHIFT) | (data_))
typedef: IOPriority
typedef int IOPriority;
IOPriorityPanel.c
linux/IOPriorityPanel.c
function: IOPriorityPanel_getIOPriority
IOPriority IOPriorityPanel_getIOPriority(Panel* this) {
const ListItem* selected = (ListItem*) Panel_getSelected(this);
return selected ? selected->key : IOPriority_None;
}function: IOPriorityPanel_new
Panel* IOPriorityPanel_new(IOPriority currPrio) {
Panel* this = Panel_new(1, 1, 1, 1, Class(ListItem), true, FunctionBar_newEnterEsc("Set ", "Cancel "));
Panel_setHeader(this, "IO Priority:");
Panel_add(this, (Object*) ListItem_new("None (based on nice)", IOPriority_None));
if (currPrio == IOPriority_None) {
Panel_setSelected(this, 0);
}
static const struct {
int klass;
const char* name;
} classes[] = {
{ .klass = IOPRIO_CLASS_RT, .name = "Realtime" },
{ .klass = IOPRIO_CLASS_BE, .name = "Best-effort" },
{ .klass = 0, .name = NULL }
};
for (int c = 0; classes[c].name; c++) {
for (int i = 0; i < 8; i++) {
char name[50];
xSnprintf(name, sizeof(name), "%s %d %s", classes[c].name, i, i == 0 ? "(High)" : (i == 7 ? "(Low)" : ""));
IOPriority ioprio = IOPriority_tuple(classes[c].klass, i);
Panel_add(this, (Object*) ListItem_new(name, ioprio));
if (currPrio == ioprio) {
Panel_setSelected(this, Panel_size(this) - 1);
}
}
}
Panel_add(this, (Object*) ListItem_new("Idle", IOPriority_Idle));
if (currPrio == IOPriority_Idle) {
Panel_setSelected(this, Panel_size(this) - 1);
}
return this;
}IOPriorityPanel.h
linux/IOPriorityPanel.h
function: IOPriorityPanel_getIOPriority
IOPriority IOPriorityPanel_getIOPriority(Panel* this);
function: IOPriorityPanel_new
Panel* IOPriorityPanel_new(IOPriority currPrio);
LibNl.c
linux/LibNl.c
function: handleNetlinkMsg
static int handleNetlinkMsg(struct nl_msg* nlmsg, void* linuxProcess) {
struct nlmsghdr* nlhdr;
struct nlattr* nlattrs[TASKSTATS_TYPE_MAX + 1];
const struct nlattr* nlattr;
struct taskstats stats;
int rem;
LinuxProcess* lp = (LinuxProcess*) linuxProcess;
nlhdr = sym_nlmsg_hdr(nlmsg);
if (sym_genlmsg_parse(nlhdr, 0, nlattrs, TASKSTATS_TYPE_MAX, NULL) < 0) {
return NL_SKIP;
}
if ((nlattr = nlattrs[TASKSTATS_TYPE_AGGR_PID]) || (nlattr = nlattrs[TASKSTATS_TYPE_NULL])) {
memcpy(&stats, sym_nla_data(sym_nla_next(sym_nla_data(nlattr), &rem)), sizeof(stats));
assert(Process_getPid(&lp->super) == (pid_t)stats.ac_pid);
// The xxx_delay_total values wrap around on overflow.
// (Linux Kernel "Documentation/accounting/taskstats-struct.rst")
unsigned long long int timeDelta = stats.ac_etime * 1000 - lp->delay_read_time;
#define DELTAPERC(x, y) (timeDelta ? MINIMUM((float)((x) - (y)) / timeDelta * 100.0F, 100.0F) : NAN)
lp->cpu_delay_percent = DELTAPERC(stats.cpu_delay_total, lp->cpu_delay_total);
lp->blkio_delay_percent = DELTAPERC(stats.blkio_delay_total, lp->blkio_delay_total);
lp->swapin_delay_percent = DELTAPERC(stats.swapin_delay_total, lp->swapin_delay_total);
#undef DELTAPERC
lp->swapin_delay_total = stats.swapin_delay_total;
lp->blkio_delay_total = stats.blkio_delay_total;
lp->cpu_delay_total = stats.cpu_delay_total;
lp->delay_read_time = stats.ac_etime * 1000;
}
return NL_OK;
}function: initNetlinkSocket
static void initNetlinkSocket(LinuxProcessTable* this) {
if (load_libnl() < 0) {
return;
}
this->netlink_socket = sym_nl_socket_alloc();
if (this->netlink_socket == NULL) {
return;
}
if (sym_nl_connect(this->netlink_socket, NETLINK_GENERIC) < 0) {
return;
}
this->netlink_family = sym_genl_ctrl_resolve(this->netlink_socket, TASKSTATS_GENL_NAME);
}function: LibNl_destroyNetlinkSocket
void LibNl_destroyNetlinkSocket(LinuxProcessTable* this) {
if (this->netlink_socket) {
assert(libnlHandle);
sym_nl_close(this->netlink_socket);
sym_nl_socket_free(this->netlink_socket);
this->netlink_socket = NULL;
}
unload_libnl();
}function: LibNl_readDelayAcctData
void LibNl_readDelayAcctData(LinuxProcessTable* this, LinuxProcess* process) {
struct nl_msg* msg;
if (!this->netlink_socket) {
initNetlinkSocket(this);
if (!this->netlink_socket) {
goto delayacct_failure;
}
}
if (sym_nl_socket_modify_cb(this->netlink_socket, NL_CB_VALID, NL_CB_CUSTOM, handleNetlinkMsg, process) < 0) {
goto delayacct_failure;
}
if (! (msg = sym_nlmsg_alloc())) {
goto delayacct_failure;
}
if (! sym_genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, this->netlink_family, 0, NLM_F_REQUEST, TASKSTATS_CMD_GET, TASKSTATS_VERSION)) {
sym_nlmsg_free(msg);
}
if (sym_nla_put_u32(msg, TASKSTATS_CMD_ATTR_PID, Process_getPid(&process->super)) < 0) {
sym_nlmsg_free(msg);
}
if (sym_nl_send_sync(this->netlink_socket, msg) < 0) {
goto delayacct_failure;
}
if (sym_nl_recvmsgs_default(this->netlink_socket) < 0) {
goto delayacct_failure;
}
return;
delayacct_failure:
process->swapin_delay_percent = NAN;
process->blkio_delay_percent = NAN;
process->cpu_delay_percent = NAN;
}function: load_libnl
static int load_libnl(void) {
if (libnlHandle && libnlGenlHandle)
return 0;
libnlHandle = dlopen("libnl-3.so", RTLD_LAZY);
if (!libnlHandle) {
libnlHandle = dlopen("libnl-3.so.200", RTLD_LAZY);
if (!libnlHandle) {
goto dlfailure;
}
}
libnlGenlHandle = dlopen("libnl-genl-3.so", RTLD_LAZY);
if (!libnlGenlHandle) {
libnlGenlHandle = dlopen("libnl-genl-3.so.200", RTLD_LAZY);
if (!libnlGenlHandle) {
goto dlfailure;
}
}
/* Clear any errors */
dlerror();
#define resolve(handle, symbolname) do { \
*(void **)(&sym_##symbolname) = dlsym(handle, #symbolname); \
if (!sym_##symbolname || dlerror() != NULL) { \
goto dlfailure; \
} \
} while(0)
resolve(libnlHandle, nl_close);
resolve(libnlHandle, nl_connect);
resolve(libnlHandle, nl_recvmsgs_default);
resolve(libnlHandle, nl_send_sync);
resolve(libnlHandle, nl_socket_alloc);
resolve(libnlHandle, nl_socket_free);
resolve(libnlHandle, nl_socket_modify_cb);
resolve(libnlHandle, nla_data);
resolve(libnlHandle, nla_next);
resolve(libnlHandle, nla_put_u32);
resolve(libnlHandle, nlmsg_alloc);
resolve(libnlHandle, nlmsg_free);
resolve(libnlHandle, nlmsg_hdr);
resolve(libnlGenlHandle, genl_ctrl_resolve);
resolve(libnlGenlHandle, genlmsg_parse);
resolve(libnlGenlHandle, genlmsg_put);
#undef resolve
return 0;
dlfailure:
unload_libnl();
return -1;
}function: unload_libnl
static void unload_libnl(void) {
sym_nl_close = NULL;
sym_nl_connect = NULL;
sym_nl_recvmsgs_default = NULL;
sym_nl_send_sync = NULL;
sym_nl_socket_alloc = NULL;
sym_nl_socket_free = NULL;
sym_nl_socket_modify_cb = NULL;
sym_nla_data = NULL;
sym_nla_next = NULL;
sym_nla_put_u32 = NULL;
sym_nlmsg_alloc = NULL;
sym_nlmsg_free = NULL;
sym_nlmsg_hdr = NULL;
sym_genl_ctrl_resolve = NULL;
sym_genlmsg_parse = NULL;
sym_genlmsg_put = NULL;
if (libnlGenlHandle) {
dlclose(libnlGenlHandle);
libnlGenlHandle = NULL;
}
if (libnlHandle) {
dlclose(libnlHandle);
libnlHandle = NULL;
}
}LibNl.h
linux/LibNl.h
function: LibNl_destroyNetlinkSocket
void LibNl_destroyNetlinkSocket(LinuxProcessTable* this);
function: LibNl_readDelayAcctData
void LibNl_readDelayAcctData(LinuxProcessTable* this, LinuxProcess* process);
LibSensors.c
linux/LibSensors.c
function: LibSensors_cleanup
void LibSensors_cleanup(void) {
#ifdef BUILD_STATIC
sym_sensors_cleanup();
#else
if (dlopenHandle) {
sym_sensors_cleanup();
dlclose(dlopenHandle);
dlopenHandle = NULL;
}
#endif /* BUILD_STATIC */
}function: LibSensors_countCCDs
int LibSensors_countCCDs(void) {
#ifndef BUILD_STATIC
if (!dlopenHandle)
return 0;
#endif /* !BUILD_STATIC */
int ccds = 0;
int n = 0;
for (const sensors_chip_name* chip = sym_sensors_get_detected_chips(NULL, &n); chip; chip = sym_sensors_get_detected_chips(NULL, &n)) {
int m = 0;
for (const sensors_feature* feature = sym_sensors_get_features(chip, &m); feature; feature = sym_sensors_get_features(chip, &m)) {
if (feature->type != SENSORS_FEATURE_TEMP)
continue;
if (!feature->name || !String_startsWith(feature->name, "temp"))
continue;
char *label = sym_sensors_get_label(chip, feature);
if (label) {
if (String_startsWith(label, "Tccd")) {
ccds++;
}
free(label);
}
}
}
return ccds;
}function: LibSensors_getCPUTemperatures
function: LibSensors_init
int LibSensors_init(void) {
#ifdef BUILD_STATIC
return sym_sensors_init(NULL);
#else
if (!dlopenHandle) {
/* Find the unversioned libsensors.so (symlink) and prefer that, but Debian has .so.5 and Fedora .so.4 without
matching symlinks (unless people install the -dev packages) */
dlopenHandle = dlopen("libsensors.so", RTLD_LAZY);
if (!dlopenHandle)
dlopenHandle = dlopen("libsensors.so.5", RTLD_LAZY);
if (!dlopenHandle)
dlopenHandle = dlopen("libsensors.so.4", RTLD_LAZY);
if (!dlopenHandle)
goto dlfailure;
/* Clear any errors */
dlerror();
#define resolve(symbolname) do { \
*(void **)(&sym_##symbolname) = dlsym(dlopenHandle, #symbolname); \
if (!sym_##symbolname || dlerror() != NULL) \
goto dlfailure; \
} while(0)
resolve(sensors_init);
resolve(sensors_cleanup);
resolve(sensors_get_detected_chips);
resolve(sensors_get_features);
resolve(sensors_get_subfeature);
resolve(sensors_get_value);
resolve(sensors_get_label);
#undef resolve
}
return sym_sensors_init(NULL);
dlfailure:
if (dlopenHandle) {
dlclose(dlopenHandle);
dlopenHandle = NULL;
}
return -1;
#endif /* BUILD_STATIC */
}function: LibSensors_reload
int LibSensors_reload(void) {
#ifndef BUILD_STATIC
if (!dlopenHandle) {
errno = ENOTSUP;
return -1;
}
#endif /* !BUILD_STATIC */
sym_sensors_cleanup();
return sym_sensors_init(NULL);
}function: tempDriverPriority
static int tempDriverPriority(const sensors_chip_name* chip) {
static const struct TempDriverDefs {
const char* prefix;
int priority;
} tempDrivers[] = {
{ "coretemp", 0 },
{ "via_cputemp", 0 },
{ "cpu_thermal", 0 },
{ "k10temp", 0 },
{ "zenpower", 0 },
/* Rockchip RK3588 */
{ "littlecore_thermal", 0 },
{ "bigcore0_thermal", 0 },
{ "bigcore1_thermal", 0 },
{ "bigcore2_thermal", 0 },
/* Rockchip RK3566 */
{ "soc_thermal", 0 },
/* Snapdragon 8cx */
{ "cpu0_thermal", 0 },
{ "cpu1_thermal", 0 },
{ "cpu2_thermal", 0 },
{ "cpu3_thermal", 0 },
{ "cpu4_thermal", 0 },
{ "cpu5_thermal", 0 },
{ "cpu6_thermal", 0 },
{ "cpu7_thermal", 0 },
/* Low priority drivers */
{ "acpitz", 1 },
};
for (size_t i = 0; i < ARRAYSIZE(tempDrivers); i++)
if (String_eq(chip->prefix, tempDrivers[i].prefix))
return tempDrivers[i].priority;
return -1;
}LibSensors.h
linux/LibSensors.h
function: LibSensors_cleanup
void LibSensors_cleanup(void);
function: LibSensors_countCCDs
int LibSensors_countCCDs(void);
function: LibSensors_getCPUTemperatures
void LibSensors_getCPUTemperatures(CPUData* cpus, unsigned int existingCPUs, unsigned int activeCPUs);
function: LibSensors_init
int LibSensors_init(void);
function: LibSensors_reload
int LibSensors_reload(void);
LinuxMachine.c
linux/LinuxMachine.c
file: LinuxMachine.c
LinuxMachine.h
linux/LinuxMachine.h
macro: HTOP_HUGEPAGE_BASE_SHIFT
#define HTOP_HUGEPAGE_BASE_SHIFT 16
macro: HTOP_HUGEPAGE_COUNT
#define HTOP_HUGEPAGE_COUNT 24
macro: PROC_LINE_LENGTH
#define PROC_LINE_LENGTH 4096
macro: PROCARCSTATSFILE
#define PROCARCSTATSFILE PROCDIR "/spl/kstat/zfs/arcstats"
macro: PROCCPUINFOFILE
#define PROCCPUINFOFILE PROCDIR "/cpuinfo"
macro: PROCDIR
#define PROCDIR "/proc"
macro: PROCMEMINFOFILE
#define PROCMEMINFOFILE PROCDIR "/meminfo"
macro: PROCSTATFILE
#define PROCSTATFILE PROCDIR "/stat"
macro: PROCTTYDRIVERSFILE
#define PROCTTYDRIVERSFILE PROCDIR "/tty/drivers"
struct: CPUData
typedef struct CPUData_ {
unsigned long long int totalTime;
unsigned long long int userTime;
unsigned long long int systemTime;
unsigned long long int systemAllTime;
unsigned long long int idleAllTime;
unsigned long long int idleTime;
unsigned long long int niceTime;
unsigned long long int ioWaitTime;
unsigned long long int irqTime;
unsigned long long int softIrqTime;
unsigned long long int stealTime;
unsigned long long int guestTime;
unsigned long long int totalPeriod;
unsigned long long int userPeriod;
unsigned long long int systemPeriod;
unsigned long long int systemAllPeriod;
unsigned long long int idleAllPeriod;
unsigned long long int idlePeriod;
unsigned long long int nicePeriod;
unsigned long long int ioWaitPeriod;
unsigned long long int irqPeriod;
unsigned long long int softIrqPeriod;
unsigned long long int stealPeriod;
unsigned long long int guestPeriod;
double frequency;
#ifdef HAVE_SENSORS_SENSORS_H
double temperature;
int physicalID; /* different for each CPU socket */
int coreID; /* same for hyperthreading */
int ccdID; /* same for each AMD chiplet */
#endif
bool online;
} CPUData;struct: GPUEngineData
typedef struct GPUEngineData_ {
unsigned long long int prevTime, curTime; /* absolute GPU time in nano seconds */
char* key; /* engine name */
struct GPUEngineData_* next;
} GPUEngineData;struct: LinuxMachine
typedef struct LinuxMachine_ {
Machine super;
long jiffies;
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;
#ifdef HAVE_SENSORS_SENSORS_H
int maxPhysicalID;
int maxCoreID;
#endif
memory_t totalHugePageMem;
memory_t usedHugePageMem[HTOP_HUGEPAGE_COUNT];
memory_t availableMem;
unsigned long long int prevGpuTime, curGpuTime; /* total absolute GPU time in nano seconds */
GPUEngineData* gpuEngineData;
ZfsArcStats zfs;
ZramStats zram;
ZswapStats zswap;
} LinuxMachine;LinuxProcess.c
linux/LinuxProcess.c
function: LinuxProcess_changeAutogroupPriorityBy
static bool LinuxProcess_changeAutogroupPriorityBy(Process* p, Arg delta) {
char buffer[256];
pid_t pid = Process_getPid(p);
xSnprintf(buffer, sizeof(buffer), PROCDIR "/%d/autogroup", pid);
FILE* file = fopen(buffer, "r+");
if (!file)
return false;
long int identity;
int nice;
int ok = fscanf(file, "/autogroup-%ld nice %d", &identity, &nice);
bool success = false;
if (ok == 2 && fseek(file, 0L, SEEK_SET) == 0) {
xSnprintf(buffer, sizeof(buffer), "%d", nice + delta.i);
success = fputs(buffer, file) > 0;
}
fclose(file);
return success;
}function: LinuxProcess_compareByKey
function: LinuxProcess_effectiveIOPriority
static int LinuxProcess_effectiveIOPriority(const LinuxProcess* this) {
if (IOPriority_class(this->ioPriority) == IOPRIO_CLASS_NONE) {
return IOPriority_tuple(IOPRIO_CLASS_BE, (this->super.nice + 20) / 5);
}
return this->ioPriority;
}function: LinuxProcess_isAutogroupEnabled
bool LinuxProcess_isAutogroupEnabled(void) {
char buf[16];
if (xReadfile(PROCDIR "/sys/kernel/sched_autogroup_enabled", buf, sizeof(buf)) < 0)
return false;
return buf[0] == '1';
}function: LinuxProcess_new
Process* LinuxProcess_new(const Machine* host) {
LinuxProcess* this = xCalloc(1, sizeof(LinuxProcess));
Object_setClass(this, Class(LinuxProcess));
Process_init(&this->super, host);
return (Process*)this;
}function: LinuxProcess_rowChangeAutogroupPriorityBy
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);
}function: LinuxProcess_rowSetIOPriority
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);
}function: LinuxProcess_rowWriteField
function: LinuxProcess_setIOPriority
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, Process_getPid(p), ioprio.i);
#endif
return LinuxProcess_updateIOPriority(p) == ioprio.i;
}function: LinuxProcess_totalIORate
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;
}function: LinuxProcess_updateIOPriority
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, Process_getPid(p));
#endif
LinuxProcess* this = (LinuxProcess*) p;
this->ioPriority = ioprio;
return ioprio;
}function: Process_delete
void Process_delete(Object* cast) {
LinuxProcess* this = (LinuxProcess*) cast;
Process_done((Process*)cast);
free(this->container_short);
free(this->cgroup_short);
free(this->cgroup);
#ifdef HAVE_OPENVZ
free(this->ctid);
#endif
free(this->secattr);
free(this);
}global constant: Process_fields
struct: LinuxProcess_class
const ProcessClass LinuxProcess_class = {
.super = {
.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
},
.compareByKey = LinuxProcess_compareByKey
};LinuxProcess.h
linux/LinuxProcess.h
function: LinuxProcess_isAutogroupEnabled
bool LinuxProcess_isAutogroupEnabled(void);
function: LinuxProcess_new
Process* LinuxProcess_new(const Machine* host);
function: Process_delete
void Process_delete(Object* cast);
method: LinuxProcess_rowChangeAutogroupPriorityBy
bool LinuxProcess_rowChangeAutogroupPriorityBy(Row* super, Arg delta);
method: LinuxProcess_rowSetIOPriority
bool LinuxProcess_rowSetIOPriority(Row* super, Arg ioprio);
method: LinuxProcess_updateIOPriority
IOPriority LinuxProcess_updateIOPriority(Process* proc);
method: Process_isThread
bool Process_isThread(const Process* this);
struct: LinuxProcess
LinuxProcessTable.c
linux/LinuxProcessTable.c
file: LinuxProcessTable.c
LinuxProcessTable.h
linux/LinuxProcessTable.h
struct: LinuxProcessTable
typedef struct LinuxProcessTable_ {
ProcessTable super;
TtyDriver* ttyDrivers;
bool haveSmapsRollup;
bool haveAutogroup;
#ifdef HAVE_DELAYACCT
struct nl_sock* netlink_socket;
int netlink_family;
#endif
} LinuxProcessTable;struct: TtyDriver
typedef struct TtyDriver_ {
char* path;
unsigned int major;
unsigned int minorFrom;
unsigned int minorTo;
} TtyDriver;Platform.c
linux/Platform.c
file: Platform.c
Platform.h
linux/Platform.h
function: Platform_addDynamicScreen
static inline void Platform_addDynamicScreen(ATTR_UNUSED ScreenSettings* ss) { }function: Platform_addDynamicScreenAvailableColumns
static inline void Platform_addDynamicScreenAvailableColumns(ATTR_UNUSED Panel* availableColumns, ATTR_UNUSED const char* screen) { }function: Platform_defaultDynamicScreens
static inline void Platform_defaultDynamicScreens(ATTR_UNUSED Settings* settings) { }function: Platform_done
void Platform_done(void);
function: Platform_dynamicColumnName
static inline const char* Platform_dynamicColumnName(ATTR_UNUSED unsigned int key) {
return NULL;
}function: Platform_dynamicColumns
static inline Hashtable* Platform_dynamicColumns(void) {
return NULL;
}function: Platform_dynamicColumnsDone
static inline void Platform_dynamicColumnsDone(ATTR_UNUSED Hashtable* table) { }function: Platform_dynamicColumnWriteField
static inline bool Platform_dynamicColumnWriteField(ATTR_UNUSED const Process* proc, ATTR_UNUSED RichString* str, ATTR_UNUSED unsigned int key) {
return false;
}function: Platform_dynamicMeterDisplay
static inline void Platform_dynamicMeterDisplay(ATTR_UNUSED const Meter* meter, ATTR_UNUSED RichString* out) { }function: Platform_dynamicMeterInit
static inline void Platform_dynamicMeterInit(ATTR_UNUSED Meter* meter) { }function: Platform_dynamicMeters
static inline Hashtable* Platform_dynamicMeters(void) {
return NULL;
}function: Platform_dynamicMetersDone
static inline void Platform_dynamicMetersDone(ATTR_UNUSED Hashtable* table) { }function: Platform_dynamicMeterUpdateValues
static inline void Platform_dynamicMeterUpdateValues(ATTR_UNUSED Meter* meter) { }function: Platform_dynamicScreens
static inline Hashtable* Platform_dynamicScreens(void) {
return NULL;
}function: Platform_dynamicScreensDone
static inline void Platform_dynamicScreensDone(ATTR_UNUSED Hashtable* screens) { }function: Platform_getBattery
void Platform_getBattery(double* percent, ACPresence* isOnAC);
function: Platform_getDiskIO
bool Platform_getDiskIO(DiskIOData* data);
function: Platform_getFileDescriptors
void Platform_getFileDescriptors(double* used, double* max);
function: Platform_getHostname
static inline void Platform_getHostname(char* buffer, size_t size) {
Generic_hostname(buffer, size);
}function: Platform_getLoadAverage
void Platform_getLoadAverage(double* one, double* five, double* fifteen);
function: Platform_getLongOption
CommandLineStatus Platform_getLongOption(int opt, int argc, char** argv);
function: Platform_getMaxPid
pid_t Platform_getMaxPid(void);
function: Platform_getNetworkIO
bool Platform_getNetworkIO(NetworkIOData* data);
function: Platform_getPressureStall
void Platform_getPressureStall(const char* file, bool some, double* ten, double* sixty, double* threehundred);
function: Platform_getProcessEnv
char* Platform_getProcessEnv(pid_t pid);
function: Platform_getProcessLocks
FileLocks_ProcessData* Platform_getProcessLocks(pid_t pid);
function: Platform_getRelease
static inline void Platform_getRelease(char** string) {
*string = Generic_uname();
}function: Platform_gettime_monotonic
static inline void Platform_gettime_monotonic(uint64_t* msec) {
Generic_gettime_monotonic(msec);
}function: Platform_gettime_realtime
static inline void Platform_gettime_realtime(struct timeval* tv, uint64_t* msec) {
Generic_gettime_realtime(tv, msec);
}function: Platform_getUptime
int Platform_getUptime(void);
function: Platform_init
bool Platform_init(void);
function: Platform_longOptionsUsage
void Platform_longOptionsUsage(const char* name);
function: Platform_setBindings
void Platform_setBindings(Htop_Action* keys);
function: Platform_setCPUValues
double Platform_setCPUValues(Meter* this, unsigned int cpu);
function: Platform_setMemoryValues
void Platform_setMemoryValues(Meter* this);
function: Platform_setSwapValues
void Platform_setSwapValues(Meter* this);
function: Platform_setZfsArcValues
void Platform_setZfsArcValues(Meter* this);
function: Platform_setZfsCompressedArcValues
void Platform_setZfsCompressedArcValues(Meter* this);
function: Platform_setZramValues
void Platform_setZramValues(Meter* this);
global variable: Platform_defaultScreens
extern const ScreenDefaults Platform_defaultScreens[];
global variable: Platform_meterTypes
extern const MeterClass* const Platform_meterTypes[];
global variable: Platform_numberOfDefaultScreens
extern const unsigned int Platform_numberOfDefaultScreens;
global variable: Platform_numberOfSignals
extern const unsigned int Platform_numberOfSignals;
global variable: Platform_signals
extern const SignalItem Platform_signals[];
global variable: Running_containerized
extern bool Running_containerized;
macro: PATH_MAX
#ifndef PATH_MAX #define PATH_MAX 4096 #endif
macro: PLATFORM_LONG_OPTIONS
#ifdef HAVE_LIBCAP
#define PLATFORM_LONG_OPTIONS \
{"drop-capabilities", optional_argument, 0, 160},
#else
#define PLATFORM_LONG_OPTIONS
#endifPressureStallMeter.c
linux/PressureStallMeter.c
function: PressureStallMeter_display
static void PressureStallMeter_display(const Object* cast, RichString* out) {
const Meter* this = (const Meter*)cast;
char buffer[20];
int len;
len = xSnprintf(buffer, sizeof(buffer), "%5.2lf%% ", this->values[0]);
RichString_appendnAscii(out, CRT_colors[PRESSURE_STALL_TEN], buffer, len);
len = xSnprintf(buffer, sizeof(buffer), "%5.2lf%% ", this->values[1]);
RichString_appendnAscii(out, CRT_colors[PRESSURE_STALL_SIXTY], buffer, len);
len = xSnprintf(buffer, sizeof(buffer), "%5.2lf%% ", this->values[2]);
RichString_appendnAscii(out, CRT_colors[PRESSURE_STALL_THREEHUNDRED], buffer, len);
}function: PressureStallMeter_updateValues
static void PressureStallMeter_updateValues(Meter* this) {
const char* file;
if (strstr(Meter_name(this), "CPU")) {
file = "cpu";
} else if (strstr(Meter_name(this), "IO")) {
file = "io";
} else if (strstr(Meter_name(this), "IRQ")) {
file = "irq";
} else {
file = "memory";
}
bool some;
if (strstr(Meter_name(this), "Some")) {
some = true;
} else {
some = false;
}
Platform_getPressureStall(file, some, &this->values[0], &this->values[1], &this->values[2]);
/* only print bar for ten (not sixty and threehundred), cause the sum is meaningless */
this->curItems = 1;
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "%s %s %5.2lf%% %5.2lf%% %5.2lf%%", some ? "some" : "full", file, this->values[0], this->values[1], this->values[2]);
}global variable: PressureStallMeter_attributes
static const int PressureStallMeter_attributes[] = {
PRESSURE_STALL_TEN,
PRESSURE_STALL_SIXTY,
PRESSURE_STALL_THREEHUNDRED
};struct: PressureStallCPUSomeMeter_class
const MeterClass PressureStallCPUSomeMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = PressureStallMeter_display,
},
.updateValues = PressureStallMeter_updateValues,
.defaultMode = TEXT_METERMODE,
.supportedModes = METERMODE_DEFAULT_SUPPORTED,
.maxItems = 3,
.total = 100.0,
.attributes = PressureStallMeter_attributes,
.name = "PressureStallCPUSome",
.uiName = "PSI some CPU",
.caption = "PSI some CPU: ",
.description = "Pressure Stall Information, some cpu"
};struct: PressureStallIOFullMeter_class
const MeterClass PressureStallIOFullMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = PressureStallMeter_display,
},
.updateValues = PressureStallMeter_updateValues,
.defaultMode = TEXT_METERMODE,
.supportedModes = METERMODE_DEFAULT_SUPPORTED,
.maxItems = 3,
.total = 100.0,
.attributes = PressureStallMeter_attributes,
.name = "PressureStallIOFull",
.uiName = "PSI full IO",
.caption = "PSI full IO: ",
.description = "Pressure Stall Information, full io"
};struct: PressureStallIOSomeMeter_class
const MeterClass PressureStallIOSomeMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = PressureStallMeter_display,
},
.updateValues = PressureStallMeter_updateValues,
.defaultMode = TEXT_METERMODE,
.supportedModes = METERMODE_DEFAULT_SUPPORTED,
.maxItems = 3,
.total = 100.0,
.attributes = PressureStallMeter_attributes,
.name = "PressureStallIOSome",
.uiName = "PSI some IO",
.caption = "PSI some IO: ",
.description = "Pressure Stall Information, some io"
};struct: PressureStallIRQFullMeter_class
const MeterClass PressureStallIRQFullMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = PressureStallMeter_display,
},
.updateValues = PressureStallMeter_updateValues,
.defaultMode = TEXT_METERMODE,
.supportedModes = METERMODE_DEFAULT_SUPPORTED,
.maxItems = 3,
.total = 100.0,
.attributes = PressureStallMeter_attributes,
.name = "PressureStallIRQFull",
.uiName = "PSI full IRQ",
.caption = "PSI full IRQ: ",
.description = "Pressure Stall Information, full irq"
};struct: PressureStallMemoryFullMeter_class
const MeterClass PressureStallMemoryFullMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = PressureStallMeter_display,
},
.updateValues = PressureStallMeter_updateValues,
.defaultMode = TEXT_METERMODE,
.supportedModes = METERMODE_DEFAULT_SUPPORTED,
.maxItems = 3,
.total = 100.0,
.attributes = PressureStallMeter_attributes,
.name = "PressureStallMemoryFull",
.uiName = "PSI full memory",
.caption = "PSI full memory: ",
.description = "Pressure Stall Information, full memory"
};struct: PressureStallMemorySomeMeter_class
const MeterClass PressureStallMemorySomeMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = PressureStallMeter_display,
},
.updateValues = PressureStallMeter_updateValues,
.defaultMode = TEXT_METERMODE,
.supportedModes = METERMODE_DEFAULT_SUPPORTED,
.maxItems = 3,
.total = 100.0,
.attributes = PressureStallMeter_attributes,
.name = "PressureStallMemorySome",
.uiName = "PSI some memory",
.caption = "PSI some memory: ",
.description = "Pressure Stall Information, some memory"
};PressureStallMeter.h
linux/PressureStallMeter.h
struct: PressureStallCPUSomeMeter_class
extern const MeterClass PressureStallCPUSomeMeter_class;
struct: PressureStallIOFullMeter_class
extern const MeterClass PressureStallIOFullMeter_class;
struct: PressureStallIOSomeMeter_class
extern const MeterClass PressureStallIOSomeMeter_class;
struct: PressureStallIRQFullMeter_class
extern const MeterClass PressureStallIRQFullMeter_class;
struct: PressureStallMemoryFullMeter_class
extern const MeterClass PressureStallMemoryFullMeter_class;
struct: PressureStallMemorySomeMeter_class
extern const MeterClass PressureStallMemorySomeMeter_class;
ProcessField.h
linux/ProcessField.h
macro: PLATFORM_PROCESS_FIELDS
#define PLATFORM_PROCESS_FIELDS \ CMINFLT = 11, \ CMAJFLT = 13, \ UTIME = 14, \ STIME = 15, \ CUTIME = 16, \ CSTIME = 17, \ M_SHARE = 41, \ M_TRS = 42, \ M_DRS = 43, \ M_LRS = 44, \ CTID = 100, \ VPID = 101, \ VXID = 102, \ RCHAR = 103, \ WCHAR = 104, \ SYSCR = 105, \ SYSCW = 106, \ RBYTES = 107, \ WBYTES = 108, \ CNCLWB = 109, \ IO_READ_RATE = 110, \ IO_WRITE_RATE = 111, \ IO_RATE = 112, \ CGROUP = 113, \ OOM = 114, \ IO_PRIORITY = 115, \ PERCENT_CPU_DELAY = 116, \ PERCENT_IO_DELAY = 117, \ PERCENT_SWAP_DELAY = 118, \ M_PSS = 119, \ M_SWAP = 120, \ M_PSSWP = 121, \ CTXT = 122, \ SECATTR = 123, \ AUTOGROUP_ID = 127, \ AUTOGROUP_NICE = 128, \ CCGROUP = 129, \ CONTAINER = 130, \ M_PRIV = 131, \ GPU_TIME = 132, \ GPU_PERCENT = 133, \ ISCONTAINER = 134, \ // End of list
SELinuxMeter.c
linux/SELinuxMeter.c
function: hasSELinuxMount
static bool hasSELinuxMount(void) {
struct statfs sfbuf;
int r = statfs("/sys/fs/selinux", &sfbuf);
if (r != 0) {
return false;
}
if ((uint32_t)sfbuf.f_type != /* SELINUX_MAGIC */ 0xf97cff8cU) {
return false;
}
struct statvfs vfsbuf;
r = statvfs("/sys/fs/selinux", &vfsbuf);
if (r != 0 || (vfsbuf.f_flag & ST_RDONLY)) {
return false;
}
return true;
}function: isSelinuxEnabled
static bool isSelinuxEnabled(void) {
return hasSELinuxMount() && (0 == access("/etc/selinux/config", F_OK));
}function: isSelinuxEnforcing
static bool isSelinuxEnforcing(void) {
if (!enabled) {
return false;
}
char buf[20];
ssize_t r = xReadfile("/sys/fs/selinux/enforce", buf, sizeof(buf));
if (r < 0)
return false;
int enforce = 0;
if (sscanf(buf, "%d", &enforce) != 1) {
return false;
}
return !!enforce;
}function: SELinuxMeter_updateValues
static void SELinuxMeter_updateValues(Meter* this) {
enabled = isSelinuxEnabled();
enforcing = isSelinuxEnforcing();
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "%s%s", enabled ? "enabled" : "disabled", enabled ? (enforcing ? "; mode: enforcing" : "; mode: permissive") : "");
}struct: SELinuxMeter_class
const MeterClass SELinuxMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
},
.updateValues = SELinuxMeter_updateValues,
.defaultMode = TEXT_METERMODE,
.supportedModes = (1 << TEXT_METERMODE),
.maxItems = 0,
.total = 0.0,
.attributes = SELinuxMeter_attributes,
.name = "SELinux",
.uiName = "SELinux",
.description = "SELinux state overview",
.caption = "SELinux: "
};variable: enabled
static bool enabled = false;
variable: enforcing
static bool enforcing = false;
variable: SELinuxMeter_attributes
static const int SELinuxMeter_attributes[] = {
METER_TEXT,
};SELinuxMeter.h
linux/SELinuxMeter.h
variable: SELinuxMeter_class
extern const MeterClass SELinuxMeter_class;
SystemdMeter.c
linux/SystemdMeter.c
function: _SystemdMeter_display
static void _SystemdMeter_display(ATTR_UNUSED const Object* cast, RichString* out, SystemdMeterContext_t* ctx) {
char buffer[16];
int len;
int color = METER_VALUE_ERROR;
if (ctx->systemState) {
color = String_eq(ctx->systemState, "running") ? METER_VALUE_OK :
String_eq(ctx->systemState, "degraded") ? METER_VALUE_ERROR : METER_VALUE_WARN;
}
RichString_writeAscii(out, CRT_colors[color], ctx->systemState ? ctx->systemState : "N/A");
RichString_appendAscii(out, CRT_colors[METER_TEXT], " (");
if (ctx->nFailedUnits == INVALID_VALUE) {
buffer[0] = '?';
buffer[1] = '\0';
len = 1;
} else {
len = xSnprintf(buffer, sizeof(buffer), "%u", ctx->nFailedUnits);
}
RichString_appendnAscii(out, zeroDigitColor(ctx->nFailedUnits), buffer, len);
RichString_appendAscii(out, CRT_colors[METER_TEXT], "/");
if (ctx->nNames == INVALID_VALUE) {
buffer[0] = '?';
buffer[1] = '\0';
len = 1;
} else {
len = xSnprintf(buffer, sizeof(buffer), "%u", ctx->nNames);
}
RichString_appendnAscii(out, valueDigitColor(ctx->nNames), buffer, len);
RichString_appendAscii(out, CRT_colors[METER_TEXT], " failed) (");
if (ctx->nJobs == INVALID_VALUE) {
buffer[0] = '?';
buffer[1] = '\0';
len = 1;
} else {
len = xSnprintf(buffer, sizeof(buffer), "%u", ctx->nJobs);
}
RichString_appendnAscii(out, zeroDigitColor(ctx->nJobs), buffer, len);
RichString_appendAscii(out, CRT_colors[METER_TEXT], "/");
if (ctx->nInstalledJobs == INVALID_VALUE) {
buffer[0] = '?';
buffer[1] = '\0';
len = 1;
} else {
len = xSnprintf(buffer, sizeof(buffer), "%u", ctx->nInstalledJobs);
}
RichString_appendnAscii(out, valueDigitColor(ctx->nInstalledJobs), buffer, len);
RichString_appendAscii(out, CRT_colors[METER_TEXT], " jobs)");
}function: SystemdMeter_display
static void SystemdMeter_display(ATTR_UNUSED const Object* cast, RichString* out) {
_SystemdMeter_display(cast, out, &ctx_system);
}function: SystemdMeter_done
static void SystemdMeter_done(ATTR_UNUSED Meter* this) {
SystemdMeterContext_t* ctx = String_eq(Meter_name(this), "SystemdUser") ? &ctx_user : &ctx_system;
free(ctx->systemState);
ctx->systemState = NULL;
#ifdef BUILD_STATIC
# ifdef HAVE_LIBSYSTEMD
if (ctx->bus) {
sym_sd_bus_unref(ctx->bus);
}
ctx->bus = NULL;
# endif /* HAVE_LIBSYSTEMD */
#else /* BUILD_STATIC */
if (ctx->bus && dlopenHandle) {
sym_sd_bus_unref(ctx->bus);
}
ctx->bus = NULL;
if (!ctx_system.systemState && !ctx_user.systemState && dlopenHandle) {
dlclose(dlopenHandle);
dlopenHandle = NULL;
}
#endif /* BUILD_STATIC */
}function: SystemdMeter_updateValues
static void SystemdMeter_updateValues(Meter* this) {
bool user = String_eq(Meter_name(this), "SystemdUser");
SystemdMeterContext_t* ctx = user ? &ctx_user : &ctx_system;
free(ctx->systemState);
ctx->systemState = NULL;
ctx->nFailedUnits = ctx->nInstalledJobs = ctx->nNames = ctx->nJobs = INVALID_VALUE;
#if !defined(BUILD_STATIC) || defined(HAVE_LIBSYSTEMD)
if (updateViaLib(user) < 0)
updateViaExec(user);
#else
updateViaExec(user);
#endif /* !BUILD_STATIC || HAVE_LIBSYSTEMD */
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "%s", ctx->systemState ? ctx->systemState : "???");
}function: SystemdUserMeter_display
static void SystemdUserMeter_display(ATTR_UNUSED const Object* cast, RichString* out) {
_SystemdMeter_display(cast, out, &ctx_user);
}function: updateViaExec
function: updateViaLib
function: valueDigitColor
static int valueDigitColor(unsigned int value) {
switch (value) {
case 0:
return CRT_colors[METER_VALUE_NOTICE];
case INVALID_VALUE:
return CRT_colors[METER_VALUE_ERROR];
default:
return CRT_colors[METER_VALUE];
}
}function: zeroDigitColor
static int zeroDigitColor(unsigned int value) {
switch (value) {
case 0:
return CRT_colors[METER_VALUE];
case INVALID_VALUE:
return CRT_colors[METER_VALUE_ERROR];
default:
return CRT_colors[METER_VALUE_NOTICE];
}
}global variable: ctx_system
static SystemdMeterContext_t ctx_system;
global variable: ctx_user
static SystemdMeterContext_t ctx_user;
global variable: dlopenHandle
#ifndef BUILD_STATIC static void* dlopenHandle = NULL; #endif
global variable: sym_sd_bus_get_property_string
#ifndef BUILD_STATIC static int (*sym_sd_bus_get_property_string)(sd_bus*, const char*, const char*, const char*, const char*, sd_bus_error*, char**); #endif
global variable: sym_sd_bus_get_property_trivial
#ifndef BUILD_STATIC static int (*sym_sd_bus_get_property_trivial)(sd_bus*, const char*, const char*, const char*, const char*, sd_bus_error*, char, void*); #endif
global variable: sym_sd_bus_open_system
#ifndef BUILD_STATIC typedef void sd_bus; typedef void sd_bus_error; static int (*sym_sd_bus_open_system)(sd_bus**); #endif
global variable: sym_sd_bus_open_user
#ifndef BUILD_STATIC static int (*sym_sd_bus_open_user)(sd_bus**); #endif
global variable: sym_sd_bus_unref
#ifndef BUILD_STATIC static sd_bus* (*sym_sd_bus_unref)(sd_bus*); #endif
global variable: SystemdMeter_attributes
static const int SystemdMeter_attributes[] = {
METER_VALUE
};global variable: SystemdMeter_class
const MeterClass SystemdMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = SystemdMeter_display
},
.updateValues = SystemdMeter_updateValues,
.done = SystemdMeter_done,
.defaultMode = TEXT_METERMODE,
.supportedModes = (1 << TEXT_METERMODE),
.maxItems = 0,
.total = 0.0,
.attributes = SystemdMeter_attributes,
.name = "Systemd",
.uiName = "Systemd state",
.description = "Systemd system state and unit overview",
.caption = "Systemd: ",
};global variable: SystemdUserMeter_class
const MeterClass SystemdUserMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = SystemdUserMeter_display
},
.updateValues = SystemdMeter_updateValues,
.done = SystemdMeter_done,
.defaultMode = TEXT_METERMODE,
.supportedModes = (1 << TEXT_METERMODE),
.maxItems = 0,
.total = 0.0,
.attributes = SystemdMeter_attributes,
.name = "SystemdUser",
.uiName = "Systemd user state",
.description = "Systemd user state and unit overview",
.caption = "Systemd User: ",
};struct: SystemdMeterContext
typedef struct SystemdMeterContext {
#if !defined(BUILD_STATIC) || defined(HAVE_LIBSYSTEMD)
sd_bus* bus;
#endif /* !BUILD_STATIC || HAVE_LIBSYSTEMD */
char* systemState;
unsigned int nFailedUnits;
unsigned int nInstalledJobs;
unsigned int nNames;
unsigned int nJobs;
} SystemdMeterContext_t;SystemdMeter.h
linux/SystemdMeter.h
class: SystemdMeter_class
extern const MeterClass SystemdMeter_class;
class: SystemdUserMeter_class
extern const MeterClass SystemdUserMeter_class;
ZramMeter.c
linux/ZramMeter.c
const struct MeterClass: ZramMeter_class
const MeterClass ZramMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = ZramMeter_display,
},
.updateValues = ZramMeter_updateValues,
.defaultMode = BAR_METERMODE,
.supportedModes = METERMODE_DEFAULT_SUPPORTED,
.maxItems = ZRAM_METER_ITEMCOUNT,
.total = 100.0,
.attributes = ZramMeter_attributes,
.name = "Zram",
.uiName = "Zram",
.caption = "zrm"
};static array: ZramMeter_attributes
static const int ZramMeter_attributes[ZRAM_METER_ITEMCOUNT] = {
[ZRAM_METER_COMPRESSED] = ZRAM_COMPRESSED,
[ZRAM_METER_UNCOMPRESSED] = ZRAM_UNCOMPRESSED,
};static function: ZramMeter_display
static void ZramMeter_display(const Object* cast, RichString* out) {
char buffer[50];
const Meter* this = (const Meter*)cast;
RichString_writeAscii(out, CRT_colors[METER_TEXT], ":");
Meter_humanUnit(buffer, this->total, sizeof(buffer));
RichString_appendAscii(out, CRT_colors[METER_VALUE], buffer);
Meter_humanUnit(buffer, this->values[ZRAM_METER_COMPRESSED], sizeof(buffer));
RichString_appendAscii(out, CRT_colors[METER_TEXT], " used:");
RichString_appendAscii(out, CRT_colors[METER_VALUE], 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);
}static function: ZramMeter_updateValues
static void ZramMeter_updateValues(Meter* this) {
char* buffer = this->txtBuffer;
size_t size = sizeof(this->txtBuffer);
int written;
Platform_setZramValues(this);
written = Meter_humanUnit(buffer, this->values[ZRAM_METER_COMPRESSED], size);
METER_BUFFER_CHECK(buffer, size, written);
METER_BUFFER_APPEND_CHR(buffer, 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, ')');
METER_BUFFER_APPEND_CHR(buffer, size, '/');
Meter_humanUnit(buffer, this->total, size);
}ZramMeter.h
linux/ZramMeter.h
enum: ZramMeterValues
typedef enum {
ZRAM_METER_COMPRESSED = 0,
ZRAM_METER_UNCOMPRESSED = 1,
ZRAM_METER_ITEMCOUNT = 2, // number of entries in this enum
} ZramMeterValues;extern const MeterClass declaration: ZramMeter_class
extern const MeterClass ZramMeter_class;
ZramStats.h
linux/ZramStats.h
struct: ZramStats
typedef struct ZramStats_ {
memory_t totalZram;
memory_t usedZramComp;
memory_t usedZramOrig;
} ZramStats;ZswapStats.h
linux/ZswapStats.h
struct: ZswapStats
typedef struct ZswapStats_ {
/* amount of RAM used by the zswap pool */
memory_t usedZswapComp;
/* amount of data stored inside the zswap pool */
memory_t usedZswapOrig;
} ZswapStats;ListItem.c
ListItem.c
function: ListItem_append
void ListItem_append(ListItem* this, const char* text) {
size_t oldLen = strlen(this->value);
size_t textLen = strlen(text);
size_t newLen = oldLen + textLen;
this->value = xRealloc(this->value, newLen + 1);
memcpy(this->value + oldLen, text, textLen);
this->value[newLen] = '\0';
}function: ListItem_compare
int ListItem_compare(const void* cast1, const void* cast2) {
const ListItem* obj1 = (const ListItem*) cast1;
const ListItem* obj2 = (const ListItem*) cast2;
return strcmp(obj1->value, obj2->value);
}function: ListItem_delete
void ListItem_delete(Object* cast) {
ListItem* this = (ListItem*)cast;
free(this->value);
free(this);
}function: ListItem_display
void ListItem_display(const Object* cast, RichString* out) {
const ListItem* const this = (const ListItem*)cast;
assert (this != NULL);
if (this->moving) {
RichString_writeWide(out, CRT_colors[DEFAULT_COLOR],
#ifdef HAVE_LIBNCURSESW
CRT_utf8 ? "↕ " :
#endif
"+ ");
}
RichString_appendWide(out, CRT_colors[DEFAULT_COLOR], this->value);
}function: ListItem_init
void ListItem_init(ListItem* this, const char* value, int key) {
this->value = xStrdup(value);
this->key = key;
this->moving = false;
}function: ListItem_new
ListItem* ListItem_new(const char* value, int key) {
ListItem* this = AllocThis(ListItem);
ListItem_init(this, value, key);
return this;
}struct constant: ListItem_class
const ObjectClass ListItem_class = {
.display = ListItem_display,
.delete = ListItem_delete,
.compare = ListItem_compare
};ListItem.h
ListItem.h
class: ListItem_class
extern const ObjectClass ListItem_class;
function: ListItem_append
void ListItem_append(ListItem* this, const char* text);
function: ListItem_compare
int ListItem_compare(const void* cast1, const void* cast2);
function: ListItem_delete
void ListItem_delete(Object* cast);
function: ListItem_display
void ListItem_display(const Object* cast, RichString* out);
function: ListItem_getRef
static inline const char* ListItem_getRef(const ListItem* this) {
return this->value;
}function: ListItem_init
void ListItem_init(ListItem* this, const char* value, int key);
function: ListItem_new
ListItem* ListItem_new(const char* value, int key);
struct: ListItem
typedef struct ListItem_ {
Object super;
char* value;
int key;
bool moving;
} ListItem;LoadAverageMeter.c
LoadAverageMeter.c
function: LoadAverageMeter_display
static void LoadAverageMeter_display(const Object* cast, RichString* out) {
const Meter* this = (const Meter*)cast;
char buffer[20];
int len;
len = xSnprintf(buffer, sizeof(buffer), "%.2f ", this->values[0]);
RichString_appendnAscii(out, CRT_colors[LOAD_AVERAGE_ONE], buffer, len);
len = xSnprintf(buffer, sizeof(buffer), "%.2f ", this->values[1]);
RichString_appendnAscii(out, CRT_colors[LOAD_AVERAGE_FIVE], buffer, len);
len = xSnprintf(buffer, sizeof(buffer), "%.2f ", this->values[2]);
RichString_appendnAscii(out, CRT_colors[LOAD_AVERAGE_FIFTEEN], buffer, len);
}function: LoadAverageMeter_updateValues
static void LoadAverageMeter_updateValues(Meter* this) {
Platform_getLoadAverage(&this->values[0], &this->values[1], &this->values[2]);
// only show bar for 1min value
this->curItems = 1;
// change bar color and total based on value
if (this->values[0] < 1.0) {
this->curAttributes = OK_attributes;
this->total = 1.0;
} else if (this->values[0] < this->host->activeCPUs) {
this->curAttributes = Medium_attributes;
this->total = this->host->activeCPUs;
} else {
this->curAttributes = High_attributes;
this->total = 2 * this->host->activeCPUs;
}
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "%.2f/%.2f/%.2f", this->values[0], this->values[1], this->values[2]);
}function: LoadMeter_display
static void LoadMeter_display(const Object* cast, RichString* out) {
const Meter* this = (const Meter*)cast;
char buffer[20];
int len;
len = xSnprintf(buffer, sizeof(buffer), "%.2f ", this->values[0]);
RichString_appendnAscii(out, CRT_colors[LOAD], buffer, len);
}function: LoadMeter_updateValues
static void LoadMeter_updateValues(Meter* this) {
double five, fifteen;
Platform_getLoadAverage(&this->values[0], &five, &fifteen);
// change bar color and total based on value
if (this->values[0] < 1.0) {
this->curAttributes = OK_attributes;
this->total = 1.0;
} else if (this->values[0] < this->host->activeCPUs) {
this->curAttributes = Medium_attributes;
this->total = this->host->activeCPUs;
} else {
this->curAttributes = High_attributes;
this->total = 2 * this->host->activeCPUs;
}
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "%.2f", this->values[0]);
}global constant: High_attributes
static const int High_attributes[] = {
METER_VALUE_ERROR
};global constant: LoadAverageMeter_attributes
static const int LoadAverageMeter_attributes[] = {
LOAD_AVERAGE_ONE,
LOAD_AVERAGE_FIVE,
LOAD_AVERAGE_FIFTEEN
};global constant: LoadMeter_attributes
static const int LoadMeter_attributes[] = {
LOAD
};global constant: Medium_attributes
static const int Medium_attributes[] = {
METER_VALUE_WARN
};global constant: OK_attributes
static const int OK_attributes[] = {
METER_VALUE_OK
};struct constant (MeterClass): LoadAverageMeter_class
const MeterClass LoadAverageMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = LoadAverageMeter_display,
},
.updateValues = LoadAverageMeter_updateValues,
.defaultMode = TEXT_METERMODE,
.supportedModes = METERMODE_DEFAULT_SUPPORTED,
.maxItems = 3,
.total = 100.0,
.attributes = LoadAverageMeter_attributes,
.name = "LoadAverage",
.uiName = "Load average",
.description = "Load averages: 1 minute, 5 minutes, 15 minutes",
.caption = "Load average: "
};struct constant (MeterClass): LoadMeter_class
const MeterClass LoadMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = LoadMeter_display,
},
.updateValues = LoadMeter_updateValues,
.defaultMode = TEXT_METERMODE,
.supportedModes = METERMODE_DEFAULT_SUPPORTED,
.maxItems = 1,
.total = 100.0,
.attributes = LoadMeter_attributes,
.name = "Load",
.uiName = "Load",
.description = "Load: average of ready processes in the last minute",
.caption = "Load: "
};LoadAverageMeter.h
LoadAverageMeter.h
file: LoadAverageMeter.h
#ifndef HEADER_LoadAverageMeter #define HEADER_LoadAverageMeter /* htop - LoadAverageMeter.h (C) 2004-2011 Hisham H. Muhammad Released under the GNU GPLv2+, see the COPYING file in the source distribution for its full text. */ #include "Meter.h" extern const MeterClass LoadAverageMeter_class; extern const MeterClass LoadMeter_class; #endif
Machine.c
Machine.c
function: Machine_addTable
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++;
}function: Machine_done
void Machine_done(Machine* this) {
#ifdef HAVE_LIBHWLOC
if (this->topologyOk) {
hwloc_topology_destroy(this->topology);
}
#endif
Object_delete(this->processTable);
free(this->tables);
}function: Machine_init
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);
#ifdef HAVE_LIBHWLOC
this->topologyOk = false;
if (hwloc_topology_init(&this->topology) == 0) {
this->topologyOk =
#if HWLOC_API_VERSION < 0x00020000
/* try to ignore the top-level machine object type */
0 == hwloc_topology_ignore_type_keep_structure(this->topology, HWLOC_OBJ_MACHINE) &&
/* ignore caches, which don't add structure */
0 == hwloc_topology_ignore_type_keep_structure(this->topology, HWLOC_OBJ_CORE) &&
0 == hwloc_topology_ignore_type_keep_structure(this->topology, HWLOC_OBJ_CACHE) &&
0 == hwloc_topology_set_flags(this->topology, HWLOC_TOPOLOGY_FLAG_WHOLE_SYSTEM) &&
#else
0 == hwloc_topology_set_all_types_filter(this->topology, HWLOC_TYPE_FILTER_KEEP_STRUCTURE) &&
#endif
0 == hwloc_topology_load(this->topology);
}
#endif
}function: Machine_populateTablesFromSettings
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);
}
}function: Machine_scanTables
void Machine_scanTables(Machine* this) {
// set scan timestamp
static bool firstScanDone = false;
if (firstScanDone) {
this->prevMonotonicMs = this->monotonicMs;
Platform_gettime_monotonic(&this->monotonicMs);
} else {
this->prevMonotonicMs = 0;
this->monotonicMs = 1;
firstScanDone = true;
}
if (this->monotonicMs <= this->prevMonotonicMs) {
return;
}
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);
}function: Machine_setTablesPanel
void Machine_setTablesPanel(Machine* this, Panel* panel) {
for (size_t i = 0; i < this->tableCount; i++) {
Table_setPanel(this->tables[i], panel);
}
}Machine.h
Machine.h
function: Machine_delete
void Machine_delete(Machine* this);
function: Machine_done
void Machine_done(Machine* this);
function: Machine_init
void Machine_init(Machine* this, UsersTable* usersTable, uid_t userId);
function: Machine_isCPUonline
bool Machine_isCPUonline(const Machine* this, unsigned int id);
function: Machine_new
Machine* Machine_new(UsersTable* usersTable, uid_t userId);
function: Machine_populateTablesFromSettings
void Machine_populateTablesFromSettings(Machine* this, Settings* settings, Table* processTable);
function: Machine_scan
void Machine_scan(Machine* this);
function: Machine_scanTables
void Machine_scanTables(Machine* this);
function: Machine_setTablesPanel
void Machine_setTablesPanel(Machine* this, Panel* panel);
macro: MAX_NAME
#define MAX_NAME 128
macro: MAX_READ
#define MAX_READ 2048
macro: MEMORY_MAX
#define MEMORY_MAX ULLONG_MAX
struct: Machine
typedef struct Machine_ {
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 */
uint64_t prevMonotonicMs; /* time in milliseconds from monotonic clock of previous scan */
int64_t iterationsRemaining;
#ifdef HAVE_LIBHWLOC
hwloc_topology_t topology;
bool topologyOk;
#endif
memory_t totalMem;
memory_t usedMem;
memory_t buffersMem;
memory_t cachedMem;
memory_t sharedMem;
memory_t availableMem;
memory_t totalSwap;
memory_t usedSwap;
memory_t cachedSwap;
unsigned int activeCPUs;
unsigned int existingCPUs;
UsersTable* usersTable;
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;typedef: memory_t
typedef unsigned long long int memory_t;
Macros.h
Macros.h
function: isNaN
/* 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);
}function: isNonnegative
/* Checks if x >= 0.0 but returns false if x is NaN. Because IEEE 754 considers
-0.0 == 0.0, this function treats both zeros as nonnegative. */
static inline bool isNonnegative(double x) {
return isgreaterequal(x, 0.0);
}function: isPositive
/* Checks if x > 0.0 but returns false if x is NaN. */
static inline bool isPositive(double x) {
return isgreater(x, 0.0);
}function: saturatingSub
/* 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;
}macro: ARRAYSIZE
#define ARRAYSIZE(x) (sizeof(x) / sizeof((x)[0]))
macro: ATTR_ACCESS2
#define ATTR_ACCESS2(mode, ref) __attribute__((access (mode, ref)))
macro: ATTR_ACCESS2_R
#define ATTR_ACCESS2_R(ref) ATTR_ACCESS2(read_only, ref)
macro: ATTR_ACCESS2_RW
#define ATTR_ACCESS2_RW(ref) ATTR_ACCESS2(read_write, ref)
macro: ATTR_ACCESS2_W
#define ATTR_ACCESS2_W(ref) ATTR_ACCESS2(write_only, ref)
macro: ATTR_ACCESS3
#define ATTR_ACCESS3(mode, ref, size) __attribute__((access (mode, ref, size)))
macro: ATTR_ACCESS3_R
#define ATTR_ACCESS3_R(ref, size) ATTR_ACCESS3(read_only, ref, size)
macro: ATTR_ACCESS3_RW
#define ATTR_ACCESS3_RW(ref, size) ATTR_ACCESS3(read_write, ref, size)
macro: ATTR_ACCESS3_W
#define ATTR_ACCESS3_W(ref, size) ATTR_ACCESS3(write_only, ref, size)
macro: ATTR_ALLOC_SIZE1
#define ATTR_ALLOC_SIZE1(a) __attribute__((alloc_size (a)))
macro: ATTR_ALLOC_SIZE2
#define ATTR_ALLOC_SIZE2(a, b) __attribute__((alloc_size (a, b)))
macro: ATTR_FORMAT
#define ATTR_FORMAT(type, index, check) __attribute__((format (type, index, check)))
macro: ATTR_MALLOC
#define ATTR_MALLOC __attribute__((malloc))
macro: ATTR_NONNULL
#define ATTR_NONNULL __attribute__((nonnull))
macro: ATTR_NONNULL_N
#define ATTR_NONNULL_N(...) __attribute__((nonnull(__VA_ARGS__)))
macro: ATTR_NORETURN
#define ATTR_NORETURN __attribute__((noreturn))
macro: ATTR_RETNONNULL
#define ATTR_RETNONNULL __attribute__((returns_nonnull))
macro: ATTR_UNUSED
#define ATTR_UNUSED __attribute__((unused))
macro: CLAMP
#define CLAMP(x, low, high) (assert((low) <= (high)), ((x) > (high)) ? (high) : MAXIMUM(x, low))
macro: IGNORE_WCASTQUAL_BEGIN
#define IGNORE_WCASTQUAL_BEGIN _Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wcast-qual\"")macro: IGNORE_WCASTQUAL_END
#define IGNORE_WCASTQUAL_END _Pragma("clang diagnostic pop")macro: MAXIMUM
#define MAXIMUM(a, b) ((a) > (b) ? (a) : (b))
macro: MINIMUM
#define MINIMUM(a, b) ((a) < (b) ? (a) : (b))
macro: SPACESHIP_DEFAULTSTR
#define SPACESHIP_DEFAULTSTR(a, b, s) strcmp((a) ? (a) : (s), (b) ? (b) : (s))
macro: SPACESHIP_NULLSTR
#define SPACESHIP_NULLSTR(a, b) strcmp((a) ? (a) : "", (b) ? (b) : "")
macro: SPACESHIP_NUMBER
#define SPACESHIP_NUMBER(a, b) (((a) > (b)) - ((a) < (b)))
MainPanel.c
MainPanel.c
const_array: MainFunctions
static const char* const MainFunctions[] = {"Help ", "Setup ", "Search", "Filter", "Tree ", "SortBy", "Nice -", "Nice +", "Kill ", "Quit ", NULL};const_array: MainFunctions_ro
static const char* const MainFunctions_ro[] = {"Help ", "Setup ", "Search", "Filter", "Tree ", "SortBy", " ", " ", " ", "Quit ", NULL};function: MainPanel_delete
void MainPanel_delete(Object* object) {
MainPanel* this = (MainPanel*) object;
MainPanel_setFunctionBar(this, false);
FunctionBar_delete(this->readonlyBar);
IncSet_delete(this->inc);
free(this->keys);
Panel_done(&this->super);
free(this);
}function: MainPanel_drawFunctionBar
static void MainPanel_drawFunctionBar(Panel* super, bool hideFunctionBar) {
MainPanel* this = (MainPanel*) super;
// Do not hide active search and filter bar.
if (hideFunctionBar && !this->inc->active)
return;
IncSet_drawBar(this->inc, CRT_colors[FUNCTION_BAR]);
if (this->state->pauseUpdate) {
FunctionBar_append("PAUSED", CRT_colors[PAUSED]);
}
}function: MainPanel_eventHandler
function: MainPanel_foreachRow
bool MainPanel_foreachRow(MainPanel* this, MainPanel_foreachRowFn fn, Arg arg, bool* wasAnyTagged) {
Panel* super = &this->super;
bool ok = true;
bool anyTagged = false;
for (int i = 0; i < Panel_size(super); i++) {
Row* row = (Row*) Panel_get(super, i);
if (row->tag) {
ok &= fn(row, arg);
anyTagged = true;
}
}
if (!anyTagged) {
Row* row = (Row*) Panel_getSelected(super);
if (row) {
ok &= fn(row, arg);
}
}
if (wasAnyTagged)
*wasAnyTagged = anyTagged;
return ok;
}function: MainPanel_getValue
static const char* MainPanel_getValue(Panel* this, int i) {
Row* row = (Row*) Panel_get(this, i);
return Row_sortKeyString(row);
}function: MainPanel_idSearch
static void MainPanel_idSearch(MainPanel* this, int ch) {
Panel* super = &this->super;
pid_t id = ch - 48 + this->idSearch;
for (int i = 0; i < Panel_size(super); i++) {
const Row* row = (const Row*) Panel_get(super, i);
if (row && row->id == id) {
Panel_setSelected(super, i);
break;
}
}
this->idSearch = id * 10;
if (this->idSearch > 10000000) {
this->idSearch = 0;
}
}function: MainPanel_new
MainPanel* MainPanel_new(void) {
MainPanel* this = AllocThis(MainPanel);
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(activeBar);
Action_setBindings(this->keys);
Platform_setBindings(this->keys);
return this;
}function: MainPanel_printHeader
static void MainPanel_printHeader(Panel* super) {
MainPanel* this = (MainPanel*) super;
Machine* host = this->state->host;
Table_printHeader(host->settings, &super->header);
}function: MainPanel_selectedRow
int MainPanel_selectedRow(MainPanel* this) {
const Row* row = (const Row*) Panel_getSelected((Panel*)this);
return row ? row->id : -1;
}function: MainPanel_setFunctionBar
void MainPanel_setFunctionBar(MainPanel* this, bool readonly) {
this->super.defaultBar = readonly ? this->readonlyBar : this->processBar;
this->inc->defaultBar = this->super.defaultBar;
}function: MainPanel_setState
void MainPanel_setState(MainPanel* this, State* state) {
this->state = state;
}function: MainPanel_updateLabels
void MainPanel_updateLabels(MainPanel* this, bool list, bool filter) {
FunctionBar* bar = MainPanel_getFunctionBar(this);
FunctionBar_setLabel(bar, KEY_F(5), list ? "List " : "Tree ");
FunctionBar_setLabel(bar, KEY_F(4), filter ? "FILTER" : "Filter");
}struct_instance: MainPanel_class
const PanelClass MainPanel_class = {
.super = {
.extends = Class(Panel),
.delete = MainPanel_delete
},
.eventHandler = MainPanel_eventHandler,
.drawFunctionBar = MainPanel_drawFunctionBar,
.printHeader = MainPanel_printHeader
};MainPanel.h
MainPanel.h
extern const: MainPanel_class
extern const PanelClass MainPanel_class;
function: MainPanel_delete
void MainPanel_delete(Object* object);
function: MainPanel_foreachRow
bool MainPanel_foreachRow(MainPanel* this, MainPanel_foreachRowFn fn, Arg arg, bool* wasAnyTagged);
function: MainPanel_new
MainPanel* MainPanel_new(void);
function: MainPanel_selectedRow
int MainPanel_selectedRow(MainPanel* this);
function: MainPanel_setFunctionBar
void MainPanel_setFunctionBar(MainPanel* this, bool readonly);
function: MainPanel_setState
void MainPanel_setState(MainPanel* this, State* state);
function: MainPanel_updateLabels
void MainPanel_updateLabels(MainPanel* this, bool list, bool filter);
macro: MainPanel_getFunctionBar
#define MainPanel_getFunctionBar(this_) (((Panel*)(this_))->defaultBar)
struct: MainPanel_
typedef struct MainPanel_ {
Panel super;
State* state;
IncSet* inc;
Htop_Action* keys;
FunctionBar* processBar; /* function bar with process-specific actions */
FunctionBar* readonlyBar; /* function bar without process actions (ro) */
unsigned int idSearch;
} MainPanel;typedef: MainPanel_foreachRowFn
typedef bool(*MainPanel_foreachRowFn)(Row*, Arg);
Makefile.am
Makefile.am
file: Makefile.am
MemoryMeter.c
MemoryMeter.c
function: MemoryMeter_display
function: MemoryMeter_updateValues
static void MemoryMeter_updateValues(Meter* this) {
char* buffer = this->txtBuffer;
size_t size = sizeof(this->txtBuffer);
int written;
Settings *settings = this->host->settings;
/* shared, compressed and available memory are not supported on all platforms */
this->values[MEMORY_METER_SHARED] = NAN;
this->values[MEMORY_METER_COMPRESSED] = NAN;
this->values[MEMORY_METER_AVAILABLE] = NAN;
Platform_setMemoryValues(this);
if ((this->mode == GRAPH_METERMODE || this->mode == BAR_METERMODE) && !settings->showCachedMemory) {
this->values[MEMORY_METER_BUFFERS] = 0;
this->values[MEMORY_METER_CACHE] = 0;
}
/* Do not print available memory in bar mode */
static_assert(MEMORY_METER_AVAILABLE + 1 == MEMORY_METER_ITEMCOUNT,
"MEMORY_METER_AVAILABLE is not the last item in MemoryMeterValues");
this->curItems = MEMORY_METER_AVAILABLE;
/* we actually want to show "used + shared + compressed" */
double used = this->values[MEMORY_METER_USED];
if (isPositive(this->values[MEMORY_METER_SHARED]))
used += this->values[MEMORY_METER_SHARED];
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);
METER_BUFFER_APPEND_CHR(buffer, size, '/');
Meter_humanUnit(buffer, this->total, size);
}global variable: MemoryMeter_attributes
static const int MemoryMeter_attributes[] = {
MEMORY_USED,
MEMORY_SHARED,
MEMORY_COMPRESSED,
MEMORY_BUFFERS,
MEMORY_CACHE
};global variable: MemoryMeter_class
const MeterClass MemoryMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = MemoryMeter_display,
},
.updateValues = MemoryMeter_updateValues,
.defaultMode = BAR_METERMODE,
.supportedModes = METERMODE_DEFAULT_SUPPORTED,
.maxItems = MEMORY_METER_ITEMCOUNT,
.total = 100.0,
.attributes = MemoryMeter_attributes,
.name = "Memory",
.uiName = "Memory",
.caption = "Mem"
};MemoryMeter.h
MemoryMeter.h
declaration: MemoryMeter_class
extern const MeterClass MemoryMeter_class;
enum: MemoryMeterValues
typedef enum {
MEMORY_METER_USED = 0,
MEMORY_METER_SHARED = 1,
MEMORY_METER_COMPRESSED = 2,
MEMORY_METER_BUFFERS = 3,
MEMORY_METER_CACHE = 4,
MEMORY_METER_AVAILABLE = 5,
MEMORY_METER_ITEMCOUNT = 6, // number of entries in this enum
} MemoryMeterValues;MemorySwapMeter.c
MemorySwapMeter.c
function: MemorySwapMeter_done
static void MemorySwapMeter_done(Meter* this) {
MemorySwapMeterData* data = this->meterData;
Meter_delete((Object*)data->swapMeter);
Meter_delete((Object*)data->memoryMeter);
free(data);
}function: MemorySwapMeter_draw
static void MemorySwapMeter_draw(Meter* this, int x, int y, int w) {
MemorySwapMeterData* data = this->meterData;
/* Use the same width for each sub meter to align with CPU meter */
const int colwidth = w / 2;
const int diff = w - colwidth * 2;
assert(data->memoryMeter->draw);
data->memoryMeter->draw(data->memoryMeter, x, y, colwidth);
assert(data->swapMeter->draw);
data->swapMeter->draw(data->swapMeter, x + colwidth + diff, y, colwidth);
}function: MemorySwapMeter_init
static void MemorySwapMeter_init(Meter* this) {
MemorySwapMeterData* data = this->meterData;
if (!data) {
data = this->meterData = xCalloc(1, sizeof(MemorySwapMeterData));
}
if (!data->memoryMeter)
data->memoryMeter = Meter_new(this->host, 0, (const MeterClass*) Class(MemoryMeter));
if (!data->swapMeter)
data->swapMeter = Meter_new(this->host, 0, (const MeterClass*) Class(SwapMeter));
if (Meter_initFn(data->memoryMeter)) {
Meter_init(data->memoryMeter);
}
if (Meter_initFn(data->swapMeter)) {
Meter_init(data->swapMeter);
}
}function: MemorySwapMeter_updateMode
static void MemorySwapMeter_updateMode(Meter* this, MeterModeId mode) {
MemorySwapMeterData* data = this->meterData;
this->mode = mode;
Meter_setMode(data->memoryMeter, mode);
Meter_setMode(data->swapMeter, mode);
this->h = MAXIMUM(data->memoryMeter->h, data->swapMeter->h);
}function: MemorySwapMeter_updateValues
static void MemorySwapMeter_updateValues(Meter* this) {
MemorySwapMeterData* data = this->meterData;
Meter_updateValues(data->memoryMeter);
Meter_updateValues(data->swapMeter);
}global constant: MemorySwapMeter_class
const MeterClass MemorySwapMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
},
.updateValues = MemorySwapMeter_updateValues,
.defaultMode = BAR_METERMODE,
.supportedModes = METERMODE_DEFAULT_SUPPORTED,
.isMultiColumn = true,
.name = "MemorySwap",
.uiName = "Memory & Swap",
.description = "Combined memory and swap usage",
.caption = "M&S",
.draw = MemorySwapMeter_draw,
.init = MemorySwapMeter_init,
.updateMode = MemorySwapMeter_updateMode,
.done = MemorySwapMeter_done
};struct: MemorySwapMeterData
typedef struct MemorySwapMeterData_ {
Meter* memoryMeter;
Meter* swapMeter;
} MemorySwapMeterData;MemorySwapMeter.h
MemorySwapMeter.h
variable: MemorySwapMeter_class
extern const MeterClass MemorySwapMeter_class;
Meter.c
Meter.c
function: BarMeterMode_draw
function: BlankMeter_display
static void BlankMeter_display(ATTR_UNUSED const Object* cast, ATTR_UNUSED RichString* out) {
}function: BlankMeter_updateValues
static void BlankMeter_updateValues(Meter* this) {
this->txtBuffer[0] = '\0';
}function: GraphMeterMode_draw
function: LEDMeterMode_draw
static void LEDMeterMode_draw(Meter* this, int x, int y, int w) {
#ifdef HAVE_LIBNCURSESW
if (CRT_utf8)
LEDMeterMode_digits = LEDMeterMode_digitsUtf8;
else
#endif
LEDMeterMode_digits = LEDMeterMode_digitsAscii;
RichString_begin(out);
Meter_displayBuffer(this, &out);
int yText =
#ifdef HAVE_LIBNCURSESW
CRT_utf8 ? y + 1 :
#endif
y + 2;
attrset(CRT_colors[LED_COLOR]);
const char* caption = Meter_getCaption(this);
mvaddstr(yText, x, caption);
int xx = x + strlen(caption);
int len = RichString_sizeVal(out);
for (int i = 0; i < len; i++) {
int c = RichString_getCharVal(out, i);
if (c >= '0' && c <= '9') {
if (xx - x + 4 > w)
break;
LEDMeterMode_drawDigit(xx, y, c - '0');
xx += 4;
} else {
if (xx - x + 1 > w)
break;
#ifdef HAVE_LIBNCURSESW
const cchar_t wc = { .chars = { c, '\0' }, .attr = 0 }; /* use LED_COLOR from attrset() */
mvadd_wch(yText, xx, &wc);
#else
mvaddch(yText, xx, c);
#endif
xx += 1;
}
}
attrset(CRT_colors[RESET_COLOR]);
RichString_delete(&out);
}function: LEDMeterMode_drawDigit
static void LEDMeterMode_drawDigit(int x, int y, int n) {
for (int i = 0; i < 3; i++)
mvaddstr(y + i, x, LEDMeterMode_digits[i * 10 + n]);
}function: Meter_delete
void Meter_delete(Object* cast) {
if (!cast)
return;
Meter* this = (Meter*) cast;
if (Meter_doneFn(this)) {
Meter_done(this);
}
free(this->drawData.values);
free(this->caption);
free(this->values);
free(this);
}function: Meter_displayBuffer
static inline void Meter_displayBuffer(const Meter* this, RichString* out) {
if (Object_displayFn(this)) {
Object_display(this, out);
} else {
RichString_writeWide(out, CRT_colors[Meter_attributes(this)[0]], this->txtBuffer);
}
}function: Meter_humanUnit
int Meter_humanUnit(char* buffer, double value, size_t size) {
size_t i = 0;
assert(value >= 0.0);
while (value >= ONE_K) {
if (i >= ARRAYSIZE(unitPrefixes) - 1) {
if (value > 9999.0) {
return xSnprintf(buffer, size, "inf");
}
break;
}
value /= ONE_K;
++i;
}
int precision = 0;
if (i > 0) {
// Fraction digits for mebibytes and above
precision = value <= 99.9 ? (value <= 9.99 ? 2 : 1) : 0;
// Round up if 'value' is in range (99.9, 100) or (9.99, 10)
if (precision < 2) {
double limit = precision == 1 ? 10.0 : 100.0;
if (value < limit) {
value = limit;
}
}
}
return xSnprintf(buffer, size, "%.*f%c", precision, value, unitPrefixes[i]);
}function: Meter_new
Meter* Meter_new(const Machine* host, unsigned int param, const MeterClass* type) {
Meter* this = xCalloc(1, sizeof(Meter));
Object_setClass(this, type);
this->h = 1;
this->param = param;
this->host = host;
this->curItems = type->maxItems;
this->curAttributes = NULL;
this->values = type->maxItems ? xCalloc(type->maxItems, sizeof(double)) : NULL;
this->total = type->total;
this->caption = xStrdup(type->caption);
if (Meter_initFn(this)) {
Meter_init(this);
}
Meter_setMode(this, type->defaultMode);
assert(this->mode > 0);
return this;
}function: Meter_nextSupportedMode
MeterModeId Meter_nextSupportedMode(const Meter* this) {
uint32_t supportedModes = Meter_supportedModes(this);
assert(supportedModes);
assert(this->mode < UINT32_WIDTH);
uint32_t modeMask = ((uint32_t)-1 << 1) << this->mode;
uint32_t nextModes = supportedModes & modeMask;
if (!nextModes) {
nextModes = supportedModes;
}
return (MeterModeId)countTrailingZeros(nextModes);
}function: Meter_setCaption
void Meter_setCaption(Meter* this, const char* caption) {
free_and_xStrdup(&this->caption, caption);
}function: Meter_setMode
void Meter_setMode(Meter* this, MeterModeId modeIndex) {
if (modeIndex == this->mode) {
assert(this->mode > 0);
return;
}
uint32_t supportedModes = Meter_supportedModes(this);
assert(supportedModes);
assert(!(supportedModes & (1 << 0)));
assert(LAST_METERMODE <= UINT32_WIDTH);
if (modeIndex >= LAST_METERMODE || !(supportedModes & (1UL << modeIndex)))
return;
assert(modeIndex >= 1);
if (Meter_updateModeFn(this)) {
assert(Meter_drawFn(this));
this->draw = Meter_drawFn(this);
Meter_updateMode(this, modeIndex);
} else {
free(this->drawData.values);
this->drawData.values = NULL;
this->drawData.nValues = 0;
const MeterMode* mode = &Meter_modes[modeIndex];
this->draw = mode->draw;
this->h = mode->h;
}
this->mode = modeIndex;
}function: Meter_toListItem
ListItem* Meter_toListItem(const Meter* this, bool moving) {
char mode[20];
if (this->mode > 0) {
xSnprintf(mode, sizeof(mode), " [%s]", Meter_modes[this->mode].uiName);
} else {
mode[0] = '\0';
}
char name[32];
if (Meter_getUiNameFn(this))
Meter_getUiName(this, name, sizeof(name));
else
xSnprintf(name, sizeof(name), "%s", Meter_uiName(this));
char buffer[50];
xSnprintf(buffer, sizeof(buffer), "%s%s", name, mode);
ListItem* li = ListItem_new(buffer, 0);
li->moving = moving;
return li;
}function: TextMeterMode_draw
static void TextMeterMode_draw(Meter* this, int x, int y, int w) {
const char* caption = Meter_getCaption(this);
attrset(CRT_colors[METER_TEXT]);
mvaddnstr(y, x, caption, w);
attrset(CRT_colors[RESET_COLOR]);
int captionLen = strlen(caption);
x += captionLen;
w -= captionLen;
if (w <= 0)
return;
RichString_begin(out);
Meter_displayBuffer(this, &out);
RichString_printoffnVal(out, y, x, 0, w);
RichString_delete(&out);
}global variable: BarMeterMode_characters
static const char BarMeterMode_characters[] = "|#*@$%&.";
global variable: BlankMeter_attributes
static const int BlankMeter_attributes[] = {
DEFAULT_COLOR
};global variable: BlankMeter_class
const MeterClass BlankMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = BlankMeter_display,
},
.updateValues = BlankMeter_updateValues,
.defaultMode = TEXT_METERMODE,
.supportedModes = (1 << TEXT_METERMODE),
.maxItems = 0,
.total = 0.0,
.attributes = BlankMeter_attributes,
.name = "Blank",
.uiName = "Blank",
.caption = ""
};global variable: GraphMeterMode_dotsAscii
static const char* const GraphMeterMode_dotsAscii[] = {
/*00*/" ", /*01*/".", /*02*/":",
/*10*/".", /*11*/".", /*12*/":",
/*20*/":", /*21*/":", /*22*/":"
};global variable: GraphMeterMode_dotsUtf8
static const char* const GraphMeterMode_dotsUtf8[] = {
/*00*/" ", /*01*/"⢀", /*02*/"⢠", /*03*/"⢰", /*04*/ "⢸",
/*10*/"⡀", /*11*/"⣀", /*12*/"⣠", /*13*/"⣰", /*14*/ "⣸",
/*20*/"⡄", /*21*/"⣄", /*22*/"⣤", /*23*/"⣴", /*24*/ "⣼",
/*30*/"⡆", /*31*/"⣆", /*32*/"⣦", /*33*/"⣶", /*34*/ "⣾",
/*40*/"⡇", /*41*/"⣇", /*42*/"⣧", /*43*/"⣷", /*44*/ "⣿"
};global variable: LEDMeterMode_digits
static const char* const* LEDMeterMode_digits;
global variable: LEDMeterMode_digitsAscii
static const char* const LEDMeterMode_digitsAscii[] = {
" __ ", " ", " __ ", " __ ", " ", " __ ", " __ ", " __ ", " __ ", " __ ",
"| |", " |", " __|", " __|", "|__|", "|__ ", "|__ ", " |", "|__|", "|__|",
"|__|", " |", "|__ ", " __|", " |", " __|", "|__|", " |", "|__|", " __|"
};global variable: LEDMeterMode_digitsUtf8
static const char* const LEDMeterMode_digitsUtf8[] = {
"┌──┐", " ┐ ", "╶──┐", "╶──┐", "╷ ╷", "┌──╴", "┌──╴", "╶──┐", "┌──┐", "┌──┐",
"│ │", " │ ", "┌──┘", " ──┤", "└──┤", "└──┐", "├──┐", " │", "├──┤", "└──┤",
"└──┘", " ╵ ", "└──╴", "╶──┘", " ╵", "╶──┘", "└──┘", " ╵", "└──┘", "╶──┘"
};global variable: Meter_class
const MeterClass Meter_class = {
.super = {
.extends = Class(Object)
}
};global variable: Meter_modes
static const MeterMode Meter_modes[] = {
[0] = {
.uiName = NULL,
.h = 0,
.draw = NULL,
},
[BAR_METERMODE] = {
.uiName = "Bar",
.h = 1,
.draw = BarMeterMode_draw,
},
[TEXT_METERMODE] = {
.uiName = "Text",
.h = 1,
.draw = TextMeterMode_draw,
},
[GRAPH_METERMODE] = {
.uiName = "Graph",
.h = GRAPH_HEIGHT,
.draw = GraphMeterMode_draw,
},
[LED_METERMODE] = {
.uiName = "LED",
.h = 3,
.draw = LEDMeterMode_draw,
},
};macro: GRAPH_HEIGHT
#define GRAPH_HEIGHT 4 /* Unit: rows (lines) */
macro: PIXPERROW_ASCII
#define PIXPERROW_ASCII 2
macro: PIXPERROW_UTF8
#define PIXPERROW_UTF8 4
macro: UINT32_WIDTH
#define UINT32_WIDTH 32
struct: MeterMode_
typedef struct MeterMode_ {
Meter_Draw draw;
const char* uiName;
int h;
} MeterMode;Meter.h
Meter.h
enum: MeterRateStatus
typedef enum {
RATESTATUS_DATA,
RATESTATUS_INIT,
RATESTATUS_NODATA,
RATESTATUS_STALE
} MeterRateStatus;extern: BlankMeter_class
extern const MeterClass BlankMeter_class;
extern: Meter_class
extern const MeterClass Meter_class;
function: Meter_delete
void Meter_delete(Object* cast);
function: Meter_humanUnit
int Meter_humanUnit(char* buffer, double value, size_t size);
function: Meter_new
Meter* Meter_new(const Machine* host, unsigned int param, const MeterClass* type);
function: Meter_nextSupportedMode
MeterModeId Meter_nextSupportedMode(const Meter* this);
function: Meter_setCaption
void Meter_setCaption(Meter* this, const char* caption);
function: Meter_setMode
void Meter_setMode(Meter* this, MeterModeId modeIndex);
function: Meter_toListItem
ListItem* Meter_toListItem(const Meter* this, bool moving);
macro: As_Meter
#define As_Meter(this_) ((const MeterClass*)((this_)->super.klass))
macro: MAX_METER_GRAPHDATA_VALUES
#define MAX_METER_GRAPHDATA_VALUES 32768
macro: Meter_attributes
#define Meter_attributes(this_) As_Meter(this_)->attributes
macro: METER_BUFFER_APPEND_CHR
#define METER_BUFFER_APPEND_CHR(buffer, size, c) \
do { \
if ((size) < 2) { \
return; \
} \
*(buffer)++ = c; \
*(buffer) = '\0'; \
(size)--; \
if ((size) == 0) { \
return; \
} \
} while (0)macro: METER_BUFFER_CHECK
#define METER_BUFFER_CHECK(buffer, size, written) \
do { \
if ((written) < 0 || (size_t)(written) >= (size)) { \
return; \
} \
(buffer) += (written); \
(size) -= (size_t)(written); \
} while (0)macro: Meter_done
#define Meter_done(this_) As_Meter(this_)->done((Meter*)(this_))
macro: Meter_doneFn
#define Meter_doneFn(this_) As_Meter(this_)->done
macro: Meter_drawFn
#define Meter_drawFn(this_) As_Meter(this_)->draw
macro: Meter_getCaption
#define Meter_getCaption(this_) (Meter_getCaptionFn(this_) ? As_Meter(this_)->getCaption((const Meter*)(this_)) : (this_)->caption)
macro: Meter_getCaptionFn
#define Meter_getCaptionFn(this_) As_Meter(this_)->getCaption
macro: Meter_getUiName
#define Meter_getUiName(this_,n_,l_) As_Meter(this_)->getUiName((const Meter*)(this_),n_,l_)
macro: Meter_getUiNameFn
#define Meter_getUiNameFn(this_) As_Meter(this_)->getUiName
macro: Meter_init
#define Meter_init(this_) As_Meter(this_)->init((Meter*)(this_))
macro: Meter_initFn
#define Meter_initFn(this_) As_Meter(this_)->init
macro: Meter_isMultiColumn
#define Meter_isMultiColumn(this_) As_Meter(this_)->isMultiColumn
macro: Meter_name
#define Meter_name(this_) As_Meter(this_)->name
macro: Meter_supportedModes
#define Meter_supportedModes(this_) As_Meter(this_)->supportedModes
macro: METER_TXTBUFFER_LEN
#define METER_TXTBUFFER_LEN 256
macro: Meter_uiName
#define Meter_uiName(this_) As_Meter(this_)->uiName
macro: Meter_updateMode
#define Meter_updateMode(this_, m_) As_Meter(this_)->updateMode((Meter*)(this_), m_)
macro: Meter_updateModeFn
#define Meter_updateModeFn(this_) As_Meter(this_)->updateMode
macro: Meter_updateValues
#define Meter_updateValues(this_) As_Meter(this_)->updateValues((Meter*)(this_))
struct: GraphData_
typedef struct GraphData_ {
struct timeval time;
size_t nValues;
double* values;
} GraphData;struct: Meter_
struct Meter_;
struct: Meter_
struct Meter_ {
Object super;
Meter_Draw draw;
const Machine* host;
char* caption;
MeterModeId mode;
unsigned int param;
GraphData drawData;
int h;
int columnWidthCount; /**< only used internally by the Header */
uint8_t curItems;
const int* curAttributes;
char txtBuffer[METER_TXTBUFFER_LEN];
double* values;
double total;
void* meterData;
};struct: MeterClass_
typedef struct MeterClass_ {
const ObjectClass super;
const Meter_Init init;
const Meter_Done done;
const Meter_UpdateMode updateMode;
const Meter_UpdateValues updateValues;
const Meter_Draw draw;
const Meter_GetCaption getCaption;
const Meter_GetUiName getUiName;
const MeterModeId defaultMode;
const uint32_t supportedModes; /* bitset of supported modes, 1<<mode_id */
const double total;
const int* const attributes;
const char* const name; /* internal name of the meter, must not contain any space */
const char* const uiName; /* display name in header setup menu */
const char* const caption; /* prefix in the actual header */
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) */
} MeterClass;typedef: Meter
typedef struct Meter_ Meter;
typedef: Meter_Done
typedef ATTR_NONNULL void (*Meter_Done)(Meter*);
typedef: Meter_Draw
typedef ATTR_NONNULL void (*Meter_Draw)(Meter*, int, int, int);
typedef: Meter_GetCaption
typedef ATTR_NONNULL const char* (*Meter_GetCaption)(const Meter*);
typedef: Meter_GetUiName
typedef ATTR_NONNULL ATTR_ACCESS3_W(2, 3) void (*Meter_GetUiName)(const Meter*, char*, size_t);
typedef: Meter_Init
typedef ATTR_NONNULL void (*Meter_Init)(Meter*);
typedef: Meter_UpdateMode
typedef ATTR_NONNULL void (*Meter_UpdateMode)(Meter*, MeterModeId);
typedef: Meter_UpdateValues
typedef ATTR_NONNULL void (*Meter_UpdateValues)(Meter*);
MeterMode.h
MeterMode.h
enum: MeterModeId_
enum MeterModeId_ {
/* Meter mode 0 is reserved */
BAR_METERMODE = 1,
TEXT_METERMODE,
GRAPH_METERMODE,
LED_METERMODE,
LAST_METERMODE
};macro: METERMODE_DEFAULT_SUPPORTED
#define METERMODE_DEFAULT_SUPPORTED ( \ (1 << BAR_METERMODE) | \ (1 << TEXT_METERMODE) | \ (1 << GRAPH_METERMODE) | \ (1 << LED_METERMODE) | \ 0) // Avoids edits when updating
typedef: MeterModeId
typedef unsigned int MeterModeId;
MetersPanel.c
MetersPanel.c
function: MetersPanel_cleanup
void MetersPanel_cleanup(void) {
if (Meters_movingBar) {
FunctionBar_delete(Meters_movingBar);
Meters_movingBar = NULL;
}
}function: MetersPanel_delete
static void MetersPanel_delete(Object* object) {
MetersPanel* this = (MetersPanel*) object;
Panel_done(&this->super);
free(this);
}function: MetersPanel_eventHandler
function: MetersPanel_new
MetersPanel* MetersPanel_new(Settings* settings, const char* header, Vector* meters, ScreenManager* scr) {
MetersPanel* this = AllocThis(MetersPanel);
Panel* super = &this->super;
FunctionBar* fuBar = FunctionBar_new(MetersFunctions, MetersKeys, MetersEvents);
if (!Meters_movingBar) {
Meters_movingBar = FunctionBar_new(MetersMovingFunctions, MetersMovingKeys, MetersMovingEvents);
}
Panel_init(super, 1, 1, 1, 1, Class(ListItem), true, fuBar);
this->settings = settings;
this->meters = meters;
this->scr = scr;
this->moving = false;
this->rightNeighbor = NULL;
this->leftNeighbor = NULL;
Panel_setHeader(super, header);
for (int i = 0; i < Vector_size(meters); i++) {
const Meter* meter = (const Meter*) Vector_get(meters, i);
Panel_add(super, (Object*) Meter_toListItem(meter, false));
}
return this;
}function: MetersPanel_setMoving
void MetersPanel_setMoving(MetersPanel* this, bool moving) {
Panel* super = &this->super;
this->moving = moving;
ListItem* selected = (ListItem*)Panel_getSelected(super);
if (selected) {
selected->moving = moving;
}
if (!moving) {
Panel_setSelectionColor(super, PANEL_SELECTION_FOCUS);
Panel_setDefaultBar(super);
} else {
Panel_setSelectionColor(super, PANEL_SELECTION_FOLLOW);
super->currentBar = Meters_movingBar;
}
}function: moveToNeighbor
static inline bool moveToNeighbor(MetersPanel* this, MetersPanel* neighbor, int selected) {
Panel* super = &this->super;
if (this->moving) {
if (neighbor) {
if (selected < Vector_size(this->meters)) {
MetersPanel_setMoving(this, false);
Meter* meter = (Meter*) Vector_take(this->meters, selected);
Panel_remove(super, selected);
Vector_insert(neighbor->meters, selected, meter);
Panel_insert(&(neighbor->super), selected, (Object*) Meter_toListItem(meter, false));
Panel_setSelected(&(neighbor->super), selected);
MetersPanel_setMoving(neighbor, true);
return true;
}
}
}
return false;
}global_variable: Meters_movingBar
static FunctionBar* Meters_movingBar = NULL;
global_variable: MetersEvents
static const int MetersEvents[] = {' ', 13, ERR, KEY_DC, KEY_F(10)};global_variable: MetersFunctions
static const char* const MetersFunctions[] = {"Style ", "Move ", " ", "Delete", "Done ", NULL};global_variable: MetersKeys
static const char* const MetersKeys[] = {"Space", "Enter", " ", "Del", "F10"};global_variable: MetersMovingEvents
static const int MetersMovingEvents[] = {' ', 13, KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, ERR, KEY_DC, KEY_F(10)};global_variable: MetersMovingFunctions
static const char* const MetersMovingFunctions[] = {"Style ", "Lock ", "Up ", "Down ", "Left ", "Right ", " ", "Delete", "Done ", NULL};global_variable: MetersMovingKeys
static const char* const MetersMovingKeys[] = {"Space", "Enter", "Up", "Dn", "<-", "->", " ", "Del", "F10"};struct_instance: MetersPanel_class
const PanelClass MetersPanel_class = {
.super = {
.extends = Class(Panel),
.delete = MetersPanel_delete
},
.eventHandler = MetersPanel_eventHandler
};MetersPanel.h
MetersPanel.h
extern const: MetersPanel_class
extern const PanelClass MetersPanel_class;
function: MetersPanel_cleanup
void MetersPanel_cleanup(void);
function: MetersPanel_new
MetersPanel* MetersPanel_new(Settings* settings, const char* header, Vector* meters, ScreenManager* scr);
method: MetersPanel_setMoving
void MetersPanel_setMoving(MetersPanel* this, bool moving);
struct: MetersPanel_
struct MetersPanel_ {
Panel super;
Settings* settings;
Vector* meters;
ScreenManager* scr;
MetersPanel* leftNeighbor;
MetersPanel* rightNeighbor;
bool moving;
};typedef: MetersPanel
struct MetersPanel_; typedef struct MetersPanel_ MetersPanel;
NetBSDMachine.c
netbsd/NetBSDMachine.c
file: NetBSDMachine.c
NetBSDMachine.h
netbsd/NetBSDMachine.h
struct: CPUData
typedef struct CPUData_ {
unsigned long long int totalTime;
unsigned long long int userTime;
unsigned long long int niceTime;
unsigned long long int sysTime;
unsigned long long int sysAllTime;
unsigned long long int spinTime;
unsigned long long int intrTime;
unsigned long long int idleTime;
unsigned long long int totalPeriod;
unsigned long long int userPeriod;
unsigned long long int nicePeriod;
unsigned long long int sysPeriod;
unsigned long long int sysAllPeriod;
unsigned long long int spinPeriod;
unsigned long long int intrPeriod;
unsigned long long int idlePeriod;
double frequency;
} CPUData;struct: NetBSDMachine
typedef struct NetBSDMachine_ {
Machine super;
kvm_t* kd;
long fscale;
int pageSize;
int pageSizeKB;
CPUData* cpuData;
} NetBSDMachine;NetBSDProcess.c
netbsd/NetBSDProcess.c
function: NetBSDProcess_compareByKey
static int NetBSDProcess_compareByKey(const Process* v1, const Process* v2, ProcessField key) {
const NetBSDProcess* p1 = (const NetBSDProcess*)v1;
const NetBSDProcess* p2 = (const NetBSDProcess*)v2;
// remove if actually used
(void)p1; (void)p2;
switch (key) {
// add NetBSD-specific fields here
default:
return Process_compareByKey_Base(v1, v2, key);
}
}function: NetBSDProcess_new
Process* NetBSDProcess_new(const Machine* host) {
NetBSDProcess* this = xCalloc(1, sizeof(NetBSDProcess));
Object_setClass(this, Class(NetBSDProcess));
Process_init(&this->super, host);
return (Process*)this;
}function: NetBSDProcess_rowWriteField
static void NetBSDProcess_rowWriteField(const Row* super, RichString* str, ProcessField field) {
const NetBSDProcess* np = (const NetBSDProcess*) super;
char buffer[256]; buffer[255] = '\0';
int attr = CRT_colors[DEFAULT_COLOR];
//size_t n = sizeof(buffer) - 1;
switch (field) {
// add NetBSD-specific fields here
default:
Process_writeField(&np->super, str, field);
return;
}
RichString_appendWide(str, attr, buffer);
}function: Process_delete
void Process_delete(Object* cast) {
NetBSDProcess* this = (NetBSDProcess*) cast;
Process_done((Process*)cast);
free(this);
}global variable: NetBSDProcess_class
const ProcessClass NetBSDProcess_class = {
.super = {
.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
},
.compareByKey = NetBSDProcess_compareByKey
};global variable: Process_fields
NetBSDProcess.h
netbsd/NetBSDProcess.h
function: NetBSDProcess_new
Process* NetBSDProcess_new(const Machine* host);
function: Process_delete
void Process_delete(Object* cast);
global_variable_declaration: NetBSDProcess_class
extern const ProcessClass NetBSDProcess_class;
global_variable_declaration: Process_fields
extern const ProcessFieldData Process_fields[LAST_PROCESSFIELD];
struct: NetBSDProcess
typedef struct NetBSDProcess_ {
Process super;
} NetBSDProcess;NetBSDProcessTable.c
netbsd/NetBSDProcessTable.c
file: NetBSDProcessTable.c
NetBSDProcessTable.h
netbsd/NetBSDProcessTable.h
struct: NetBSDProcessTable_
typedef struct NetBSDProcessTable_ {
ProcessTable super;
} NetBSDProcessTable;Platform.c
netbsd/Platform.c
file: Platform.c
Platform.h
netbsd/Platform.h
function: Platform_addDynamicScreen
static inline void Platform_addDynamicScreen(ATTR_UNUSED ScreenSettings* ss) { }function: Platform_addDynamicScreenAvailableColumns
static inline void Platform_addDynamicScreenAvailableColumns(ATTR_UNUSED Panel* availableColumns, ATTR_UNUSED const char* screen) { }function: Platform_defaultDynamicScreens
static inline void Platform_defaultDynamicScreens(ATTR_UNUSED Settings* settings) { }function: Platform_done
void Platform_done(void);
function: Platform_dynamicColumnName
static inline const char* Platform_dynamicColumnName(ATTR_UNUSED unsigned int key) {
return NULL;
}function: Platform_dynamicColumns
static inline Hashtable* Platform_dynamicColumns(void) {
return NULL;
}function: Platform_dynamicColumnsDone
static inline void Platform_dynamicColumnsDone(ATTR_UNUSED Hashtable* table) { }function: Platform_dynamicColumnWriteField
static inline bool Platform_dynamicColumnWriteField(ATTR_UNUSED const Process* proc, ATTR_UNUSED RichString* str, ATTR_UNUSED unsigned int key) {
return false;
}function: Platform_dynamicMeterDisplay
static inline void Platform_dynamicMeterDisplay(ATTR_UNUSED const Meter* meter, ATTR_UNUSED RichString* out) { }function: Platform_dynamicMeterInit
static inline void Platform_dynamicMeterInit(ATTR_UNUSED Meter* meter) { }function: Platform_dynamicMeters
static inline Hashtable* Platform_dynamicMeters(void) {
return NULL;
}function: Platform_dynamicMetersDone
static inline void Platform_dynamicMetersDone(ATTR_UNUSED Hashtable* table) { }function: Platform_dynamicMeterUpdateValues
static inline void Platform_dynamicMeterUpdateValues(ATTR_UNUSED Meter* meter) { }function: Platform_dynamicScreens
static inline Hashtable* Platform_dynamicScreens(void) {
return NULL;
}function: Platform_dynamicScreensDone
static inline void Platform_dynamicScreensDone(ATTR_UNUSED Hashtable* screens) { }function: Platform_getBattery
void Platform_getBattery(double* percent, ACPresence* isOnAC);
function: Platform_getDiskIO
bool Platform_getDiskIO(DiskIOData* data);
function: Platform_getFileDescriptors
void Platform_getFileDescriptors(double* used, double* max);
function: Platform_getHostname
static inline void Platform_getHostname(char* buffer, size_t size) {
Generic_hostname(buffer, size);
}function: Platform_getLoadAverage
void Platform_getLoadAverage(double* one, double* five, double* fifteen);
function: Platform_getLongOption
static inline CommandLineStatus Platform_getLongOption(ATTR_UNUSED int opt, ATTR_UNUSED int argc, ATTR_UNUSED char** argv) {
return STATUS_ERROR_EXIT;
}function: Platform_getMaxPid
pid_t Platform_getMaxPid(void);
function: Platform_getNetworkIO
bool Platform_getNetworkIO(NetworkIOData* data);
function: Platform_getProcessEnv
char* Platform_getProcessEnv(pid_t pid);
function: Platform_getProcessLocks
FileLocks_ProcessData* Platform_getProcessLocks(pid_t pid);
function: Platform_getRelease
static inline void Platform_getRelease(char** string) {
*string = Generic_uname();
}function: Platform_gettime_monotonic
static inline void Platform_gettime_monotonic(uint64_t* msec) {
Generic_gettime_monotonic(msec);
}function: Platform_gettime_realtime
static inline void Platform_gettime_realtime(struct timeval* tv, uint64_t* msec) {
Generic_gettime_realtime(tv, msec);
}function: Platform_getUptime
int Platform_getUptime(void);
function: Platform_init
bool Platform_init(void);
function: Platform_longOptionsUsage
static inline void Platform_longOptionsUsage(ATTR_UNUSED const char* name) { }function: Platform_setBindings
void Platform_setBindings(Htop_Action* keys);
function: Platform_setCPUValues
double Platform_setCPUValues(Meter* this, int cpu);
function: Platform_setMemoryValues
void Platform_setMemoryValues(Meter* this);
function: Platform_setSwapValues
void Platform_setSwapValues(Meter* this);
ProcessField.h
netbsd/ProcessField.h
macro: PLATFORM_PROCESS_FIELDS
#define PLATFORM_PROCESS_FIELDS \ // End of list
README.md
netbsd/README.md
build option: --disable-unicode
`--disable-unicode`
build option: --with-curses=curses
`--with-curses=curses`
function: kvm_getprocs
The full source code for this entity is not provided in the 'netbsd/README.md' file, which is a descriptive document.
function: sysctl
The full source code for this entity is not provided in the 'netbsd/README.md' file, which is a descriptive document.
library: ncurses
The full source code for this entity is not provided in the 'netbsd/README.md' file, which is a descriptive document.
library: NetBSD's curses
The full source code for this entity is not provided in the 'netbsd/README.md' file, which is a descriptive document.
struct: cchar_t
The full source code for this entity is not provided in the 'netbsd/README.md' file, which is a descriptive document.
NetworkIOMeter.c
NetworkIOMeter.c
const MeterClass instance: NetworkIOMeter_class
const MeterClass NetworkIOMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = NetworkIOMeter_display
},
.updateValues = NetworkIOMeter_updateValues,
.defaultMode = TEXT_METERMODE,
.supportedModes = METERMODE_DEFAULT_SUPPORTED,
.maxItems = 2,
.total = 100.0,
.attributes = NetworkIOMeter_attributes,
.name = "NetworkIO",
.uiName = "Network IO",
.caption = "Network: "
};function: NetworkIOMeter_display
static void NetworkIOMeter_display(ATTR_UNUSED const Object* cast, RichString* out) {
switch (status) {
case RATESTATUS_NODATA:
RichString_writeAscii(out, CRT_colors[METER_VALUE_ERROR], "no data");
return;
case RATESTATUS_INIT:
RichString_writeAscii(out, CRT_colors[METER_VALUE], "initializing...");
return;
case RATESTATUS_STALE:
RichString_writeAscii(out, CRT_colors[METER_VALUE_WARN], "stale data");
return;
case RATESTATUS_DATA:
break;
}
char buffer[64];
RichString_writeAscii(out, CRT_colors[METER_TEXT], "rx: ");
RichString_appendAscii(out, CRT_colors[METER_VALUE_IOREAD], cached_rxb_diff_str);
RichString_appendAscii(out, CRT_colors[METER_VALUE_IOREAD], "iB/s");
RichString_appendAscii(out, CRT_colors[METER_TEXT], " tx: ");
RichString_appendAscii(out, CRT_colors[METER_VALUE_IOWRITE], cached_txb_diff_str);
RichString_appendAscii(out, CRT_colors[METER_VALUE_IOWRITE], "iB/s");
int len = xSnprintf(buffer, sizeof(buffer), " (%u/%u pkts/s) ", cached_rxp_diff, cached_txp_diff);
RichString_appendnAscii(out, CRT_colors[METER_TEXT], buffer, len);
}function: NetworkIOMeter_updateValues
static const int array: NetworkIOMeter_attributes
static const int NetworkIOMeter_attributes[] = {
METER_VALUE_IOREAD,
METER_VALUE_IOWRITE,
};static variable: cached_rxb_diff
static double cached_rxb_diff;
static variable: cached_rxb_diff_str
static char cached_rxb_diff_str[6];
static variable: cached_rxp_diff
static uint32_t cached_rxp_diff;
static variable: cached_txb_diff
static double cached_txb_diff;
static variable: cached_txb_diff_str
static char cached_txb_diff_str[6];
static variable: cached_txp_diff
static uint32_t cached_txp_diff;
static variable: status
static MeterRateStatus status = RATESTATUS_INIT;
NetworkIOMeter.h
NetworkIOMeter.h
struct: NetworkIOData
typedef struct NetworkIOData_ {
uint64_t bytesReceived;
uint64_t packetsReceived;
uint64_t bytesTransmitted;
uint64_t packetsTransmitted;
} NetworkIOData;variable: NetworkIOMeter_class
extern const MeterClass NetworkIOMeter_class;
NEWS
NEWS
file: NEWS
See the commit history for news of the past. See the bug tracker for news of the future. Run the program for news of the present.
Object.c
Object.c
function: Object_isA
bool Object_isA(const Object* o, const ObjectClass* klass) {
if (!o)
return false;
for (const ObjectClass* type = o->klass; type; type = type->extends) {
if (type == klass) {
return true;
}
}
return false;
}global variable: Object_class
const ObjectClass Object_class = {
.extends = NULL
};Object.h
Object.h
function: Object_isA
bool Object_isA(const Object* o, const ObjectClass* klass);
global constant: Object_class
extern const ObjectClass Object_class;
macro: AllocThis
#define AllocThis(class_) (class_*) xMalloc(sizeof(class_)); Object_setClass(this, Class(class_))
macro: Class
#define Class(class_) ((const ObjectClass*)(&(class_ ## _class)))
macro: Object_compare
#define Object_compare(obj_, other_) (assert(Object_getClass(obj_)->compare), Object_getClass(obj_)->compare((const void*)(obj_), other_))
macro: Object_delete
#define Object_delete(obj_) (assert(Object_getClass(obj_)->delete), Object_getClass(obj_)->delete((Object*)(obj_)))
macro: Object_display
#define Object_display(obj_, str_) (assert(Object_getClass(obj_)->display), Object_getClass(obj_)->display((const Object*)(obj_), str_))
macro: Object_displayFn
#define Object_displayFn(obj_) Object_getClass(obj_)->display
macro: Object_getClass
#define Object_getClass(obj_) ((const Object*)(obj_))->klass
macro: Object_setClass
#define Object_setClass(obj_, class_) (((Object*)(obj_))->klass = (const ObjectClass*) (class_))
struct: struct Object_
struct Object_ {
const ObjectClass* klass;
};typedef: Object_Compare
typedef int(*Object_Compare)(const void*, const void*);
typedef: Object_Delete
typedef void(*Object_Delete)(Object*);
typedef: Object_Display
typedef void(*Object_Display)(const Object*, RichString*);
typedef struct: Object
struct Object_; typedef struct Object_ Object;
typedef struct: ObjectClass
typedef struct ObjectClass_ {
const void* const extends;
const Object_Display display;
const Object_Delete delete;
const Object_Compare compare;
} ObjectClass;typedef union: Arg
typedef union {
int i;
void* v;
} Arg;OpenBSDMachine.c
openbsd/OpenBSDMachine.c
function: getKernelCPUTimes
static void getKernelCPUTimes(unsigned int cpuId, u_int64_t* times) {
const int mib[] = { CTL_KERN, KERN_CPTIME2, cpuId };
size_t length = sizeof(*times) * CPUSTATES;
if (sysctl(mib, 3, times, &length, NULL, 0) == -1 || length != sizeof(*times) * CPUSTATES) {
CRT_fatalError("sysctl kern.cp_time2 failed");
}
}function: kernelCPUTimesToHtop
static void kernelCPUTimesToHtop(const u_int64_t* times, CPUData* cpu) {
unsigned long long totalTime = 0;
for (int i = 0; i < CPUSTATES; i++) {
totalTime += times[i];
}
unsigned long long sysAllTime = times[CP_INTR] + times[CP_SYS];
// XXX Not sure if CP_SPIN should be added to sysAllTime.
// See https://github.com/openbsd/src/commit/531d8034253fb82282f0f353c086e9ad827e031c
#ifdef CP_SPIN
sysAllTime += times[CP_SPIN];
#endif
cpu->totalPeriod = saturatingSub(totalTime, cpu->totalTime);
cpu->userPeriod = saturatingSub(times[CP_USER], cpu->userTime);
cpu->nicePeriod = saturatingSub(times[CP_NICE], cpu->niceTime);
cpu->sysPeriod = saturatingSub(times[CP_SYS], cpu->sysTime);
cpu->sysAllPeriod = saturatingSub(sysAllTime, cpu->sysAllTime);
#ifdef CP_SPIN
cpu->spinPeriod = saturatingSub(times[CP_SPIN], cpu->spinTime);
#endif
cpu->intrPeriod = saturatingSub(times[CP_INTR], cpu->intrTime);
cpu->idlePeriod = saturatingSub(times[CP_IDLE], cpu->idleTime);
cpu->totalTime = totalTime;
cpu->userTime = times[CP_USER];
cpu->niceTime = times[CP_NICE];
cpu->sysTime = times[CP_SYS];
cpu->sysAllTime = sysAllTime;
#ifdef CP_SPIN
cpu->spinTime = times[CP_SPIN];
#endif
cpu->intrTime = times[CP_INTR];
cpu->idleTime = times[CP_IDLE];
}function: Machine_delete
void Machine_delete(Machine* super) {
OpenBSDMachine* this = (OpenBSDMachine*) super;
if (this->kd) {
kvm_close(this->kd);
}
free(this->cpuData);
Machine_done(super);
free(this);
}function: Machine_isCPUonline
bool Machine_isCPUonline(const Machine* super, unsigned int id) {
assert(id < super->existingCPUs);
const OpenBSDMachine* this = (const OpenBSDMachine*) super;
return this->cpuData[id + 1].online;
}function: Machine_new
Machine* Machine_new(UsersTable* usersTable, uid_t userId) {
const int fmib[] = { CTL_KERN, KERN_FSCALE };
size_t size;
char errbuf[_POSIX2_LINE_MAX];
OpenBSDMachine* this = xCalloc(1, sizeof(OpenBSDMachine));
Machine* super = &this->super;
Machine_init(super, usersTable, userId);
OpenBSDMachine_updateCPUcount(this);
size = sizeof(this->fscale);
if (sysctl(fmib, 2, &this->fscale, &size, NULL, 0) < 0 || this->fscale <= 0) {
CRT_fatalError("fscale sysctl call failed");
}
if ((this->pageSize = sysconf(_SC_PAGESIZE)) == -1)
CRT_fatalError("pagesize sysconf call failed");
this->pageSizeKB = this->pageSize / ONE_K;
this->kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf);
if (this->kd == NULL) {
CRT_fatalError("kvm_openfiles() failed");
}
this->cpuSpeed = -1;
return super;
}function: Machine_scan
void Machine_scan(Machine* super) {
OpenBSDMachine* this = (OpenBSDMachine*) super;
OpenBSDMachine_updateCPUcount(this);
OpenBSDMachine_scanMemoryInfo(this);
OpenBSDMachine_scanCPUTime(this);
}function: OpenBSDMachine_scanCPUTime
static void OpenBSDMachine_scanCPUTime(OpenBSDMachine* this) {
Machine* super = &this->super;
u_int64_t kernelTimes[CPUSTATES] = {0};
u_int64_t avg[CPUSTATES] = {0};
for (unsigned int i = 0; i < super->existingCPUs; i++) {
CPUData* cpu = &this->cpuData[i + 1];
if (!cpu->online) {
continue;
}
getKernelCPUTimes(i, kernelTimes);
kernelCPUTimesToHtop(kernelTimes, cpu);
avg[CP_USER] += cpu->userTime;
avg[CP_NICE] += cpu->niceTime;
avg[CP_SYS] += cpu->sysTime;
#ifdef CP_SPIN
avg[CP_SPIN] += cpu->spinTime;
#endif
avg[CP_INTR] += cpu->intrTime;
avg[CP_IDLE] += cpu->idleTime;
}
for (int i = 0; i < CPUSTATES; i++) {
avg[i] /= super->activeCPUs;
}
kernelCPUTimesToHtop(avg, &this->cpuData[0]);
{
const int mib[] = { CTL_HW, HW_CPUSPEED };
int cpuSpeed;
size_t size = sizeof(cpuSpeed);
if (sysctl(mib, 2, &cpuSpeed, &size, NULL, 0) == -1) {
this->cpuSpeed = -1;
} else {
this->cpuSpeed = cpuSpeed;
}
}
}function: OpenBSDMachine_scanMemoryInfo
static void OpenBSDMachine_scanMemoryInfo(OpenBSDMachine* this) {
Machine* super = &this->super;
const int uvmexp_mib[] = { CTL_VM, VM_UVMEXP };
struct uvmexp uvmexp;
size_t size_uvmexp = sizeof(uvmexp);
if (sysctl(uvmexp_mib, 2, &uvmexp, &size_uvmexp, NULL, 0) < 0) {
CRT_fatalError("uvmexp sysctl call failed");
}
super->totalMem = uvmexp.npages * this->pageSizeKB;
super->usedMem = (uvmexp.npages - uvmexp.free - uvmexp.paging) * this->pageSizeKB;
// Taken from OpenBSD systat/iostat.c, top/machine.c and uvm_sysctl(9)
const int bcache_mib[] = { CTL_VFS, VFS_GENERIC, VFS_BCACHESTAT };
struct bcachestats bcstats;
size_t size_bcstats = sizeof(bcstats);
if (sysctl(bcache_mib, 3, &bcstats, &size_bcstats, NULL, 0) < 0) {
CRT_fatalError("cannot get vfs.bcachestat");
}
super->cachedMem = bcstats.numbufpages * this->pageSizeKB;
/*
* Copyright (c) 1994 Thorsten Lockert <tholo@sigmasoft.com>
* All rights reserved.
*
* Taken almost directly from OpenBSD's top(1)
*
* Originally released under a BSD-3 license
* Modified through htop developers applying GPL-2
*/
int nswap = swapctl(SWAP_NSWAP, 0, 0);
if (nswap > 0) {
struct swapent* swdev = xMallocArray(nswap, sizeof(struct swapent));
int rnswap = swapctl(SWAP_STATS, swdev, nswap);
/* Total things up */
unsigned long long int total = 0, used = 0;
for (int i = 0; i < rnswap; i++) {
if (swdev[i].se_flags & SWF_ENABLE) {
used += (swdev[i].se_inuse / (1024 / DEV_BSIZE));
total += (swdev[i].se_nblks / (1024 / DEV_BSIZE));
}
}
super->totalSwap = total;
super->usedSwap = used;
free(swdev);
} else {
super->totalSwap = super->usedSwap = 0;
}
}function: OpenBSDMachine_updateCPUcount
static void OpenBSDMachine_updateCPUcount(OpenBSDMachine* this) {
Machine* super = &this->super;
const int nmib[] = { CTL_HW, HW_NCPU };
const int mib[] = { CTL_HW, HW_NCPUONLINE };
int r;
unsigned int value;
size_t size;
bool change = false;
size = sizeof(value);
r = sysctl(mib, 2, &value, &size, NULL, 0);
if (r < 0 || value < 1) {
value = 1;
}
if (value != super->activeCPUs) {
super->activeCPUs = value;
change = true;
}
size = sizeof(value);
r = sysctl(nmib, 2, &value, &size, NULL, 0);
if (r < 0 || value < 1) {
value = super->activeCPUs;
}
if (value != super->existingCPUs) {
this->cpuData = xReallocArray(this->cpuData, value + 1, sizeof(CPUData));
super->existingCPUs = value;
change = true;
}
if (change) {
CPUData* dAvg = &this->cpuData[0];
memset(dAvg, '\0', sizeof(CPUData));
dAvg->totalTime = 1;
dAvg->totalPeriod = 1;
dAvg->online = true;
for (unsigned int i = 0; i < super->existingCPUs; i++) {
CPUData* d = &this->cpuData[i + 1];
memset(d, '\0', sizeof(CPUData));
d->totalTime = 1;
d->totalPeriod = 1;
const int ncmib[] = { CTL_KERN, KERN_CPUSTATS, i };
struct cpustats cpu_stats;
size = sizeof(cpu_stats);
if (sysctl(ncmib, 3, &cpu_stats, &size, NULL, 0) < 0) {
CRT_fatalError("ncmib sysctl call failed");
}
d->online = (cpu_stats.cs_flags & CPUSTATS_ONLINE);
}
}
}OpenBSDMachine.h
openbsd/OpenBSDMachine.h
struct: CPUData_
typedef struct CPUData_ {
unsigned long long int totalTime;
unsigned long long int userTime;
unsigned long long int niceTime;
unsigned long long int sysTime;
unsigned long long int sysAllTime;
unsigned long long int spinTime;
unsigned long long int intrTime;
unsigned long long int idleTime;
unsigned long long int totalPeriod;
unsigned long long int userPeriod;
unsigned long long int nicePeriod;
unsigned long long int sysPeriod;
unsigned long long int sysAllPeriod;
unsigned long long int spinPeriod;
unsigned long long int intrPeriod;
unsigned long long int idlePeriod;
bool online;
} CPUData;struct: OpenBSDMachine_
typedef struct OpenBSDMachine_ {
Machine super;
kvm_t* kd;
CPUData* cpuData;
long fscale;
int cpuSpeed;
int pageSize;
int pageSizeKB;
} OpenBSDMachine;OpenBSDProcess.c
openbsd/OpenBSDProcess.c
function: OpenBSDProcess_new
Process* OpenBSDProcess_new(const Machine* host) {
OpenBSDProcess* this = xCalloc(1, sizeof(OpenBSDProcess));
Object_setClass(this, Class(OpenBSDProcess));
Process_init(&this->super, host);
return (Process*)this;
}function: Process_delete
void Process_delete(Object* cast) {
OpenBSDProcess* this = (OpenBSDProcess*) cast;
Process_done((Process*)cast);
free(this);
}global variable: OpenBSDProcess_class
const ProcessClass OpenBSDProcess_class = {
.super = {
.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
},
.compareByKey = OpenBSDProcess_compareByKey
};global variable: Process_fields
static function: OpenBSDProcess_compareByKey
static int OpenBSDProcess_compareByKey(const Process* v1, const Process* v2, ProcessField key) {
const OpenBSDProcess* p1 = (const OpenBSDProcess*)v1;
const OpenBSDProcess* p2 = (const OpenBSDProcess*)v2;
// remove if actually used
(void)p1; (void)p2;
switch (key) {
// add OpenBSD-specific fields here
default:
return Process_compareByKey_Base(v1, v2, key);
}
}static function: OpenBSDProcess_rowWriteField
static void OpenBSDProcess_rowWriteField(const Row* super, RichString* str, ProcessField field) {
const OpenBSDProcess* op = (const OpenBSDProcess*) super;
char buffer[256]; buffer[255] = '\0';
int attr = CRT_colors[DEFAULT_COLOR];
//size_t n = sizeof(buffer) - 1;
switch (field) {
// add OpenBSD-specific fields here
default:
Process_writeField(&op->super, str, field);
return;
}
RichString_appendWide(str, attr, buffer);
}OpenBSDProcess.h
openbsd/OpenBSDProcess.h
function: OpenBSDProcess_new
Process* OpenBSDProcess_new(const Machine* host);
function: Process_delete
void Process_delete(Object* cast);
global variable: OpenBSDProcess_class
extern const ProcessClass OpenBSDProcess_class;
global variable: Process_fields
extern const ProcessFieldData Process_fields[LAST_PROCESSFIELD];
struct: OpenBSDProcess
typedef struct OpenBSDProcess_ {
Process super;
/* 'Kernel virtual addr of u-area' to detect main threads */
uint64_t addr;
} OpenBSDProcess;OpenBSDProcessTable.c
openbsd/OpenBSDProcessTable.c
file: OpenBSDProcessTable.c
OpenBSDProcessTable.h
openbsd/OpenBSDProcessTable.h
struct: OpenBSDProcessTable
typedef struct OpenBSDProcessTable_ {
ProcessTable super;
} OpenBSDProcessTable;Platform.c
openbsd/Platform.c
array: Platform_defaultScreens
const ScreenDefaults Platform_defaultScreens[] = {
{
.name = "Main",
.columns = "PID USER PRIORITY NICE M_VIRT M_RESIDENT STATE PERCENT_CPU PERCENT_MEM TIME Command",
.sortKey = "PERCENT_CPU",
},
};array: Platform_meterTypes
const MeterClass* const Platform_meterTypes[] = {
&CPUMeter_class,
&ClockMeter_class,
&DateMeter_class,
&DateTimeMeter_class,
&LoadAverageMeter_class,
&LoadMeter_class,
&MemoryMeter_class,
&SwapMeter_class,
&MemorySwapMeter_class,
&TasksMeter_class,
&UptimeMeter_class,
&BatteryMeter_class,
&HostnameMeter_class,
&SysArchMeter_class,
&AllCPUsMeter_class,
&AllCPUs2Meter_class,
&AllCPUs4Meter_class,
&AllCPUs8Meter_class,
&LeftCPUsMeter_class,
&RightCPUsMeter_class,
&LeftCPUs2Meter_class,
&RightCPUs2Meter_class,
&LeftCPUs4Meter_class,
&RightCPUs4Meter_class,
&LeftCPUs8Meter_class,
&RightCPUs8Meter_class,
&FileDescriptorMeter_class,
&BlankMeter_class,
NULL
};array: Platform_signals
const SignalItem Platform_signals[] = {
{ .name = " 0 Cancel", .number = 0 },
{ .name = " 1 SIGHUP", .number = 1 },
{ .name = " 2 SIGINT", .number = 2 },
{ .name = " 3 SIGQUIT", .number = 3 },
{ .name = " 4 SIGILL", .number = 4 },
{ .name = " 5 SIGTRAP", .number = 5 },
{ .name = " 6 SIGABRT", .number = 6 },
{ .name = " 6 SIGIOT", .number = 6 },
{ .name = " 7 SIGEMT", .number = 7 },
{ .name = " 8 SIGFPE", .number = 8 },
{ .name = " 9 SIGKILL", .number = 9 },
{ .name = "10 SIGBUS", .number = 10 },
{ .name = "11 SIGSEGV", .number = 11 },
{ .name = "12 SIGSYS", .number = 12 },
{ .name = "13 SIGPIPE", .number = 13 },
{ .name = "14 SIGALRM", .number = 14 },
{ .name = "15 SIGTERM", .number = 15 },
{ .name = "16 SIGURG", .number = 16 },
{ .name = "17 SIGSTOP", .number = 17 },
{ .name = "18 SIGTSTP", .number = 18 },
{ .name = "19 SIGCONT", .number = 19 },
{ .name = "20 SIGCHLD", .number = 20 },
{ .name = "21 SIGTTIN", .number = 21 },
{ .name = "22 SIGTTOU", .number = 22 },
{ .name = "23 SIGIO", .number = 23 },
{ .name = "24 SIGXCPU", .number = 24 },
{ .name = "25 SIGXFSZ", .number = 25 },
{ .name = "26 SIGVTALRM", .number = 26 },
{ .name = "27 SIGPROF", .number = 27 },
{ .name = "28 SIGWINCH", .number = 28 },
{ .name = "29 SIGINFO", .number = 29 },
{ .name = "30 SIGUSR1", .number = 30 },
{ .name = "31 SIGUSR2", .number = 31 },
{ .name = "32 SIGTHR", .number = 32 },
};function: findDevice
static bool findDevice(const char* name, int* mib, struct sensordev* snsrdev, size_t* sdlen) {
for (int devn = 0;; devn++) {
mib[2] = devn;
if (sysctl(mib, 3, snsrdev, sdlen, NULL, 0) == -1) {
if (errno == ENXIO)
continue;
if (errno == ENOENT)
return false;
}
if (String_eq(name, snsrdev->xname)) {
return true;
}
}
}function: Platform_done
void Platform_done(void) {
/* no platform-specific cleanup needed */
}function: Platform_getBattery
void Platform_getBattery(double* percent, ACPresence* isOnAC) {
int mib[] = {CTL_HW, HW_SENSORS, 0, 0, 0};
struct sensor s;
size_t slen = sizeof(struct sensor);
struct sensordev snsrdev;
size_t sdlen = sizeof(struct sensordev);
bool found = findDevice("acpibat0", mib, &snsrdev, &sdlen);
*percent = NAN;
if (found) {
/* last full capacity */
mib[3] = 7;
mib[4] = 0;
double last_full_capacity = 0;
if (sysctl(mib, 5, &s, &slen, NULL, 0) != -1)
last_full_capacity = s.value;
if (last_full_capacity > 0) {
/* remaining capacity */
mib[3] = 7;
mib[4] = 3;
if (sysctl(mib, 5, &s, &slen, NULL, 0) != -1) {
double charge = s.value;
*percent = 100 * (charge / last_full_capacity);
if (charge >= last_full_capacity) {
*percent = 100;
}
}
}
}
found = findDevice("acpiac0", mib, &snsrdev, &sdlen);
*isOnAC = AC_ERROR;
if (found) {
mib[3] = 9;
mib[4] = 0;
if (sysctl(mib, 5, &s, &slen, NULL, 0) != -1)
*isOnAC = s.value;
}
}function: Platform_getDiskIO
bool Platform_getDiskIO(DiskIOData* data) {
// TODO
(void)data;
return false;
}function: Platform_getFileDescriptors
void Platform_getFileDescriptors(double* used, double* max) {
static const int mib_kern_maxfile[] = { CTL_KERN, KERN_MAXFILES };
int sysctl_maxfile = 0;
size_t size_maxfile = sizeof(int);
if (sysctl(mib_kern_maxfile, ARRAYSIZE(mib_kern_maxfile), &sysctl_maxfile, &size_maxfile, NULL, 0) < 0) {
*max = NAN;
} else if (size_maxfile != sizeof(int) || sysctl_maxfile < 1) {
*max = NAN;
} else {
*max = sysctl_maxfile;
}
static const int mib_kern_nfiles[] = { CTL_KERN, KERN_NFILES };
int sysctl_nfiles = 0;
size_t size_nfiles = sizeof(int);
if (sysctl(mib_kern_nfiles, ARRAYSIZE(mib_kern_nfiles), &sysctl_nfiles, &size_nfiles, NULL, 0) < 0) {
*used = NAN;
} else if (size_nfiles != sizeof(int) || sysctl_nfiles < 0) {
*used = NAN;
} else {
*used = sysctl_nfiles;
}
}function: Platform_getLoadAverage
void Platform_getLoadAverage(double* one, double* five, double* fifteen) {
struct loadavg loadAverage;
const int mib[2] = { CTL_VM, VM_LOADAVG };
size_t size = sizeof(loadAverage);
int err = sysctl(mib, 2, &loadAverage, &size, NULL, 0);
if (err) {
*one = 0;
*five = 0;
*fifteen = 0;
return;
}
*one = (double) loadAverage.ldavg[0] / loadAverage.fscale;
*five = (double) loadAverage.ldavg[1] / loadAverage.fscale;
*fifteen = (double) loadAverage.ldavg[2] / loadAverage.fscale;
}function: Platform_getMaxPid
pid_t Platform_getMaxPid(void) {
return 2 * THREAD_PID_OFFSET;
}function: Platform_getNetworkIO
bool Platform_getNetworkIO(NetworkIOData* data) {
// TODO
(void)data;
return false;
}function: Platform_getProcessEnv
char* Platform_getProcessEnv(pid_t pid) {
char errbuf[_POSIX2_LINE_MAX];
char* env;
char** ptr;
int count;
kvm_t* kt;
struct kinfo_proc* kproc;
size_t capacity = 4096, size = 0;
if ((kt = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf)) == NULL) {
return NULL;
}
if ((kproc = kvm_getprocs(kt, KERN_PROC_PID, pid,
sizeof(struct kinfo_proc), &count)) == NULL) {
(void) kvm_close(kt);
return NULL;
}
if ((ptr = kvm_getenvv(kt, kproc, 0)) == NULL) {
(void) kvm_close(kt);
return NULL;
}
env = xMalloc(capacity);
for (char** p = ptr; *p; p++) {
size_t len = strlen(*p) + 1;
while (size + len > capacity) {
if (capacity > (SIZE_MAX / 2)) {
free(env);
env = NULL;
goto end;
}
capacity *= 2;
env = xRealloc(env, capacity);
}
strlcpy(env + size, *p, len);
size += len;
}
if (size < 2 || env[size - 1] || env[size - 2]) {
if (size + 2 < capacity)
env = xRealloc(env, capacity + 2);
env[size] = 0;
env[size + 1] = 0;
}
end:
(void) kvm_close(kt);
return env;
}function: Platform_getProcessLocks
FileLocks_ProcessData* Platform_getProcessLocks(pid_t pid) {
(void)pid;
return NULL;
}function: Platform_getUptime
int Platform_getUptime(void) {
struct timeval bootTime, currTime;
const int mib[2] = { CTL_KERN, KERN_BOOTTIME };
size_t size = sizeof(bootTime);
int err = sysctl(mib, 2, &bootTime, &size, NULL, 0);
if (err) {
return -1;
}
gettimeofday(&currTime, NULL);
return (int) difftime(currTime.tv_sec, bootTime.tv_sec);
}function: Platform_init
bool Platform_init(void) {
/* no platform-specific setup needed */
return true;
}function: Platform_setBindings
void Platform_setBindings(Htop_Action* keys) {
/* no platform-specific key bindings */
(void) keys;
}function: Platform_setCPUValues
double Platform_setCPUValues(Meter* this, unsigned int cpu) {
const Machine* host = this->host;
const OpenBSDMachine* ohost = (const OpenBSDMachine*) host;
const CPUData* cpuData = &ohost->cpuData[cpu];
double total;
double totalPercent;
double* v = this->values;
if (!cpuData->online) {
this->curItems = 0;
return NAN;
}
total = cpuData->totalPeriod == 0 ? 1 : cpuData->totalPeriod;
v[CPU_METER_NICE] = cpuData->nicePeriod / total * 100.0;
v[CPU_METER_NORMAL] = cpuData->userPeriod / total * 100.0;
if (host->settings->detailedCPUTime) {
v[CPU_METER_KERNEL] = cpuData->sysPeriod / total * 100.0;
v[CPU_METER_IRQ] = cpuData->intrPeriod / total * 100.0;
v[CPU_METER_SOFTIRQ] = 0.0;
v[CPU_METER_STEAL] = 0.0;
v[CPU_METER_GUEST] = 0.0;
v[CPU_METER_IOWAIT] = 0.0;
v[CPU_METER_FREQUENCY] = NAN;
this->curItems = 8;
} else {
v[CPU_METER_KERNEL] = cpuData->sysAllPeriod / total * 100.0;
v[CPU_METER_IRQ] = 0.0; // No steal nor guest on OpenBSD
this->curItems = 4;
}
totalPercent = v[CPU_METER_NICE] + v[CPU_METER_NORMAL] + v[CPU_METER_KERNEL] + v[CPU_METER_IRQ];
totalPercent = CLAMP(totalPercent, 0.0, 100.0);
v[CPU_METER_TEMPERATURE] = NAN;
v[CPU_METER_FREQUENCY] = (ohost->cpuSpeed != -1) ? ohost->cpuSpeed : NAN;
return totalPercent;
}function: Platform_setMemoryValues
void Platform_setMemoryValues(Meter* this) {
const Machine* host = this->host;
long int usedMem = host->usedMem;
long int buffersMem = host->buffersMem;
long int cachedMem = host->cachedMem;
usedMem -= buffersMem + cachedMem;
this->total = host->totalMem;
this->values[MEMORY_METER_USED] = usedMem;
// this->values[MEMORY_METER_SHARED] = "shared memory, like tmpfs and shm"
// this->values[MEMORY_METER_COMPRESSED] = "compressed memory, like zswap on linux"
this->values[MEMORY_METER_BUFFERS] = buffersMem;
this->values[MEMORY_METER_CACHE] = cachedMem;
// this->values[MEMORY_METER_AVAILABLE] = "available memory"
}function: Platform_setSwapValues
void Platform_setSwapValues(Meter* this) {
const Machine* host = this->host;
this->total = host->totalSwap;
this->values[SWAP_METER_USED] = host->usedSwap;
// this->values[SWAP_METER_CACHE] = "pages that are both in swap and RAM, like SwapCached on linux"
// this->values[SWAP_METER_FRONTSWAP] = "pages that are accounted to swap but stored elsewhere, like frontswap on linux"
}unsigned int: Platform_numberOfDefaultScreens
const unsigned int Platform_numberOfDefaultScreens = ARRAYSIZE(Platform_defaultScreens);
unsigned int: Platform_numberOfSignals
const unsigned int Platform_numberOfSignals = ARRAYSIZE(Platform_signals);
Platform.h
openbsd/Platform.h
function: Platform_addDynamicScreen
static inline void Platform_addDynamicScreen(ATTR_UNUSED ScreenSettings* ss) { }function: Platform_addDynamicScreenAvailableColumns
static inline void Platform_addDynamicScreenAvailableColumns(ATTR_UNUSED Panel* availableColumns, ATTR_UNUSED const char* screen) { }function: Platform_defaultDynamicScreens
static inline void Platform_defaultDynamicScreens(ATTR_UNUSED Settings* settings) { }function: Platform_done
void Platform_done(void);
function: Platform_dynamicColumnName
static inline const char* Platform_dynamicColumnName(ATTR_UNUSED unsigned int key) {
return NULL;
}function: Platform_dynamicColumns
static inline Hashtable* Platform_dynamicColumns(void) {
return NULL;
}function: Platform_dynamicColumnsDone
static inline void Platform_dynamicColumnsDone(ATTR_UNUSED Hashtable* table) { }function: Platform_dynamicColumnWriteField
static inline bool Platform_dynamicColumnWriteField(ATTR_UNUSED const Process* proc, ATTR_UNUSED RichString* str, ATTR_UNUSED unsigned int key) {
return false;
}function: Platform_dynamicMeterDisplay
static inline void Platform_dynamicMeterDisplay(ATTR_UNUSED const Meter* meter, ATTR_UNUSED RichString* out) { }function: Platform_dynamicMeterInit
static inline void Platform_dynamicMeterInit(ATTR_UNUSED Meter* meter) { }function: Platform_dynamicMeters
static inline Hashtable* Platform_dynamicMeters(void) {
return NULL;
}function: Platform_dynamicMetersDone
static inline void Platform_dynamicMetersDone(ATTR_UNUSED Hashtable* table) { }function: Platform_dynamicMeterUpdateValues
static inline void Platform_dynamicMeterUpdateValues(ATTR_UNUSED Meter* meter) { }function: Platform_dynamicScreens
static inline Hashtable* Platform_dynamicScreens(void) {
return NULL;
}function: Platform_dynamicScreensDone
static inline void Platform_dynamicScreensDone(ATTR_UNUSED Hashtable* screens) { }function: Platform_getBattery
void Platform_getBattery(double* percent, ACPresence* isOnAC);
function: Platform_getDiskIO
bool Platform_getDiskIO(DiskIOData* data);
function: Platform_getFileDescriptors
void Platform_getFileDescriptors(double* used, double* max);
function: Platform_getHostname
static inline void Platform_getHostname(char* buffer, size_t size) {
Generic_hostname(buffer, size);
}function: Platform_getLoadAverage
void Platform_getLoadAverage(double* one, double* five, double* fifteen);
function: Platform_getLongOption
static inline CommandLineStatus Platform_getLongOption(ATTR_UNUSED int opt, ATTR_UNUSED int argc, ATTR_UNUSED char** argv) {
return STATUS_ERROR_EXIT;
}function: Platform_getMaxPid
pid_t Platform_getMaxPid(void);
function: Platform_getNetworkIO
bool Platform_getNetworkIO(NetworkIOData* data);
function: Platform_getProcessEnv
char* Platform_getProcessEnv(pid_t pid);
function: Platform_getProcessLocks
FileLocks_ProcessData* Platform_getProcessLocks(pid_t pid);
function: Platform_getRelease
static inline void Platform_getRelease(char** string) {
*string = Generic_uname();
}function: Platform_gettime_monotonic
static inline void Platform_gettime_monotonic(uint64_t* msec) {
Generic_gettime_monotonic(msec);
}function: Platform_gettime_realtime
static inline void Platform_gettime_realtime(struct timeval* tv, uint64_t* msec) {
Generic_gettime_realtime(tv, msec);
}function: Platform_getUptime
int Platform_getUptime(void);
function: Platform_init
bool Platform_init(void);
function: Platform_longOptionsUsage
static inline void Platform_longOptionsUsage(ATTR_UNUSED const char* name) { }function: Platform_setBindings
void Platform_setBindings(Htop_Action* keys);
function: Platform_setCPUValues
double Platform_setCPUValues(Meter* this, unsigned int cpu);
function: Platform_setMemoryValues
void Platform_setMemoryValues(Meter* this);
function: Platform_setSwapValues
void Platform_setSwapValues(Meter* this);
variable: Platform_defaultScreens
extern const ScreenDefaults Platform_defaultScreens[];
variable: Platform_meterTypes
extern const MeterClass* const Platform_meterTypes[];
variable: Platform_numberOfDefaultScreens
extern const unsigned int Platform_numberOfDefaultScreens;
variable: Platform_numberOfSignals
extern const unsigned int Platform_numberOfSignals;
variable: Platform_signals
extern const SignalItem Platform_signals[];
ProcessField.h
openbsd/ProcessField.h
macro: PLATFORM_PROCESS_FIELDS
#define PLATFORM_PROCESS_FIELDS \ // End of list
OpenFilesScreen.c
OpenFilesScreen.c
file: OpenFilesScreen.c
OpenFilesScreen.h
OpenFilesScreen.h
extern variable: OpenFilesScreen_class
extern const InfoScreenClass OpenFilesScreen_class;
function: OpenFilesScreen_delete
void OpenFilesScreen_delete(Object* this);
function: OpenFilesScreen_new
OpenFilesScreen* OpenFilesScreen_new(const Process* process);
struct: OpenFilesScreen_
typedef struct OpenFilesScreen_ {
InfoScreen super;
pid_t pid;
} OpenFilesScreen;OptionItem.c
OptionItem.c
constant: CheckItem_class
const OptionItemClass CheckItem_class = {
.super = {
.extends = Class(OptionItem),
.delete = OptionItem_delete,
.display = CheckItem_display
},
.kind = OPTION_ITEM_CHECK
};constant: NumberItem_class
const OptionItemClass NumberItem_class = {
.super = {
.extends = Class(OptionItem),
.delete = OptionItem_delete,
.display = NumberItem_display
},
.kind = OPTION_ITEM_NUMBER
};constant: OptionItem_class
const OptionItemClass OptionItem_class = {
.super = {
.extends = Class(Object),
.delete = OptionItem_delete
}
};constant: TextItem_class
const OptionItemClass TextItem_class = {
.super = {
.extends = Class(OptionItem),
.delete = OptionItem_delete,
.display = TextItem_display
},
.kind = OPTION_ITEM_TEXT
};function: CheckItem_display
static void CheckItem_display(const Object* cast, RichString* out) {
const CheckItem* this = (const CheckItem*)cast;
assert (this != NULL);
RichString_writeAscii(out, CRT_colors[CHECK_BOX], "[");
if (CheckItem_get(this)) {
RichString_appendAscii(out, CRT_colors[CHECK_MARK], "x");
} else {
RichString_appendAscii(out, CRT_colors[CHECK_MARK], " ");
}
RichString_appendAscii(out, CRT_colors[CHECK_BOX], "] ");
RichString_appendWide(out, CRT_colors[CHECK_TEXT], this->super.text);
}function: CheckItem_get
bool CheckItem_get(const CheckItem* this) {
if (this->ref) {
return *(this->ref);
} else {
return this->value;
}
}function: CheckItem_newByRef
CheckItem* CheckItem_newByRef(const char* text, bool* ref) {
CheckItem* this = AllocThis(CheckItem);
this->super.text = xStrdup(text);
this->value = false;
this->ref = ref;
return this;
}function: CheckItem_newByVal
CheckItem* CheckItem_newByVal(const char* text, bool value) {
CheckItem* this = AllocThis(CheckItem);
this->super.text = xStrdup(text);
this->value = value;
this->ref = NULL;
return this;
}function: CheckItem_set
void CheckItem_set(CheckItem* this, bool value) {
if (this->ref) {
*(this->ref) = value;
} else {
this->value = value;
}
}function: CheckItem_toggle
void CheckItem_toggle(CheckItem* this) {
if (this->ref) {
*(this->ref) = !*(this->ref);
} else {
this->value = !this->value;
}
}function: NumberItem_decrease
void NumberItem_decrease(NumberItem* this) {
if (this->ref) {
*(this->ref) = CLAMP(*(this->ref) - 1, this->min, this->max);
} else {
this->value = CLAMP(this->value - 1, this->min, this->max);
}
}function: NumberItem_display
static void NumberItem_display(const Object* cast, RichString* out) {
const NumberItem* this = (const NumberItem*)cast;
assert (this != NULL);
char buffer[12];
RichString_writeAscii(out, CRT_colors[CHECK_BOX], "[");
int written;
if (this->scale < 0) {
written = xSnprintf(buffer, sizeof(buffer), "%.*f", -this->scale, pow(10, this->scale) * NumberItem_get(this));
} else if (this->scale > 0) {
written = xSnprintf(buffer, sizeof(buffer), "%d", (int) (pow(10, this->scale) * NumberItem_get(this)));
} else {
written = xSnprintf(buffer, sizeof(buffer), "%d", NumberItem_get(this));
}
RichString_appendnAscii(out, CRT_colors[CHECK_MARK], buffer, written);
RichString_appendAscii(out, CRT_colors[CHECK_BOX], "]");
for (int i = written; i < 5; i++) {
RichString_appendAscii(out, CRT_colors[CHECK_BOX], " ");
}
RichString_appendWide(out, CRT_colors[CHECK_TEXT], this->super.text);
}function: NumberItem_get
int NumberItem_get(const NumberItem* this) {
if (this->ref) {
return *(this->ref);
} else {
return this->value;
}
}function: NumberItem_increase
void NumberItem_increase(NumberItem* this) {
if (this->ref) {
*(this->ref) = CLAMP(*(this->ref) + 1, this->min, this->max);
} else {
this->value = CLAMP(this->value + 1, this->min, this->max);
}
}function: NumberItem_newByRef
NumberItem* NumberItem_newByRef(const char* text, int* ref, int scale, int min, int max) {
assert(min <= max);
NumberItem* this = AllocThis(NumberItem);
this->super.text = xStrdup(text);
this->value = 0;
this->ref = ref;
this->scale = scale;
this->min = min;
this->max = max;
return this;
}function: NumberItem_newByVal
NumberItem* NumberItem_newByVal(const char* text, int value, int scale, int min, int max) {
assert(min <= max);
NumberItem* this = AllocThis(NumberItem);
this->super.text = xStrdup(text);
this->value = CLAMP(value, min, max);
this->ref = NULL;
this->scale = scale;
this->min = min;
this->max = max;
return this;
}function: NumberItem_toggle
void NumberItem_toggle(NumberItem* this) {
if (this->ref) {
if (*(this->ref) >= this->max)
*(this->ref) = this->min;
else
*(this->ref) += 1;
} else {
if (this->value >= this->max)
this->value = this->min;
else
this->value += 1;
}
}function: OptionItem_delete
static void OptionItem_delete(Object* cast) {
OptionItem* this = (OptionItem*)cast;
assert (this != NULL);
free(this->text);
free(this);
}function: TextItem_display
static void TextItem_display(const Object* cast, RichString* out) {
const TextItem* this = (const TextItem*)cast;
assert (this != NULL);
RichString_appendWide(out, CRT_colors[HELP_BOLD], this->super.text);
}function: TextItem_new
TextItem* TextItem_new(const char* text) {
TextItem* this = AllocThis(TextItem);
this->super.text = xStrdup(text);
return this;
}OptionItem.h
OptionItem.h
enum: OptionItemType
enum OptionItemType {
OPTION_ITEM_TEXT,
OPTION_ITEM_CHECK,
OPTION_ITEM_NUMBER,
};function: CheckItem_get
bool CheckItem_get(const CheckItem* this);
function: CheckItem_newByRef
CheckItem* CheckItem_newByRef(const char* text, bool* ref);
function: CheckItem_newByVal
CheckItem* CheckItem_newByVal(const char* text, bool value);
function: CheckItem_set
void CheckItem_set(CheckItem* this, bool value);
function: CheckItem_toggle
void CheckItem_toggle(CheckItem* this);
function: NumberItem_decrease
void NumberItem_decrease(NumberItem* this);
function: NumberItem_get
int NumberItem_get(const NumberItem* this);
function: NumberItem_increase
void NumberItem_increase(NumberItem* this);
function: NumberItem_newByRef
NumberItem* NumberItem_newByRef(const char* text, int* ref, int scale, int min, int max);
function: NumberItem_newByVal
NumberItem* NumberItem_newByVal(const char* text, int value, int scale, int min, int max);
function: NumberItem_toggle
void NumberItem_toggle(NumberItem* this);
function: TextItem_new
TextItem* TextItem_new(const char* text);
global object: CheckItem_class
extern const OptionItemClass CheckItem_class;
global object: NumberItem_class
extern const OptionItemClass NumberItem_class;
global object: OptionItem_class
extern const OptionItemClass OptionItem_class;
global object: TextItem_class
extern const OptionItemClass TextItem_class;
macro: As_OptionItem
#define As_OptionItem(this_) ((const OptionItemClass*)((this_)->super.klass))
macro: OptionItem_kind
#define OptionItem_kind(this_) As_OptionItem(this_)->kind
struct: CheckItem
typedef struct CheckItem_ {
OptionItem super;
bool* ref;
bool value;
} CheckItem;struct: CheckItem_
typedef struct CheckItem_ {
OptionItem super;
bool* ref;
bool value;
} CheckItem;struct: NumberItem
typedef struct NumberItem_ {
OptionItem super;
char* text;
int* ref;
int value;
int scale;
int min;
int max;
} NumberItem;struct: NumberItem_
typedef struct NumberItem_ {
OptionItem super;
char* text;
int* ref;
int value;
int scale;
int min;
int max;
} NumberItem;struct: OptionItem
typedef struct OptionItem_ {
Object super;
char* text;
} OptionItem;struct: OptionItem_
typedef struct OptionItem_ {
Object super;
char* text;
} OptionItem;struct: OptionItemClass
typedef struct OptionItemClass_ {
const ObjectClass super;
enum OptionItemType kind;
} OptionItemClass;struct: OptionItemClass_
typedef struct OptionItemClass_ {
const ObjectClass super;
enum OptionItemType kind;
} OptionItemClass;struct: TextItem
typedef struct TextItem_ {
OptionItem super;
char* text;
} TextItem;struct: TextItem_
typedef struct TextItem_ {
OptionItem super;
char* text;
} TextItem;Panel.c
Panel.c
file: Panel.c
Panel.h
Panel.h
enum: HandlerResult_
typedef enum HandlerResult_ {
HANDLED = 0x01,
IGNORED = 0x02,
BREAK_LOOP = 0x04,
REFRESH = 0x08,
REDRAW = 0x10,
RESCAN = 0x20,
RESIZE = 0x40,
SYNTH_KEY = 0x80,
} HandlerResult;function: Panel_add
void Panel_add(Panel* this, Object* o);
function: Panel_delete
void Panel_delete(Object* cast);
function: Panel_done
void Panel_done(Panel* this);
function: Panel_draw
void Panel_draw(Panel* this, bool force_redraw, bool focus, bool highlightSelected, bool hideFunctionBar);
function: Panel_get
Object* Panel_get(Panel* this, int i);
function: Panel_getCh
int Panel_getCh(Panel* this);
function: Panel_getSelected
Object* Panel_getSelected(Panel* this);
function: Panel_getSelectedIndex
int Panel_getSelectedIndex(const Panel* this);
function: Panel_init
void Panel_init(Panel* this, int x, int y, int w, int h, const ObjectClass* type, bool owner, FunctionBar* fuBar);
function: Panel_insert
void Panel_insert(Panel* this, int i, Object* o);
function: Panel_move
void Panel_move(Panel* this, int x, int y);
function: Panel_moveSelectedDown
void Panel_moveSelectedDown(Panel* this);
function: Panel_moveSelectedUp
void Panel_moveSelectedUp(Panel* this);
function: Panel_new
Panel* Panel_new(int x, int y, int w, int h, const ObjectClass* type, bool owner, FunctionBar* fuBar);
function: Panel_onKey
bool Panel_onKey(Panel* this, int key);
function: Panel_prune
void Panel_prune(Panel* this);
function: Panel_remove
Object* Panel_remove(Panel* this, int i);
function: Panel_resize
void Panel_resize(Panel* this, int w, int h);
function: Panel_selectByTyping
HandlerResult Panel_selectByTyping(Panel* this, int ch);
function: Panel_set
void Panel_set(Panel* this, int i, Object* o);
function: Panel_setCursorToSelection
void Panel_setCursorToSelection(Panel* this);
function: Panel_setHeader
void Panel_setHeader(Panel* this, const char* header);
function: Panel_setSelected
void Panel_setSelected(Panel* this, int selected);
function: Panel_setSelectionColor
void Panel_setSelectionColor(Panel* this, ColorElements colorId);
function: Panel_size
int Panel_size(const Panel* this);
function: Panel_splice
void Panel_splice(Panel* this, Vector* from);
macro: As_Panel
#define As_Panel(this_) ((const PanelClass*)((this_)->super.klass))
macro: EVENT_HEADER_CLICK
#define EVENT_HEADER_CLICK(x_) (-10000 + (x_))
macro: EVENT_HEADER_CLICK_GET_X
#define EVENT_HEADER_CLICK_GET_X(ev_) ((ev_) + 10000)
macro: EVENT_IS_HEADER_CLICK
#define EVENT_IS_HEADER_CLICK(ev_) ((ev_) >= -10000 && (ev_) <= -9000)
macro: EVENT_IS_SCREEN_TAB_CLICK
#define EVENT_IS_SCREEN_TAB_CLICK(ev_) ((ev_) >= -20000 && (ev_) < -10000)
macro: EVENT_SCREEN_TAB_CLICK
#define EVENT_SCREEN_TAB_CLICK(x_) (-20000 + (x_))
macro: EVENT_SCREEN_TAB_GET_X
#define EVENT_SCREEN_TAB_GET_X(ev_) ((ev_) + 20000)
macro: EVENT_SET_SELECTED
#define EVENT_SET_SELECTED (-1)
macro: KEY_CTRL
#define KEY_CTRL(l) ((l)-'A'+1)
macro: Panel_drawFunctionBar
#define Panel_drawFunctionBar(this_, hideFB_) (assert(As_Panel(this_)->drawFunctionBar), As_Panel(this_)->drawFunctionBar((Panel*)(this_), hideFB_))
macro: Panel_drawFunctionBarFn
#define Panel_drawFunctionBarFn(this_) As_Panel(this_)->drawFunctionBar
macro: Panel_eventHandler
#define Panel_eventHandler(this_, ev_) (assert(As_Panel(this_)->eventHandler), As_Panel(this_)->eventHandler((Panel*)(this_), ev_))
macro: Panel_eventHandlerFn
#define Panel_eventHandlerFn(this_) As_Panel(this_)->eventHandler
macro: Panel_printHeader
#define Panel_printHeader(this_) (assert(As_Panel(this_)->printHeader), As_Panel(this_)->printHeader((Panel*)(this_)))
macro: Panel_printHeaderFn
#define Panel_printHeaderFn(this_) As_Panel(this_)->printHeader
macro: Panel_setDefaultBar
#define Panel_setDefaultBar(this_) do { (this_)->currentBar = (this_)->defaultBar; } while (0)struct: Panel_
struct Panel_ {
Object super;
int x, y, w, h;
int cursorX, cursorY;
Vector* items;
int selected;
int oldSelected;
int selectedLen;
void* eventHandlerState;
int scrollV;
int scrollH;
bool needsRedraw;
bool cursorOn;
bool wasFocus;
FunctionBar* currentBar;
FunctionBar* defaultBar;
RichString header;
ColorElements selectionColorId;
};struct: Panel_
struct Panel_;
struct: PanelClass_
typedef struct PanelClass_ {
const ObjectClass super;
const Panel_EventHandler eventHandler;
const Panel_DrawFunctionBar drawFunctionBar;
const Panel_PrintHeader printHeader;
} PanelClass;typedef: Panel
typedef struct Panel_ Panel;
typedef: Panel_DrawFunctionBar
typedef void (*Panel_DrawFunctionBar)(Panel*, bool);
typedef: Panel_EventHandler
typedef HandlerResult (*Panel_EventHandler)(Panel*, int);
typedef: Panel_PrintHeader
typedef void (*Panel_PrintHeader)(Panel*);
variable: Panel_class
extern const PanelClass Panel_class;
pcp-htop.5.in
pcp-htop.5.in
file: pcp-htop.5.in
pcp-htop.c
pcp-htop.c
function: main
int main(int argc, char** argv) {
pmSetProgname(program);
/* extract environment variables */
opts.flags |= PM_OPTFLAG_ENV_ONLY;
(void)pmGetOptions(argc, argv, &opts);
return CommandLine_run(argc, argv);
}variable: program
const char* program = "pcp-htop";
container
pcp/columns/container
file: container
# # pcp-htop(1) configuration file - see pcp-htop(5) # [container] heading = Container caption = CONTAINER width = -12 metric = proc.id.container description = Name of processes container via cgroup heuristics
delayacct
pcp/columns/delayacct
file: delayacct
# # pcp-htop(1) configuration file - see pcp-htop(5) # [blkio] heading = BLKIOD caption = BLKIO_TIME width = 6 metric = proc.psinfo.delayacct_blkio_time description = Aggregated block I/O delays
fdcount
pcp/columns/fdcount
file: fdcount
# # pcp-htop(1) configuration file - see pcp-htop(5) # [fds] heading = FDS caption = FDCOUNT width = 4 metric = proc.fd.count description = Open file descriptors
gpu_memory
pcp/columns/gpu_memory
file: gpu_memory
guest
pcp/columns/guest
file: guest
# # pcp-htop(1) configuration file - see pcp-htop(5) # [guest] heading = GUEST caption = GUEST_TIME width = 6 metric = proc.psinfo.guest_time description = Guest time for the process [cguest] heading = CGUEST caption = CGUEST_TIME width = 6 metric = proc.psinfo.guest_time + proc.psinfo.cguest_time description = Cumulative guest time for the process and its children
memory
pcp/columns/memory
file: memory
# # pcp-htop(1) configuration file - see pcp-htop(5) # [vmdata] heading = VDATA width = 6 metric = proc.memory.vmdata description = Virtual memory used for data [vmstack] heading = VSTACK width = -6 metric = proc.memory.vmstack description = Virtual memory used for stack [vmexe] heading = VEXEC width = 6 metric = proc.memory.vmexe description = Virtual memory used for non-library executable code [vmlib] heading = VLIBS width = 6 metric = proc.memory.vmlib description = Virtual memory used for libraries [vmswap] heading = VSWAP width = 6 metric = proc.memory.vmswap description = Virtual memory size currently swapped out [vmlock] heading = VLOCK width = 6 metric = proc.memory.vmlock description = Locked virtual memory
sched
pcp/columns/sched
file: sched
# # pcp-htop(1) configuration file - see pcp-htop(5) # [rundelay] heading = RUNQ caption = RUN_DELAY width = 4 metric = proc.schedstat.run_delay description = Run queue time
swap
pcp/columns/swap
file: swap
# # pcp-htop(1) configuration file - see pcp-htop(5) # [swap] heading = SWAP width = 5 metric = proc.psinfo.nswap description = Count of swap operations for the process [cswap] heading = CSWAP width = 5 metric = proc.psinfo.nswap + proc.psinfo.cnswap description = Cumulative swap operations for the process and its children
tcp
pcp/columns/tcp
file: tcp
# # pcp-htop(1) configuration file - see pcp-htop(5) # [tcp_send_packets] heading = TCPS caption = TCP_SEND width = 6 metric = bpf.proc.net.tcp.send.packets description = Count of TCP packets sent [tcp_send_bytes] heading = TCPSB caption = TCP_SEND_BYTES width = 6 metric = bpf.proc.net.tcp.send.bytes description = Cumulative bytes sent via TCP [tcp_recv_packets] heading = TCPR caption = TCP_RECV width = 6 metric = bpf.proc.net.tcp.recv.packets description = Count of TCP packets received [tcp_recv_bytes] heading = TCPRB caption = TCP_RECV_BYTES width = 6 metric = bpf.proc.net.tcp.recv.bytes description = Cumulative bytes received via TCP
udp
pcp/columns/udp
file: udp
# # pcp-htop(1) configuration file - see pcp-htop(5) # [udp_send_packets] heading = UDPS caption = UDP_SEND width = 6 metric = bpf.proc.net.udp.send.packets description = Count of UDP packets sent [udp_send_bytes] heading = UDPSB caption = UDP_SEND_BYTES width = 6 metric = bpf.proc.net.udp.send.bytes description = Cumulative bytes sent via UDP [udp_recv_packets] heading = UDPR caption = UDP_RECV width = 6 metric = bpf.proc.net.udp.recv.packets description = Count of UDP packets received [udp_recv_bytes] heading = UDPRB caption = UDP_RECV_BYTES width = 6 metric = bpf.proc.net.udp.recv.bytes description = Cumulative bytes received via UDP
wchan
pcp/columns/wchan
file: wchan
# # pcp-htop(1) configuration file - see pcp-htop(5) # [wchan] heading = WCHAN caption = WCHAN_ADDRESS width = 8 metric = proc.psinfo.wchan description = Wait channel, kernel address process is blocked or sleeping on [wchans] heading = WCHANS caption = WCHAN_SYMBOL width = -12 metric = proc.psinfo.wchan_s description = Wait channel, kernel symbol process is blocked or sleeping on
InDomTable.c
pcp/InDomTable.c
function: InDomTable_delete
static void InDomTable_delete(Object* cast) {
InDomTable* this = (InDomTable*) cast;
InDomTable_done(this);
free(this);
}function: InDomTable_done
void InDomTable_done(InDomTable* this) {
Table_done(&this->super);
}function: InDomTable_getInstance
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;
}function: InDomTable_goThroughEntries
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 = (Row*) inst;
if (!preExisting)
Table_add(super, row);
row->updated = true;
row->show = true;
}
}function: InDomTable_iterateEntries
static void InDomTable_iterateEntries(Table* super) {
InDomTable* this = (InDomTable*) super;
InDomTable_goThroughEntries(this);
}function: InDomTable_new
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;
}struct: InDomTable_class
const TableClass InDomTable_class = {
.super = {
.extends = Class(Table),
.delete = InDomTable_delete,
},
.prepare = Table_prepareEntries,
.iterate = InDomTable_iterateEntries,
.cleanup = Table_cleanupEntries,
};InDomTable.h
pcp/InDomTable.h
function: InDomTable_done
void InDomTable_done(InDomTable* this);
function: InDomTable_new
InDomTable* InDomTable_new(Machine* host, pmInDom indom, int metricKey);
function: InDomTable_scan
void InDomTable_scan(Table* super);
function: RowField_keyAt
RowField RowField_keyAt(const Settings* settings, int at);
struct: InDomTable
typedef struct InDomTable_ {
Table super;
pmInDom id; /* shared by metrics in the table */
unsigned int metricKey; /* representative metric using this indom */
} InDomTable;variable: InDomTable_class
extern const TableClass InDomTable_class;
Instance.c
pcp/Instance.c
function: Instance_compare
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;
}function: Instance_compareByKey
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;
}function: Instance_delete
static void Instance_delete(Object* cast) {
Instance* this = (Instance*) cast;
Instance_done(this);
free(this);
}function: Instance_done
void Instance_done(Instance* this) {
if (this->name)
free(this->name);
Row_done(&this->super);
}function: Instance_externalName
static const char* Instance_externalName(Row* super) {
Instance* this = (Instance*) super;
if (!this->name)
/* ignore any failure here - its safe and we try again next time */
(void)pmNameInDom(InDom_getId(this), Instance_getId(this), &this->name);
return this->name;
}function: Instance_new
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;
}function: Instance_writeField
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;
if (!cp)
return;
pmAtomValue atom;
pmAtomValue* ap = &atom;
const pmDesc* descp = Metric_desc(cp->id);
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);
}global constant struct initialization: Instance_class
const RowClass Instance_class = {
.super = {
.extends = Class(Row),
.display = Row_display,
.delete = Instance_delete,
.compare = Instance_compare,
},
.sortKeyString = Instance_externalName,
.writeField = Instance_writeField,
};Instance.h
pcp/Instance.h
extern const variable: Instance_class
extern const RowClass Instance_class;
function: Instance_done
void Instance_done(Instance* this);
function: Instance_new
Instance* Instance_new(const Machine* host, const struct InDomTable_* indom);
macro: InDom_getId
#define InDom_getId(i_) ((i_)->indom->id)
macro: Instance_getId
#define Instance_getId(i_) ((i_)->super.id)
macro: Instance_setId
#define Instance_setId(i_, id_) ((i_)->super.id = (id_))
struct: Instance_
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;typedef: Instance
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;entropy
pcp/meters/entropy
file: entropy
# # pcp-htop(1) configuration file - see pcp-htop(5) # [entropy] caption = Entropy description = Entropy pool avail.metric = kernel.all.entropy.avail / kernel.all.entropy.poolsize * 100 avail.label = avail avail.suffix = %
freespace
pcp/meters/freespace
file: freespace
# # pcp-htop(1) configuration file - see pcp-htop(5) # [freespace] caption = Freespace description = Filesystem space used.metric = sum(filesys.used) used.color = blue free.metric = sum(filesys.free) free.color = green
gpu
pcp/meters/gpu
file: gpu
# # pcp-htop(1) configuration file - see pcp-htop(5) # [amd_gpu_load] caption = AMD GPU load description = AMD GPU load load.metric = amdgpu.gpu.load load.suffix = % [amd_gpu_average_power] caption = AMD GPU average power description = AMD GPU average power in Watts average_power.metric = amdgpu.gpu.average_power average_power.suffix = W [amd_gpu_memory] type = bar caption = AMD GPU memory description = Allocated frame buffer memory used.metric = amdgpu.memory.used used.color = red total.metric = amdgpu.memory.total total.color: blue [amd_gpu_clock] caption = AMD GPU clock description = The GPU clock speed in MHz clock.metric = amdgpu.gpu.clock clock.label = MHz [amd_gpu_memory_clock] caption = AMD GPU memory clock description = The GDDRx memory clock speed in MHz clock.metric = amdgpu.memory.clock clock.label = MHz [amd_gpu_temp] caption = AMD GPU temperature description = The GPU temperature in degrees Celsius temp.metric = amdgpu.gpu.temperature / 1000 temp.label = °C
ipc
pcp/meters/ipc
file: ipc
# # pcp-htop(1) configuration file - see pcp-htop(5) # [ipc] caption = SysV IPC description = SysV IPC counts msg.metric = ipc.msg.used_queues msg.color = blue sem.metric = ipc.sem.used_sem sem.color = green shm.metric = ipc.shm.used_ids shm.color = cyan
locks
pcp/meters/locks
file: locks
# # pcp-htop(1) configuration file - see pcp-htop(5) # [locks] caption = File locks description = VFS file locks posix.metric = vfs.locks.posix.count posix.color = blue flock.metric = vfs.locks.flock.count flock.color = green readlock.metric = vfs.locks.posix.read + vfs.locks.flock.read readlock.color = red writelock.metric = vfs.locks.posix.write + vfs.locks.flock.write writelock.color = yellow
memcache
pcp/meters/memcache
file: memcache
# # pcp-htop(1) configuration file - see pcp-htop(5) # [memcache] caption = Memcache description = Memcache Hits hit.metric = sum(memcache.hits) hit.color = green miss.metric = sum(memcache.misses) miss.color = blue
mysql
pcp/meters/mysql
file: mysql
# # pcp-htop(1) configuration file - see pcp-htop(5) # [mysql_io] caption = MySQL I/O description = MySQL throughput recv.metric = mysql.status.bytes_received recv.color = green sent.metric = mysql.status.bytes_sent sent.color = blue [mysql_keys] caption = MySQL keys description = MySQL key status key_blocks_used.metric = mysql.status.key_blocks_used key_blocks_used.color = yellow key_blocks_used.label = used key_reads.metric = mysql.status.key_reads key_reads.label = read key_reads.color = green key_writes.metric = mysql.status.key_writes key_writes.label = writ key_writes.color = blue key_read_requests.metric = mysql.status.key_read_requests key_read_requests.label = rreq key_read_requests.color = green key_write_requests.metric = mysql.status.key_write_requests key_write_requests.label = wreq key_write_requests.color = blue [innodb_buffer] caption = InnoDB pool description = InnoDB buffer pool created.metric = mysql.status.innodb_pages_created created.label = cr created.color = yellow read.metric = mysql.status.innodb_pages_read read.label = rd read.color = green written.metric = mysql.status.innodb_pages_written written.label = wr written.color = red [innodb_io] caption = InnoDB I/O description = InnoDB I/O operations read.metric = mysql.status.innodb_data_read read.label = rd read.color = green written.metric = mysql.status.innodb_data.writes written.label = wr written.color = blue sync.metric = mysql.status.innodb_data_fsyncs sync.label = sync sync.color = cyan [innodb_ops] caption = InnoDB ops description = InnoDB operations inserted.metric = mysql.status.innodb_rows_inserted inserted.label = ins inserted.color = blue updated.metric = mysql.status.innodb_rows_updated updated.label = upd updated.color = cyan deleted.metric = mysql.status.innodb_rows_deleted deleted.label = del deleted.color = red read.metric = mysql.status.innodb_rows_read read.label = rd read.color = green
postfix
pcp/meters/postfix
file: postfix
# # pcp-htop(1) configuration file - see pcp-htop(5) # [postfix] caption = Postfix incoming.metric = sum(postfix.queues.incoming) incoming.color = green incoming.label = in active.metric = sum(postfix.queues.active) active.color = blue active.label = act deferred.metric = sum(postfix.queues.deferred) deferred.color = cyan deferred.label = dfr bounce.metric = sum(postfix.queues.maildrop) bounce.color = red bounce.label = bnc hold.metric = sum(postfix.queues.hold) hold.color = yellow
redis
pcp/meters/redis
file: redis
# # pcp-htop(1) configuration file - see pcp-htop(5) # [redisxact] caption = Redis xact description = Redis transactions tps.metric = redis.instantaneous_ops_per_sec tps.color = green [redismem] caption = Redis mem description = Redis memory lua.metric = redis.used_memory_lua lua.color = magenta used.metric = redis.used_memory used.color = blue [redisclient] caption = Redis clients description = Redis clients type = bar blocked.metric = redis.blocked_clients blocked.color = blue blocked.label = blk clients.metric = redis.connected_clients clients.color = green clients.label = conn [redisconn] caption = Redis conn description = Redis connections type = bar reject.metric = redis.rejected_connections reject.color = magenta reject.label = fail/s total.metric = redis.total_connections_received total.color = blue total.label = conn/s
tcp
pcp/meters/tcp
file: tcp
# # pcp-htop(1) configuration file - see pcp-htop(5) # [tcp] caption = TCP description = TCP sockets listen.metric = network.tcpconn.listen listen.color = green listen.label = lis active.metric = network.tcpconn.established active.color = blue active.label = act syn.metric = network.tcpconn.syn_sent + network.tcpconn.syn_recv + network.tcpconn.last_ack syn.color = cyan wait.metric = network.tcpconn.time_wait wait.color = red wait.label = tim close.metric = network.tcpconn.fin_wait1 + network.tcpconn.fin_wait2 + network.tcpconn.close + network.tcpconn.close_wait + network.tcpconn.closing close.color = yellow close.label = clo
Metric.c
pcp/Metric.c
function: Metric_desc
const pmDesc* Metric_desc(Metric metric) {
return &pcp->descs[metric];
}function: Metric_enable
void Metric_enable(Metric metric, bool enable) {
pcp->fetch[metric] = enable ? pcp->pmids[metric] : PM_ID_NULL;
}function: Metric_enabled
bool Metric_enabled(Metric metric) {
return pcp->fetch[metric] != PM_ID_NULL;
}function: Metric_enableThreads
void Metric_enableThreads(void) {
pmValueSet* vset = xCalloc(1, sizeof(pmValueSet));
vset->vlist[0].inst = PM_IN_NULL;
vset->vlist[0].value.lval = 1;
vset->valfmt = PM_VAL_INSITU;
vset->numval = 1;
vset->pmid = pcp->pmids[PCP_CONTROL_THREADS];
pmResult* result = xCalloc(1, sizeof(pmResult));
result->vset[0] = vset;
result->numpmid = 1;
int sts = pmStore(result);
if (sts < 0 && pmDebugOptions.appl0)
fprintf(stderr, "Error: cannot enable threads: %s\n", pmErrStr(sts));
pmFreeResult(result);
}function: Metric_externalName
void Metric_externalName(Metric metric, int inst, char** externalName) {
const pmDesc* desc = &pcp->descs[metric];
/* ignore a failure here - its safe to do so */
(void)pmNameInDom(desc->indom, inst, externalName);
}function: Metric_extract
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];
const pmValue* value = &vset->vlist[offset];
int sts = pmExtractValue(vset->valfmt, value, desc->type, atom, type);
if (sts < 0) {
if (pmDebugOptions.appl0)
fprintf(stderr, "Error: cannot extract %s instance %d value: %s\n",
pcp->names[metric], inst, pmErrStr(sts));
memset(atom, 0, sizeof(pmAtomValue));
}
return atom;
}function: Metric_fetch
bool Metric_fetch(struct timeval* timestamp) {
if (pcp->result) {
pmFreeResult(pcp->result);
pcp->result = NULL;
}
int sts, count = 0;
do {
sts = pmFetch(pcp->totalMetrics, pcp->fetch, &pcp->result);
} while (sts == PM_ERR_IPC && ++count < 3);
if (sts < 0) {
if (pmDebugOptions.appl0)
fprintf(stderr, "Error: cannot fetch metric values: %s\n",
pmErrStr(sts));
return false;
}
if (timestamp)
*timestamp = pcp->result->timestamp;
return true;
}function: Metric_instance
pmAtomValue* Metric_instance(Metric metric, int inst, int offset, pmAtomValue* atom, int type) {
pmValueSet* vset = pcp->result->vset[metric];
if (!vset || vset->numval <= 0)
return NULL;
/* fast-path using heuristic offset based on expected location */
if (offset >= 0 && offset < vset->numval && inst == vset->vlist[offset].inst)
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 Metric_extract(metric, inst, i, vset, atom, type);
}
return NULL;
}function: Metric_instanceCount
int Metric_instanceCount(Metric metric) {
pmValueSet* vset = pcp->result->vset[metric];
if (vset)
return vset->numval;
return 0;
}function: Metric_instanceOffset
int Metric_instanceOffset(Metric metric, int inst) {
pmValueSet* vset = pcp->result->vset[metric];
if (!vset || vset->numval <= 0)
return 0;
/* search for optimal offset for subsequent inst lookups to begin */
for (int i = 0; i < vset->numval; i++) {
if (inst == vset->vlist[i].inst)
return i;
}
return 0;
}function: Metric_iterate
bool Metric_iterate(Metric metric, int* instp, int* offsetp) {
if (!pcp->result)
return false;
pmValueSet* vset = pcp->result->vset[metric];
if (!vset || vset->numval <= 0)
return false;
int offset = *offsetp;
offset = (offset < 0) ? 0 : offset + 1;
if (offset > vset->numval - 1)
return false;
*offsetp = offset;
*instp = vset->vlist[offset].inst;
return true;
}function: Metric_lookupText
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;
}function: Metric_type
int Metric_type(Metric metric) {
return pcp->descs[metric].type;
}function: Metric_values
pmAtomValue* Metric_values(Metric metric, pmAtomValue* atom, int count, int type) {
if (pcp->result == NULL)
return NULL;
pmValueSet* vset = pcp->result->vset[metric];
if (!vset || vset->numval <= 0)
return NULL;
/* extract requested number of values as requested type */
const pmDesc* desc = &pcp->descs[metric];
for (int i = 0; i < vset->numval; i++) {
if (i == count)
break;
const pmValue* value = &vset->vlist[i];
int sts = pmExtractValue(vset->valfmt, value, desc->type, &atom[i], type);
if (sts < 0) {
if (pmDebugOptions.appl0)
fprintf(stderr, "Error: cannot extract metric value: %s\n",
pmErrStr(sts));
memset(&atom[i], 0, sizeof(pmAtomValue));
}
}
return atom;
}Metric.h
pcp/Metric.h
enum: Metric
function: Metric_desc
const pmDesc* Metric_desc(Metric metric);
function: Metric_enable
void Metric_enable(Metric metric, bool enable);
function: Metric_enabled
bool Metric_enabled(Metric metric);
function: Metric_enableThreads
void Metric_enableThreads(void);
function: Metric_externalName
void Metric_externalName(Metric metric, int inst, char** externalName);
function: Metric_fetch
bool Metric_fetch(struct timeval* timestamp);
function: Metric_instance
pmAtomValue* Metric_instance(Metric metric, int inst, int offset, pmAtomValue* atom, int type);
function: Metric_instanceCount
int Metric_instanceCount(Metric metric);
function: Metric_instanceOffset
int Metric_instanceOffset(Metric metric, int inst);
function: Metric_iterate
bool Metric_iterate(Metric metric, int* instp, int* offsetp);
function: Metric_lookupText
int Metric_lookupText(const char* metric, char** desc);
function: Metric_type
int Metric_type(Metric metric);
function: Metric_values
pmAtomValue* Metric_values(Metric metric, pmAtomValue* atom, int count, int type);
PCPDynamicColumn.c
pcp/PCPDynamicColumn.c
function: PCPDynamicColumn_addMetric
static bool PCPDynamicColumn_addMetric(PCPDynamicColumns* columns, PCPDynamicColumn* column) {
if (!column->super.name[0])
return false;
char* metricName = NULL;
xAsprintf(&metricName, "htop.column.%s", column->super.name);
column->metricName = metricName;
column->id = columns->offset + columns->cursor;
columns->cursor++;
Platform_addMetric(column->id, metricName);
return true;
}function: PCPDynamicColumn_compareByKey
int PCPDynamicColumn_compareByKey(const PCPProcess* p1, const PCPProcess* p2, ProcessField 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 = Metric_type(metric);
pmAtomValue atom1 = {0}, atom2 = {0};
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);
}
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 compareRealNumbers(atom2.f, atom1.f);
case PM_TYPE_DOUBLE:
return compareRealNumbers(atom2.d, atom1.d);
default:
break;
}
return -1;
}function: PCPDynamicColumn_done
void PCPDynamicColumn_done(PCPDynamicColumn* this) {
DynamicColumn_done(&this->super);
free(this->metricName);
free(this->format);
}function: PCPDynamicColumn_new
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);
columns->count++;
return column;
}function: PCPDynamicColumn_normalize
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_32:
*value = (double) atom.l;
break;
case PM_TYPE_U32:
*value = (double) atom.ul;
break;
case PM_TYPE_64:
*value = (double) atom.ll;
break;
case PM_TYPE_U64:
*value = (double) atom.ull;
break;
case PM_TYPE_FLOAT:
*value = (double) atom.f;
break;
case PM_TYPE_DOUBLE:
*value = atom.d;
break;
default:
return PM_ERR_CONV;
}
return 0;
}function: PCPDynamicColumn_parseFile
function: PCPDynamicColumn_parseMetric
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;
/* derived metrics in all dynamic columns for simplicity */
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);
}
}function: PCPDynamicColumn_scanDir
static void PCPDynamicColumn_scanDir(PCPDynamicColumns* columns, 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);
PCPDynamicColumn_parseFile(columns, file);
free(file);
}
closedir(dir);
}function: PCPDynamicColumn_setupWidth
static void PCPDynamicColumn_setupWidth(ATTR_UNUSED ht_key_t key, void* value, ATTR_UNUSED void* data) {
PCPDynamicColumn* column = (PCPDynamicColumn*) value;
/* 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;
}
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;
}
}
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
}function: PCPDynamicColumn_uniqueName
static bool PCPDynamicColumn_uniqueName(char* key, PCPDynamicColumns* columns) {
return DynamicColumn_search(columns->table, key, NULL) == NULL;
}function: PCPDynamicColumn_validateColumnName
static bool PCPDynamicColumn_validateColumnName(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 column 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 column name at %s line %u\n\"%s\"",
pmGetProgname(), path, line, key);
return false;
}
return true;
}function: PCPDynamicColumn_writeAtomValue
function: PCPDynamicColumn_writeField
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);
}function: PCPDynamicColumns_done
void PCPDynamicColumns_done(Hashtable* table) {
Hashtable_foreach(table, PCPDynamicColumns_free, NULL);
}function: PCPDynamicColumns_free
static void PCPDynamicColumns_free(ATTR_UNUSED ht_key_t key, void* value, ATTR_UNUSED void* data) {
PCPDynamicColumn* column = (PCPDynamicColumn*) value;
PCPDynamicColumn_done(column);
}function: PCPDynamicColumns_init
void PCPDynamicColumns_init(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;
if (!xdgConfigHome && !home) {
const struct passwd* pw = getpwuid(getuid());
if (pw)
home = pw->pw_dir;
}
columns->table = Hashtable_new(0, true);
/* developer paths - PCP_HTOP_DIR=./pcp ./pcp-htop */
if (override) {
path = String_cat(override, "/columns/");
PCPDynamicColumn_scanDir(columns, path);
free(path);
}
/* next, search in home directory alongside htoprc */
if (xdgConfigHome)
path = String_cat(xdgConfigHome, "/htop/columns/");
else if (home)
path = String_cat(home, CONFIGDIR "/htop/columns/");
else
path = NULL;
if (path) {
PCPDynamicColumn_scanDir(columns, path);
free(path);
}
/* next, search in the system columns directory */
path = String_cat(sysconf, "/htop/columns/");
PCPDynamicColumn_scanDir(columns, path);
free(path);
/* next, try the readonly system columns directory */
path = String_cat(share, "/htop/columns/");
PCPDynamicColumn_scanDir(columns, path);
free(path);
}function: PCPDynamicColumns_setupWidths
void PCPDynamicColumns_setupWidths(PCPDynamicColumns* columns) {
Hashtable_foreach(columns->table, PCPDynamicColumn_setupWidth, NULL);
}PCPDynamicColumn.h
pcp/PCPDynamicColumn.h
function: PCPDynamicColumn_compareByKey
int PCPDynamicColumn_compareByKey(const PCPProcess* p1, const PCPProcess* p2, ProcessField key);
function: PCPDynamicColumn_done
void PCPDynamicColumn_done(PCPDynamicColumn* this);
function: PCPDynamicColumn_writeAtomValue
void PCPDynamicColumn_writeAtomValue(PCPDynamicColumn* column, RichString* str, const struct Settings_* settings, int metric, int instance, const struct pmDesc* desc, const void* atomvalue);
function: PCPDynamicColumn_writeField
void PCPDynamicColumn_writeField(PCPDynamicColumn* this, const Process* proc, RichString* str);
function: PCPDynamicColumns_done
void PCPDynamicColumns_done(Hashtable* table);
function: PCPDynamicColumns_init
void PCPDynamicColumns_init(PCPDynamicColumns* columns);
function: PCPDynamicColumns_setupWidths
void PCPDynamicColumns_setupWidths(PCPDynamicColumns* columns);
struct: PCPDynamicColumn_
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;struct: PCPDynamicColumns_
typedef struct PCPDynamicColumns_ {
Hashtable* table;
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;PCPDynamicMeter.c
pcp/PCPDynamicMeter.c
function: PCPDynamicMeter_display
function: PCPDynamicMeter_enable
void PCPDynamicMeter_enable(PCPDynamicMeter* this) {
for (size_t i = 0; i < this->totalMetrics; i++)
Metric_enable(this->metrics[i].id, true);
}function: PCPDynamicMeter_free
static void PCPDynamicMeter_free(ATTR_UNUSED ht_key_t key, void* value, ATTR_UNUSED void* data) {
PCPDynamicMeter* meter = (PCPDynamicMeter*) value;
for (size_t i = 0; i < meter->totalMetrics; i++) {
free(meter->metrics[i].name);
free(meter->metrics[i].label);
free(meter->metrics[i].suffix);
}
free(meter->metrics);
free(meter->super.caption);
free(meter->super.description);
}function: PCPDynamicMeter_lookupMetric
static PCPDynamicMetric* PCPDynamicMeter_lookupMetric(PCPDynamicMeters* meters, PCPDynamicMeter* meter, const char* name) {
char* metricName = NULL;
xAsprintf(&metricName, "htop.meter.%s.%s", meter->super.name, name);
PCPDynamicMetric* metric;
for (size_t i = 0; i < meter->totalMetrics; i++) {
metric = &meter->metrics[i];
if (String_eq(metric->name, metricName)) {
free(metricName);
return metric;
}
}
/* not an existing metric in this meter - add it */
size_t n = meter->totalMetrics + 1;
meter->metrics = xReallocArray(meter->metrics, n, sizeof(PCPDynamicMetric));
meter->totalMetrics = n;
metric = &meter->metrics[n - 1];
memset(metric, 0, sizeof(PCPDynamicMetric));
metric->name = metricName;
metric->label = String_cat(name, ": ");
metric->id = meters->offset + meters->cursor;
meters->cursor++;
Platform_addMetric(metric->id, metricName);
return metric;
}function: PCPDynamicMeter_new
static PCPDynamicMeter* PCPDynamicMeter_new(PCPDynamicMeters* meters, const char* name) {
PCPDynamicMeter* meter = xCalloc(1, sizeof(*meter));
String_safeStrncpy(meter->super.name, name, sizeof(meter->super.name));
Hashtable_put(meters->table, ++meters->count, meter);
return meter;
}function: PCPDynamicMeter_parseFile
function: PCPDynamicMeter_parseMetric
function: PCPDynamicMeter_scanDir
static void PCPDynamicMeter_scanDir(PCPDynamicMeters* meters, 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);
PCPDynamicMeter_parseFile(meters, file);
free(file);
}
closedir(dir);
}function: PCPDynamicMeter_uniqueName
// Ensure a meter name has not been defined previously
static bool PCPDynamicMeter_uniqueName(char* key, PCPDynamicMeters* meters) {
return !DynamicMeter_search(meters->table, key, NULL);
}function: PCPDynamicMeter_updateValues
function: PCPDynamicMeter_validateMeterName
// Ensure a valid name for use in a PCP metric name and in htoprc
static bool PCPDynamicMeter_validateMeterName(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 meter name at %s line %u\n\"%s\"\n",
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 meter name at %s line %u\n\"%s\"\n",
pmGetProgname(), path, line, key);
return false;
}
return true;
}function: PCPDynamicMeters_done
void PCPDynamicMeters_done(Hashtable* table) {
Hashtable_foreach(table, PCPDynamicMeter_free, NULL);
}function: PCPDynamicMeters_init
void PCPDynamicMeters_init(PCPDynamicMeters* meters) {
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;
if (!xdgConfigHome && !home) {
const struct passwd* pw = getpwuid(getuid());
if (pw)
home = pw->pw_dir;
}
meters->table = Hashtable_new(0, true);
/* developer paths - PCP_HTOP_DIR=./pcp ./pcp-htop */
if (override) {
path = String_cat(override, "/meters/");
PCPDynamicMeter_scanDir(meters, path);
free(path);
}
/* next, search in home directory alongside htoprc */
if (xdgConfigHome)
path = String_cat(xdgConfigHome, "/htop/meters/");
else if (home)
path = String_cat(home, CONFIGDIR "/htop/meters/");
else
path = NULL;
if (path) {
PCPDynamicMeter_scanDir(meters, path);
free(path);
}
/* next, search in the system meters directory */
path = String_cat(sysconf, "/htop/meters/");
PCPDynamicMeter_scanDir(meters, path);
free(path);
/* next, try the readonly system meters directory */
path = String_cat(share, "/htop/meters/");
PCPDynamicMeter_scanDir(meters, path);
free(path);
}PCPDynamicMeter.h
pcp/PCPDynamicMeter.h
function: PCPDynamicMeter_display
void PCPDynamicMeter_display(PCPDynamicMeter* this, const Meter* meter, RichString* out);
function: PCPDynamicMeter_enable
void PCPDynamicMeter_enable(PCPDynamicMeter* this);
function: PCPDynamicMeter_updateValues
void PCPDynamicMeter_updateValues(PCPDynamicMeter* this, Meter* meter);
function: PCPDynamicMeters_done
void PCPDynamicMeters_done(Hashtable* table);
function: PCPDynamicMeters_init
void PCPDynamicMeters_init(PCPDynamicMeters* meters);
struct: PCPDynamicMeter
typedef struct PCPDynamicMeter_ {
DynamicMeter super;
PCPDynamicMetric* metrics;
size_t totalMetrics;
} PCPDynamicMeter;struct: PCPDynamicMeters
typedef struct PCPDynamicMeters_ {
Hashtable* table;
size_t count; /* count of dynamic meters discovered by scan */
size_t offset; /* start offset into the Platform metric array */
size_t cursor; /* identifier allocator for each new metric used */
} PCPDynamicMeters;struct: PCPDynamicMetric
typedef struct PCPDynamicMetric_ {
size_t id; /* index into metric array */
ColorElements color;
char* name; /* derived metric name */
char* label;
char* suffix;
} PCPDynamicMetric;PCPDynamicScreen.c
pcp/PCPDynamicScreen.c
function: formatFields
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;
}function: PCPDynamicScreen_addDynamicScreen
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;
}
}function: PCPDynamicScreen_appendScreens
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);
}
}function: PCPDynamicScreen_appendTables
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);
}
}function: PCPDynamicScreen_done
static void PCPDynamicScreen_done(PCPDynamicScreen* ds) {
DynamicScreen_done(&ds->super);
Object_delete(ds->table);
free(ds->columns);
}function: PCPDynamicScreen_lookupMetric
static PCPDynamicColumn* PCPDynamicScreen_lookupMetric(PCPDynamicScreen* screen, const char* name) {
PCPDynamicColumn* column = NULL;
if ((strlen(name) + strlen(screen->super.name) + 1) >= sizeof(column->super.name)) /* colon */
return NULL;
char* metricName = NULL;
xAsprintf(&metricName, "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;
}function: PCPDynamicScreen_new
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;
}function: PCPDynamicScreen_parseColumn
function: PCPDynamicScreen_parseFile
function: PCPDynamicScreen_scanDir
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);
}function: PCPDynamicScreen_uniqueName
static bool PCPDynamicScreen_uniqueName(char* key, PCPDynamicScreens* screens) {
return !DynamicScreen_search(screens->table, key, NULL);
}function: PCPDynamicScreen_validateScreenName
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;
}function: PCPDynamicScreens_addAvailableColumns
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 (!dynamicScreen)
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));
}
}function: PCPDynamicScreens_appendDynamicColumns
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);
}
}function: PCPDynamicScreens_done
void PCPDynamicScreens_done(Hashtable* table) {
Hashtable_foreach(table, PCPDynamicScreens_free, NULL);
}function: PCPDynamicScreens_free
static void PCPDynamicScreens_free(ATTR_UNUSED ht_key_t key, void* value, ATTR_UNUSED void* data) {
PCPDynamicScreen* ds = (PCPDynamicScreen*) value;
PCPDynamicScreen_done(ds);
}function: PCPDynamicScreens_init
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, CONFIGDIR "/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);
}PCPDynamicScreen.h
pcp/PCPDynamicScreen.h
function: PCPDynamicScreen_addDynamicScreen
void PCPDynamicScreen_addDynamicScreen(PCPDynamicScreens* screens, ScreenSettings* ss);
function: PCPDynamicScreen_appendScreens
void PCPDynamicScreen_appendScreens(PCPDynamicScreens* screens, Settings* settings);
function: PCPDynamicScreen_appendTables
void PCPDynamicScreen_appendTables(PCPDynamicScreens* screens, Machine* host);
function: PCPDynamicScreens_addAvailableColumns
void PCPDynamicScreens_addAvailableColumns(Panel* availableColumns, Hashtable* screens, const char* screen);
function: PCPDynamicScreens_done
void PCPDynamicScreens_done(Hashtable* table);
function: PCPDynamicScreens_init
void PCPDynamicScreens_init(PCPDynamicScreens* screens, struct PCPDynamicColumns_* columns);
struct: PCPDynamicScreen_
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;struct: PCPDynamicScreens_
typedef struct PCPDynamicScreens_ {
Hashtable* table;
size_t count; /* count of dynamic screens discovered from scan */
} PCPDynamicScreens;PCPMachine.c
pcp/PCPMachine.c
function: Machine_delete
void Machine_delete(Machine* super) {
PCPMachine* this = (PCPMachine*) super;
Machine_done(super);
free(this->values);
for (unsigned int i = 0; i < super->existingCPUs; i++)
free(this->percpu[i]);
free(this->percpu);
free(this->cpu);
free(this);
}function: Machine_isCPUonline
bool Machine_isCPUonline(const Machine* host, unsigned int id) {
assert(id < host->existingCPUs);
(void) host;
pmAtomValue value;
if (Metric_instance(PCP_PERCPU_SYSTEM, id, id, &value, PM_TYPE_U32))
return true;
return false;
}function: Machine_new
Machine* Machine_new(UsersTable* usersTable, uid_t userId) {
PCPMachine* this = xCalloc(1, sizeof(PCPMachine));
Machine* super = &this->super;
Machine_init(super, usersTable, userId);
struct timeval timestamp;
gettimeofday(×tamp, NULL);
this->timestamp = pmtimevalToReal(×tamp);
this->cpu = xCalloc(CPU_METRIC_COUNT, sizeof(pmAtomValue));
PCPMachine_updateCPUcount(this);
Platform_updateTables(super);
return super;
}function: Machine_scan
void Machine_scan(Machine* super) {
PCPMachine* host = (PCPMachine*) super;
const Settings* settings = super->settings;
uint32_t flags = settings->ss->flags;
bool flagged;
for (int metric = PCP_PROC_PID; metric < PCP_METRIC_COUNT; metric++)
Metric_enable(metric, true);
flagged = settings->showCPUFrequency;
Metric_enable(PCP_HINV_CPUCLOCK, flagged);
flagged = flags & PROCESS_FLAG_LINUX_CGROUP;
Metric_enable(PCP_PROC_CGROUPS, flagged);
flagged = flags & PROCESS_FLAG_LINUX_OOM;
Metric_enable(PCP_PROC_OOMSCORE, flagged);
flagged = flags & PROCESS_FLAG_LINUX_CTXT;
Metric_enable(PCP_PROC_VCTXSW, flagged);
Metric_enable(PCP_PROC_NVCTXSW, flagged);
flagged = flags & PROCESS_FLAG_LINUX_SECATTR;
Metric_enable(PCP_PROC_LABELS, flagged);
flagged = flags & PROCESS_FLAG_LINUX_AUTOGROUP;
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;
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 (Metric_fetch(×tamp) != true)
return;
double sample = host->timestamp;
host->timestamp = pmtimevalToReal(×tamp);
host->period = (host->timestamp - sample) * 100;
PCPMachine_scan(host);
}function: PCPMachine_backupCPUTime
/* make copies of previously sampled values to avoid overwrite */
static inline void PCPMachine_backupCPUTime(pmAtomValue* values) {
/* the PERIOD fields (must) mirror the TIME fields */
for (int metric = CPU_TOTAL_TIME; metric < CPU_TOTAL_PERIOD; metric++) {
values[metric + CPU_TOTAL_PERIOD] = values[metric];
}
}function: PCPMachine_deriveCPUTime
function: PCPMachine_saveCPUTimePeriod
static inline void PCPMachine_saveCPUTimePeriod(pmAtomValue* values, CPUMetric previous, pmAtomValue* latest) {
pmAtomValue* value;
/* new value for period */
value = &values[previous];
if (latest->ull > value->ull)
value->ull = latest->ull - value->ull;
else
value->ull = 0;
/* new value for time */
value = &values[previous - CPU_TOTAL_PERIOD];
value->ull = latest->ull;
}function: PCPMachine_scan
static void PCPMachine_scan(PCPMachine* this) {
Machine* super = &this->super;
PCPMachine_updateMemoryInfo(super);
PCPMachine_updateCPUcount(this);
PCPMachine_backupCPUTime(this->cpu);
PCPMachine_updateAllCPUTime(this, PCP_CPU_USER, CPU_USER_TIME);
PCPMachine_updateAllCPUTime(this, PCP_CPU_NICE, CPU_NICE_TIME);
PCPMachine_updateAllCPUTime(this, PCP_CPU_SYSTEM, CPU_SYSTEM_TIME);
PCPMachine_updateAllCPUTime(this, PCP_CPU_IDLE, CPU_IDLE_TIME);
PCPMachine_updateAllCPUTime(this, PCP_CPU_IOWAIT, CPU_IOWAIT_TIME);
PCPMachine_updateAllCPUTime(this, PCP_CPU_IRQ, CPU_IRQ_TIME);
PCPMachine_updateAllCPUTime(this, PCP_CPU_SOFTIRQ, CPU_SOFTIRQ_TIME);
PCPMachine_updateAllCPUTime(this, PCP_CPU_STEAL, CPU_STEAL_TIME);
PCPMachine_updateAllCPUTime(this, PCP_CPU_GUEST, CPU_GUEST_TIME);
PCPMachine_deriveCPUTime(this->cpu);
for (unsigned int i = 0; i < super->existingCPUs; i++)
PCPMachine_backupCPUTime(this->percpu[i]);
PCPMachine_updatePerCPUTime(this, PCP_PERCPU_USER, CPU_USER_TIME);
PCPMachine_updatePerCPUTime(this, PCP_PERCPU_NICE, CPU_NICE_TIME);
PCPMachine_updatePerCPUTime(this, PCP_PERCPU_SYSTEM, CPU_SYSTEM_TIME);
PCPMachine_updatePerCPUTime(this, PCP_PERCPU_IDLE, CPU_IDLE_TIME);
PCPMachine_updatePerCPUTime(this, PCP_PERCPU_IOWAIT, CPU_IOWAIT_TIME);
PCPMachine_updatePerCPUTime(this, PCP_PERCPU_IRQ, CPU_IRQ_TIME);
PCPMachine_updatePerCPUTime(this, PCP_PERCPU_SOFTIRQ, CPU_SOFTIRQ_TIME);
PCPMachine_updatePerCPUTime(this, PCP_PERCPU_STEAL, CPU_STEAL_TIME);
PCPMachine_updatePerCPUTime(this, PCP_PERCPU_GUEST, CPU_GUEST_TIME);
for (unsigned int i = 0; i < super->existingCPUs; i++)
PCPMachine_deriveCPUTime(this->percpu[i]);
if (super->settings->showCPUFrequency)
PCPMachine_updatePerCPUReal(this, PCP_HINV_CPUCLOCK, CPU_FREQUENCY);
PCPMachine_scanZfsArcstats(this);
PCPMachine_scanZswapInfo(this);
}function: PCPMachine_scanZfsArcstats
static inline void PCPMachine_scanZfsArcstats(PCPMachine* this) {
unsigned long long int dbufSize = 0;
unsigned long long int dnodeSize = 0;
unsigned long long int bonusSize = 0;
pmAtomValue value;
memset(&this->zfs, 0, sizeof(ZfsArcStats));
if (Metric_values(PCP_ZFS_ARC_ANON_SIZE, &value, 1, PM_TYPE_U64))
this->zfs.anon = value.ull / ONE_K;
if (Metric_values(PCP_ZFS_ARC_C_MIN, &value, 1, PM_TYPE_U64))
this->zfs.min = value.ull / ONE_K;
if (Metric_values(PCP_ZFS_ARC_C_MAX, &value, 1, PM_TYPE_U64))
this->zfs.max = value.ull / ONE_K;
if (Metric_values(PCP_ZFS_ARC_BONUS_SIZE, &value, 1, PM_TYPE_U64))
bonusSize = value.ull / ONE_K;
if (Metric_values(PCP_ZFS_ARC_DBUF_SIZE, &value, 1, PM_TYPE_U64))
dbufSize = value.ull / ONE_K;
if (Metric_values(PCP_ZFS_ARC_DNODE_SIZE, &value, 1, PM_TYPE_U64))
dnodeSize = value.ull / ONE_K;
if (Metric_values(PCP_ZFS_ARC_COMPRESSED_SIZE, &value, 1, PM_TYPE_U64))
this->zfs.compressed = value.ull / ONE_K;
if (Metric_values(PCP_ZFS_ARC_UNCOMPRESSED_SIZE, &value, 1, PM_TYPE_U64))
this->zfs.uncompressed = value.ull / ONE_K;
if (Metric_values(PCP_ZFS_ARC_HDR_SIZE, &value, 1, PM_TYPE_U64))
this->zfs.header = value.ull / ONE_K;
if (Metric_values(PCP_ZFS_ARC_MFU_SIZE, &value, 1, PM_TYPE_U64))
this->zfs.MFU = value.ull / ONE_K;
if (Metric_values(PCP_ZFS_ARC_MRU_SIZE, &value, 1, PM_TYPE_U64))
this->zfs.MRU = value.ull / ONE_K;
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;
this->zfs.enabled = (this->zfs.size > 0);
this->zfs.isCompressed = (this->zfs.compressed > 0);
}function: PCPMachine_scanZswapInfo
static inline void PCPMachine_scanZswapInfo(PCPMachine* this) {
pmAtomValue value;
memset(&this->zswap, 0, sizeof(ZswapStats));
if (Metric_values(PCP_MEM_ZSWAP, &value, 1, PM_TYPE_U64))
this->zswap.usedZswapComp = value.ull;
if (Metric_values(PCP_MEM_ZSWAPPED, &value, 1, PM_TYPE_U64))
this->zswap.usedZswapOrig = value.ull;
}function: PCPMachine_updateAllCPUTime
static void PCPMachine_updateAllCPUTime(PCPMachine* this, Metric metric, CPUMetric cpumetric)
{
pmAtomValue* value = &this->cpu[cpumetric];
if (Metric_values(metric, value, 1, PM_TYPE_U64) == NULL)
memset(value, 0, sizeof(pmAtomValue));
}function: PCPMachine_updateCPUcount
static void PCPMachine_updateCPUcount(PCPMachine* this) {
Machine* super = &this->super;
super->activeCPUs = Metric_instanceCount(PCP_PERCPU_SYSTEM);
unsigned int cpus = Platform_getMaxCPU();
if (cpus == super->existingCPUs)
return;
if (cpus == 0)
cpus = super->activeCPUs;
if (cpus <= 1)
cpus = super->activeCPUs = 1;
super->existingCPUs = cpus;
free(this->percpu);
free(this->values);
this->percpu = xCalloc(cpus, sizeof(pmAtomValue*));
for (unsigned int i = 0; i < cpus; i++)
this->percpu[i] = xCalloc(CPU_METRIC_COUNT, sizeof(pmAtomValue));
this->values = xCalloc(cpus, sizeof(pmAtomValue));
}function: PCPMachine_updateMemoryInfo
static void PCPMachine_updateMemoryInfo(Machine* host) {
unsigned long long int freeMem = 0;
unsigned long long int swapFreeMem = 0;
unsigned long long int sreclaimableMem = 0;
host->totalMem = host->usedMem = host->cachedMem = 0;
host->usedSwap = host->totalSwap = host->sharedMem = 0;
pmAtomValue value;
if (Metric_values(PCP_MEM_TOTAL, &value, 1, PM_TYPE_U64) != NULL)
host->totalMem = value.ull;
if (Metric_values(PCP_MEM_FREE, &value, 1, PM_TYPE_U64) != NULL)
freeMem = value.ull;
if (Metric_values(PCP_MEM_BUFFERS, &value, 1, PM_TYPE_U64) != NULL)
host->buffersMem = value.ull;
if (Metric_values(PCP_MEM_SRECLAIM, &value, 1, PM_TYPE_U64) != NULL)
sreclaimableMem = value.ull;
if (Metric_values(PCP_MEM_SHARED, &value, 1, PM_TYPE_U64) != NULL)
host->sharedMem = value.ull;
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 (Metric_values(PCP_MEM_AVAILABLE, &value, 1, PM_TYPE_U64) != NULL)
host->availableMem = MINIMUM(value.ull, host->totalMem);
else
host->availableMem = freeMem;
if (Metric_values(PCP_MEM_SWAPFREE, &value, 1, PM_TYPE_U64) != NULL)
swapFreeMem = value.ull;
if (Metric_values(PCP_MEM_SWAPTOTAL, &value, 1, PM_TYPE_U64) != NULL)
host->totalSwap = value.ull;
if (Metric_values(PCP_MEM_SWAPCACHED, &value, 1, PM_TYPE_U64) != NULL)
host->cachedSwap = value.ull;
host->usedSwap = host->totalSwap - swapFreeMem - host->cachedSwap;
}function: PCPMachine_updatePerCPUReal
static void PCPMachine_updatePerCPUReal(PCPMachine* this, Metric metric, CPUMetric cpumetric)
{
int cpus = this->super.existingCPUs;
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;
}function: PCPMachine_updatePerCPUTime
static void PCPMachine_updatePerCPUTime(PCPMachine* this, Metric metric, CPUMetric cpumetric)
{
int cpus = this->super.existingCPUs;
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;
}PCPMachine.h
pcp/PCPMachine.h
enum: CPUMetric
typedef enum CPUMetric_ {
CPU_TOTAL_TIME,
CPU_USER_TIME,
CPU_SYSTEM_TIME,
CPU_SYSTEM_ALL_TIME,
CPU_IDLE_ALL_TIME,
CPU_IDLE_TIME,
CPU_NICE_TIME,
CPU_IOWAIT_TIME,
CPU_IRQ_TIME,
CPU_SOFTIRQ_TIME,
CPU_STEAL_TIME,
CPU_GUEST_TIME,
CPU_GUESTNICE_TIME,
CPU_TOTAL_PERIOD,
CPU_USER_PERIOD,
CPU_SYSTEM_PERIOD,
CPU_SYSTEM_ALL_PERIOD,
CPU_IDLE_ALL_PERIOD,
CPU_IDLE_PERIOD,
CPU_NICE_PERIOD,
CPU_IOWAIT_PERIOD,
CPU_IRQ_PERIOD,
CPU_SOFTIRQ_PERIOD,
CPU_STEAL_PERIOD,
CPU_GUEST_PERIOD,
CPU_GUESTNICE_PERIOD,
CPU_FREQUENCY,
CPU_METRIC_COUNT
} CPUMetric;struct: PCPMachine
typedef struct PCPMachine_ {
Machine super;
int smaps_flag;
double period;
double timestamp; /* previous sample timestamp */
pmAtomValue* cpu; /* aggregate values for each metric */
pmAtomValue** percpu; /* per-processor values for each metric */
pmAtomValue* values; /* per-processor buffer for just one metric */
ZfsArcStats zfs;
/*ZramStats zram; -- not needed, calculated in-line in Platform.c */
ZswapStats zswap;
} PCPMachine;PCPProcess.c
pcp/PCPProcess.c
function: PCPProcess_compareByKey
function: PCPProcess_new
Process* PCPProcess_new(const Machine* host) {
PCPProcess* this = xCalloc(1, sizeof(PCPProcess));
Object_setClass(this, Class(PCPProcess));
Process_init(&this->super, host);
return (Process*)this;
}function: PCPProcess_printDelay
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 ");
}
}function: PCPProcess_rowWriteField
function: PCPProcess_totalIORate
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;
}function: Process_delete
void Process_delete(Object* cast) {
PCPProcess* this = (PCPProcess*) cast;
Process_done((Process*)cast);
free(this->cgroup_short);
free(this->cgroup);
free(this->secattr);
free(this);
}global constant struct: PCPProcess_class
const ProcessClass PCPProcess_class = {
.super = {
.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,
},
.compareByKey = PCPProcess_compareByKey,
};global variable: Process_fields
PCPProcess.h
pcp/PCPProcess.h
function: PCPProcess_new
Process* PCPProcess_new(const Machine* host);
function: Process_delete
void Process_delete(Object* cast);
function: Process_isThread
bool Process_isThread(const Process* this);
macro: PROCESS_FLAG_LINUX_AUTOGROUP
#define PROCESS_FLAG_LINUX_AUTOGROUP 0x00080000
macro: PROCESS_FLAG_LINUX_CGROUP
#define PROCESS_FLAG_LINUX_CGROUP 0x00000800
macro: PROCESS_FLAG_LINUX_CTXT
#define PROCESS_FLAG_LINUX_CTXT 0x00004000
macro: PROCESS_FLAG_LINUX_OOM
#define PROCESS_FLAG_LINUX_OOM 0x00001000
macro: PROCESS_FLAG_LINUX_SECATTR
#define PROCESS_FLAG_LINUX_SECATTR 0x00008000
macro: PROCESS_FLAG_LINUX_SMAPS
#define PROCESS_FLAG_LINUX_SMAPS 0x00002000
struct: PCPProcess
typedef struct PCPProcess_ {
Process super;
/* default result offset to use for searching proc metrics */
unsigned int offset;
unsigned long int cminflt;
unsigned long int cmajflt;
unsigned long long int utime;
unsigned long long int stime;
unsigned long long int cutime;
unsigned long long int cstime;
long m_share;
long m_priv;
long m_pss;
long m_swap;
long m_psswp;
long m_trs;
long m_drs;
long m_lrs;
long m_dt;
/* Data read (in kilobytes) */
unsigned long long io_rchar;
/* Data written (in kilobytes) */
unsigned long long io_wchar;
/* Number of read(2) syscalls */
unsigned long long io_syscr;
/* Number of write(2) syscalls */
unsigned long long io_syscw;
/* Storage data read (in kilobytes) */
unsigned long long io_read_bytes;
/* Storage data written (in kilobytes) */
unsigned long long io_write_bytes;
/* Storage data cancelled (in kilobytes) */
unsigned long long io_cancelled_write_bytes;
/* Point in time of last io scan (in seconds elapsed since the Epoch) */
unsigned long long io_last_scan_time;
double io_rate_read_bps;
double io_rate_write_bps;
char* cgroup;
char* cgroup_short;
char* container_short;
long int autogroup_id;
int autogroup_nice;
unsigned int oom;
unsigned long long int delay_read_time;
unsigned long long cpu_delay_total;
unsigned long long blkio_delay_total;
unsigned long long swapin_delay_total;
float cpu_delay_percent;
float blkio_delay_percent;
float swapin_delay_percent;
unsigned long ctxt_total;
unsigned long ctxt_diff;
char* secattr;
unsigned long long int last_mlrs_calctime;
} PCPProcess;variable: PCPProcess_class
extern const ProcessClass PCPProcess_class;
variable: Process_fields
extern const ProcessFieldData Process_fields[LAST_PROCESSFIELD];
PCPProcessTable.c
pcp/PCPProcessTable.c
function: Metric_instance_char
static inline char Metric_instance_char(int metric, int pid, int offset, char fallback) {
pmAtomValue value;
if (Metric_instance(metric, pid, offset, &value, PM_TYPE_STRING)) {
char uchar = value.cp[0];
free(value.cp);
return uchar;
}
return fallback;
}function: Metric_instance_ONE_K
static inline unsigned long long Metric_instance_ONE_K(int metric, int pid, int offset) {
pmAtomValue value;
if (Metric_instance(metric, pid, offset, &value, PM_TYPE_U64))
return value.ull / ONE_K;
return ULLONG_MAX;
}function: Metric_instance_s32
static inline long Metric_instance_s32(int metric, int pid, int offset, long fallback) {
pmAtomValue value;
if (Metric_instance(metric, pid, offset, &value, PM_TYPE_32))
return value.l;
return fallback;
}function: Metric_instance_s64
static inline long long Metric_instance_s64(int metric, int pid, int offset, long long fallback) {
pmAtomValue value;
if (Metric_instance(metric, pid, offset, &value, PM_TYPE_64))
return value.l;
return fallback;
}function: Metric_instance_time
static inline unsigned long long Metric_instance_time(int metric, int pid, int offset) {
pmAtomValue value;
if (Metric_instance(metric, pid, offset, &value, PM_TYPE_U64))
return value.ull / 10;
return 0;
}function: Metric_instance_u32
static inline unsigned long Metric_instance_u32(int metric, int pid, int offset, unsigned long fallback) {
pmAtomValue value;
if (Metric_instance(metric, pid, offset, &value, PM_TYPE_U32))
return value.ul;
return fallback;
}function: Metric_instance_u64
static inline unsigned long long Metric_instance_u64(int metric, int pid, int offset, unsigned long long fallback) {
pmAtomValue value;
if (Metric_instance(metric, pid, offset, &value, PM_TYPE_U64))
return value.ull;
return fallback;
}function: PCPProcessTable_getProcessState
static inline ProcessState PCPProcessTable_getProcessState(char state) {
switch (state) {
case '?': return UNKNOWN;
case 'R': return RUNNING;
case 'W': return WAITING;
case 'D': return UNINTERRUPTIBLE_WAIT;
case 'P': return PAGING;
case 'T': return STOPPED;
case 't': return TRACED;
case 'Z': return ZOMBIE;
case 'X': return DEFUNCT;
case 'I': return IDLE;
case 'S': return SLEEPING;
default: return UNKNOWN;
}
}function: PCPProcessTable_readAutogroup
static void PCPProcessTable_readAutogroup(PCPProcess* pp, int pid, int offset) {
pp->autogroup_id = Metric_instance_s64(PCP_PROC_AUTOGROUP_ID, pid, offset, -1);
pp->autogroup_nice = Metric_instance_s32(PCP_PROC_AUTOGROUP_NICE, pid, offset, 0);
}function: PCPProcessTable_readCGroups
static void PCPProcessTable_readCGroups(PCPProcess* pp, int pid, int offset) {
pp->cgroup = setString(PCP_PROC_CGROUPS, pid, offset, pp->cgroup);
if (pp->cgroup) {
char* cgroup_short = CGroup_filterName(pp->cgroup);
if (cgroup_short) {
Row_updateFieldWidth(CCGROUP, strlen(cgroup_short));
free_and_xStrdup(&pp->cgroup_short, cgroup_short);
free(cgroup_short);
} else {
//CCGROUP is alias to normal CGROUP if shortening fails
Row_updateFieldWidth(CCGROUP, strlen(pp->cgroup));
free(pp->cgroup_short);
pp->cgroup_short = NULL;
}
char* container_short = CGroup_filterName(pp->cgroup);
if (container_short) {
Row_updateFieldWidth(CONTAINER, strlen(container_short));
free_and_xStrdup(&pp->container_short, container_short);
free(container_short);
} else {
Row_updateFieldWidth(CONTAINER, strlen("N/A"));
free(pp->container_short);
pp->container_short = NULL;
}
} else {
free(pp->cgroup_short);
pp->cgroup_short = NULL;
free(pp->container_short);
pp->container_short = NULL;
}
}function: PCPProcessTable_readCtxtData
static void PCPProcessTable_readCtxtData(PCPProcess* pp, int pid, int offset) {
pmAtomValue value;
unsigned long ctxt = 0;
if (Metric_instance(PCP_PROC_VCTXSW, pid, offset, &value, PM_TYPE_U32))
ctxt += value.ul;
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;
}function: PCPProcessTable_readCwd
static void PCPProcessTable_readCwd(PCPProcess* pp, int pid, int offset) {
pp->super.procCwd = setString(PCP_PROC_CWD, pid, offset, pp->super.procCwd);
}function: PCPProcessTable_readOomData
static void PCPProcessTable_readOomData(PCPProcess* pp, int pid, int offset) {
pp->oom = Metric_instance_u32(PCP_PROC_OOMSCORE, pid, offset, 0);
}function: PCPProcessTable_readSecattrData
static void PCPProcessTable_readSecattrData(PCPProcess* pp, int pid, int offset) {
pp->secattr = setString(PCP_PROC_LABELS, pid, offset, pp->secattr);
}function: PCPProcessTable_updateCmdline
static void PCPProcessTable_updateCmdline(Process* process, int pid, int offset, const char* comm) {
pmAtomValue value;
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);
return;
}
char* command = value.cp;
int length = strlen(command);
if (command[0] != '(') {
process->isKernelThread = false;
} else {
++command;
--length;
if (command[length - 1] == ')')
command[--length] = '\0';
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;
}
tokenEnd = length;
if (argSepSpace)
tokenStart = 0;
Process_updateCmdline(process, command, tokenStart, tokenEnd);
free(value.cp);
Process_updateComm(process, comm);
if (Metric_instance(PCP_PROC_EXE, pid, offset, &value, PM_TYPE_STRING)) {
Process_updateExe(process, value.cp[0] ? value.cp : NULL);
free(value.cp);
}
}function: PCPProcessTable_updateID
static void PCPProcessTable_updateID(Process* process, int pid, int offset) {
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 = PCPProcessTable_getProcessState(Metric_instance_char(PCP_PROC_STATE, pid, offset, '?'));
}function: PCPProcessTable_updateInfo
static void PCPProcessTable_updateInfo(PCPProcess* pp, int pid, int offset, char* command, size_t commLen) {
Process* process = &pp->super;
pmAtomValue value;
if (!Metric_instance(PCP_PROC_CMD, pid, offset, &value, PM_TYPE_STRING))
value.cp = xStrdup("<unknown>");
String_safeStrncpy(command, value.cp, commLen);
free(value.cp);
process->pgrp = Metric_instance_u32(PCP_PROC_PGRP, pid, offset, 0);
process->session = Metric_instance_u32(PCP_PROC_SESSION, pid, offset, 0);
process->tty_nr = Metric_instance_u32(PCP_PROC_TTY, pid, offset, 0);
process->tpgid = Metric_instance_u32(PCP_PROC_TTYPGRP, pid, offset, 0);
process->minflt = Metric_instance_u32(PCP_PROC_MINFLT, pid, offset, 0);
pp->cminflt = Metric_instance_u32(PCP_PROC_CMINFLT, pid, offset, 0);
process->majflt = Metric_instance_u32(PCP_PROC_MAJFLT, pid, offset, 0);
pp->cmajflt = Metric_instance_u32(PCP_PROC_CMAJFLT, pid, offset, 0);
pp->utime = Metric_instance_time(PCP_PROC_UTIME, pid, offset);
pp->stime = Metric_instance_time(PCP_PROC_STIME, pid, offset);
pp->cutime = Metric_instance_time(PCP_PROC_CUTIME, pid, offset);
pp->cstime = Metric_instance_time(PCP_PROC_CSTIME, pid, offset);
process->priority = Metric_instance_u32(PCP_PROC_PRIORITY, pid, offset, 0);
process->nice = Metric_instance_s32(PCP_PROC_NICE, pid, offset, 0);
process->nlwp = Metric_instance_u32(PCP_PROC_THREADS, pid, offset, 0);
process->starttime_ctime = Metric_instance_time(PCP_PROC_STARTTIME, pid, offset);
process->processor = Metric_instance_u32(PCP_PROC_PROCESSOR, pid, offset, 0);
process->time = pp->utime + pp->stime;
}function: PCPProcessTable_updateIO
static void PCPProcessTable_updateIO(PCPProcess* pp, int pid, int offset, unsigned long long now) {
pmAtomValue value;
pp->io_rchar = Metric_instance_ONE_K(PCP_PROC_IO_RCHAR, pid, offset);
pp->io_wchar = Metric_instance_ONE_K(PCP_PROC_IO_WCHAR, pid, offset);
pp->io_syscr = Metric_instance_u64(PCP_PROC_IO_SYSCR, pid, offset, ULLONG_MAX);
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 (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) /
(now - pp->io_last_scan_time);
} else {
pp->io_read_bytes = ULLONG_MAX;
pp->io_rate_read_bps = NAN;
}
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) /
(now - pp->io_last_scan_time);
} else {
pp->io_write_bytes = ULLONG_MAX;
pp->io_rate_write_bps = NAN;
}
pp->io_last_scan_time = now;
}function: PCPProcessTable_updateMemory
static void PCPProcessTable_updateMemory(PCPProcess* pp, int pid, int offset) {
pp->super.m_virt = Metric_instance_u32(PCP_PROC_MEM_SIZE, pid, offset, 0);
pp->super.m_resident = Metric_instance_u32(PCP_PROC_MEM_RSS, pid, offset, 0);
pp->m_share = Metric_instance_u32(PCP_PROC_MEM_SHARE, pid, offset, 0);
pp->m_priv = pp->super.m_resident - pp->m_share;
pp->m_trs = Metric_instance_u32(PCP_PROC_MEM_TEXTRS, pid, offset, 0);
pp->m_lrs = Metric_instance_u32(PCP_PROC_MEM_LIBRS, pid, offset, 0);
pp->m_drs = Metric_instance_u32(PCP_PROC_MEM_DATRS, pid, offset, 0);
pp->m_dt = Metric_instance_u32(PCP_PROC_MEM_DIRTY, pid, offset, 0);
}function: PCPProcessTable_updateProcesses
function: PCPProcessTable_updateSmaps
static void PCPProcessTable_updateSmaps(PCPProcess* pp, pid_t pid, int offset) {
pp->m_pss = Metric_instance_u64(PCP_PROC_SMAPS_PSS, pid, offset, 0);
pp->m_swap = Metric_instance_u64(PCP_PROC_SMAPS_SWAP, pid, offset, 0);
pp->m_psswp = Metric_instance_u64(PCP_PROC_SMAPS_SWAPPSS, pid, offset, 0);
}function: PCPProcessTable_updateTTY
static void PCPProcessTable_updateTTY(Process* process, int pid, int offset) {
process->tty_name = setString(PCP_PROC_TTYNAME, pid, offset, process->tty_name);
}function: PCPProcessTable_updateUsername
static void PCPProcessTable_updateUsername(Process* process, int pid, int offset, UsersTable* users) {
process->st_uid = Metric_instance_u32(PCP_PROC_ID_UID, pid, offset, 0);
process->user = setUser(users, process->st_uid, pid, offset);
}function: ProcessTable_delete
void ProcessTable_delete(Object* cast) {
PCPProcessTable* this = (PCPProcessTable*) cast;
ProcessTable_done(&this->super);
free(this);
}function: ProcessTable_goThroughEntries
void ProcessTable_goThroughEntries(ProcessTable* super) {
PCPProcessTable* this = (PCPProcessTable*) super;
PCPProcessTable_updateProcesses(this);
}function: ProcessTable_new
ProcessTable* ProcessTable_new(Machine* host, Hashtable* pidMatchList) {
PCPProcessTable* this = xCalloc(1, sizeof(PCPProcessTable));
Object_setClass(this, Class(ProcessTable));
ProcessTable* super = &this->super;
ProcessTable_init(super, Class(PCPProcess), host, pidMatchList);
return super;
}function: setString
static char* setString(Metric metric, int pid, int offset, char* string) {
if (string)
free(string);
pmAtomValue value;
if (Metric_instance(metric, pid, offset, &value, PM_TYPE_STRING))
string = value.cp;
else
string = NULL;
return string;
}function: setUser
static char* setUser(UsersTable* this, unsigned int uid, int pid, int offset) {
char* name = Hashtable_get(this->users, uid);
if (name)
return name;
pmAtomValue value;
if (Metric_instance(PCP_PROC_ID_USER, pid, offset, &value, PM_TYPE_STRING)) {
Hashtable_put(this->users, uid, value.cp);
name = value.cp;
}
return name;
}struct: PCPProcessTable
// The full definition of struct PCPProcessTable is not present in this file. // It is declared in 'pcp/PCPProcessTable.h' and typically includes: // struct ProcessTable super; // Base ProcessTable structure // ... other PCP-specific members ...
PCPProcessTable.h
pcp/PCPProcessTable.h
struct: PCPProcessTable
typedef struct PCPProcessTable_ {
ProcessTable super;
} PCPProcessTable;Platform.c
pcp/Platform.c
file: Platform.c
Platform.h
pcp/Platform.h
enum: PLATFORM_LONGOPT_enum
enum {
PLATFORM_LONGOPT_HOST = 128,
PLATFORM_LONGOPT_TIMEZONE,
PLATFORM_LONGOPT_HOSTZONE,
};function: Platform_addDynamicScreen
void Platform_addDynamicScreen(ScreenSettings* ss);
function: Platform_addDynamicScreenAvailableColumns
void Platform_addDynamicScreenAvailableColumns(Panel* availableColumns, const char* screen);
function: Platform_addMetric
size_t Platform_addMetric(Metric id, const char* name);
function: Platform_defaultDynamicScreens
void Platform_defaultDynamicScreens(Settings* settings);
function: Platform_done
void Platform_done(void);
function: Platform_dynamicColumnName
const char* Platform_dynamicColumnName(unsigned int key);
function: Platform_dynamicColumns
Hashtable* Platform_dynamicColumns(void);
function: Platform_dynamicColumnsDone
void Platform_dynamicColumnsDone(Hashtable* columns);
function: Platform_dynamicColumnWriteField
bool Platform_dynamicColumnWriteField(const Process* proc, RichString* str, unsigned int key);
function: Platform_dynamicMeterDisplay
void Platform_dynamicMeterDisplay(const Meter* meter, RichString* out);
function: Platform_dynamicMeterInit
void Platform_dynamicMeterInit(Meter* meter);
function: Platform_dynamicMeters
Hashtable* Platform_dynamicMeters(void);
function: Platform_dynamicMetersDone
void Platform_dynamicMetersDone(Hashtable* meters);
function: Platform_dynamicMeterUpdateValues
void Platform_dynamicMeterUpdateValues(Meter* meter);
function: Platform_dynamicScreens
Hashtable* Platform_dynamicScreens(void);
function: Platform_dynamicScreensDone
void Platform_dynamicScreensDone(Hashtable* screens);
function: Platform_getBattery
void Platform_getBattery(double* percent, ACPresence* isOnAC);
function: Platform_getBootTime
long long Platform_getBootTime(void);
function: Platform_getDiskIO
bool Platform_getDiskIO(DiskIOData* data);
function: Platform_getFileDescriptors
void Platform_getFileDescriptors(double* used, double* max);
function: Platform_getHostname
void Platform_getHostname(char* buffer, size_t size);
function: Platform_getLoadAverage
void Platform_getLoadAverage(double* one, double* five, double* fifteen);
function: Platform_getLongOption
CommandLineStatus Platform_getLongOption(int opt, int argc, char** argv);
function: Platform_getMaxCPU
unsigned int Platform_getMaxCPU(void);
function: Platform_getMaxPid
pid_t Platform_getMaxPid(void);
function: Platform_getNetworkIO
bool Platform_getNetworkIO(NetworkIOData* data);
function: Platform_getPressureStall
void Platform_getPressureStall(const char* file, bool some, double* ten, double* sixty, double* threehundred);
function: Platform_getProcessEnv
char* Platform_getProcessEnv(pid_t pid);
function: Platform_getProcessLocks
FileLocks_ProcessData* Platform_getProcessLocks(pid_t pid);
function: Platform_getRelease
void Platform_getRelease(char** string);
function: Platform_gettime_monotonic
void Platform_gettime_monotonic(uint64_t* msec);
function: Platform_gettime_realtime
void Platform_gettime_realtime(struct timeval* tv, uint64_t* msec);
function: Platform_getUptime
int Platform_getUptime(void);
function: Platform_init
bool Platform_init(void);
function: Platform_longOptionsUsage
void Platform_longOptionsUsage(const char* name);
function: Platform_setBindings
void Platform_setBindings(Htop_Action* keys);
function: Platform_setCPUValues
double Platform_setCPUValues(Meter* this, int cpu);
function: Platform_setMemoryValues
void Platform_setMemoryValues(Meter* this);
function: Platform_setSwapValues
void Platform_setSwapValues(Meter* this);
function: Platform_setZfsArcValues
void Platform_setZfsArcValues(Meter* this);
function: Platform_setZfsCompressedArcValues
void Platform_setZfsCompressedArcValues(Meter* this);
function: Platform_setZramValues
void Platform_setZramValues(Meter* this);
function: Platform_updateTables
void Platform_updateTables(Machine* host);
macro: PLATFORM_LONG_OPTIONS
#define PLATFORM_LONG_OPTIONS \
{PMLONGOPT_HOST, optional_argument, 0, PLATFORM_LONGOPT_HOST}, \
{PMLONGOPT_TIMEZONE, optional_argument, 0, PLATFORM_LONGOPT_TIMEZONE}, \
{PMLONGOPT_HOSTZONE, optional_argument, 0, PLATFORM_LONGOPT_HOSTZONE}, \struct: Platform
typedef struct Platform_ {
int context; /* PMAPI(3) context identifier */
size_t totalMetrics; /* total number of all metrics */
const char** names; /* name array indexed by Metric */
pmID* pmids; /* all known metric identifiers */
pmID* fetch; /* enabled identifiers for sampling */
pmDesc* descs; /* metric desc array indexed by Metric */
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 */
int pidmax; /* maximum platform process identifier */
unsigned int ncpu; /* maximum processor count configured */
} Platform;variable: opts
extern pmOptions opts;
variable: Platform_defaultScreens
extern const ScreenDefaults Platform_defaultScreens[];
variable: Platform_meterTypes
extern const MeterClass* const Platform_meterTypes[];
variable: Platform_numberOfDefaultScreens
extern const unsigned int Platform_numberOfDefaultScreens;
variable: Platform_numberOfSignals
extern const unsigned int Platform_numberOfSignals;
variable: Platform_signals
extern const SignalItem Platform_signals[];
ProcessField.h
pcp/ProcessField.h
macro: PLATFORM_PROCESS_FIELDS
#define PLATFORM_PROCESS_FIELDS \ CMINFLT = 11, \ CMAJFLT = 13, \ UTIME = 14, \ STIME = 15, \ CUTIME = 16, \ CSTIME = 17, \ M_SHARE = 41, \ M_TRS = 42, \ M_DRS = 43, \ M_LRS = 44, \ M_DT = 45, \ CTID = 100, \ RCHAR = 103, \ WCHAR = 104, \ SYSCR = 105, \ SYSCW = 106, \ RBYTES = 107, \ WBYTES = 108, \ CNCLWB = 109, \ IO_READ_RATE = 110, \ IO_WRITE_RATE = 111, \ IO_RATE = 112, \ CGROUP = 113, \ OOM = 114, \ PERCENT_CPU_DELAY = 116, \ PERCENT_IO_DELAY = 117, \ PERCENT_SWAP_DELAY = 118, \ M_PSS = 119, \ M_SWAP = 120, \ M_PSSWP = 121, \ CTXT = 122, \ SECATTR = 123, \ AUTOGROUP_ID = 127, \ AUTOGROUP_NICE = 128, \ CCGROUP = 129, \ CONTAINER = 130, \ M_PRIV = 131, \ // End of list
biosnoop
pcp/screens/biosnoop
file: biosnoop
# # 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
cgroups
pcp/screens/cgroups
file: cgroups
# # 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
cgroupsio
pcp/screens/cgroupsio
file: cgroupsio
# # 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
cgroupsmem
pcp/screens/cgroupsmem
file: cgroupsmem
# # 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
devices
pcp/screens/devices
file: devices
execsnoop
pcp/screens/execsnoop
file: execsnoop
# # 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
exitsnoop
pcp/screens/exitsnoop
file: exitsnoop
# # 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
filesystems
pcp/screens/filesystems
file: filesystems
# # 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
opensnoop
pcp/screens/opensnoop
file: opensnoop
# # 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
Process.c
Process.c
file: Process.c
Process.h
Process.h
enum: ProcessState
typedef enum ProcessState_ {
UNKNOWN = 1,
RUNNABLE,
RUNNING,
QUEUED,
WAITING,
UNINTERRUPTIBLE_WAIT,
BLOCKED,
PAGING,
STOPPED,
TRACED,
ZOMBIE,
DEFUNCT,
IDLE,
SLEEPING
} ProcessState;enum: Tristate
typedef enum Tristate_ {
TRI_INITIAL = 0,
TRI_OFF = -1,
TRI_ON = 1,
} Tristate;function: Process_compare
int Process_compare(const void* v1, const void* v2);
function: Process_compareByKey_Base
int Process_compareByKey_Base(const Process* p1, const Process* p2, ProcessField key);
function: Process_compareByParent
int Process_compareByParent(const Row* r1, const Row* r2);
function: Process_delete
void Process_delete(Object* cast);
function: Process_done
void Process_done(Process* this);
function: Process_fillStarttimeBuffer
void Process_fillStarttimeBuffer(Process* this);
function: Process_getCommand
const char* Process_getCommand(const Process* this);
function: Process_getGroupOrParent
static inline pid_t Process_getGroupOrParent(const Process* this) {
return Row_getGroupOrParent(&this->super);
}function: Process_getParent
static inline pid_t Process_getParent(const Process* this) {
return (pid_t)this->super.parent;
}function: Process_getPid
static inline pid_t Process_getPid(const Process* this) {
return (pid_t)this->super.id;
}function: Process_getThreadGroup
static inline pid_t Process_getThreadGroup(const Process* this) {
return (pid_t)this->super.group;
}function: Process_init
void Process_init(Process* this, const struct Machine_* host);
function: Process_isKernelThread
static inline bool Process_isKernelThread(const Process* this) {
return this->isKernelThread;
}function: Process_isThread
static inline bool Process_isThread(const Process* this) {
return Process_isUserlandThread(this) || Process_isKernelThread(this);
}function: Process_isUserlandThread
static inline bool Process_isUserlandThread(const Process* this) {
return this->isUserlandThread;
}function: Process_makeCommandStr
void Process_makeCommandStr(Process* this, const struct Settings_ *settings);
function: Process_pidEqualCompare
static inline int Process_pidEqualCompare(const void* v1, const void* v2) {
return Row_idEqualCompare(v1, v2);
}function: Process_rowChangePriorityBy
bool Process_rowChangePriorityBy(Row* super, Arg delta);
function: Process_rowGetSortKey
const char* Process_rowGetSortKey(Row* super);
function: Process_rowIsHighlighted
bool Process_rowIsHighlighted(const Row* super);
function: Process_rowIsVisible
bool Process_rowIsVisible(const Row* super, const struct Table_* table);
function: Process_rowMatchesFilter
bool Process_rowMatchesFilter(const Row* super, const struct Table_* table);
function: Process_rowSendSignal
bool Process_rowSendSignal(Row* super, Arg sgn);
function: Process_setParent
static inline void Process_setParent(Process* this, pid_t pid) {
this->super.parent = pid;
}function: Process_setPid
static inline void Process_setPid(Process* this, pid_t pid) {
this->super.id = pid;
}function: Process_setThreadGroup
static inline void Process_setThreadGroup(Process* this, pid_t pid) {
this->super.group = pid;
}function: Process_updateCmdline
void Process_updateCmdline(Process* this, const char* cmdline, int basenameStart, int basenameEnd);
function: Process_updateComm
void Process_updateComm(Process* this, const char* comm);
function: Process_updateCPUFieldWidths
void Process_updateCPUFieldWidths(float percentage);
function: Process_updateExe
void Process_updateExe(Process* this, const char* exe);
function: Process_writeCommand
void Process_writeCommand(const Process* this, int attr, int baseAttr, RichString* str);
function: Process_writeField
void Process_writeField(const Process* this, RichString* str, ProcessField field);
global_variable: Process_class
extern const ProcessClass Process_class;
global_variable: Process_fields
extern const ProcessFieldData Process_fields[LAST_PROCESSFIELD];
macro: As_Process
#define As_Process(this_) ((const ProcessClass*)((this_)->super.super.klass))
macro: CMDLINE_HIGHLIGHT_FLAG_BASENAME
#define CMDLINE_HIGHLIGHT_FLAG_BASENAME 0x00000002
macro: CMDLINE_HIGHLIGHT_FLAG_COMM
#define CMDLINE_HIGHLIGHT_FLAG_COMM 0x00000004
macro: CMDLINE_HIGHLIGHT_FLAG_DELETED
#define CMDLINE_HIGHLIGHT_FLAG_DELETED 0x00000008
macro: CMDLINE_HIGHLIGHT_FLAG_PREFIXDIR
#define CMDLINE_HIGHLIGHT_FLAG_PREFIXDIR 0x00000010
macro: CMDLINE_HIGHLIGHT_FLAG_SEPARATOR
#define CMDLINE_HIGHLIGHT_FLAG_SEPARATOR 0x00000001
macro: DEFAULT_HIGHLIGHT_SECS
#define DEFAULT_HIGHLIGHT_SECS 5
macro: LAST_PROCESSFIELD
#define LAST_PROCESSFIELD LAST_RESERVED_FIELD
macro: Process_compareByKey
#define Process_compareByKey(p1_, p2_, key_) (As_Process(p1_)->compareByKey ? (As_Process(p1_)->compareByKey(p1_, p2_, key_)) : Process_compareByKey_Base(p1_, p2_, key_))
macro: PROCESS_FLAG_CWD
#define PROCESS_FLAG_CWD 0x00000002
macro: PROCESS_FLAG_IO
#define PROCESS_FLAG_IO 0x00000001
macro: PROCESS_FLAG_SCHEDPOL
#define PROCESS_FLAG_SCHEDPOL 0x00000004
macro: PROCESS_NICE_UNKNOWN
#define PROCESS_NICE_UNKNOWN (-LONG_MAX)
macro: Process_pidDigits
#define Process_pidDigits Row_pidDigits
macro: Process_uidDigits
#define Process_uidDigits Row_uidDigits
struct: Machine_
struct Machine_;
struct: Process
struct: ProcessClass
typedef struct ProcessClass_ {
const RowClass super;
const Process_CompareByKey compareByKey;
} ProcessClass;struct: ProcessCmdlineHighlight
typedef struct ProcessCmdlineHighlight_ {
size_t offset; /* first character to highlight */
size_t length; /* How many characters to highlight, zero if unused */
int attr; /* The attributes used to highlight */
int flags; /* Special flags used for selective highlighting, zero for always */
} ProcessCmdlineHighlight;struct: ProcessFieldData
typedef struct ProcessFieldData_ {
/* Name (displayed in setup menu) */
const char* name;
/* Title (display in main screen); must have same width as the printed values */
const char* title;
/* Description (displayed in setup menu) */
const char* description;
/* Scan flag to enable scan-method otherwise not run */
uint32_t flags;
/* Whether the values are process identifiers; adjusts the width of title and values if true */
bool pidColumn;
/* Whether the column should be sorted in descending order by default */
bool defaultSortDesc;
/* Whether the column width is dynamically adjusted (the minimum width is determined by the title length) */
bool autoWidth;
/* Whether the title of a column with dynamically adjusted width is right aligned (default is left aligned) */
bool autoTitleRightAlign;
} ProcessFieldData;struct: ProcessMergedCommand
typedef struct ProcessMergedCommand_ {
uint64_t lastUpdate; /* Marker based on settings->lastUpdate to track when the rendering needs refreshing */
char* str; /* merged Command string */
size_t highlightCount; /* how many portions of cmdline to highlight */
ProcessCmdlineHighlight highlights[8]; /* which portions of cmdline to highlight */
} ProcessMergedCommand;struct: Settings_
struct Settings_;
typedef: Process_CompareByKey
typedef int (*Process_CompareByKey)(const Process*, const Process*, ProcessField);
typedef: Process_New
typedef Process* (*Process_New)(const struct Machine_*);
typedef: ProcessField
typedef int32_t ProcessField;
ProcessLocksScreen.c
ProcessLocksScreen.c
function: FileLocks_Data_clear
static inline void FileLocks_Data_clear(FileLocks_Data* data) {
free(data->locktype);
free(data->exclusive);
free(data->readwrite);
free(data->filename);
}function: ProcessLocksScreen_delete
void ProcessLocksScreen_delete(Object* this) {
free(InfoScreen_done((InfoScreen*)this));
}function: ProcessLocksScreen_draw
static void ProcessLocksScreen_draw(InfoScreen* this) {
InfoScreen_drawTitled(this, "Snapshot of file locks of process %d - %s", ((ProcessLocksScreen*)this)->pid, Process_getCommand(this->process));
}function: ProcessLocksScreen_new
ProcessLocksScreen* ProcessLocksScreen_new(const Process* process) {
ProcessLocksScreen* this = xMalloc(sizeof(ProcessLocksScreen));
Object_setClass(this, Class(ProcessLocksScreen));
if (Process_isThread(process))
this->pid = Process_getThreadGroup(process);
else
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");
}function: ProcessLocksScreen_scan
static void ProcessLocksScreen_scan(InfoScreen* this) {
Panel* panel = this->display;
int idx = Panel_getSelectedIndex(panel);
Panel_prune(panel);
FileLocks_ProcessData* pdata = Platform_getProcessLocks(((ProcessLocksScreen*)this)->pid);
if (!pdata) {
InfoScreen_addLine(this, "This feature is not supported on your platform.");
} else if (pdata->error) {
InfoScreen_addLine(this, "Could not determine file locks.");
} else {
FileLocks_LockData* ldata = pdata->locks;
if (!ldata) {
InfoScreen_addLine(this, "No locks have been found for the selected process.");
}
while (ldata) {
FileLocks_Data* data = &ldata->data;
char entry[512];
if (ULLONG_MAX == data->end) {
xSnprintf(entry, sizeof(entry), "%5d %-10s %-10s %-10s %#6"PRIx64" %10"PRIu64" %19"PRIu64" %19s %s",
data->fd,
data->locktype, data->exclusive, data->readwrite,
(uint64_t) data->dev, data->inode,
data->start, "<END OF FILE>",
data->filename ? data->filename : "<N/A>"
);
} else {
xSnprintf(entry, sizeof(entry), "%5d %-10s %-10s %-10s %#6"PRIx64" %10"PRIu64" %19"PRIu64" %19"PRIu64" %s",
data->fd,
data->locktype, data->exclusive, data->readwrite,
(uint64_t) data->dev, data->inode,
data->start, data->end,
data->filename ? data->filename : "<N/A>"
);
}
InfoScreen_addLine(this, entry);
FileLocks_Data_clear(&ldata->data);
FileLocks_LockData* old = ldata;
ldata = ldata->next;
free(old);
}
}
free(pdata);
Vector_insertionSort(this->lines);
Vector_insertionSort(panel->items);
Panel_setSelected(panel, idx);
}struct: ProcessLocksScreen_class
const InfoScreenClass ProcessLocksScreen_class = {
.super = {
.extends = Class(Object),
.delete = ProcessLocksScreen_delete
},
.scan = ProcessLocksScreen_scan,
.draw = ProcessLocksScreen_draw
};ProcessLocksScreen.h
ProcessLocksScreen.h
class: ProcessLocksScreen
typedef struct ProcessLocksScreen_ {
InfoScreen super;
pid_t pid;
} ProcessLocksScreen;function: ProcessLocksScreen_delete
void ProcessLocksScreen_delete(Object* this);
function: ProcessLocksScreen_new
ProcessLocksScreen* ProcessLocksScreen_new(const Process* process);
global_variable: ProcessLocksScreen_class
extern const InfoScreenClass ProcessLocksScreen_class;
struct: FileLocks_Data
typedef struct FileLocks_Data_ {
char* locktype;
char* exclusive;
char* readwrite;
char* filename;
int fd;
dev_t dev;
uint64_t inode;
uint64_t start;
uint64_t end;
} FileLocks_Data;struct: FileLocks_LockData
typedef struct FileLocks_LockData_ {
FileLocks_Data data;
struct FileLocks_LockData_* next;
} FileLocks_LockData;struct: FileLocks_ProcessData
typedef struct FileLocks_ProcessData_ {
bool error;
struct FileLocks_LockData_* locks;
} FileLocks_ProcessData;ProcessTable.c
ProcessTable.c
function: ProcessTable_cleanupEntries
static void ProcessTable_cleanupEntries(Table* super) {
Machine* host = super->host;
const Settings* settings = host->settings;
// 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 ProcessTable table
Process_makeCommandStr(p, settings);
// keep track of the highest UID for column scaling
if (p->st_uid > host->maxUserId)
host->maxUserId = p->st_uid;
Table_cleanupRow(super, (Row*) p, i);
}
// compact the table in case of deletions
Table_compact(super);
}function: ProcessTable_done
void ProcessTable_done(ProcessTable* this) {
Table_done(&this->super);
}function: ProcessTable_getProcess
Process* ProcessTable_getProcess(ProcessTable* this, pid_t pid, bool* preExisting, Process_New constructor) {
const Table* table = &this->super;
Process* proc = (Process*) Hashtable_get(table->table, pid);
*preExisting = proc != NULL;
if (proc) {
assert(Vector_indexOf(table->rows, proc, Row_idEqualCompare) != -1);
assert(Process_getPid(proc) == pid);
} else {
proc = constructor(table->host);
assert(proc->cmdline == NULL);
Process_setPid(proc, pid);
}
return proc;
}function: ProcessTable_init
void ProcessTable_init(ProcessTable* this, const ObjectClass* klass, Machine* host, Hashtable* pidMatchList) {
Table_init(&this->super, klass, host);
this->pidMatchList = pidMatchList;
}function: ProcessTable_iterateEntries
static void ProcessTable_iterateEntries(Table* super) {
ProcessTable* this = (ProcessTable*) super;
// calling into platform-specific code
ProcessTable_goThroughEntries(this);
}function: ProcessTable_prepareEntries
static void ProcessTable_prepareEntries(Table* super) {
ProcessTable* this = (ProcessTable*) super;
this->totalTasks = 0;
this->userlandThreads = 0;
this->kernelThreads = 0;
this->runningTasks = 0;
Table_prepareEntries(super);
}struct: ProcessTable_class
const TableClass ProcessTable_class = {
.super = {
.extends = Class(Table),
.delete = ProcessTable_delete,
},
.prepare = ProcessTable_prepareEntries,
.iterate = ProcessTable_iterateEntries,
.cleanup = ProcessTable_cleanupEntries,
};ProcessTable.h
ProcessTable.h
function: ProcessTable_add
static inline void ProcessTable_add(ProcessTable* this, Process* process) {
Table_add(&this->super, &process->super);
}function: ProcessTable_delete
void ProcessTable_delete(Object* cast);
function: ProcessTable_done
void ProcessTable_done(ProcessTable* this);
function: ProcessTable_findProcess
static inline Process* ProcessTable_findProcess(ProcessTable* this, pid_t pid) {
return (Process*) Table_findRow(&this->super, pid);
}function: ProcessTable_getProcess
Process* ProcessTable_getProcess(ProcessTable* this, pid_t pid, bool* preExisting, Process_New constructor);
function: ProcessTable_goThroughEntries
void ProcessTable_goThroughEntries(ProcessTable* this);
function: ProcessTable_init
void ProcessTable_init(ProcessTable* this, const ObjectClass* klass, Machine* host, Hashtable* pidMatchList);
function: ProcessTable_new
ProcessTable* ProcessTable_new(Machine* host, Hashtable* pidMatchList);
struct: ProcessTable_
typedef struct ProcessTable_ {
Table super;
Hashtable* pidMatchList;
unsigned int totalTasks;
unsigned int runningTasks;
unsigned int userlandThreads;
unsigned int kernelThreads;
} ProcessTable;variable: ProcessTable_class
extern const TableClass ProcessTable_class;
ProvideCurses.h
ProvideCurses.h
file: ProvideCurses.h
#ifndef HEADER_ProvideCurses #define HEADER_ProvideCurses /* htop - ProvideCurses.h (C) 2004,2011 Hisham H. Muhammad Released under the GNU GPLv2+, see the COPYING file in the source distribution for its full text. */ // This header is also used in tests by configure, thus conditionally // including "config.h". #if defined(HAVE_CONFIG_H) #include "config.h" // IWYU pragma: keep #endif // IWYU pragma: begin_exports #if defined(HAVE_NCURSESW_CURSES_H) #include <ncursesw/curses.h> #elif defined(HAVE_NCURSES_NCURSES_H) #include <ncurses/ncurses.h> #elif defined(HAVE_NCURSES_CURSES_H) #include <ncurses/curses.h> #elif defined(HAVE_NCURSES_H) #include <ncurses.h> #elif defined(HAVE_CURSES_H) #include <curses.h> #endif #ifdef HAVE_LIBNCURSESW #include <wchar.h> #include <wctype.h> #endif // IWYU pragma: end_exports #endif // HEADER_ProvideCurses
ProvideTerm.h
ProvideTerm.h
file: ProvideTerm.h
#ifndef HEADER_ProvideTerm #define HEADER_ProvideTerm /* htop - ProvideTerm.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 <ncursesw/term.h> #elif defined(HAVE_NCURSES_TERM_H) #include <ncurses/term.h> #elif defined(HAVE_TERM_H) #include <term.h> #endif // IWYU pragma: end_exports #endif // HEADER_ProvideTerm
README
README
file: README
README.md
README.md
README.md
function: compile_htop_from_source
./autogen.sh && ./configure && make
function: configure_htop_installation_prefix
./configure --prefix=/some/path
function: install_archlinux_manjaro_build_dependencies
sudo pacman -S ncurses automake autoconf gcc
function: install_debian_ubuntu_build_dependencies
sudo apt install libncursesw5-dev autotools-dev autoconf automake build-essential
function: install_fedora_rhel_build_dependencies
sudo dnf install ncurses-devel automake autoconf gcc
function: install_htop_locally
make install
function: install_macos_build_dependencies
brew install ncurses automake autoconf gcc
function: view_htop_manual_page
man htop
method: get_htop_in_app_help
F1 or h inside htop
RichString.c
RichString.c
function: mbstowcs_nonfatal
static size_t mbstowcs_nonfatal(wchar_t* restrict dest, const char* restrict src, size_t n) {
size_t written = 0;
mbstate_t ps = { 0 };
bool broken = false;
while (n > 0) {
size_t ret = mbrtowc(dest, src, n, &ps);
if (ret == (size_t)-1 || ret == (size_t)-2) {
if (!broken) {
broken = true;
*dest++ = L'\xFFFD';
written++;
}
src++;
n--;
continue;
}
broken = false;
if (ret == 0) {
break;
}
dest++;
written++;
src += ret;
n -= ret;
}
return written;
}function: RichString_appendAscii
int RichString_appendAscii(RichString* this, int attrs, const char* data) {
return RichString_writeFromAscii(this, attrs, data, this->chlen, strlen(data));
}function: RichString_appendChr (!HAVE_LIBNCURSESW)
void RichString_appendChr(RichString* this, int attrs, char c, int count) {
int from = this->chlen;
int newLen = from + count;
RichString_setLen(this, newLen);
for (int i = from; i < newLen; i++) {
this->chptr[i] = c | attrs;
}
}function: RichString_appendChr (HAVE_LIBNCURSESW)
void RichString_appendChr(RichString* this, int attrs, char c, int count) {
int from = this->chlen;
int newLen = from + count;
RichString_setLen(this, newLen);
for (int i = from; i < newLen; i++) {
this->chptr[i] = (CharType) { .attr = attrs, .chars = { c, 0 } };
}
}function: RichString_appendnAscii
int RichString_appendnAscii(RichString* this, int attrs, const char* data, int len) {
return RichString_writeFromAscii(this, attrs, data, this->chlen, len);
}function: RichString_appendnWide
int RichString_appendnWide(RichString* this, int attrs, const char* data, int len) {
return RichString_writeFromWide(this, attrs, data, this->chlen, len);
}function: RichString_appendnWideColumns (!HAVE_LIBNCURSESW)
int RichString_appendnWideColumns(RichString* this, int attrs, const char* data_c, int len, int* columns) {
int written = RichString_writeFromWide(this, attrs, data_c, this->chlen, MINIMUM(len, *columns));
*columns = written;
return written;
}function: RichString_appendnWideColumns (HAVE_LIBNCURSESW)
int RichString_appendnWideColumns(RichString* this, int attrs, const char* data_c, int len, int* columns) {
wchar_t data[len];
len = mbstowcs_nonfatal(data, data_c, len);
if (len <= 0)
return 0;
int from = this->chlen;
int newLen = from + len;
RichString_setLen(this, newLen);
int columnsWritten = 0;
int pos = from;
for (int j = 0; j < len; j++) {
wchar_t c = iswprint(data[j]) ? data[j] : L'\xFFFD';
int cwidth = wcwidth(c);
if (cwidth > *columns)
break;
*columns -= cwidth;
columnsWritten += cwidth;
this->chptr[pos] = (CharType) { .attr = attrs & 0xffffff, .chars = { c, '\0' } };
pos++;
}
RichString_setLen(this, pos);
*columns = columnsWritten;
return pos - from;
}function: RichString_appendWide
int RichString_appendWide(RichString* this, int attrs, const char* data) {
return RichString_writeFromWide(this, attrs, data, this->chlen, strlen(data));
}function: RichString_delete
void RichString_delete(RichString* this) {
if (this->chlen > RICHSTRING_MAXLEN) {
free(this->chptr);
this->chptr = this->chstr;
}
}function: RichString_extendLen
static void RichString_extendLen(RichString* this, int len) {
if (this->chptr == this->chstr) {
// String is in internal buffer
if (len > RICHSTRING_MAXLEN) {
// Copy from internal buffer to allocated string
this->chptr = xMalloc(charBytes(len + 1));
memcpy(this->chptr, this->chstr, charBytes(this->chlen));
} else {
// Still fits in internal buffer, do nothing
assert(this->chlen <= RICHSTRING_MAXLEN);
}
} else {
// String is managed externally
if (len > RICHSTRING_MAXLEN) {
// Just reallocate the buffer accordingly
this->chptr = xRealloc(this->chptr, charBytes(len + 1));
} else {
// Move string into internal buffer and free resources
memcpy(this->chstr, this->chptr, charBytes(len));
free(this->chptr);
this->chptr = this->chstr;
}
}
RichString_setChar(this, len, 0);
this->chlen = len;
}function: RichString_findChar (!HAVE_LIBNCURSESW)
int RichString_findChar(const RichString* this, char c, int start) {
const chtype* ch = this->chptr + start;
for (int i = start; i < this->chlen; i++) {
if ((*ch & 0xff) == (chtype) c)
return i;
ch++;
}
return -1;
}function: RichString_findChar (HAVE_LIBNCURSESW)
int RichString_findChar(const RichString* this, char c, int start) {
const wchar_t wc = btowc(c);
const cchar_t* ch = this->chptr + start;
for (int i = start; i < this->chlen; i++) {
if (ch->chars[0] == wc)
return i;
ch++;
}
return -1;
}function: RichString_rewind
void RichString_rewind(RichString* this, int count) {
RichString_setLen(this, this->chlen - count);
}function: RichString_setAttr
void RichString_setAttr(RichString* this, int attrs) {
RichString_setAttrn(this, attrs, 0, this->chlen);
}function: RichString_setAttrn (!HAVE_LIBNCURSESW)
void RichString_setAttrn(RichString* this, int attrs, int start, int charcount) {
int end = CLAMP(start + charcount, 0, this->chlen);
for (int i = start; i < end; i++) {
this->chptr[i] = (this->chptr[i] & 0xff) | attrs;
}
}function: RichString_setAttrn (HAVE_LIBNCURSESW)
inline void RichString_setAttrn(RichString* this, int attrs, int start, int charcount) {
int end = CLAMP(start + charcount, 0, this->chlen);
for (int i = start; i < end; i++) {
this->chptr[i].attr = attrs;
}
}function: RichString_setLen
static void RichString_setLen(RichString* this, int len) {
if (len < RICHSTRING_MAXLEN && this->chlen < RICHSTRING_MAXLEN) {
RichString_setChar(this, len, 0);
this->chlen = len;
} else {
RichString_extendLen(this, len);
}
}function: RichString_writeAscii
int RichString_writeAscii(RichString* this, int attrs, const char* data) {
return RichString_writeFromAscii(this, attrs, data, 0, strlen(data));
}function: RichString_writeFromAscii (!HAVE_LIBNCURSESW)
static inline int RichString_writeFromAscii(RichString* this, int attrs, const char* data_c, int from, int len) {
return RichString_writeFromWide(this, attrs, data_c, from, len);
}function: RichString_writeFromAscii (HAVE_LIBNCURSESW)
static inline int RichString_writeFromAscii(RichString* this, int attrs, const char* data, int from, int len) {
int newLen = from + len;
RichString_setLen(this, newLen);
for (int i = from, j = 0; i < newLen; i++, j++) {
assert((unsigned char)data[j] <= SCHAR_MAX);
this->chptr[i] = (CharType) { .attr = attrs & 0xffffff, .chars = { (isprint((unsigned char)data[j]) ? data[j] : L'\xFFFD') } };
}
return len;
}function: RichString_writeFromWide (!HAVE_LIBNCURSESW)
static inline int RichString_writeFromWide(RichString* this, int attrs, const char* data_c, int from, int len) {
int newLen = from + len;
RichString_setLen(this, newLen);
for (int i = from, j = 0; i < newLen; i++, j++) {
this->chptr[i] = (((unsigned char)data_c[j]) >= 32 ? ((unsigned char)data_c[j]) : '?') | attrs;
}
this->chptr[newLen] = 0;
return len;
}function: RichString_writeFromWide (HAVE_LIBNCURSESW)
static inline int RichString_writeFromWide(RichString* this, int attrs, const char* data_c, int from, int len) {
wchar_t data[len];
len = mbstowcs_nonfatal(data, data_c, len);
if (len <= 0)
return 0;
int newLen = from + len;
RichString_setLen(this, newLen);
for (int i = from, j = 0; i < newLen; i++, j++) {
this->chptr[i] = (CharType) { .attr = attrs & 0xffffff, .chars = { (iswprint(data[j]) ? data[j] : L'\xFFFD') } };
}
return len;
}function: RichString_writeWide
int RichString_writeWide(RichString* this, int attrs, const char* data) {
return RichString_writeFromWide(this, attrs, data, 0, strlen(data));
}RichString.h
RichString.h
function: RichString_appendAscii
int RichString_appendAscii(RichString* this, int attrs, const char* data);
function: RichString_appendChr
void RichString_appendChr(RichString* this, int attrs, char c, int count);
function: RichString_appendnAscii
ATTR_ACCESS3_R(3, 4) int RichString_appendnAscii(RichString* this, int attrs, const char* data, int len);
function: RichString_appendnWide
ATTR_ACCESS3_R(3, 4) int RichString_appendnWide(RichString* this, int attrs, const char* data, int len);
function: RichString_appendnWideColumns
int RichString_appendnWideColumns(RichString* this, int attrs, const char* data, int len, int* columns);
function: RichString_appendWide
int RichString_appendWide(RichString* this, int attrs, const char* data);
function: RichString_delete
void RichString_delete(RichString* this);
function: RichString_findChar
int RichString_findChar(const RichString* this, char c, int start);
function: RichString_rewind
void RichString_rewind(RichString* this, int count);
function: RichString_setAttr
void RichString_setAttr(RichString* this, int attrs);
function: RichString_setAttrn
void RichString_setAttrn(RichString* this, int attrs, int start, int charcount);
function: RichString_writeAscii
int RichString_writeAscii(RichString* this, int attrs, const char* data);
function: RichString_writeWide
int RichString_writeWide(RichString* this, int attrs, const char* data);
macro: CharType
#ifdef HAVE_LIBNCURSESW #define CharType cchar_t #else #define CharType chtype #endif
macro: RichString_begin
#define RichString_begin(this) RichString this; RichString_beginAllocated(this)
macro: RichString_beginAllocated
#define RichString_beginAllocated(this) \
do { \
(this).chlen = 0; \
(this).chptr = (this).chstr; \
RichString_setChar(&(this), 0, 0); \
(this).highlightAttr = 0; \
} while(0)macro: RichString_getCharVal
#ifdef HAVE_LIBNCURSESW #define RichString_getCharVal(this, i) ((this).chptr[i].chars[0]) #else #define RichString_getCharVal(this, i) ((this).chptr[i] & 0xff) #endif
macro: RICHSTRING_MAXLEN
#define RICHSTRING_MAXLEN 350
macro: RichString_printoffnVal
#ifdef HAVE_LIBNCURSESW #define RichString_printoffnVal(this, y, x, off, n) mvadd_wchnstr(y, x, (this).chptr + (off), n) #else #define RichString_printoffnVal(this, y, x, off, n) mvaddchnstr(y, x, (this).chptr + (off), n) #endif
macro: RichString_printVal
#ifdef HAVE_LIBNCURSESW #define RichString_printVal(this, y, x) mvadd_wchstr(y, x, (this).chptr) #else #define RichString_printVal(this, y, x) mvaddchstr(y, x, (this).chptr) #endif
macro: RichString_setChar
#ifdef HAVE_LIBNCURSESW
#define RichString_setChar(this, at, ch) do { (this)->chptr[(at)] = (CharType) { .chars = { ch, 0 } }; } while (0)
#else
#define RichString_setChar(this, at, ch) do { (this)->chptr[(at)] = ch; } while (0)
#endifmacro: RichString_size
#define RichString_size(this) ((this)->chlen)
macro: RichString_sizeVal
#define RichString_sizeVal(this) ((this).chlen)
struct: RichString
typedef struct RichString_ {
int chlen;
CharType* chptr;
CharType chstr[RICHSTRING_MAXLEN + 1];
int highlightAttr;
} RichString;Row.c
Row.c
function: alignedTitleDynamicColumn
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;
}function: alignedTitleProcessField
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 (Process_fields[field].autoTitleRightAlign)
xSnprintf(titleBuffer, titleBufferSize, "%*s ", Row_fieldWidths[field], title);
else
xSnprintf(titleBuffer, titleBufferSize, "%-*.*s ", Row_fieldWidths[field], Row_fieldWidths[field], title);
return titleBuffer;
}
return title;
}function: Row_compare
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);
}function: Row_compareByParent_Base
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);
}function: Row_display
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);
}function: Row_done
void Row_done(Row* this) {
assert(this != NULL);
(void) this;
}function: Row_init
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;
}function: Row_isNew
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;
}function: Row_isTomb
static inline bool Row_isTomb(const Row* this) {
return this->tombStampMs > 0;
}function: Row_printBytes
void Row_printBytes(RichString* str, unsigned long long number, bool coloring) {
if (number == ULLONG_MAX)
Row_printKBytes(str, ULLONG_MAX, coloring);
else
Row_printKBytes(str, number / ONE_K, coloring);
}function: Row_printCount
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);
}
}function: Row_printKBytes
function: Row_printLeftAlignedField
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);
}function: Row_printNanoseconds
void Row_printNanoseconds(RichString* str, unsigned long long totalNanoseconds, bool coloring) {
if (totalNanoseconds == 0) {
int shadowColor = coloring ? CRT_colors[PROCESS_SHADOW] : CRT_colors[PROCESS];
RichString_appendAscii(str, shadowColor, " 0ns ");
return;
}
char buffer[10];
int len;
int baseColor = CRT_colors[PROCESS];
if (totalNanoseconds < 1000000) {
len = xSnprintf(buffer, sizeof(buffer), "%6luns ", (unsigned long)totalNanoseconds);
RichString_appendnAscii(str, baseColor, buffer, len);
return;
}
unsigned long long totalMicroseconds = totalNanoseconds / 1000;
if (totalMicroseconds < 1000000) {
len = xSnprintf(buffer, sizeof(buffer), ".%06lus ", (unsigned long)totalMicroseconds);
RichString_appendnAscii(str, baseColor, buffer, len);
return;
}
unsigned long long totalSeconds = totalMicroseconds / 1000000;
unsigned long microseconds = totalMicroseconds % 1000000;
if (totalSeconds < 60) {
int width = 5;
unsigned long fraction = microseconds / 10;
if (totalSeconds >= 10) {
width--;
fraction /= 10;
}
len = xSnprintf(buffer, sizeof(buffer), "%u.%0*lus ", (unsigned int)totalSeconds, width, fraction);
RichString_appendnAscii(str, baseColor, buffer, len);
return;
}
if (totalSeconds < 600) {
unsigned int minutes = totalSeconds / 60;
unsigned int seconds = totalSeconds % 60;
unsigned int milliseconds = microseconds / 1000;
len = xSnprintf(buffer, sizeof(buffer), "%u:%02u.%03u ", minutes, seconds, milliseconds);
RichString_appendnAscii(str, baseColor, buffer, len);
return;
}
unsigned long long totalHundredths = totalMicroseconds / 1000 / 10;
Row_printTime(str, totalHundredths, coloring);
}function: Row_printPercentage
int Row_printPercentage(float val, char* buffer, size_t n, uint8_t width, int* attr) {
assert(n >= 6 && width >= 4 && "Invalid width in Row_printPercentage()");
// truncate in favour of abort in xSnprintf()
width = (uint8_t)CLAMP(width, 4, n - 2);
assert(width < n - 1 && "Insufficient space to print column");
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");
}function: Row_printRate
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);
}
}function: Row_printTime
function: Row_resetFieldWidths
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;
}
}function: Row_setPidColumnWidth
void Row_setPidColumnWidth(pid_t maxPid) {
if (maxPid < (int)pow(10, ROW_MIN_PID_DIGITS)) {
Row_pidDigits = ROW_MIN_PID_DIGITS;
return;
}
Row_pidDigits = countDigits((size_t)maxPid, 10);
assert(Row_pidDigits <= ROW_MAX_PID_DIGITS);
}function: Row_setUidColumnWidth
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 = countDigits((size_t)maxUid, 10);
assert(Row_uidDigits <= ROW_MAX_UID_DIGITS);
}function: Row_toggleTag
void Row_toggleTag(Row* this) {
this->tag = !this->tag;
}function: Row_updateFieldWidth
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;
}function: RowField_alignedTitle
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));
}function: RowField_keyAt
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;
}global_variable: Row_fieldWidths
uint8_t Row_fieldWidths[LAST_PROCESSFIELD] = { 0 };global_variable: Row_pidDigits
int Row_pidDigits = ROW_MIN_PID_DIGITS;
global_variable: Row_uidDigits
int Row_uidDigits = ROW_MIN_UID_DIGITS;
struct: Row_class
const RowClass Row_class = {
.super = {
.extends = Class(Object),
.compare = Row_compare
},
};Row.h
Row.h
function prototype: Row_compare
int Row_compare(const void* v1, const void* v2);
function prototype: Row_compareByParent_Base
int Row_compareByParent_Base(const void* v1, const void* v2);
function prototype: Row_display
void Row_display(const Object* cast, RichString* out);
function prototype: Row_done
void Row_done(Row* this);
function prototype: Row_init
void Row_init(Row* this, const struct Machine_* host);
function prototype: Row_printBytes
void Row_printBytes(RichString* str, unsigned long long number, bool coloring);
function prototype: Row_printCount
void Row_printCount(RichString* str, unsigned long long number, bool coloring);
function prototype: Row_printKBytes
void Row_printKBytes(RichString* str, unsigned long long number, bool coloring);
function prototype: Row_printLeftAlignedField
void Row_printLeftAlignedField(RichString* str, int attr, const char* content, unsigned int width);
function prototype: Row_printNanoseconds
void Row_printNanoseconds(RichString* str, unsigned long long totalNanoseconds, bool coloring);
function prototype: Row_printPercentage
int Row_printPercentage(float val, char* buffer, size_t n, uint8_t width, int* attr);
function prototype: Row_printRate
void Row_printRate(RichString* str, double rate, bool coloring);
function prototype: Row_printTime
void Row_printTime(RichString* str, unsigned long long totalHundredths, bool coloring);
function prototype: Row_resetFieldWidths
void Row_resetFieldWidths(void);
function prototype: Row_setPidColumnWidth
void Row_setPidColumnWidth(pid_t maxPid);
function prototype: Row_setUidColumnWidth
void Row_setUidColumnWidth(uid_t maxUid);
function prototype: Row_toggleTag
void Row_toggleTag(Row* this);
function prototype: Row_updateFieldWidth
void Row_updateFieldWidth(RowField key, size_t width);
function prototype: RowField_alignedTitle
const char* RowField_alignedTitle(const struct Settings_* settings, RowField field);
function prototype: RowField_keyAt
RowField RowField_keyAt(const struct Settings_* settings, int at);
global variable: Row_class
extern const RowClass Row_class;
global variable: Row_fieldWidths
extern uint8_t Row_fieldWidths[LAST_RESERVED_FIELD];
global variable: Row_pidDigits
extern int Row_pidDigits;
global variable: Row_uidDigits
extern int Row_uidDigits;
inline function: Row_getGroupOrParent
static inline int Row_getGroupOrParent(const Row* this) {
return this->group == this->id ? this->parent : this->group;
}inline function: Row_idEqualCompare
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 */
}inline function: Row_isChildOf
static inline bool Row_isChildOf(const Row* this, int id) {
return id == Row_getGroupOrParent(this);
}macro: As_Row
#define As_Row(this_) ((const RowClass*)((this_)->super.klass))
macro: ONE_DECIMAL_G
#define ONE_DECIMAL_G (ONE_DECIMAL_M * ONE_DECIMAL_K)
macro: ONE_DECIMAL_K
#define ONE_DECIMAL_K 1000UL
macro: ONE_DECIMAL_M
#define ONE_DECIMAL_M (ONE_DECIMAL_K * ONE_DECIMAL_K)
macro: ONE_DECIMAL_P
#define ONE_DECIMAL_P (1ULL * ONE_DECIMAL_T * ONE_DECIMAL_K)
macro: ONE_DECIMAL_T
#define ONE_DECIMAL_T (1ULL * ONE_DECIMAL_G * ONE_DECIMAL_K)
macro: ONE_G
#define ONE_G (ONE_M * ONE_K)
macro: ONE_K
#define ONE_K 1024UL
macro: ONE_M
#define ONE_M (ONE_K * ONE_K)
macro: ONE_P
#define ONE_P (1ULL * ONE_T * ONE_K)
macro: ONE_T
#define ONE_T (1ULL * ONE_G * ONE_K)
macro: Row_compareByParent
#define Row_compareByParent(r1_, r2_) (As_Row(r1_)->compareByParent ? (As_Row(r1_)->compareByParent(r1_, r2_)) : Row_compareByParent_Base(r1_, r2_))
macro: Row_isHighlighted
#define Row_isHighlighted(r_) (As_Row(r_)->isHighlighted ? (As_Row(r_)->isHighlighted(r_)) : false)
macro: Row_isVisible
#define Row_isVisible(r_, t_) (As_Row(r_)->isVisible ? (As_Row(r_)->isVisible(r_, t_)) : true)
macro: Row_matchesFilter
#define Row_matchesFilter(r_, t_) (As_Row(r_)->matchesFilter ? (As_Row(r_)->matchesFilter(r_, t_)) : false)
macro: ROW_MAX_PID_DIGITS
#define ROW_MAX_PID_DIGITS 19
macro: ROW_MAX_UID_DIGITS
#define ROW_MAX_UID_DIGITS 20
macro: ROW_MIN_PID_DIGITS
#define ROW_MIN_PID_DIGITS 5
macro: ROW_MIN_UID_DIGITS
#define ROW_MIN_UID_DIGITS 5
macro: Row_sortKeyString
#define Row_sortKeyString(r_) (As_Row(r_)->sortKeyString ? (As_Row(r_)->sortKeyString(r_)) : "")
struct: Row_
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;struct: RowClass_
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;struct forward declaration: Machine_
struct Machine_;
struct forward declaration: Settings_
struct Settings_;
struct forward declaration: Table_
struct Table_;
typedef: Row
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: RowClass
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;typedef function pointer: Row_CompareByParent
typedef int (*Row_CompareByParent)(const Row*, const Row*);
typedef function pointer: Row_IsHighlighted
typedef bool (*Row_IsHighlighted)(const Row*);
typedef function pointer: Row_IsVisible
typedef bool (*Row_IsVisible)(const Row*, const struct Table_*);
typedef function pointer: Row_MatchesFilter
typedef bool (*Row_MatchesFilter)(const Row*, const struct Table_*);
typedef function pointer: Row_New
typedef Row* (*Row_New)(const struct Machine_*);
typedef function pointer: Row_SortKeyString
typedef const char* (*Row_SortKeyString)(Row*);
typedef function pointer: Row_WriteField
typedef void (*Row_WriteField)(const Row*, RichString*, RowField);
RowField.h
RowField.h
macro: ROW_DYNAMIC_FIELDS
#define ROW_DYNAMIC_FIELDS LAST_RESERVED_FIELD
typedef: RowField
typedef int32_t RowField;
typedef enum: ReservedFields
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;Scheduling.c
Scheduling.c
array: policies
static const SchedulingPolicy policies[] = {
[SCHED_OTHER] = { "Other", SCHED_OTHER, false },
#ifdef SCHED_BATCH
[SCHED_BATCH] = { "Batch", SCHED_BATCH, false },
#endif
#ifdef SCHED_IDLE
[SCHED_IDLE] = { "Idle", SCHED_IDLE, false },
#endif
[SCHED_FIFO] = { "FiFo", SCHED_FIFO, true },
[SCHED_RR] = { "RoundRobin", SCHED_RR, true },
};function: Scheduling_formatPolicy
const char* Scheduling_formatPolicy(int policy) {
#ifdef SCHED_RESET_ON_FORK
policy = policy & ~SCHED_RESET_ON_FORK;
#endif
switch (policy) {
case SCHED_OTHER:
return "OTHER";
case SCHED_FIFO:
return "FIFO";
case SCHED_RR:
return "RR";
#ifdef SCHED_BATCH
case SCHED_BATCH:
return "BATCH";
#endif
#ifdef SCHED_IDLE
case SCHED_IDLE:
return "IDLE";
#endif
#ifdef SCHED_DEADLINE
case SCHED_DEADLINE:
return "EDF";
#endif
default:
return "???";
}
}function: Scheduling_newPolicyPanel
Panel* Scheduling_newPolicyPanel(int preSelectedPolicy) {
Panel* this = Panel_new(0, 0, 0, 0, Class(ListItem), true, FunctionBar_newEnterEsc("Select ", "Cancel "));
Panel_setHeader(this, "New policy:");
#ifdef SCHED_RESET_ON_FORK
Panel_add(this, (Object*) ListItem_new(reset_on_fork ? "Reset on fork: on" : "Reset on fork: off", -1));
#endif
for (unsigned i = 0; i < ARRAYSIZE(policies); i++) {
if (!policies[i].name)
continue;
Panel_add(this, (Object*) ListItem_new(policies[i].name, policies[i].id));
if (policies[i].id == preSelectedPolicy)
Panel_setSelected(this, i);
}
return this;
}function: Scheduling_newPriorityPanel
Panel* Scheduling_newPriorityPanel(int policy, int preSelectedPriority) {
if (policy < 0 || (unsigned)policy >= ARRAYSIZE(policies) || policies[policy].name == NULL)
return NULL;
if (!policies[policy].prioritySupport)
return NULL;
int min = sched_get_priority_min(policy);
if (min < 0)
return NULL;
int max = sched_get_priority_max(policy);
if (max < 0 )
return NULL;
Panel* this = Panel_new(0, 0, 0, 0, Class(ListItem), true, FunctionBar_newEnterEsc("Select ", "Cancel "));
Panel_setHeader(this, "Priority:");
for (int i = min; i <= max; i++) {
char buf[16];
xSnprintf(buf, sizeof(buf), "%d", i);
Panel_add(this, (Object*) ListItem_new(buf, i));
if (i == preSelectedPriority)
Panel_setSelected(this, i);
}
return this;
}function: Scheduling_readProcessPolicy
void Scheduling_readProcessPolicy(Process* proc) {
proc->scheduling_policy = sched_getscheduler(Process_getPid(proc));
}function: Scheduling_rowSetPolicy
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);
}function: Scheduling_setPolicy
static bool Scheduling_setPolicy(Process* p, Arg arg) {
const SchedulingArg* sarg = arg.v;
int policy = sarg->policy;
assert(policy >= 0);
assert((unsigned)policy < ARRAYSIZE(policies));
assert(policies[policy].name);
const struct sched_param param = { .sched_priority = policies[policy].prioritySupport ? sarg->priority : 0 };
#ifdef SCHED_RESET_ON_FORK
if (reset_on_fork)
policy &= SCHED_RESET_ON_FORK;
#endif
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;
}function: Scheduling_togglePolicyPanelResetOnFork
void Scheduling_togglePolicyPanelResetOnFork(Panel* schedPanel) {
#ifdef SCHED_RESET_ON_FORK
reset_on_fork = !reset_on_fork;
ListItem* item = (ListItem*) Panel_get(schedPanel, 0);
free_and_xStrdup(&item->value, reset_on_fork ? "Reset on fork: on" : "Reset on fork: off");
#else
(void)schedPanel;
#endif
}variable: reset_on_fork
#ifdef SCHED_RESET_ON_FORK static bool reset_on_fork = false; #endif
Scheduling.h
Scheduling.h
function: Scheduling_formatPolicy
const char* Scheduling_formatPolicy(int policy);
function: Scheduling_newPolicyPanel
Panel* Scheduling_newPolicyPanel(int preSelectedPolicy);
function: Scheduling_newPriorityPanel
Panel* Scheduling_newPriorityPanel(int policy, int preSelectedPriority);
function: Scheduling_readProcessPolicy
void Scheduling_readProcessPolicy(Process* proc);
function: Scheduling_rowSetPolicy
bool Scheduling_rowSetPolicy(Row* proc, Arg arg);
function: Scheduling_togglePolicyPanelResetOnFork
void Scheduling_togglePolicyPanelResetOnFork(Panel* schedPanel);
macro: SCHEDULER_SUPPORT
#define SCHEDULER_SUPPORT
macro: SCHEDULINGPANEL_INITSELECTEDPOLICY
#define SCHEDULINGPANEL_INITSELECTEDPOLICY SCHED_OTHER
macro: SCHEDULINGPANEL_INITSELECTEDPRIORITY
#define SCHEDULINGPANEL_INITSELECTEDPRIORITY 50
struct: SchedulingArg
typedef struct {
int policy;
int priority;
} SchedulingArg;struct: SchedulingPolicy
typedef struct {
const char* name;
int id;
bool prioritySupport;
} SchedulingPolicy;ScreenManager.c
ScreenManager.c
function: checkRecalculation
static void checkRecalculation(ScreenManager* this, double* oldTime, int* sortTimeout, bool* redraw, bool* rescan, bool* timedOut, bool* force_redraw) {
Machine* host = this->host;
Platform_gettime_realtime(&host->realtime, &host->realtimeMs);
double newTime = ((double)host->realtime.tv_sec * 10) + ((double)host->realtime.tv_usec / 100000);
*timedOut = (newTime - *oldTime > host->settings->delay);
*rescan |= *timedOut;
if (newTime < *oldTime) {
*rescan = true; // clock was adjusted?
}
if (*rescan) {
*oldTime = newTime;
int oldUidDigits = Process_uidDigits;
if (!this->state->pauseUpdate && (*sortTimeout == 0 || host->settings->ss->treeView)) {
host->activeTable->needsSort = true;
*sortTimeout = 1;
}
// sample current values for system metrics and processes if not paused
Machine_scan(host);
if (!this->state->pauseUpdate)
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
if (Process_uidDigits != oldUidDigits) {
*force_redraw = true;
}
*redraw = true;
}
if (*redraw) {
Table_rebuildPanel(host->activeTable);
if (!this->state->hideMeters)
Header_draw(this->header);
}
*rescan = false;
}function: drawTab
static inline bool drawTab(const int* y, int* x, int l, const char* name, bool cur) {
attrset(CRT_colors[cur ? SCREENS_CUR_BORDER : SCREENS_OTH_BORDER]);
mvaddch(*y, *x, '[');
(*x)++;
if (*x >= l)
return false;
int nameLen = strlen(name);
int n = MINIMUM(l - *x, nameLen);
attrset(CRT_colors[cur ? SCREENS_CUR_TEXT : SCREENS_OTH_TEXT]);
mvaddnstr(*y, *x, name, n);
*x += n;
if (*x >= l)
return false;
attrset(CRT_colors[cur ? SCREENS_CUR_BORDER : SCREENS_OTH_BORDER]);
mvaddch(*y, *x, ']');
*x += 1 + SCREEN_TAB_COLUMN_GAP;
if (*x >= l)
return false;
return true;
}function: header_height
static int header_height(const ScreenManager* this) {
if (this->state->hideMeters)
return 0;
if (this->header)
return this->header->height;
return 0;
}function: ScreenManager_add
void ScreenManager_add(ScreenManager* this, Panel* item, int size) {
ScreenManager_insert(this, item, size, Vector_size(this->panels));
}function: ScreenManager_delete
void ScreenManager_delete(ScreenManager* this) {
Vector_delete(this->panels);
free(this);
}function: ScreenManager_drawPanels
static void ScreenManager_drawPanels(ScreenManager* this, int focus, bool force_redraw) {
Settings* settings = this->host->settings;
if (settings->screenTabs) {
ScreenManager_drawScreenTabs(this);
}
const int nPanels = this->panelCount;
for (int i = 0; i < nPanels; i++) {
Panel* panel = (Panel*) Vector_get(this->panels, i);
Panel_draw(panel,
force_redraw,
i == focus,
panel != (Panel*)this->state->mainPanel || !this->state->hideSelection,
State_hideFunctionBar(this->state));
mvvline(panel->y, panel->x + panel->w, ' ', panel->h + (State_hideFunctionBar(this->state) ? 1 : 0));
}
}function: ScreenManager_drawScreenTabs
static void ScreenManager_drawScreenTabs(ScreenManager* this) {
Settings* settings = this->host->settings;
ScreenSettings** screens = settings->screens;
int cur = settings->ssIndex;
int l = COLS;
Panel* panel = (Panel*) Vector_get(this->panels, 0);
int y = panel->y - 1;
int x = SCREEN_TAB_MARGIN_LEFT;
if (this->name) {
drawTab(&y, &x, l, this->name, true);
return;
}
for (int s = 0; screens[s]; s++) {
bool ok = drawTab(&y, &x, l, screens[s]->heading, s == cur);
if (!ok) {
break;
}
}
attrset(CRT_colors[RESET_COLOR]);
}function: ScreenManager_insert
void ScreenManager_insert(ScreenManager* this, Panel* item, int size, int idx) {
int lastX = 0;
if (idx > 0) {
const Panel* last = (const Panel*) Vector_get(this->panels, idx - 1);
lastX = last->x + last->w + 1;
}
int height = LINES - this->y1 - header_height(this) + this->y2;
if (size <= 0) {
size = COLS - this->x1 + this->x2 - lastX;
}
Panel_resize(item, size, height);
Panel_move(item, lastX, this->y1 + header_height(this));
if (idx < this->panelCount) {
for (int i = idx + 1; i <= this->panelCount; i++) {
Panel* p = (Panel*) Vector_get(this->panels, i);
Panel_move(p, p->x + size, p->y);
}
}
Vector_insert(this->panels, idx, item);
item->needsRedraw = true;
this->panelCount++;
}function: ScreenManager_new
ScreenManager* ScreenManager_new(Header* header, Machine* host, State* state, bool owner) {
ScreenManager* this;
this = xMalloc(sizeof(ScreenManager));
this->x1 = 0;
this->y1 = 0;
this->x2 = 0;
this->y2 = -1;
this->panels = Vector_new(Class(Panel), owner, DEFAULT_SIZE);
this->panelCount = 0;
this->header = header;
this->host = host;
this->state = state;
this->allowFocusChange = true;
return this;
}function: ScreenManager_remove
Panel* ScreenManager_remove(ScreenManager* this, int idx) {
assert(this->panelCount > idx);
int w = ((Panel*) Vector_get(this->panels, idx))->w;
Panel* panel = (Panel*) Vector_remove(this->panels, idx);
this->panelCount--;
if (idx < this->panelCount) {
for (int i = idx; i < this->panelCount; i++) {
Panel* p = (Panel*) Vector_get(this->panels, i);
Panel_move(p, p->x - w, p->y);
}
}
return panel;
}function: ScreenManager_resize
void ScreenManager_resize(ScreenManager* this) {
int y1_header = this->y1 + header_height(this);
int panels = this->panelCount;
int lastX = 0;
for (int i = 0; i < panels - 1; i++) {
Panel* panel = (Panel*) Vector_get(this->panels, i);
Panel_resize(panel, panel->w, LINES - y1_header + this->y2);
Panel_move(panel, lastX, y1_header);
lastX = panel->x + panel->w + 1;
}
Panel* panel = (Panel*) Vector_get(this->panels, panels - 1);
Panel_resize(panel, COLS - this->x1 + this->x2 - lastX, LINES - y1_header + this->y2);
Panel_move(panel, lastX, y1_header);
}function: ScreenManager_run
function: ScreenManager_size
inline int ScreenManager_size(const ScreenManager* this) {
return this->panelCount;
}ScreenManager.h
ScreenManager.h
method: ScreenManager_add
void ScreenManager_add(ScreenManager* this, Panel* item, int size);
method: ScreenManager_delete
void ScreenManager_delete(ScreenManager* this);
method: ScreenManager_insert
void ScreenManager_insert(ScreenManager* this, Panel* item, int size, int idx);
method: ScreenManager_new
ScreenManager* ScreenManager_new(Header* header, Machine* host, State* state, bool owner);
method: ScreenManager_remove
Panel* ScreenManager_remove(ScreenManager* this, int idx);
method: ScreenManager_resize
void ScreenManager_resize(ScreenManager* this);
method: ScreenManager_run
void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey, const char* name);
method: ScreenManager_size
int ScreenManager_size(const ScreenManager* this);
struct: ScreenManager
typedef struct ScreenManager_ {
int x1;
int y1;
int x2;
int y2;
Vector* panels;
const char* name;
int panelCount;
Header* header;
Machine* host;
State* state;
bool allowFocusChange;
} ScreenManager;ScreensPanel.c
ScreensPanel.c
function: addNewScreen
static void addNewScreen(Panel* super) {
ScreensPanel* const this = (ScreensPanel*) super;
const char* name = "New";
ScreenSettings* ss = Settings_newScreen(this->settings, &(const ScreenDefaults) { .name = name, .columns = "PID Command", .sortKey = "PID" });
ScreenListItem* item = ScreenListItem_new(name, ss);
int idx = Panel_getSelectedIndex(super);
Panel_insert(super, idx + 1, (Object*) item);
Panel_setSelected(super, idx + 1);
}function: rebuildSettingsArray
static void rebuildSettingsArray(Panel* super, int selected) {
ScreensPanel* const this = (ScreensPanel*) super;
int n = Panel_size(super);
free(this->settings->screens);
this->settings->screens = xMallocArray(n + 1, sizeof(ScreenSettings*));
this->settings->screens[n] = NULL;
for (int i = 0; i < n; i++) {
ScreenListItem* item = (ScreenListItem*) Panel_get(super, i);
this->settings->screens[i] = item->ss;
}
this->settings->nScreens = n;
/* ensure selection is in valid range */
if (selected > n - 1)
selected = n - 1;
else if (selected < 0)
selected = 0;
this->settings->ssIndex = selected;
this->settings->ss = this->settings->screens[selected];
}function: ScreenListItem_delete
static void ScreenListItem_delete(Object* cast) {
ScreenListItem* this = (ScreenListItem*)cast;
if (this->ss) {
ScreenSettings_delete(this->ss);
}
ListItem_delete(cast);
}function: ScreenListItem_new
ScreenListItem* ScreenListItem_new(const char* value, ScreenSettings* ss) {
ScreenListItem* this = AllocThis(ScreenListItem);
ListItem_init((ListItem*)this, value, 0);
this->ss = ss;
return this;
}function: ScreensPanel_delete
static void ScreensPanel_delete(Object* object) {
Panel* super = (Panel*) object;
/* do not delete screen settings still in use */
int n = Panel_size(super);
for (int i = 0; i < n; i++) {
ScreenListItem* item = (ScreenListItem*) Panel_get(super, i);
item->ss = NULL;
}
Panel_delete(object);
}function: ScreensPanel_eventHandler
static HandlerResult ScreensPanel_eventHandler(Panel* super, int ch) {
ScreensPanel* const this = (ScreensPanel*) super;
if (this->renamingItem) {
return ScreensPanel_eventHandlerRenaming(super, ch);
} else {
return ScreensPanel_eventHandlerNormal(super, ch);
}
}function: ScreensPanel_eventHandlerNormal
function: ScreensPanel_eventHandlerRenaming
static HandlerResult ScreensPanel_eventHandlerRenaming(Panel* super, int ch) {
ScreensPanel* const this = (ScreensPanel*) 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);
}
return HANDLED;
}
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);
ScreensPanel_update(super);
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;
}function: ScreensPanel_new
ScreensPanel* ScreensPanel_new(Settings* settings) {
ScreensPanel* this = AllocThis(ScreensPanel);
Panel* super = &this->super;
FunctionBar* fuBar = FunctionBar_new(settings->dynamicScreens ? DynamicFunctions : ScreensFunctions, NULL, NULL);
Panel_init(super, 1, 1, 1, 1, Class(ListItem), true, fuBar);
Hashtable* columns = settings->dynamicColumns;
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;
this->cursor = 0;
Panel_setHeader(super, "Screens");
for (unsigned int i = 0; i < settings->nScreens; i++) {
ScreenSettings* ss = settings->screens[i];
char* name = ss->heading;
Panel_add(super, (Object*) ScreenListItem_new(name, ss));
}
return this;
}function: ScreensPanel_update
void ScreensPanel_update(Panel* super) {
ScreensPanel* this = (ScreensPanel*) super;
int size = Panel_size(super);
this->settings->changed = true;
this->settings->lastUpdate++;
this->settings->screens = xReallocArray(this->settings->screens, size + 1, sizeof(ScreenSettings*));
for (int i = 0; i < size; i++) {
ScreenListItem* item = (ScreenListItem*) Panel_get(super, i);
ScreenSettings* ss = item->ss;
free_and_xStrdup(&ss->heading, ((ListItem*) item)->value);
this->settings->screens[i] = ss;
}
this->settings->screens[size] = NULL;
}function: startRenaming
static void startRenaming(Panel* super) {
ScreensPanel* const this = (ScreensPanel*) 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);
}global_variable: DynamicFunctions
static const char* const DynamicFunctions[] = {" ", "Rename", " ", " ", " ", " ", "MoveUp", "MoveDn", "Remove", "Done ", NULL};global_variable: ScreensFunctions
static const char* const ScreensFunctions[] = {" ", "Rename", " ", " ", "New ", " ", "MoveUp", "MoveDn", "Remove", "Done ", NULL};struct: ScreenListItem_class
ObjectClass ScreenListItem_class = {
.extends = Class(ListItem),
.display = ListItem_display,
.delete = ScreenListItem_delete,
.compare = ListItem_compare
};struct: ScreensPanel_class
PanelClass ScreensPanel_class = {
.super = {
.extends = Class(Panel),
.delete = ScreensPanel_delete
},
.eventHandler = ScreensPanel_eventHandler
};ScreensPanel.h
ScreensPanel.h
function prototype: ScreenListItem_new
ScreenListItem* ScreenListItem_new(const char* value, ScreenSettings* ss);
function prototype: ScreensPanel_new
ScreensPanel* ScreensPanel_new(Settings* settings);
function prototype: ScreensPanel_update
void ScreensPanel_update(Panel* super);
global variable declaration: ScreenListItem_class
extern ObjectClass ScreenListItem_class;
struct definition: ScreenListItem
typedef struct ScreenListItem_ {
ListItem super;
DynamicScreen* ds;
ScreenSettings* ss;
} ScreenListItem;struct definition: ScreensPanel
typedef struct ScreensPanel_ {
Panel super;
ScreenManager* scr;
Settings* settings;
ColumnsPanel* columns;
AvailableColumnsPanel* availableColumns;
char buffer[SCREEN_NAME_LEN + 1];
char* saved;
int cursor;
bool moving;
ListItem* renamingItem;
} ScreensPanel;ScreenTabsPanel.c
ScreenTabsPanel.c
function: addDynamicScreen
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));
}function: addNewScreen
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);
}function: renameScreenSettings
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++;
}function: ScreenNameListItem_new
ScreenNameListItem* ScreenNameListItem_new(const char* value, ScreenSettings* ss) {
ScreenNameListItem* this = AllocThis(ScreenNameListItem);
ListItem_init((ListItem*)this, value, 0);
this->ss = ss;
return this;
}function: ScreenNamesPanel_delete
static void ScreenNamesPanel_delete(Object* object) {
ScreenNamesPanel* this = (ScreenNamesPanel*) object;
Panel* super = &this->super;
/* 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);
}function: ScreenNamesPanel_eventHandler
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);
}function: ScreenNamesPanel_eventHandlerNormal
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;
}function: ScreenNamesPanel_eventHandlerRenaming
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);
}
return HANDLED;
}
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;
}function: ScreenNamesPanel_fill
static void ScreenNamesPanel_fill(ScreenNamesPanel* this, DynamicScreen* ds) {
const Settings* settings = this->settings;
Panel* super = &this->super;
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;
}function: ScreenNamesPanel_new
ScreenNamesPanel* ScreenNamesPanel_new(Settings* settings) {
ScreenNamesPanel* this = AllocThis(ScreenNamesPanel);
Panel* super = &this->super;
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;
}function: ScreenTabListItem_new
static ScreenTabListItem* ScreenTabListItem_new(const char* value, DynamicScreen* ds) {
ScreenTabListItem* this = AllocThis(ScreenTabListItem);
ListItem_init((ListItem*)this, value, 0);
this->ds = ds;
return this;
}function: ScreenTabsPanel_delete
static void ScreenTabsPanel_delete(Object* object) {
ScreenTabsPanel* this = (ScreenTabsPanel*) object;
Panel_done(&this->super);
free(this);
}function: ScreenTabsPanel_eventHandler
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);
if (focus) {
ScreenNamesPanel_fill(this->names, focus->ds);
}
}
return result;
}function: ScreenTabsPanel_new
ScreenTabsPanel* ScreenTabsPanel_new(Settings* settings) {
ScreenTabsPanel* this = AllocThis(ScreenTabsPanel);
Panel* super = &this->super;
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;
}function: startRenaming
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);
}global variable: ScreenNameListItem_class
ObjectClass ScreenNameListItem_class = {
.extends = Class(ListItem),
.display = ListItem_display,
.delete = ListItem_delete,
.compare = ListItem_compare
};global variable: ScreenNamesFunctions
static const char* const ScreenNamesFunctions[] = {" ", " ", " ", " ", "New ", " ", " ", " ", " ", "Done ", NULL};global variable: ScreenNamesPanel_class
PanelClass ScreenNamesPanel_class = {
.super = {
.extends = Class(Panel),
.delete = ScreenNamesPanel_delete
},
.eventHandler = ScreenNamesPanel_eventHandler
};global variable: ScreenTabListItem_class
ObjectClass ScreenTabListItem_class = {
.extends = Class(ListItem),
.display = ListItem_display,
.delete = ListItem_delete,
.compare = ListItem_compare
};global variable: ScreenTabsFunctions
static const char* const ScreenTabsFunctions[] = {" ", " ", " ", " ", "New ", " ", " ", " ", " ", "Done ", NULL};global variable: ScreenTabsPanel_class
PanelClass ScreenTabsPanel_class = {
.super = {
.extends = Class(Panel),
.delete = ScreenTabsPanel_delete,
},
.eventHandler = ScreenTabsPanel_eventHandler
};ScreenTabsPanel.h
ScreenTabsPanel.h
external variable: ScreenNameListItem_class
extern ObjectClass ScreenNameListItem_class;
external variable: ScreenNamesPanel_class
extern PanelClass ScreenNamesPanel_class;
function: ScreenNameListItem_new
ScreenNameListItem* ScreenNameListItem_new(const char* value, ScreenSettings* ss);
function: ScreenNamesPanel_new
ScreenNamesPanel* ScreenNamesPanel_new(Settings* settings);
function: ScreenTabsPanel_new
ScreenTabsPanel* ScreenTabsPanel_new(Settings* settings);
struct: ScreenNameListItem_
typedef struct ScreenNameListItem_ {
ListItem super;
ScreenSettings* ss;
} ScreenNameListItem;struct: ScreenNamesPanel_
typedef struct ScreenNamesPanel_ {
Panel super;
ScreenManager* scr;
Settings* settings;
char buffer[SCREEN_NAME_LEN + 1];
DynamicScreen* ds;
char* saved;
int cursor;
ListItem* renamingItem;
} ScreenNamesPanel;struct: ScreenTabListItem_
typedef struct ScreenTabListItem_ {
ListItem super;
DynamicScreen* ds;
} ScreenTabListItem;struct: ScreenTabsPanel_
typedef struct ScreenTabsPanel_ {
Panel super;
ScreenManager* scr;
Settings* settings;
ScreenNamesPanel* names;
int cursor;
} ScreenTabsPanel;htop_suppressions.valgrind
scripts/htop_suppressions.valgrind
file: htop_suppressions.valgrind
{
<ncurses internal memory>
Memcheck:Leak
match-leak-kinds: possible,reachable
...
fun:doupdate_sp
fun:wrefresh
}
{
<ncurses internal memory>
Memcheck:Leak
match-leak-kinds: possible,reachable
...
fun:newterm_sp
fun:newterm
fun:initscr
fun:CRT_init
}
{
<ncurses internal memory>
Memcheck:Leak
match-leak-kinds: reachable
...
obj:*/libtinfo*
fun:CRT_init
}
{
<ncurses internal memory>
Memcheck:Leak
match-leak-kinds: reachable
...
obj:*/libncurses*
fun:CRT_init
}
{
<ncurses internal memory>
Memcheck:Leak
match-leak-kinds: possible,reachable
...
obj:*/libncurses*
fun:CRT_setColors
fun:CRT_init
}
{
<devstat internal memory>
Memcheck:Leak
match-leak-kinds: possible,reachable
...
obj:*/libdevstat*
...
fun:Platform_getDiskIO
}
run_valgrind.sh
scripts/run_valgrind.sh
function: main
#!/bin/sh
SCRIPT=$(readlink -f "$0")
SCRIPTDIR=$(dirname "$SCRIPT")
valgrind --leak-check=full --show-reachable=yes --show-leak-kinds=all --track-fds=yes --errors-for-leak-kinds=all --track-origins=yes --suppressions="${SCRIPTDIR}/htop_suppressions.valgrind" "${SCRIPTDIR}/../htop"Settings.c
Settings.c
function: ScreenSettings_delete
void ScreenSettings_delete(ScreenSettings* this) {
free(this->heading);
free(this->dynamic);
free(this->fields);
free(this);
}function: ScreenSettings_invertSortOrder
void ScreenSettings_invertSortOrder(ScreenSettings* this) {
int* attr = (this->treeView) ? &(this->treeDirection) : &(this->direction);
*attr = (*attr == 1) ? -1 : 1;
}function: ScreenSettings_readFields
static void ScreenSettings_readFields(ScreenSettings* ss, Hashtable* columns, const char* line) {
char* trim = String_trim(line);
char** ids = String_split(trim, ' ', NULL);
free(trim);
/* reset default fields */
memset(ss->fields, '\0', LAST_PROCESSFIELD * sizeof(ProcessField));
for (size_t j = 0, i = 0; ids[i]; i++) {
if (j >= UINT_MAX / sizeof(ProcessField))
continue;
if (j >= LAST_PROCESSFIELD) {
ss->fields = xRealloc(ss->fields, (j + 1) * sizeof(ProcessField));
memset(&ss->fields[j], 0, sizeof(ProcessField));
}
int id = toFieldIndex(columns, ids[i]);
if (id >= 0)
ss->fields[j++] = id;
if (id > 0 && id < LAST_PROCESSFIELD)
ss->flags |= Process_fields[id].flags;
}
String_freeArray(ids);
}function: ScreenSettings_setSortKey
void ScreenSettings_setSortKey(ScreenSettings* this, ProcessField sortKey) {
if (this->treeViewAlwaysByPID || !this->treeView) {
this->sortKey = sortKey;
this->direction = (Process_fields[sortKey].defaultSortDesc) ? -1 : 1;
this->treeView = false;
} else {
this->treeSortKey = sortKey;
this->treeDirection = (Process_fields[sortKey].defaultSortDesc) ? -1 : 1;
}
}function: Settings_defaultMeters
function: Settings_defaultScreens
static ScreenSettings* Settings_defaultScreens(Settings* this) {
if (this->nScreens)
return this->screens[0];
for (unsigned int i = 0; i < Platform_numberOfDefaultScreens; i++) {
const ScreenDefaults* defaults = &Platform_defaultScreens[i];
Settings_newScreen(this, defaults);
}
Platform_defaultDynamicScreens(this);
return this->screens[0];
}function: Settings_delete
void Settings_delete(Settings* this) {
free(this->filename);
free(this->initialFilename);
Settings_deleteColumns(this);
Settings_deleteScreens(this);
free(this);
}function: Settings_deleteColumns
static void Settings_deleteColumns(Settings* this) {
for (size_t i = 0; i < HeaderLayout_getColumns(this->hLayout); i++) {
String_freeArray(this->hColumns[i].names);
free(this->hColumns[i].modes);
}
free(this->hColumns);
}function: Settings_deleteScreens
static void Settings_deleteScreens(Settings* this) {
if (this->screens) {
for (size_t i = 0; this->screens[i]; i++)
ScreenSettings_delete(this->screens[i]);
free(this->screens);
}
}function: Settings_enableReadonly
static bool readonly = false;
void Settings_enableReadonly(void) {
readonly = true;
}function: Settings_initScreenSettings
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;
}function: Settings_isReadonly
bool Settings_isReadonly(void) {
return readonly;
}function: Settings_new
function: Settings_newDynamicScreen
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);
}function: Settings_newScreen
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) {
.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 = treeSortKey,
.treeView = false,
.treeViewAlwaysByPID = false,
.allBranchesCollapsed = false,
};
return Settings_initScreenSettings(ss, this, defaults->columns);
}function: Settings_read
function: Settings_readMeterModes
static void Settings_readMeterModes(Settings* this, const char* line, size_t column) {
char** ids = Settings_splitLineToIDs(line);
size_t len = 0;
for (size_t i = 0; ids[i]; i++) {
len++;
}
column = MINIMUM(column, HeaderLayout_getColumns(this->hLayout) - 1);
this->hColumns[column].len = len;
MeterModeId* modes = len ? xCalloc(len, sizeof(MeterModeId)) : NULL;
for (size_t i = 0; i < len; i++) {
modes[i] = (MeterModeId) atoi(ids[i]);
}
this->hColumns[column].modes = modes;
String_freeArray(ids);
}function: Settings_readMeters
static void Settings_readMeters(Settings* this, const char* line, size_t column) {
column = MINIMUM(column, HeaderLayout_getColumns(this->hLayout) - 1);
this->hColumns[column].names = Settings_splitLineToIDs(line);
}function: Settings_setHeaderLayout
void Settings_setHeaderLayout(Settings* this, HeaderLayout hLayout) {
unsigned int oldColumns = HeaderLayout_getColumns(this->hLayout);
unsigned int newColumns = HeaderLayout_getColumns(hLayout);
if (newColumns > oldColumns) {
this->hColumns = xReallocArray(this->hColumns, newColumns, sizeof(MeterColumnSetting));
memset(this->hColumns + oldColumns, 0, (newColumns - oldColumns) * sizeof(MeterColumnSetting));
} else if (newColumns < oldColumns) {
for (unsigned int i = newColumns; i < oldColumns; i++) {
if (this->hColumns[i].names) {
for (size_t j = 0; j < this->hColumns[i].len; j++)
free(this->hColumns[i].names[j]);
free(this->hColumns[i].names);
}
free(this->hColumns[i].modes);
}
this->hColumns = xReallocArray(this->hColumns, newColumns, sizeof(MeterColumnSetting));
}
this->hLayout = hLayout;
this->changed = true;
}function: Settings_splitLineToIDs
static char** Settings_splitLineToIDs(const char* line) {
char* trim = String_trim(line);
char** ids = String_split(trim, ' ', NULL);
free(trim);
return ids;
}function: Settings_validateMeters
static bool Settings_validateMeters(Settings* this) {
const size_t colCount = HeaderLayout_getColumns(this->hLayout);
bool anyMeter = false;
for (size_t column = 0; column < colCount; column++) {
char** names = this->hColumns[column].names;
const MeterModeId* modes = this->hColumns[column].modes;
const size_t len = this->hColumns[column].len;
if (!len)
continue;
if (!names || !modes)
return false;
anyMeter |= !!len;
// Check for each mode there is an entry with a non-NULL name
for (size_t meterIdx = 0; meterIdx < len; meterIdx++)
if (!names[meterIdx])
return false;
if (names[len])
return false;
}
return anyMeter;
}function: Settings_write
function: signal_safe_fprintf
ATTR_FORMAT(printf, 2, 3)
static int signal_safe_fprintf(FILE* stream, const char* fmt, ...) {
char buf[2048];
va_list vl;
va_start(vl, fmt);
int n = vsnprintf(buf, sizeof(buf), fmt, vl);
va_end(vl);
if (n <= 0)
return n;
return full_write_str(fileno(stream), buf);
}function: toFieldIndex
static int toFieldIndex(Hashtable* columns, const char* str) {
if (isdigit((unsigned char)str[0])) {
// This "+1" is for compatibility with the older enum format.
int id = atoi(str) + 1;
if (toFieldName(columns, id, NULL)) {
return id;
}
} else {
// Dynamically-defined columns are always stored by-name.
char dynamic[32] = {0};
if (sscanf(str, "Dynamic(%30s)", dynamic) == 1) {
char* end;
if ((end = strrchr(dynamic, ')')) != NULL) {
bool success;
unsigned int key;
*end = '\0';
success = DynamicColumn_search(columns, dynamic, &key) != NULL;
*end = ')';
if (success)
return key;
}
}
// Fallback to iterative scan of table of fields by-name.
for (int p = 1; p < LAST_PROCESSFIELD; p++) {
const char* pName = toFieldName(columns, p, NULL);
if (pName && strcmp(pName, str) == 0)
return p;
}
}
return -1;
}function: toFieldName
static const char* toFieldName(Hashtable* columns, int id, bool* enabled) {
if (id < 0) {
if (enabled)
*enabled = false;
return NULL;
}
if (id >= ROW_DYNAMIC_FIELDS) {
const DynamicColumn* column = DynamicColumn_lookup(columns, id);
if (enabled)
*enabled = column ? column->enabled : false;
return column ? column->name : NULL;
}
if (enabled)
*enabled = true;
return Process_fields[id].name;
}function: writeFields
static void writeFields(OutputFunc of, FILE* fp,
const ProcessField* fields, Hashtable* columns,
bool byName, char separator) {
const char* sep = "";
for (unsigned int i = 0; fields[i]; i++) {
if (fields[i] < LAST_PROCESSFIELD && byName) {
const char* pName = toFieldName(columns, fields[i], NULL);
of(fp, "%s%s", sep, pName);
} else if (fields[i] >= LAST_PROCESSFIELD && byName) {
bool enabled;
const char* pName = toFieldName(columns, fields[i], &enabled);
if (enabled)
of(fp, "%sDynamic(%s)", sep, pName);
} else {
// This "-1" is for compatibility with the older enum format.
of(fp, "%s%d", sep, (int) fields[i] - 1);
}
sep = " ";
}
of(fp, "%c", separator);
}function: writeList
static void writeList(OutputFunc of, FILE* fp,
char** list, int len, char separator) {
const char* sep = "";
for (int i = 0; i < len; i++) {
of(fp, "%s%s", sep, list[i]);
sep = " ";
}
of(fp, "%c", separator);
}function: writeMeterModes
static void writeMeterModes(const Settings* this, OutputFunc of,
FILE* fp, char separator, unsigned int column) {
if (this->hColumns[column].len) {
const char* sep = "";
for (size_t i = 0; i < this->hColumns[column].len; i++) {
of(fp, "%s%u", sep, this->hColumns[column].modes[i]);
sep = " ";
}
} else {
of(fp, "!");
}
of(fp, "%c", separator);
}function: writeMeters
static void writeMeters(const Settings* this, OutputFunc of,
FILE* fp, char separator, unsigned int column) {
if (this->hColumns[column].len) {
writeList(of, fp, this->hColumns[column].names, this->hColumns[column].len, separator);
} else {
of(fp, "!%c", separator);
}
}struct: ScreenSettings
/* Struct definition is not in this file, but implied by usage */
struct: Settings
/* Struct definition is not in this file, but implied by usage */
Settings.h
Settings.h
function: ScreenSettings_delete
void ScreenSettings_delete(ScreenSettings* this);
function: ScreenSettings_getActiveDirection
static inline int ScreenSettings_getActiveDirection(const ScreenSettings* this) {
return this->treeView ? this->treeDirection : this->direction;
}function: ScreenSettings_getActiveSortKey
static inline RowField ScreenSettings_getActiveSortKey(const ScreenSettings* this) {
return (this->treeView)
? (this->treeViewAlwaysByPID ? 1 : this->treeSortKey)
: this->sortKey;
}function: ScreenSettings_invertSortOrder
void ScreenSettings_invertSortOrder(ScreenSettings* this);
function: ScreenSettings_setSortKey
void ScreenSettings_setSortKey(ScreenSettings* this, RowField sortKey);
function: Settings_delete
void Settings_delete(Settings* this);
function: Settings_enableReadonly
void Settings_enableReadonly(void);
function: Settings_isReadonly
bool Settings_isReadonly(void);
function: Settings_new
Settings* Settings_new(const struct Machine_* host, Hashtable* dynamicMeters, Hashtable* dynamicColumns, Hashtable* dynamicScreens);
function: Settings_newDynamicScreen
ScreenSettings* Settings_newDynamicScreen(Settings* this, const char* tab, const struct DynamicScreen_* screen, struct Table_* table);
function: Settings_newScreen
ScreenSettings* Settings_newScreen(Settings* this, const ScreenDefaults* defaults);
function: Settings_setHeaderLayout
void Settings_setHeaderLayout(Settings* this, HeaderLayout hLayout);
function: Settings_write
int Settings_write(const Settings* this, bool onCrash);
macro: CONFIG_READER_MIN_VERSION
#define CONFIG_READER_MIN_VERSION 3
macro: DEFAULT_DELAY
#define DEFAULT_DELAY 15
macro: Settings_cpuId
#define Settings_cpuId(settings, cpu) ((settings)->countCPUsFromOne ? (cpu)+1 : (cpu))
struct: MeterColumnSetting
typedef struct {
size_t len;
char** names;
MeterModeId* modes;
} MeterColumnSetting;struct: ScreenDefaults
typedef struct {
const char* name;
const char* columns;
const char* sortKey;
const char* treeSortKey;
} ScreenDefaults;struct: ScreenSettings
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;
RowField sortKey;
RowField treeSortKey;
bool treeView;
bool treeViewAlwaysByPID;
bool allBranchesCollapsed;
} ScreenSettings;struct: Settings
typedef struct Settings_ {
char* filename;
char* initialFilename;
bool writeConfig; /* whether to write the current settings on exit */
int config_version;
HeaderLayout hLayout;
MeterColumnSetting* hColumns;
Hashtable* dynamicColumns; /* runtime-discovered columns */
Hashtable* dynamicMeters; /* runtime-discovered meters */
Hashtable* dynamicScreens; /* runtime-discovered screens */
ScreenSettings** screens;
unsigned int nScreens;
unsigned int ssIndex;
ScreenSettings* ss;
int colorScheme;
int delay;
bool countCPUsFromOne;
bool detailedCPUTime;
bool showCPUUsage;
bool showCPUFrequency;
#ifdef BUILD_WITH_CPU_TEMP
bool showCPUTemperature;
bool degreeFahrenheit;
#endif
bool showProgramPath;
bool shadowOtherUsers;
bool showThreadNames;
bool hideKernelThreads;
bool hideRunningInContainer;
bool hideUserlandThreads;
bool highlightBaseName;
bool highlightDeletedExe;
bool shadowDistPathPrefix;
bool highlightMegabytes;
bool highlightThreads;
bool highlightChanges;
int highlightDelaySecs;
bool findCommInCmdline;
bool stripExeFromCmdline;
bool showMergedCommand;
bool updateProcessNames;
bool accountGuestInCPUMeter;
bool headerMargin;
bool screenTabs;
bool showCachedMemory;
#ifdef HAVE_GETMOUSE
bool enableMouse;
#endif
int hideFunctionBar; // 0 - off, 1 - on ESC until next input, 2 - permanently
#ifdef HAVE_LIBHWLOC
bool topologyAffinity;
#endif
bool changed;
uint64_t lastUpdate;
} Settings;SignalsPanel.c
SignalsPanel.c
function: SignalsPanel_new
Panel* SignalsPanel_new(int preSelectedSignal) {
Panel* this = Panel_new(1, 1, 1, 1, Class(ListItem), true, FunctionBar_newEnterEsc("Send ", "Cancel "));
int defaultPosition = 15;
unsigned int i;
for (i = 0; i < Platform_numberOfSignals; i++) {
Panel_set(this, i, (Object*) ListItem_new(Platform_signals[i].name, Platform_signals[i].number));
// signal 15 is not always the 15th signal in the table
if (Platform_signals[i].number == preSelectedSignal) {
defaultPosition = i;
}
}
#if (defined(SIGRTMIN) && defined(SIGRTMAX))
if (SIGRTMAX - SIGRTMIN <= 100) {
static char buf[16];
for (int sig = SIGRTMIN; sig <= SIGRTMAX; i++, sig++) {
int n = sig - SIGRTMIN;
xSnprintf(buf, sizeof(buf), "%2d SIGRTMIN%-+3d", sig, n);
if (n == 0) {
buf[11] = '\0';
}
Panel_set(this, i, (Object*) ListItem_new(buf, sig));
}
}
#endif
Panel_setHeader(this, "Send signal:");
Panel_setSelected(this, defaultPosition);
return this;
}SignalsPanel.h
SignalsPanel.h
function: SignalsPanel_new
Panel* SignalsPanel_new(int preSelectedSignal);
macro: SIGNALSPANEL_INITSELECTEDSIGNAL
#define SIGNALSPANEL_INITSELECTEDSIGNAL SIGTERM
struct: SignalItem
typedef struct SignalItem_ {
const char* name;
int number;
} SignalItem;Platform.c
solaris/Platform.c
function: Platform_buildenv
static int Platform_buildenv(void* accum, struct ps_prochandle* Phandle, uintptr_t addr, const char* str) {
envAccum* accump = accum;
(void) Phandle;
(void) addr;
size_t thissz = strlen(str);
while ((thissz + 2) > (accump->capacity - accump->size)) {
if (accump->capacity > (SIZE_MAX / 2))
return 1;
accump->capacity *= 2;
accump->env = xRealloc(accump->env, accump->capacity);
}
strlcpy( accump->env + accump->size, str, accump->capacity - accump->size);
strncpy( accump->env + accump->size + thissz + 1, "\n", 2);
accump->size += thissz + 1;
return 0;
}function: Platform_done
void Platform_done(void) {
/* no platform-specific cleanup needed */
}function: Platform_getBattery
void Platform_getBattery(double* percent, ACPresence* isOnAC) {
*percent = NAN;
*isOnAC = AC_ERROR;
}function: Platform_getDiskIO
bool Platform_getDiskIO(DiskIOData* data) {
// TODO
(void)data;
return false;
}function: Platform_getFileDescriptors
void Platform_getFileDescriptors(double* used, double* max) {
*used = NAN;
*max = NAN;
}function: Platform_getLoadAverage
void Platform_getLoadAverage(double* one, double* five, double* fifteen) {
double plat_loadavg[3];
if (getloadavg( plat_loadavg, 3 ) < 0) {
*one = NAN;
*five = NAN;
*fifteen = NAN;
return;
}
*one = plat_loadavg[LOADAVG_1MIN];
*five = plat_loadavg[LOADAVG_5MIN];
*fifteen = plat_loadavg[LOADAVG_15MIN];
}function: Platform_getMaxPid
pid_t Platform_getMaxPid(void) {
int vproc = 32778; // Reasonable Solaris default
kstat_ctl_t* kc = kstat_open();
if (kc != NULL) {
kstat_t* kshandle = kstat_lookup_wrapper(kc, "unix", 0, "var");
if (kshandle != NULL) {
kstat_read(kc, kshandle, NULL);
kvar_t* ksvar = kshandle->ks_data;
if (ksvar && ksvar->v_proc > 0) {
vproc = ksvar->v_proc;
}
}
kstat_close(kc);
}
return vproc;
}function: Platform_getNetworkIO
bool Platform_getNetworkIO(NetworkIOData* data) {
// TODO
(void)data;
return false;
}function: Platform_getProcessEnv
char* Platform_getProcessEnv(pid_t pid) {
envAccum envBuilder;
pid_t realpid = pid / 1024;
int graberr;
struct ps_prochandle* Phandle;
if ((Phandle = Pgrab(realpid, PGRAB_RDONLY, &graberr)) == NULL) {
return NULL;
}
envBuilder.capacity = 4096;
envBuilder.size = 0;
envBuilder.env = xMalloc(envBuilder.capacity);
(void) Penv_iter(Phandle, Platform_buildenv, &envBuilder);
Prelease(Phandle, 0);
strncpy( envBuilder.env + envBuilder.size, "\0", 1);
return xRealloc(envBuilder.env, envBuilder.size + 1);
}function: Platform_getProcessLocks
FileLocks_ProcessData* Platform_getProcessLocks(pid_t pid) {
(void)pid;
return NULL;
}function: Platform_getUptime
int Platform_getUptime(void) {
int boot_time = 0;
int curr_time = time(NULL);
struct utmpx* ent;
while (( ent = getutxent() )) {
if ( String_eq("system boot", ent->ut_line )) {
boot_time = ent->ut_tv.tv_sec;
}
}
endutxent();
return (curr_time - boot_time);
}function: Platform_init
bool Platform_init(void) {
/* no platform-specific setup needed */
return true;
}function: Platform_setBindings
void Platform_setBindings(Htop_Action* keys) {
/* no platform-specific key bindings */
(void) keys;
}function: Platform_setCPUValues
double Platform_setCPUValues(Meter* this, unsigned int cpu) {
const Machine* host = this->host;
const SolarisMachine* shost = (const SolarisMachine*) host;
unsigned int cpus = host->existingCPUs;
const CPUData* cpuData = NULL;
if (cpus == 1) {
// single CPU box has everything in spl->cpus[0]
cpuData = &(shost->cpus[0]);
} else {
cpuData = &(shost->cpus[cpu]);
}
if (!cpuData->online) {
this->curItems = 0;
return NAN;
}
double percent;
double* v = this->values;
v[CPU_METER_NICE] = cpuData->nicePercent;
v[CPU_METER_NORMAL] = cpuData->userPercent;
if (host->settings->detailedCPUTime) {
v[CPU_METER_KERNEL] = cpuData->systemPercent;
v[CPU_METER_IRQ] = cpuData->irqPercent;
this->curItems = 4;
} else {
v[CPU_METER_KERNEL] = cpuData->systemAllPercent;
this->curItems = 3;
}
percent = sumPositiveValues(v, this->curItems);
percent = MINIMUM(percent, 100.0);
v[CPU_METER_FREQUENCY] = cpuData->frequency;
v[CPU_METER_TEMPERATURE] = NAN;
return percent;
}function: Platform_setMemoryValues
void Platform_setMemoryValues(Meter* this) {
const Machine* host = this->host;
this->total = host->totalMem;
this->values[MEMORY_METER_USED] = host->usedMem;
// this->values[MEMORY_METER_SHARED] = "shared memory, like tmpfs and shm"
// this->values[MEMORY_METER_COMPRESSED] = "compressed memory, like zswap on linux"
this->values[MEMORY_METER_BUFFERS] = host->buffersMem;
this->values[MEMORY_METER_CACHE] = host->cachedMem;
// this->values[MEMORY_METER_AVAILABLE] = "available memory"
}function: Platform_setSwapValues
void Platform_setSwapValues(Meter* this) {
const Machine* host = this->host;
this->total = host->totalSwap;
this->values[SWAP_METER_USED] = host->usedSwap;
// this->values[SWAP_METER_CACHE] = "pages that are both in swap and RAM, like SwapCached on linux"
// this->values[SWAP_METER_FRONTSWAP] = "pages that are accounted to swap but stored elsewhere, like frontswap on linux"
}function: Platform_setZfsArcValues
void Platform_setZfsArcValues(Meter* this) {
const SolarisMachine* shost = (const SolarisMachine*) this->host;
ZfsArcMeter_readStats(this, &shost->zfs);
}function: Platform_setZfsCompressedArcValues
void Platform_setZfsCompressedArcValues(Meter* this) {
const SolarisMachine* shost = (const SolarisMachine*) this->host;
ZfsCompressedArcMeter_readStats(this, &shost->zfs);
}variable: Platform_defaultScreens
const ScreenDefaults Platform_defaultScreens[] = {
{
.name = "Default",
.columns = "PID LWPID USER PRIORITY NICE M_VIRT M_RESIDENT STATE PERCENT_CPU PERCENT_MEM TIME Command",
.sortKey = "PERCENT_CPU",
},
};variable: Platform_meterTypes
const MeterClass* const Platform_meterTypes[] = {
&CPUMeter_class,
&ClockMeter_class,
&DateMeter_class,
&DateTimeMeter_class,
&LoadAverageMeter_class,
&LoadMeter_class,
&MemoryMeter_class,
&SwapMeter_class,
&MemorySwapMeter_class,
&TasksMeter_class,
&BatteryMeter_class,
&HostnameMeter_class,
&SysArchMeter_class,
&UptimeMeter_class,
&AllCPUsMeter_class,
&AllCPUs2Meter_class,
&AllCPUs4Meter_class,
&AllCPUs8Meter_class,
&LeftCPUsMeter_class,
&RightCPUsMeter_class,
&LeftCPUs2Meter_class,
&RightCPUs2Meter_class,
&LeftCPUs4Meter_class,
&RightCPUs4Meter_class,
&LeftCPUs8Meter_class,
&RightCPUs8Meter_class,
&ZfsArcMeter_class,
&ZfsCompressedArcMeter_class,
&BlankMeter_class,
NULL
};variable: Platform_numberOfDefaultScreens
const unsigned int Platform_numberOfDefaultScreens = ARRAYSIZE(Platform_defaultScreens);
variable: Platform_numberOfSignals
const unsigned int Platform_numberOfSignals = ARRAYSIZE(Platform_signals);
variable: Platform_signals
Platform.h
solaris/Platform.h
function: kstat_data_lookup_wrapper
static inline void* kstat_data_lookup_wrapper(kstat_t* ksp, const char* name) {
IGNORE_WCASTQUAL_BEGIN
return kstat_data_lookup(ksp, (char*)name);
IGNORE_WCASTQUAL_END
}function: kstat_lookup_wrapper
static inline kstat_t* kstat_lookup_wrapper(kstat_ctl_t* kc, const char* ks_module, int ks_instance, const char* ks_name) {
IGNORE_WCASTQUAL_BEGIN
return kstat_lookup(kc, (char*)ks_module, ks_instance, (char*)ks_name);
IGNORE_WCASTQUAL_END
}function: Platform_addDynamicScreen
static inline void Platform_addDynamicScreen(ATTR_UNUSED ScreenSettings* ss) { }function: Platform_addDynamicScreenAvailableColumns
static inline void Platform_addDynamicScreenAvailableColumns(ATTR_UNUSED Panel* availableColumns, ATTR_UNUSED const char* screen) { }function: Platform_defaultDynamicScreens
static inline void Platform_defaultDynamicScreens(ATTR_UNUSED Settings* settings) { }function: Platform_done
void Platform_done(void);
function: Platform_dynamicColumnName
static inline const char* Platform_dynamicColumnName(ATTR_UNUSED unsigned int key) {
return NULL;
}function: Platform_dynamicColumns
static inline Hashtable* Platform_dynamicColumns(void) {
return NULL;
}function: Platform_dynamicColumnsDone
static inline void Platform_dynamicColumnsDone(ATTR_UNUSED Hashtable* table) { }function: Platform_dynamicColumnWriteField
static inline bool Platform_dynamicColumnWriteField(ATTR_UNUSED const Process* proc, ATTR_UNUSED RichString* str, ATTR_UNUSED unsigned int key) {
return false;
}function: Platform_dynamicMeterDisplay
static inline void Platform_dynamicMeterDisplay(ATTR_UNUSED const Meter* meter, ATTR_UNUSED RichString* out) { }function: Platform_dynamicMeterInit
static inline void Platform_dynamicMeterInit(ATTR_UNUSED Meter* meter) { }function: Platform_dynamicMeters
static inline Hashtable* Platform_dynamicMeters(void) {
return NULL;
}function: Platform_dynamicMetersDone
static inline void Platform_dynamicMetersDone(ATTR_UNUSED Hashtable* table) { }function: Platform_dynamicMeterUpdateValues
static inline void Platform_dynamicMeterUpdateValues(ATTR_UNUSED Meter* meter) { }function: Platform_dynamicScreens
static inline Hashtable* Platform_dynamicScreens(void) {
return NULL;
}function: Platform_dynamicScreensDone
static inline void Platform_dynamicScreensDone(ATTR_UNUSED Hashtable* screens) { }function: Platform_getBattery
void Platform_getBattery(double* percent, ACPresence* isOnAC);
function: Platform_getDiskIO
bool Platform_getDiskIO(DiskIOData* data);
function: Platform_getFileDescriptors
void Platform_getFileDescriptors(double* used, double* max);
function: Platform_getHostname
static inline void Platform_getHostname(char* buffer, size_t size) {
Generic_hostname(buffer, size);
}function: Platform_getLoadAverage
void Platform_getLoadAverage(double* one, double* five, double* fifteen);
function: Platform_getLongOption
static inline CommandLineStatus Platform_getLongOption(ATTR_UNUSED int opt, ATTR_UNUSED int argc, ATTR_UNUSED char** argv) {
return STATUS_ERROR_EXIT;
}function: Platform_getMaxPid
pid_t Platform_getMaxPid(void);
function: Platform_getNetworkIO
bool Platform_getNetworkIO(NetworkIOData* data);
function: Platform_getProcessEnv
char* Platform_getProcessEnv(pid_t pid);
function: Platform_getProcessLocks
FileLocks_ProcessData* Platform_getProcessLocks(pid_t pid);
function: Platform_getRelease
static inline void Platform_getRelease(char** string) {
*string = Generic_uname();
}function: Platform_gettime_monotonic
static inline void Platform_gettime_monotonic(uint64_t* msec) {
Generic_gettime_monotonic(msec);
}function: Platform_gettime_realtime
static inline void Platform_gettime_realtime(struct timeval* tv, uint64_t* msec) {
Generic_gettime_realtime(tv, msec);
}function: Platform_getUptime
int Platform_getUptime(void);
function: Platform_init
bool Platform_init(void);
function: Platform_longOptionsUsage
static inline void Platform_longOptionsUsage(ATTR_UNUSED const char* name) { }function: Platform_setBindings
void Platform_setBindings(Htop_Action* keys);
function: Platform_setCPUValues
double Platform_setCPUValues(Meter* this, unsigned int cpu);
function: Platform_setMemoryValues
void Platform_setMemoryValues(Meter* this);
function: Platform_setSwapValues
void Platform_setSwapValues(Meter* this);
function: Platform_setZfsArcValues
void Platform_setZfsArcValues(Meter* this);
function: Platform_setZfsCompressedArcValues
void Platform_setZfsCompressedArcValues(Meter* this);
global variable: Platform_defaultScreens
extern const ScreenDefaults Platform_defaultScreens[];
global variable: Platform_meterTypes
extern const MeterClass* const Platform_meterTypes[];
global variable: Platform_numberOfDefaultScreens
extern const unsigned int Platform_numberOfDefaultScreens;
global variable: Platform_numberOfSignals
extern const unsigned int Platform_numberOfSignals;
global variable: Platform_signals
extern const SignalItem Platform_signals[];
macro: ERR
#undef ERR #include <libproc.h> #undef ERR #define ERR (-1)
macro: IGNORE_WCASTQUAL_BEGIN
IGNORE_WCASTQUAL_BEGIN
macro: IGNORE_WCASTQUAL_END
IGNORE_WCASTQUAL_END
macro: kill
#define kill(pid, signal) kill(pid / 1024, signal)
macro: PLATFORM_LONG_OPTIONS
#define PLATFORM_LONG_OPTIONS
struct: envAccum
typedef struct envAccum_ {
size_t capacity;
size_t size;
size_t bytes;
char* env;
} envAccum;typedef: kvar_t
typedef struct var kvar_t;
ProcessField.h
solaris/ProcessField.h
macro: PLATFORM_PROCESS_FIELDS
#define PLATFORM_PROCESS_FIELDS \
ZONEID = 100, \
ZONE = 101, \
PROJID = 102, \
TASKID = 103, \
POOLID = 104, \
CONTID = 105, \
LWPID = 106, \
\
DUMMY_BUMP_FIELD = CWD, \
// End of listSolarisMachine.c
solaris/SolarisMachine.c
function: Machine_delete
void Machine_delete(Machine* super) {
SolarisMachine* this = (SolarisMachine*) super;
Machine_done(super);
free(this->cpus);
if (this->kd) {
kstat_close(this->kd);
}
free(this);
}function: Machine_isCPUonline
bool Machine_isCPUonline(const Machine* super, unsigned int id) {
assert(id < super->existingCPUs);
const SolarisMachine* this = (const SolarisMachine*) super;
return (super->existingCPUs == 1) ? true : this->cpus[id + 1].online;
}function: Machine_new
Machine* Machine_new(UsersTable* usersTable, uid_t userId) {
SolarisMachine* this = xCalloc(1, sizeof(SolarisMachine));
Machine* super = &this->super;
Machine_init(super, usersTable, userId);
this->pageSize = sysconf(_SC_PAGESIZE);
if (this->pageSize == -1)
CRT_fatalError("Cannot get pagesize by sysconf(_SC_PAGESIZE)");
this->pageSizeKB = this->pageSize / 1024;
this->kd = kstat_open();
if (!this->kd)
CRT_fatalError("Cannot open kstat handle");
SolarisMachine_updateCPUcount(this);
return super;
}function: Machine_scan
void Machine_scan(Machine* super) {
SolarisMachine* this = (SolarisMachine*) super;
SolarisMachine_updateCPUcount(this);
SolarisMachine_scanCPUTime(this);
SolarisMachine_scanMemoryInfo(this);
SolarisMachine_scanZfsArcstats(this);
}function: SolarisMachine_scanCPUTime
function: SolarisMachine_scanMemoryInfo
function: SolarisMachine_scanZfsArcstats
static void SolarisMachine_scanZfsArcstats(SolarisMachine* this) {
kstat_named_t *cur_kstat;
kstat_t *arcstats;
int ksrphyserr;
if (this->kd == NULL)
return;
arcstats = kstat_lookup_wrapper(this->kd, "zfs", 0, "arcstats");
if (arcstats == NULL)
return;
ksrphyserr = kstat_read(this->kd, arcstats, NULL);
if (ksrphyserr == -1)
return;
cur_kstat = kstat_data_lookup_wrapper( arcstats, "size" );
this->zfs.size = cur_kstat->value.ui64 / 1024;
this->zfs.enabled = this->zfs.size > 0 ? 1 : 0;
cur_kstat = kstat_data_lookup_wrapper( arcstats, "c_max" );
this->zfs.max = cur_kstat->value.ui64 / 1024;
cur_kstat = kstat_data_lookup_wrapper( arcstats, "mfu_size" );
this->zfs.MFU = cur_kstat != NULL ? cur_kstat->value.ui64 / 1024 : 0;
cur_kstat = kstat_data_lookup_wrapper( arcstats, "mru_size" );
this->zfs.MRU = cur_kstat != NULL ? cur_kstat->value.ui64 / 1024 : 0;
cur_kstat = kstat_data_lookup_wrapper( arcstats, "anon_size" );
this->zfs.anon = cur_kstat != NULL ? cur_kstat->value.ui64 / 1024 : 0;
cur_kstat = kstat_data_lookup_wrapper( arcstats, "hdr_size" );
this->zfs.header = cur_kstat != NULL ? cur_kstat->value.ui64 / 1024 : 0;
cur_kstat = kstat_data_lookup_wrapper( arcstats, "other_size" );
this->zfs.other = cur_kstat != NULL ? cur_kstat->value.ui64 / 1024 : 0;
if ((cur_kstat = kstat_data_lookup_wrapper( arcstats, "compressed_size" )) != NULL) {
this->zfs.compressed = cur_kstat->value.ui64 / 1024;
this->zfs.isCompressed = 1;
cur_kstat = kstat_data_lookup_wrapper( arcstats, "uncompressed_size" );
this->zfs.uncompressed = cur_kstat->value.ui64 / 1024;
} else {
this->zfs.isCompressed = 0;
}
}function: SolarisMachine_updateCPUcount
static void SolarisMachine_updateCPUcount(SolarisMachine* this) {
Machine* super = &this->super;
long int s;
bool change = false;
s = sysconf(_SC_NPROCESSORS_CONF);
if (s < 1)
CRT_fatalError("Cannot get existing CPU count by sysconf(_SC_NPROCESSORS_CONF)");
if (s != super->existingCPUs) {
if (s == 1) {
this->cpus = xRealloc(this->cpus, sizeof(CPUData));
this->cpus[0].online = true;
} else {
this->cpus = xReallocArray(this->cpus, s + 1, sizeof(CPUData));
this->cpus[0].online = true; /* average is always "online" */
for (int i = 1; i < s + 1; i++) {
this->cpus[i].online = false;
}
}
change = true;
super->existingCPUs = s;
}
s = sysconf(_SC_NPROCESSORS_ONLN);
if (s < 1)
CRT_fatalError("Cannot get active CPU count by sysconf(_SC_NPROCESSORS_ONLN)");
if (s != super->activeCPUs) {
change = true;
super->activeCPUs = s;
}
if (change) {
kstat_close(this->kd);
this->kd = kstat_open();
if (!this->kd)
CRT_fatalError("Cannot open kstat handle");
}
}SolarisMachine.h
solaris/SolarisMachine.h
struct: CPUData
typedef struct CPUData_ {
double userPercent;
double nicePercent;
double systemPercent;
double irqPercent;
double idlePercent;
double systemAllPercent;
double frequency;
uint64_t luser;
uint64_t lkrnl;
uint64_t lintr;
uint64_t lidle;
bool online;
} CPUData;struct: SolarisMachine
typedef struct SolarisMachine_ {
Machine super;
kstat_ctl_t* kd;
CPUData* cpus;
int pageSize;
int pageSizeKB;
ZfsArcStats zfs;
} SolarisMachine;variable: zone_errmsg
extern char zone_errmsg[ZONE_ERRMSGLEN];
SolarisProcess.c
solaris/SolarisProcess.c
Function: SolarisProcess_new
Process* SolarisProcess_new(const Machine* host) {
SolarisProcess* this = xCalloc(1, sizeof(SolarisProcess));
Object_setClass(this, Class(SolarisProcess));
Process_init(&this->super, host);
return (Process*)this;
}Global Constant Array: Process_fields
Global Constant Structure (ProcessClass): SolarisProcess_class
const ProcessClass SolarisProcess_class = {
.super = {
.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
},
.compareByKey = SolarisProcess_compareByKey
};Method: Process_delete
void Process_delete(Object* cast) {
SolarisProcess* sp = (SolarisProcess*) cast;
Process_done((Process*)cast);
free(sp->zname);
free(sp);
}Static Method: SolarisProcess_compareByKey
static int SolarisProcess_compareByKey(const Process* v1, const Process* v2, ProcessField key) {
const SolarisProcess* p1 = (const SolarisProcess*)v1;
const SolarisProcess* p2 = (const SolarisProcess*)v2;
switch (key) {
case ZONEID:
return SPACESHIP_NUMBER(p1->zoneid, p2->zoneid);
case PROJID:
return SPACESHIP_NUMBER(p1->projid, p2->projid);
case TASKID:
return SPACESHIP_NUMBER(p1->taskid, p2->taskid);
case POOLID:
return SPACESHIP_NUMBER(p1->poolid, p2->poolid);
case CONTID:
return SPACESHIP_NUMBER(p1->contid, p2->contid);
case ZONE:
return strcmp(p1->zname ? p1->zname : "global", p2->zname ? p2->zname : "global");
case PID:
return SPACESHIP_NUMBER(p1->realpid, p2->realpid);
case PPID:
return SPACESHIP_NUMBER(p1->realppid, p2->realppid);
case LWPID:
return SPACESHIP_NUMBER(p1->lwpid, p2->lwpid);
default:
return Process_compareByKey_Base(v1, v2, key);
}
}Static Method: SolarisProcess_rowWriteField
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];
size_t n = sizeof(buffer) - 1;
switch (field) {
// add Solaris-specific fields here
case ZONEID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, sp->zoneid); break;
case PROJID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, sp->projid); break;
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: 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(&sp->super, str, field);
return;
}
RichString_appendWide(str, attr, buffer);
}SolarisProcess.h
solaris/SolarisProcess.h
function: Process_delete
void Process_delete(Object* cast);
function: SolarisProcess_new
Process* SolarisProcess_new(const Machine* host);
struct: SolarisProcess
typedef struct SolarisProcess_ {
Process super;
zoneid_t zoneid;
char* zname;
taskid_t taskid;
projid_t projid;
poolid_t poolid;
ctid_t contid;
pid_t realpid;
pid_t realppid;
pid_t realtgid;
pid_t lwpid;
} SolarisProcess;variable: Process_fields
extern const ProcessFieldData Process_fields[LAST_PROCESSFIELD];
variable: SolarisProcess_class
extern const ProcessClass SolarisProcess_class;
SolarisProcessTable.c
solaris/SolarisProcessTable.c
constant: GZONE
#define GZONE "global "
constant: UZONE
#define UZONE "unknown "
function: ProcessTable_delete
void ProcessTable_delete(Object* cast) {
SolarisProcessTable* this = (SolarisProcessTable*) cast;
ProcessTable_done(&this->super);
free(this);
}function: ProcessTable_goThroughEntries
void ProcessTable_goThroughEntries(ProcessTable* super) {
super->kernelThreads = 1;
proc_walk(&SolarisProcessTable_walkproc, super, PR_WALK_LWP);
}function: ProcessTable_new
ProcessTable* ProcessTable_new(Machine* host, Hashtable* pidMatchList) {
SolarisProcessTable* this = xCalloc(1, sizeof(SolarisProcessTable));
Object_setClass(this, Class(ProcessTable));
ProcessTable* super = &this->super;
ProcessTable_init(super, Class(SolarisProcess), host, pidMatchList);
return super;
}function: SolarisProcessTable_getProcessState
static inline ProcessState SolarisProcessTable_getProcessState(char state) {
switch (state) {
case 'S': return SLEEPING;
case 'R': return RUNNABLE;
case 'O': return RUNNING;
case 'Z': return ZOMBIE;
case 'T': return STOPPED;
case 'I': return IDLE;
default: return UNKNOWN;
}
}function: SolarisProcessTable_readZoneName
static char* SolarisProcessTable_readZoneName(kstat_ctl_t* kd, SolarisProcess* sproc) {
char* zname;
if ( sproc->zoneid == 0 ) {
zname = xStrdup(GZONE);
} else if ( kd == NULL ) {
zname = xStrdup(UZONE);
} else {
kstat_t* ks = kstat_lookup_wrapper( kd, "zones", sproc->zoneid, NULL );
zname = xStrdup(ks == NULL ? UZONE : ks->ks_name);
}
return zname;
}function: SolarisProcessTable_updateCwd
static void SolarisProcessTable_updateCwd(pid_t pid, Process* proc) {
char path[32];
xSnprintf(path, sizeof(path), "/proc/%d/cwd", pid);
char target[PATH_MAX];
ssize_t ret = readlink(path, target, sizeof(target) - 1);
if (ret <= 0)
return;
target[ret] = '\0';
free_and_xStrdup(&proc->procCwd, target);
}function: SolarisProcessTable_updateExe
static void SolarisProcessTable_updateExe(pid_t pid, Process* proc) {
char path[32];
xSnprintf(path, sizeof(path), "/proc/%d/path/a.out", pid);
char target[PATH_MAX];
ssize_t ret = readlink(path, target, sizeof(target) - 1);
if (ret <= 0)
return;
target[ret] = '\0';
Process_updateExe(proc, target);
}function: SolarisProcessTable_walkproc
SolarisProcessTable.h
solaris/SolarisProcessTable.h
struct: SolarisProcessTable
typedef struct SolarisProcessTable_ {
ProcessTable super;
} SolarisProcessTable;SwapMeter.c
SwapMeter.c
function: SwapMeter_display
static void SwapMeter_display(const Object* cast, RichString* out) {
char buffer[50];
const Meter* this = (const Meter*)cast;
RichString_writeAscii(out, CRT_colors[METER_TEXT], ":");
Meter_humanUnit(buffer, this->total, sizeof(buffer));
RichString_appendAscii(out, CRT_colors[METER_VALUE], buffer);
Meter_humanUnit(buffer, this->values[SWAP_METER_USED], sizeof(buffer));
RichString_appendAscii(out, CRT_colors[METER_TEXT], " used:");
RichString_appendAscii(out, CRT_colors[METER_VALUE], buffer);
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 (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);
}
}function: SwapMeter_updateValues
static void SwapMeter_updateValues(Meter* this) {
char* buffer = this->txtBuffer;
size_t size = sizeof(this->txtBuffer);
int written;
this->values[SWAP_METER_CACHE] = NAN; /* 'cached' not present on all platforms */
this->values[SWAP_METER_FRONTSWAP] = NAN; /* 'frontswap' not present on all platforms */
Platform_setSwapValues(this);
written = Meter_humanUnit(buffer, this->values[SWAP_METER_USED], size);
METER_BUFFER_CHECK(buffer, size, written);
METER_BUFFER_APPEND_CHR(buffer, size, '/');
Meter_humanUnit(buffer, this->total, size);
}global_variable: SwapMeter_attributes
static const int SwapMeter_attributes[] = {
SWAP,
SWAP_CACHE,
SWAP_FRONTSWAP,
};struct: SwapMeter_class
const MeterClass SwapMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = SwapMeter_display,
},
.updateValues = SwapMeter_updateValues,
.defaultMode = BAR_METERMODE,
.supportedModes = METERMODE_DEFAULT_SUPPORTED,
.maxItems = SWAP_METER_ITEMCOUNT,
.total = 100.0,
.attributes = SwapMeter_attributes,
.name = "Swap",
.uiName = "Swap",
.caption = "Swp"
};SwapMeter.h
SwapMeter.h
enum: SwapMeterValues
typedef enum {
SWAP_METER_USED = 0,
SWAP_METER_CACHE = 1,
SWAP_METER_FRONTSWAP = 2,
SWAP_METER_ITEMCOUNT = 3, // number of entries in this enum
} SwapMeterValues;variable: SwapMeter_class
extern const MeterClass SwapMeter_class;
SysArchMeter.c
SysArchMeter.c
function: SysArchMeter_updateValues
static void SysArchMeter_updateValues(Meter* this) {
static char* string;
if (string == NULL)
Platform_getRelease(&string);
String_safeStrncpy(this->txtBuffer, string, sizeof(this->txtBuffer));
}global struct: SysArchMeter_class
const MeterClass SysArchMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete
},
.updateValues = SysArchMeter_updateValues,
.defaultMode = TEXT_METERMODE,
.supportedModes = (1 << TEXT_METERMODE),
.maxItems = 0,
.total = 0.0,
.attributes = SysArchMeter_attributes,
.name = "System",
.uiName = "System",
.caption = "System: ",
};global variable: SysArchMeter_attributes
static const int SysArchMeter_attributes[] = {HOSTNAME};SysArchMeter.h
SysArchMeter.h
struct: SysArchMeter_class
extern const MeterClass SysArchMeter_class;
Table.c
Table.c
function: compareRowByKnownParentThenNatural
static int compareRowByKnownParentThenNatural(const void* v1, const void* v2) {
return Row_compareByParent((const Row*) v1, (const Row*) v2);
}function: Table_add
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)));
}function: Table_buildTree
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;
}function: Table_buildTreeBranch
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;
}
}function: Table_cleanupEntries
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);
}function: Table_cleanupRow
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);
}
}
}function: Table_collapseAllBranches
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;
}
}function: Table_delete
static void Table_delete(Object* cast) {
Table* this = (Table*) cast;
Table_done(this);
free(this);
}function: Table_done
void Table_done(Table* this) {
Hashtable_delete(this->table);
Vector_delete(this->displayList);
Vector_delete(this->rows);
}function: Table_expandTree
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;
}
}function: Table_init
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;
}function: Table_prepareEntries
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;
}
}function: Table_printHeader
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_appendWide(header,
CRT_colors[PANEL_SELECTION_FOCUS],
CRT_treeStr[ascending ? TREE_STR_ASC : TREE_STR_DESC]);
}
if (COMM == fields[i] && settings->showMergedCommand) {
RichString_appendAscii(header, color, "(merged)");
}
}
}function: Table_rebuildPanel
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;
}
}function: Table_removeIndex
static 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)));
}function: Table_setPanel
void Table_setPanel(Table* this, Panel* panel) {
this->panel = panel;
}function: Table_updateDisplayList
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;
}struct: Table_class
const TableClass Table_class = {
.super = {
.extends = Class(Object),
.delete = Table_delete,
},
.prepare = Table_prepareEntries,
.cleanup = Table_cleanupEntries,
};Table.h
Table.h
extern const: Table_class
extern const TableClass Table_class;
function: Table_add
void Table_add(Table* this, struct Row_* row);
function: Table_cleanupEntries
void Table_cleanupEntries(Table* this);
function: Table_cleanupRow
void Table_cleanupRow(Table* this, Row* row, int idx);
function: Table_collapseAllBranches
void Table_collapseAllBranches(Table* this);
function: Table_compact
static inline void Table_compact(Table* this) {
Vector_compact(this->rows);
this->needsSort = true;
}function: Table_done
void Table_done(Table* this);
function: Table_expandTree
void Table_expandTree(Table* this);
function: Table_findRow
static inline struct Row_* Table_findRow(Table* this, int id) {
return (struct Row_*) Hashtable_get(this->table, id);
}function: Table_init
Table* Table_init(Table* this, const ObjectClass* klass, struct Machine_* host);
function: Table_prepareEntries
void Table_prepareEntries(Table* this);
function: Table_printHeader
void Table_printHeader(const Settings* settings, RichString* header);
function: Table_rebuildPanel
void Table_rebuildPanel(Table* this);
function: Table_setPanel
void Table_setPanel(Table* this, struct Panel_* panel);
function: Table_updateDisplayList
void Table_updateDisplayList(Table* this);
macro: As_Table
#define As_Table(this_) ((const TableClass*)((this_)->super.klass))
macro: Table_scanCleanup
#define Table_scanCleanup(t_) (As_Table(t_)->cleanup ? (As_Table(t_)->cleanup(t_)) : Table_cleanupEntries(t_))
macro: Table_scanIterate
#define Table_scanIterate(t_) (As_Table(t_)->iterate(t_)) /* mandatory; must have a custom iterate method */
macro: Table_scanPrepare
#define Table_scanPrepare(t_) (As_Table(t_)->prepare ? (As_Table(t_)->prepare(t_)) : Table_prepareEntries(t_))
struct: Table
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;struct: TableClass
typedef struct TableClass_ {
const ObjectClass super;
const Table_ScanPrepare prepare;
const Table_ScanIterate iterate;
const Table_ScanCleanup cleanup;
} TableClass;typedef: Table_New
typedef Table* (*Table_New)(const struct Machine_*);
typedef: Table_ScanCleanup
typedef void (*Table_ScanCleanup)(Table* this);
typedef: Table_ScanIterate
typedef void (*Table_ScanIterate)(Table* this);
typedef: Table_ScanPrepare
typedef void (*Table_ScanPrepare)(Table* this);
TasksMeter.c
TasksMeter.c
function: TasksMeter_display
static void TasksMeter_display(const Object* cast, RichString* out) {
const Meter* this = (const Meter*)cast;
const Settings* settings = this->host->settings;
char buffer[20];
int len;
len = xSnprintf(buffer, sizeof(buffer), "%d", (int)this->values[2]);
RichString_appendnAscii(out, CRT_colors[METER_VALUE], buffer, len);
RichString_appendAscii(out, settings->hideUserlandThreads ? CRT_colors[METER_SHADOW] : CRT_colors[METER_TEXT], ", ");
len = xSnprintf(buffer, sizeof(buffer), "%d", (int)this->values[1]);
RichString_appendnAscii(out, settings->hideUserlandThreads ? CRT_colors[METER_SHADOW] : CRT_colors[TASKS_RUNNING], buffer, len);
RichString_appendAscii(out, settings->hideUserlandThreads ? CRT_colors[METER_SHADOW] : CRT_colors[METER_TEXT], " thr");
RichString_appendAscii(out, settings->hideKernelThreads ? CRT_colors[METER_SHADOW] : CRT_colors[METER_TEXT], ", ");
len = xSnprintf(buffer, sizeof(buffer), "%d", (int)this->values[0]);
RichString_appendnAscii(out, settings->hideKernelThreads ? CRT_colors[METER_SHADOW] : CRT_colors[TASKS_RUNNING], buffer, len);
RichString_appendAscii(out, settings->hideKernelThreads ? CRT_colors[METER_SHADOW] : CRT_colors[METER_TEXT], " kthr");
RichString_appendAscii(out, CRT_colors[METER_TEXT], "; ");
len = xSnprintf(buffer, sizeof(buffer), "%d", (int)this->values[3]);
RichString_appendnAscii(out, CRT_colors[TASKS_RUNNING], buffer, len);
RichString_appendAscii(out, CRT_colors[METER_TEXT], " running");
}function: TasksMeter_updateValues
static void TasksMeter_updateValues(Meter* this) {
const Machine* host = this->host;
const ProcessTable* pt = (const ProcessTable*) host->processTable;
this->values[0] = pt->kernelThreads;
this->values[1] = pt->userlandThreads;
this->values[2] = pt->totalTasks - pt->kernelThreads - pt->userlandThreads;
this->values[3] = MINIMUM(pt->runningTasks, host->activeCPUs);
this->total = pt->totalTasks;
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "%u/%u", MINIMUM(pt->runningTasks, host->activeCPUs), pt->totalTasks);
}struct: TasksMeter_class
const MeterClass TasksMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = TasksMeter_display,
},
.updateValues = TasksMeter_updateValues,
.defaultMode = TEXT_METERMODE,
.supportedModes = METERMODE_DEFAULT_SUPPORTED,
.maxItems = 4,
.total = 100.0,
.attributes = TasksMeter_attributes,
.name = "Tasks",
.uiName = "Task counter",
.caption = "Tasks: "
};variable: TasksMeter_attributes
static const int TasksMeter_attributes[] = {
CPU_SYSTEM,
PROCESS_THREAD,
PROCESS,
TASKS_RUNNING
};TasksMeter.h
TasksMeter.h
external constant variable: TasksMeter_class
extern const MeterClass TasksMeter_class;
test_spec.lua
test_spec.lua
file: test_spec.lua
TESTPLAN
TESTPLAN
file: TESTPLAN
TraceScreen.c
TraceScreen.c
array: TraceScreenEvents
static const int TraceScreenEvents[] = {KEY_F(3), KEY_F(4), KEY_F(8), KEY_F(9), 27};array: TraceScreenFunctions
static const char* const TraceScreenFunctions[] = {"Search ", "Filter ", "AutoScroll ", "Stop Tracing ", "Done ", NULL};array: TraceScreenKeys
static const char* const TraceScreenKeys[] = {"F3", "F4", "F8", "F9", "Esc"};function: TraceScreen_delete
void TraceScreen_delete(Object* cast) {
TraceScreen* this = (TraceScreen*) cast;
if (this->child > 0) {
kill(this->child, SIGTERM);
while (waitpid(this->child, NULL, 0) == -1)
if (errno != EINTR)
break;
}
if (this->strace) {
fclose(this->strace);
}
CRT_enableDelay();
free(InfoScreen_done((InfoScreen*)this));
}function: TraceScreen_draw
static void TraceScreen_draw(InfoScreen* this) {
InfoScreen_drawTitled(this, "Trace of process %d - %s", Process_getPid(this->process), Process_getCommand(this->process));
}function: TraceScreen_forkTracer
function: TraceScreen_new
TraceScreen* TraceScreen_new(const Process* process) {
// This initializes all TraceScreen variables to "false" so only default = true ones need to be set below
TraceScreen* this = xCalloc(1, sizeof(TraceScreen));
Object_setClass(this, Class(TraceScreen));
this->tracing = true;
this->strace_alive = false;
FunctionBar* fuBar = FunctionBar_new(TraceScreenFunctions, TraceScreenKeys, TraceScreenEvents);
CRT_disableDelay();
return (TraceScreen*) InfoScreen_init(&this->super, process, fuBar, LINES - 2, " ");
}function: TraceScreen_onKey
static bool TraceScreen_onKey(InfoScreen* super, int ch) {
TraceScreen* this = (TraceScreen*) super;
switch (ch) {
case 'f':
case KEY_F(8):
this->follow = !(this->follow);
if (this->follow)
Panel_setSelected(super->display, Panel_size(super->display) - 1);
return true;
case 't':
case KEY_F(9):
this->tracing = !this->tracing;
FunctionBar_setLabel(super->display->defaultBar, KEY_F(9), this->tracing ? "Stop Tracing " : "Resume Tracing ");
InfoScreen_draw(this);
return true;
}
this->follow = false;
return false;
}function: TraceScreen_updateTrace
static void TraceScreen_updateTrace(InfoScreen* super) {
TraceScreen* this = (TraceScreen*) super;
int fd_strace = fileno(this->strace);
fd_set fds;
FD_ZERO(&fds);
FD_SET(STDIN_FILENO, &fds);
if (this->strace_alive) {
assert(fd_strace != -1);
FD_SET(fd_strace, &fds);
}
struct timeval tv = { .tv_sec = 0, .tv_usec = 500 };
int ready = select(MAXIMUM(STDIN_FILENO, fd_strace) + 1, &fds, NULL, NULL, &tv);
char buffer[1025];
size_t nread = 0;
if (ready > 0 && FD_ISSET(fd_strace, &fds))
nread = fread(buffer, 1, sizeof(buffer) - 1, this->strace);
if (nread && this->tracing) {
const char* line = buffer;
buffer[nread] = '\0';
for (size_t i = 0; i < nread; i++) {
if (buffer[i] == '\n') {
buffer[i] = '\0';
if (this->contLine) {
InfoScreen_appendLine(&this->super, line);
this->contLine = false;
} else {
InfoScreen_addLine(&this->super, line);
}
line = buffer + i + 1;
}
}
if (line < buffer + nread) {
InfoScreen_addLine(&this->super, line);
buffer[nread] = '\0';
this->contLine = true;
}
if (this->follow) {
Panel_setSelected(this->super.display, Panel_size(this->super.display) - 1);
}
} else {
if (this->strace_alive && waitpid(this->child, NULL, WNOHANG) != 0)
this->strace_alive = false;
}
}struct: TraceScreen_class
const InfoScreenClass TraceScreen_class = {
.super = {
.extends = Class(Object),
.delete = TraceScreen_delete
},
.draw = TraceScreen_draw,
.onErr = TraceScreen_updateTrace,
.onKey = TraceScreen_onKey,
};TraceScreen.h
TraceScreen.h
function: TraceScreen_delete
void TraceScreen_delete(Object* cast);
function: TraceScreen_forkTracer
bool TraceScreen_forkTracer(TraceScreen* this);
function: TraceScreen_new
TraceScreen* TraceScreen_new(const Process* process);
struct: TraceScreen
typedef struct TraceScreen_ {
InfoScreen super;
bool tracing;
pid_t child;
FILE* strace;
bool contLine;
bool follow;
bool strace_alive;
} TraceScreen;struct: TraceScreen_class
extern const InfoScreenClass TraceScreen_class;
Platform.c
unsupported/Platform.c
array: Platform_defaultScreens
const ScreenDefaults Platform_defaultScreens[] = {
{
.name = "Main",
.columns = "PID USER PRIORITY NICE M_VIRT M_RESIDENT STATE PERCENT_CPU PERCENT_MEM TIME Command",
.sortKey = "PERCENT_CPU",
},
};array: Platform_meterTypes
const MeterClass* const Platform_meterTypes[] = {
&CPUMeter_class,
&ClockMeter_class,
&DateMeter_class,
&DateTimeMeter_class,
&LoadAverageMeter_class,
&LoadMeter_class,
&MemoryMeter_class,
&SwapMeter_class,
&MemorySwapMeter_class,
&TasksMeter_class,
&BatteryMeter_class,
&HostnameMeter_class,
&SysArchMeter_class,
&UptimeMeter_class,
&AllCPUsMeter_class,
&AllCPUs2Meter_class,
&AllCPUs4Meter_class,
&AllCPUs8Meter_class,
&LeftCPUsMeter_class,
&RightCPUsMeter_class,
&LeftCPUs2Meter_class,
&RightCPUs2Meter_class,
&LeftCPUs4Meter_class,
&RightCPUs4Meter_class,
&LeftCPUs8Meter_class,
&RightCPUs8Meter_class,
&FileDescriptorMeter_class,
&BlankMeter_class,
NULL
};array: Platform_signals
const SignalItem Platform_signals[] = {
{ .name = " 0 Cancel", .number = 0 },
};
function: Platform_done
void Platform_done(void) {
/* no platform-specific cleanup needed */
}function: Platform_getBattery
void Platform_getBattery(double* percent, ACPresence* isOnAC) {
*percent = NAN;
*isOnAC = AC_ERROR;
}function: Platform_getDiskIO
bool Platform_getDiskIO(DiskIOData* data) {
(void)data;
return false;
}function: Platform_getFileDescriptors
void Platform_getFileDescriptors(double* used, double* max) {
*used = 1337;
*max = 4711;
}function: Platform_getHostname
void Platform_getHostname(char* buffer, size_t size) {
String_safeStrncpy(buffer, Platform_unsupported, size);
}function: Platform_getLoadAverage
void Platform_getLoadAverage(double* one, double* five, double* fifteen) {
*one = 0;
*five = 0;
*fifteen = 0;
}function: Platform_getMaxPid
pid_t Platform_getMaxPid(void) {
return INT_MAX;
}function: Platform_getNetworkIO
bool Platform_getNetworkIO(NetworkIOData* data) {
(void)data;
return false;
}function: Platform_getProcessEnv
char* Platform_getProcessEnv(pid_t pid) {
(void) pid;
return NULL;
}function: Platform_getProcessLocks
FileLocks_ProcessData* Platform_getProcessLocks(pid_t pid) {
(void)pid;
return NULL;
}function: Platform_getRelease
void Platform_getRelease(char** string) {
*string = xStrdup(Platform_unsupported);
}function: Platform_getUptime
int Platform_getUptime(void) {
return 0;
}function: Platform_init
bool Platform_init(void) {
/* no platform-specific setup needed */
return true;
}function: Platform_setBindings
void Platform_setBindings(Htop_Action* keys) {
/* no platform-specific key bindings */
(void) keys;
}function: Platform_setCPUValues
double Platform_setCPUValues(Meter* this, unsigned int cpu) {
(void) cpu;
double* v = this->values;
v[CPU_METER_FREQUENCY] = NAN;
v[CPU_METER_TEMPERATURE] = NAN;
this->curItems = 1;
return 0.0;
}function: Platform_setMemoryValues
void Platform_setMemoryValues(Meter* this) {
(void) this;
}function: Platform_setSwapValues
void Platform_setSwapValues(Meter* this) {
(void) this;
}variable: Platform_numberOfDefaultScreens
const unsigned int Platform_numberOfDefaultScreens = ARRAYSIZE(Platform_defaultScreens);
variable: Platform_numberOfSignals
const unsigned int Platform_numberOfSignals = ARRAYSIZE(Platform_signals);
variable: Platform_unsupported
static const char Platform_unsupported[] = "unsupported";
Platform.h
unsupported/Platform.h
function: Platform_addDynamicScreen
static inline void Platform_addDynamicScreen(ATTR_UNUSED ScreenSettings* ss) { }function: Platform_addDynamicScreenAvailableColumns
static inline void Platform_addDynamicScreenAvailableColumns(ATTR_UNUSED Panel* availableColumns, ATTR_UNUSED const char* screen) { }function: Platform_defaultDynamicScreens
static inline void Platform_defaultDynamicScreens(ATTR_UNUSED Settings* settings) { }function: Platform_done
void Platform_done(void);
function: Platform_dynamicColumnName
static inline const char* Platform_dynamicColumnName(ATTR_UNUSED unsigned int key) {
return NULL;
}function: Platform_dynamicColumns
static inline Hashtable* Platform_dynamicColumns(void) {
return NULL;
}function: Platform_dynamicColumnsDone
static inline void Platform_dynamicColumnsDone(ATTR_UNUSED Hashtable* table) { }function: Platform_dynamicColumnWriteField
static inline bool Platform_dynamicColumnWriteField(ATTR_UNUSED const Process* proc, ATTR_UNUSED RichString* str, ATTR_UNUSED unsigned int key) {
return false;
}function: Platform_dynamicMeterDisplay
static inline void Platform_dynamicMeterDisplay(ATTR_UNUSED const Meter* meter, ATTR_UNUSED RichString* out) { }function: Platform_dynamicMeterInit
static inline void Platform_dynamicMeterInit(ATTR_UNUSED Meter* meter) { }function: Platform_dynamicMeters
static inline Hashtable* Platform_dynamicMeters(void) {
return NULL;
}function: Platform_dynamicMetersDone
static inline void Platform_dynamicMetersDone(ATTR_UNUSED Hashtable* table) { }function: Platform_dynamicMeterUpdateValues
static inline void Platform_dynamicMeterUpdateValues(ATTR_UNUSED Meter* meter) { }function: Platform_dynamicScreens
static inline Hashtable* Platform_dynamicScreens(void) {
return NULL;
}function: Platform_dynamicScreensDone
static inline void Platform_dynamicScreensDone(ATTR_UNUSED Hashtable* screens) { }function: Platform_getBattery
void Platform_getBattery(double* percent, ACPresence* isOnAC);
function: Platform_getDiskIO
bool Platform_getDiskIO(DiskIOData* data);
function: Platform_getFileDescriptors
void Platform_getFileDescriptors(double* used, double* max);
function: Platform_getHostname
void Platform_getHostname(char* buffer, size_t size);
function: Platform_getLoadAverage
void Platform_getLoadAverage(double* one, double* five, double* fifteen);
function: Platform_getLongOption
static inline CommandLineStatus Platform_getLongOption(ATTR_UNUSED int opt, ATTR_UNUSED int argc, ATTR_UNUSED char** argv) {
return STATUS_ERROR_EXIT;
}function: Platform_getMaxPid
pid_t Platform_getMaxPid(void);
function: Platform_getNetworkIO
bool Platform_getNetworkIO(NetworkIOData* data);
function: Platform_getProcessEnv
char* Platform_getProcessEnv(pid_t pid);
function: Platform_getProcessLocks
FileLocks_ProcessData* Platform_getProcessLocks(pid_t pid);
function: Platform_getRelease
void Platform_getRelease(char** string);
function: Platform_gettime_monotonic
static inline void Platform_gettime_monotonic(uint64_t* msec) {
Generic_gettime_monotonic(msec);
}function: Platform_gettime_realtime
static inline void Platform_gettime_realtime(struct timeval* tv, uint64_t* msec) {
Generic_gettime_realtime(tv, msec);
}function: Platform_getUptime
int Platform_getUptime(void);
function: Platform_init
bool Platform_init(void);
function: Platform_longOptionsUsage
static inline void Platform_longOptionsUsage(ATTR_UNUSED const char* name) { }function: Platform_setBindings
void Platform_setBindings(Htop_Action* keys);
function: Platform_setCPUValues
double Platform_setCPUValues(Meter* this, unsigned int cpu);
function: Platform_setMemoryValues
void Platform_setMemoryValues(Meter* this);
function: Platform_setSwapValues
void Platform_setSwapValues(Meter* this);
global variable: Platform_numberOfDefaultScreens
extern const unsigned int Platform_numberOfDefaultScreens;
global variable: Platform_numberOfSignals
extern const unsigned int Platform_numberOfSignals;
global variable (array of pointers): Platform_meterTypes
extern const MeterClass* const Platform_meterTypes[];
global variable (array): Platform_defaultScreens
extern const ScreenDefaults Platform_defaultScreens[];
global variable (array): Platform_signals
extern const SignalItem Platform_signals[];
macro: PLATFORM_LONG_OPTIONS
#define PLATFORM_LONG_OPTIONS
ProcessField.h
unsupported/ProcessField.h
macro: PLATFORM_PROCESS_FIELDS
#define PLATFORM_PROCESS_FIELDS \ // End of list
UnsupportedMachine.c
unsupported/UnsupportedMachine.c
function: Machine_delete
void Machine_delete(Machine* super) {
UnsupportedMachine* this = (UnsupportedMachine*) super;
Machine_done(super);
free(this);
}function: Machine_isCPUonline
bool Machine_isCPUonline(const Machine* host, unsigned int id) {
assert(id < host->existingCPUs);
(void) host; (void) id;
return true;
}function: Machine_new
Machine* Machine_new(UsersTable* usersTable, uid_t userId) {
UnsupportedMachine* this = xCalloc(1, sizeof(UnsupportedMachine));
Machine* super = &this->super;
Machine_init(super, usersTable, userId);
super->existingCPUs = 1;
super->activeCPUs = 1;
return super;
}function: Machine_scan
void Machine_scan(Machine* super) {
super->existingCPUs = 1;
super->activeCPUs = 1;
super->totalMem = 0;
super->usedMem = 0;
super->buffersMem = 0;
super->cachedMem = 0;
super->sharedMem = 0;
super->availableMem = 0;
super->totalSwap = 0;
super->usedSwap = 0;
super->cachedSwap = 0;
}UnsupportedMachine.h
unsupported/UnsupportedMachine.h
struct: UnsupportedMachine
typedef struct UnsupportedMachine_ {
Machine super;
} UnsupportedMachine;UnsupportedProcess.c
unsupported/UnsupportedProcess.c
function: Process_delete
void Process_delete(Object* cast) {
Process* super = (Process*) cast;
Process_done(super);
// free platform-specific fields here
free(cast);
}function: UnsupportedProcess_compareByKey
static int UnsupportedProcess_compareByKey(const Process* v1, const Process* v2, ProcessField key) {
const UnsupportedProcess* p1 = (const UnsupportedProcess*)v1;
const UnsupportedProcess* p2 = (const UnsupportedProcess*)v2;
(void) p1;
(void) p2;
switch (key) {
/* Add platform specific fields */
default:
return Process_compareByKey_Base(v1, v2, key);
}
}function: UnsupportedProcess_new
Process* UnsupportedProcess_new(const Machine* host) {
Process* this = xCalloc(1, sizeof(UnsupportedProcess));
Object_setClass(this, Class(UnsupportedProcess));
Process_init(this, host);
return this;
}function: UnsupportedProcess_rowWriteField
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) coloring;
(void) n;
switch (field) {
/* Add platform specific fields */
default:
Process_writeField(&up->super, str, field);
return;
}
RichString_appendWide(str, attr, buffer);
}global_variable: Process_fields
global_variable: UnsupportedProcess_class
const ProcessClass UnsupportedProcess_class = {
.super = {
.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
},
.compareByKey = UnsupportedProcess_compareByKey
};UnsupportedProcess.h
unsupported/UnsupportedProcess.h
extern variable: Process_fields
extern const ProcessFieldData Process_fields[LAST_PROCESSFIELD];
extern variable: UnsupportedProcess_class
extern const ProcessClass UnsupportedProcess_class;
function: Process_delete
void Process_delete(Object* cast);
function: UnsupportedProcess_new
Process* UnsupportedProcess_new(const Machine* host);
struct: UnsupportedProcess_
typedef struct UnsupportedProcess_ {
Process super;
/* Add platform specific fields */
} UnsupportedProcess;UnsupportedProcessTable.c
unsupported/UnsupportedProcessTable.c
function: ProcessTable_delete
void ProcessTable_delete(Object* cast) {
UnsupportedProcessTable* this = (UnsupportedProcessTable*) cast;
ProcessTable_done(&this->super);
free(this);
}function: ProcessTable_goThroughEntries
void ProcessTable_goThroughEntries(ProcessTable* super) {
bool preExisting = true;
Process* proc;
proc = ProcessTable_getProcess(super, 1, &preExisting, UnsupportedProcess_new);
/* Empty values */
proc->time = proc->time + 10;
Process_setPid(proc, 1);
Process_setParent(proc, 1);
Process_setThreadGroup(proc, 0);
Process_updateComm(proc, "commof16char");
Process_updateCmdline(proc, "<unsupported architecture>", 0, 0);
Process_updateExe(proc, "/path/to/executable");
const Settings* settings = super->super.host->settings;
if (settings->ss->flags & PROCESS_FLAG_CWD) {
free_and_xStrdup(&proc->procCwd, "/current/working/directory");
}
proc->super.updated = true;
proc->state = RUNNING;
proc->isKernelThread = false;
proc->isUserlandThread = false;
proc->super.show = true; /* Reflected in settings-> "hideXXX" really */
proc->pgrp = 0;
proc->session = 0;
proc->tty_nr = 0;
proc->tty_name = NULL;
proc->tpgid = 0;
proc->processor = 0;
proc->percent_cpu = 2.5;
proc->percent_mem = 2.5;
Process_updateCPUFieldWidths(proc->percent_cpu);
proc->st_uid = 0;
proc->user = "nobody"; /* Update whenever proc->st_uid is changed */
proc->priority = 0;
proc->nice = 0;
proc->nlwp = 1;
proc->starttime_ctime = 1433116800; // Jun 01, 2015
Process_fillStarttimeBuffer(proc);
proc->m_virt = 100;
proc->m_resident = 100;
proc->minflt = 20;
proc->majflt = 20;
if (!preExisting)
ProcessTable_add(super, proc);
}function: ProcessTable_new
ProcessTable* ProcessTable_new(Machine* host, Hashtable* pidMatchList) {
UnsupportedProcessTable* this = xCalloc(1, sizeof(UnsupportedProcessTable));
Object_setClass(this, Class(ProcessTable));
ProcessTable* super = &this->super;
ProcessTable_init(super, Class(Process), host, pidMatchList);
return super;
}UnsupportedProcessTable.h
unsupported/UnsupportedProcessTable.h
struct: UnsupportedProcessTable_
typedef struct UnsupportedProcessTable_ {
ProcessTable super;
} UnsupportedProcessTable;UptimeMeter.c
UptimeMeter.c
function: UptimeMeter_updateValues
static void UptimeMeter_updateValues(Meter* this) {
int totalseconds = Platform_getUptime();
if (totalseconds <= 0) {
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "(unknown)");
return;
}
int seconds = totalseconds % 60;
int minutes = (totalseconds / 60) % 60;
int hours = (totalseconds / 3600) % 24;
int days = (totalseconds / 86400);
char daysbuf[32];
if (days > 100) {
xSnprintf(daysbuf, sizeof(daysbuf), "%d days(!), ", days);
} else if (days > 1) {
xSnprintf(daysbuf, sizeof(daysbuf), "%d days, ", days);
} else if (days == 1) {
xSnprintf(daysbuf, sizeof(daysbuf), "1 day, ");
} else {
daysbuf[0] = '\0';
}
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "%s%02d:%02d:%02d", daysbuf, hours, minutes, seconds);
}global variable: UptimeMeter_attributes
static const int UptimeMeter_attributes[] = {
UPTIME
};global variable: UptimeMeter_class
const MeterClass UptimeMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete
},
.updateValues = UptimeMeter_updateValues,
.defaultMode = TEXT_METERMODE,
.supportedModes = (1 << TEXT_METERMODE) | (1 << LED_METERMODE),
.maxItems = 0,
.total = 0.0,
.attributes = UptimeMeter_attributes,
.name = "Uptime",
.uiName = "Uptime",
.caption = "Uptime: "
};UptimeMeter.h
UptimeMeter.h
variable: UptimeMeter_class
extern const MeterClass UptimeMeter_class;
UsersTable.c
UsersTable.c
function: UsersTable_delete
void UsersTable_delete(UsersTable* this) {
Hashtable_delete(this->users);
free(this);
}function: UsersTable_foreach
inline void UsersTable_foreach(UsersTable* this, Hashtable_PairFunction f, void* userData) {
Hashtable_foreach(this->users, f, userData);
}function: UsersTable_getRef
char* UsersTable_getRef(UsersTable* this, unsigned int uid) {
char* name = Hashtable_get(this->users, uid);
if (name == NULL) {
const struct passwd* userData = getpwuid(uid);
if (userData != NULL) {
name = xStrdup(userData->pw_name);
Hashtable_put(this->users, uid, name);
}
}
return name;
}function: UsersTable_new
UsersTable* UsersTable_new(void) {
UsersTable* this;
this = xMalloc(sizeof(UsersTable));
this->users = Hashtable_new(10, true);
return this;
}UsersTable.h
UsersTable.h
function: UsersTable_delete
void UsersTable_delete(UsersTable* this);
function: UsersTable_foreach
void UsersTable_foreach(UsersTable* this, Hashtable_PairFunction f, void* userData);
function: UsersTable_getRef
char* UsersTable_getRef(UsersTable* this, unsigned int uid);
function: UsersTable_new
UsersTable* UsersTable_new(void);
struct: UsersTable
typedef struct UsersTable_ {
Hashtable* users;
} UsersTable;Vector.c
Vector.c
function: insertionSort
static void insertionSort(Object** array, int left, int right, Object_Compare compare) {
for (int i = left + 1; i <= right; i++) {
Object* t = array[i];
int j = i - 1;
while (j >= left) {
//comparisons++;
if (compare(array[j], t) <= 0)
break;
array[j + 1] = array[j];
j--;
}
array[j + 1] = t;
}
}function: partition
static int partition(Object** array, int left, int right, int pivotIndex, Object_Compare compare) {
const Object* pivotValue = array[pivotIndex];
swap(array, pivotIndex, right);
int storeIndex = left;
for (int i = left; i < right; i++) {
//comparisons++;
if (compare(array[i], pivotValue) <= 0) {
swap(array, i, storeIndex);
storeIndex++;
}
}
swap(array, storeIndex, right);
return storeIndex;
}function: quickSort
static void quickSort(Object** array, int left, int right, Object_Compare compare) {
if (left >= right)
return;
int pivotIndex = (left + right) / 2;
int pivotNewIndex = partition(array, left, right, pivotIndex, compare);
quickSort(array, left, pivotNewIndex - 1, compare);
quickSort(array, pivotNewIndex + 1, right, compare);
}function: swap
static void swap(Object** array, int indexA, int indexB) {
assert(indexA >= 0);
assert(indexB >= 0);
Object* tmp = array[indexA];
array[indexA] = array[indexB];
array[indexB] = tmp;
}function: Vector_add
void Vector_add(Vector* this, void* data_) {
Object* data = data_;
assert(Object_isA(data, this->type));
assert(Vector_isConsistent(this));
int i = this->items;
Vector_set(this, this->items, data);
assert(this->items == i + 1); (void)(i);
assert(Vector_isConsistent(this));
}function: Vector_compact
void Vector_compact(Vector* this) {
if (!Vector_isDirty(this)) {
return;
}
const int size = this->items;
assert(0 <= this->dirty_index && this->dirty_index < size);
assert(this->array[this->dirty_index] == NULL);
int idx = this->dirty_index;
// one deletion: use memmove, which should be faster
if (this->dirty_count == 1) {
memmove(&this->array[idx], &this->array[idx + 1], (this->items - idx - 1) * sizeof(this->array[0]));
this->array[this->items - 1] = NULL;
} else {
// multiple deletions
for (int i = idx + 1; i < size; i++) {
if (this->array[i]) {
this->array[idx++] = this->array[i];
}
}
// idx is now at the end of the vector and on the first index which should be set to NULL
memset(&this->array[idx], '\0', (size - idx) * sizeof(this->array[0]));
}
this->items -= this->dirty_count;
this->dirty_index = -1;
this->dirty_count = 0;
assert(Vector_isConsistent(this));
}function: Vector_countEquals
bool Vector_countEquals(const Vector* this, unsigned int expectedCount) {
unsigned int n = 0;
for (int i = 0; i < this->items; i++) {
if (this->array[i]) {
n++;
}
}
return n == expectedCount;
}function: Vector_delete
void Vector_delete(Vector* this) {
if (this->owner) {
for (int i = 0; i < this->items; i++) {
if (this->array[i]) {
Object_delete(this->array[i]);
}
}
}
free(this->array);
free(this);
}function: Vector_get
Object* Vector_get(const Vector* this, int idx) {
assert(idx >= 0 && idx < this->items);
assert(this->array[idx]);
assert(Object_isA(this->array[idx], this->type));
return this->array[idx];
}function: Vector_indexOf
int Vector_indexOf(const Vector* this, const void* search_, Object_Compare compare) {
const Object* search = search_;
assert(Object_isA(search, this->type));
assert(compare);
assert(Vector_isConsistent(this));
for (int i = 0; i < this->items; i++) {
const Object* o = this->array[i];
assert(o);
if (compare(search, o) == 0) {
return i;
}
}
return -1;
}function: Vector_insert
void Vector_insert(Vector* this, int idx, void* data_) {
Object* data = data_;
assert(idx >= 0);
assert(Object_isA(data, this->type));
assert(Vector_isConsistent(this));
if (idx > this->items) {
idx = this->items;
}
Vector_resizeIfNecessary(this, this->items + 1);
//assert(this->array[this->items] == NULL);
if (idx < this->items) {
memmove(&this->array[idx + 1], &this->array[idx], (this->items - idx) * sizeof(this->array[0]));
}
this->array[idx] = data;
this->items++;
assert(Vector_isConsistent(this));
}function: Vector_insertionSort
void Vector_insertionSort(Vector* this) {
assert(this->type->compare);
assert(Vector_isConsistent(this));
insertionSort(this->array, 0, this->items - 1, this->type->compare);
assert(Vector_isConsistent(this));
}function: Vector_isConsistent
static bool Vector_isConsistent(const Vector* this) {
assert(this->items <= this->arraySize);
assert(!Vector_isDirty(this));
return true;
}function: Vector_isDirty
static inline bool Vector_isDirty(const Vector* this) {
if (this->dirty_count > 0) {
assert(0 <= this->dirty_index && this->dirty_index < this->items);
assert(this->dirty_count <= this->items);
return true;
}
assert(this->dirty_index == -1);
return false;
}function: Vector_moveDown
void Vector_moveDown(Vector* this, int idx) {
assert(idx >= 0 && idx < this->items);
assert(Vector_isConsistent(this));
if (idx == this->items - 1)
return;
Object* temp = this->array[idx];
this->array[idx] = this->array[idx + 1];
this->array[idx + 1] = temp;
}function: Vector_moveUp
void Vector_moveUp(Vector* this, int idx) {
assert(idx >= 0 && idx < this->items);
assert(Vector_isConsistent(this));
if (idx == 0)
return;
Object* temp = this->array[idx];
this->array[idx] = this->array[idx - 1];
this->array[idx - 1] = temp;
}function: Vector_new
Vector* Vector_new(const ObjectClass* type, bool owner, int size) {
Vector* this;
if (size == DEFAULT_SIZE) {
size = 10;
}
assert(size > 0);
this = xMalloc(sizeof(Vector));
*this = (Vector) {
.growthRate = size,
.array = xCalloc(size, sizeof(Object*)),
.arraySize = size,
.items = 0,
.type = type,
.owner = owner,
.dirty_index = -1,
.dirty_count = 0,
};
return this;
}function: Vector_prune
void Vector_prune(Vector* this) {
assert(Vector_isConsistent(this));
if (this->owner) {
for (int i = 0; i < this->items; i++) {
if (this->array[i]) {
Object_delete(this->array[i]);
}
}
}
this->items = 0;
this->dirty_index = -1;
this->dirty_count = 0;
memset(this->array, '\0', this->arraySize * sizeof(Object*));
}function: Vector_quickSortCustomCompare
void Vector_quickSortCustomCompare(Vector* this, Object_Compare compare) {
assert(compare);
assert(Vector_isConsistent(this));
quickSort(this->array, 0, this->items - 1, compare);
assert(Vector_isConsistent(this));
}function: Vector_remove
Object* Vector_remove(Vector* this, int idx) {
Object* removed = Vector_take(this, idx);
if (this->owner) {
Object_delete(removed);
return NULL;
} else {
return removed;
}
}function: Vector_resizeIfNecessary
static void Vector_resizeIfNecessary(Vector* this, int newSize) {
assert(newSize >= 0);
if (newSize > this->arraySize) {
assert(Vector_isConsistent(this));
int oldSize = this->arraySize;
this->arraySize = newSize + this->growthRate;
this->array = (Object**)xReallocArrayZero(this->array, oldSize, this->arraySize, sizeof(Object*));
}
assert(Vector_isConsistent(this));
}function: Vector_set
void Vector_set(Vector* this, int idx, void* data_) {
Object* data = data_;
assert(idx >= 0);
assert(Object_isA(data, this->type));
assert(Vector_isConsistent(this));
Vector_resizeIfNecessary(this, idx + 1);
if (idx >= this->items) {
this->items = idx + 1;
} else {
if (this->owner) {
Object* removed = this->array[idx];
if (removed != NULL) {
Object_delete(removed);
}
}
}
this->array[idx] = data;
assert(Vector_isConsistent(this));
}function: Vector_size
int Vector_size(const Vector* this) {
assert(Vector_isConsistent(this));
return this->items;
}function: Vector_softRemove
Object* Vector_softRemove(Vector* this, int idx) {
assert(idx >= 0 && idx < this->items);
Object* removed = this->array[idx];
assert(removed);
if (removed) {
this->array[idx] = NULL;
this->dirty_count++;
if (this->dirty_index < 0 || idx < this->dirty_index) {
this->dirty_index = idx;
}
if (this->owner) {
Object_delete(removed);
return NULL;
}
}
return removed;
}function: Vector_splice
void Vector_splice(Vector* this, Vector* from) {
assert(Vector_isConsistent(this));
assert(Vector_isConsistent(from));
assert(!this->owner);
int olditems = this->items;
Vector_resizeIfNecessary(this, this->items + from->items);
this->items += from->items;
for (int j = 0; j < from->items; j++) {
this->array[olditems + j] = from->array[j];
}
}function: Vector_take
Object* Vector_take(Vector* this, int idx) {
assert(idx >= 0 && idx < this->items);
assert(Vector_isConsistent(this));
Object* removed = this->array[idx];
assert(removed);
this->items--;
if (idx < this->items) {
memmove(&this->array[idx], &this->array[idx + 1], (this->items - idx) * sizeof(this->array[0]));
}
this->array[this->items] = NULL;
assert(Vector_isConsistent(this));
return removed;
}Vector.h
Vector.h
conditional compilation block: Conditional Debug/Release Implementations
#ifndef NDEBUG
Object* Vector_get(const Vector* this, int idx);
int Vector_size(const Vector* this);
/* Vector_countEquals returns true if the number of non-NULL items
in the Vector is equal to expectedCount. This is only for debugging
and consistency checks. */
bool Vector_countEquals(const Vector* this, unsigned int expectedCount);
#else /* NDEBUG */
static inline Object* Vector_get(const Vector* this, int idx) {
return this->array[idx];
}
static inline int Vector_size(const Vector* this) {
return this->items;
}
#endif /* NDEBUG */function: Vector_add
void Vector_add(Vector* this, void* data_);
function: Vector_compact
void Vector_compact(Vector* this);
function: Vector_delete
void Vector_delete(Vector* this);
function: Vector_indexOf
int Vector_indexOf(const Vector* this, const void* search_, Object_Compare compare);
function: Vector_insert
void Vector_insert(Vector* this, int idx, void* data_);
function: Vector_insertionSort
void Vector_insertionSort(Vector* this);
function: Vector_moveDown
void Vector_moveDown(Vector* this, int idx);
function: Vector_moveUp
void Vector_moveUp(Vector* this, int idx);
function: Vector_new
Vector* Vector_new(const ObjectClass* type, bool owner, int size);
function: Vector_prune
void Vector_prune(Vector* this);
function: Vector_quickSort
static inline void Vector_quickSort(Vector* this) {
Vector_quickSortCustomCompare(this, this->type->compare);
}function: Vector_quickSortCustomCompare
void Vector_quickSortCustomCompare(Vector* this, Object_Compare compare);
function: Vector_remove
Object* Vector_remove(Vector* this, int idx);
function: Vector_set
void Vector_set(Vector* this, int idx, void* data_);
function: Vector_softRemove
Object* Vector_softRemove(Vector* this, int idx);
function: Vector_splice
void Vector_splice(Vector* this, Vector* from);
function: Vector_take
Object* Vector_take(Vector* this, int idx);
function: Vector_type
static inline const ObjectClass* Vector_type(const Vector* this) {
return this->type;
}macro: DEFAULT_SIZE
#ifndef DEFAULT_SIZE #define DEFAULT_SIZE (-1) #endif
macro guard: HEADER_Vector
#ifndef HEADER_Vector #define HEADER_Vector
struct: Vector
typedef struct Vector_ {
Object** array;
const ObjectClass* type;
int arraySize;
int growthRate;
int items;
/* lowest index of a pending soft remove/delete operation,
used to speed up compaction */
int dirty_index;
/* count of soft deletes, required for Vector_count to work in debug mode */
int dirty_count;
bool owner;
} Vector;XUtils.c
XUtils.c
function: compareRealNumbers
/* 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);
}function: countDigits
/* Counts the number of digits needed to print "n" with a given base.
If "n" is zero, returns 1. This function expects small numbers to
appear often, hence it uses a O(log(n)) time algorithm. */
size_t countDigits(size_t n, size_t base) {
assert(base > 1);
size_t res = 1;
for (size_t limit = base; n >= limit; limit *= base) {
res++;
if (base && limit > SIZE_MAX / base) {
break;
}
}
return res;
}function: countTrailingZeros
#if !defined(HAVE_BUILTIN_CTZ)
// map a bit value mod 37 to its position
static const uint8_t mod37BitPosition[] = {
32, 0, 1, 26, 2, 23, 27, 0, 3, 16, 24, 30, 28, 11, 0, 13, 4,
7, 17, 0, 25, 22, 31, 15, 29, 10, 12, 6, 0, 21, 14, 9, 5,
20, 8, 19, 18
};
/* Returns the number of trailing zero bits */
unsigned int countTrailingZeros(unsigned int x) {
return mod37BitPosition[(-x & x) % 37];
}
#endiffunction: fail
void fail(void) {
CRT_done();
abort();
_exit(1); // Should never reach here
}function: free_and_xStrdup
void free_and_xStrdup(char** ptr, const char* str) {
if (*ptr && String_eq(*ptr, str))
return;
free(*ptr);
*ptr = xStrdup(str);
}function: full_write
ssize_t full_write(int fd, const void* buf, size_t count) {
ssize_t written = 0;
while (count > 0) {
ssize_t r = write(fd, buf, count);
if (r < 0) {
if (errno == EINTR)
continue;
return r;
}
if (r == 0)
break;
written += r;
buf = (const unsigned char*)buf + r;
count -= (size_t)r;
}
return written;
}function: readfd_internal
ATTR_ACCESS3_W(2, 3)
static ssize_t readfd_internal(int fd, void* buffer, size_t count) {
if (!count) {
close(fd);
return -EINVAL;
}
ssize_t alreadyRead = 0;
count--; // reserve one for null-terminator
for (;;) {
ssize_t res = read(fd, buffer, count);
if (res == -1) {
if (errno == EINTR)
continue;
close(fd);
*((char*)buffer) = '\0';
return -errno;
}
if (res > 0) {
assert((size_t)res <= count);
buffer = ((char*)buffer) + res;
count -= (size_t)res;
alreadyRead += res;
}
if (count == 0 || res == 0) {
close(fd);
*((char*)buffer) = '\0';
return alreadyRead;
}
}
}function: String_cat
char* String_cat(const char* s1, const char* s2) {
const size_t l1 = strlen(s1);
const size_t l2 = strlen(s2);
if (SIZE_MAX - l1 <= l2) {
fail();
}
char* out = xMalloc(l1 + l2 + 1);
memcpy(out, s1, l1);
memcpy(out + l1, s2, l2);
out[l1 + l2] = '\0';
return out;
}function: String_contains_i
inline bool String_contains_i(const char* s1, const char* s2, bool multi) {
// we have a multi-string search term, handle as special case for performance reasons
if (multi && strstr(s2, "|")) {
size_t nNeedles;
char** needles = String_split(s2, '|', &nNeedles);
for (size_t i = 0; i < nNeedles; i++) {
if (strcasestr(s1, needles[i]) != NULL) {
String_freeArray(needles);
return true;
}
}
String_freeArray(needles);
return false;
} else {
return strcasestr(s1, s2) != NULL;
}
}function: String_freeArray
void String_freeArray(char** s) {
if (!s) {
return;
}
for (size_t i = 0; s[i] != NULL; i++) {
free(s[i]);
}
free(s);
}function: String_readLine
char* String_readLine(FILE* fp) {
const size_t step = 1024;
size_t bufSize = step;
char* buffer = xMalloc(step + 1);
char* at = buffer;
for (;;) {
const char* ok = fgets(at, step + 1, fp);
if (!ok) {
free(buffer);
return NULL;
}
char* newLine = strrchr(at, '\n');
if (newLine) {
*newLine = '\0';
return buffer;
} else {
if (feof(fp)) {
return buffer;
}
}
bufSize += step;
buffer = xRealloc(buffer, bufSize + 1);
at = buffer + bufSize - step;
}
}function: String_safeStrncpy
size_t String_safeStrncpy(char* restrict dest, const char* restrict src, size_t size) {
assert(size > 0);
size_t i = 0;
for (; i < size - 1 && src[i]; i++)
dest[i] = src[i];
dest[i] = '\0';
return i;
}function: String_split
char** String_split(const char* s, char sep, size_t* n) {
const size_t rate = 10;
char** out = xCalloc(rate, sizeof(char*));
size_t ctr = 0;
size_t blocks = rate;
const char* where;
while ((where = strchr(s, sep)) != NULL) {
size_t size = (size_t)(where - s);
out[ctr] = xStrndup(s, size);
ctr++;
if (ctr == blocks) {
blocks += rate;
out = (char**) xRealloc(out, sizeof(char*) * blocks);
}
s += size + 1;
}
if (s[0] != '\0') {
out[ctr] = xStrdup(s);
ctr++;
}
out = xRealloc(out, sizeof(char*) * (ctr + 1));
out[ctr] = NULL;
if (n)
*n = ctr;
return out;
}function: String_trim
char* String_trim(const char* in) {
while (in[0] == ' ' || in[0] == '\t' || in[0] == '\n') {
in++;
}
size_t len = strlen(in);
while (len > 0 && (in[len - 1] == ' ' || in[len - 1] == '\t' || in[len - 1] == '\n')) {
len--;
}
return xStrndup(in, len);
}function: sumPositiveValues
/* 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;
}function: xAsprintf
int xAsprintf(char** strp, const char* fmt, ...) {
va_list vl;
va_start(vl, fmt);
int r = vasprintf(strp, fmt, vl);
va_end(vl);
if (r < 0 || !*strp) {
fail();
}
return r;
}function: xCalloc
void* xCalloc(size_t nmemb, size_t size) {
assert(nmemb > 0);
assert(size > 0);
if (SIZE_MAX / nmemb < size) {
fail();
}
void* data = calloc(nmemb, size);
if (!data) {
fail();
}
return data;
}function: xMalloc
void* xMalloc(size_t size) {
assert(size > 0);
void* data = malloc(size);
if (!data) {
fail();
}
return data;
}function: xMallocArray
void* xMallocArray(size_t nmemb, size_t size) {
assert(nmemb > 0);
assert(size > 0);
if (SIZE_MAX / nmemb < size) {
fail();
}
return xMalloc(nmemb * size);
}function: xReadfile
ssize_t xReadfile(const char* pathname, void* buffer, size_t count) {
int fd = open(pathname, O_RDONLY);
if (fd < 0)
return -errno;
return readfd_internal(fd, buffer, count);
}function: xReadfileat
ssize_t xReadfileat(openat_arg_t dirfd, const char* pathname, void* buffer, size_t count) {
int fd = Compat_openat(dirfd, pathname, O_RDONLY);
if (fd < 0)
return -errno;
return readfd_internal(fd, buffer, count);
}function: xRealloc
void* xRealloc(void* ptr, size_t size) {
assert(size > 0);
void* data = realloc(ptr, size);
if (!data) {
/* free'ing ptr here causes an indirect memory leak if pointers
* are held as part of an potential array referenced in ptr.
* In GCC 14 -fanalyzer recognizes this leak, but fails to
* ignore it given that this path ends in a noreturn function.
* Thus to avoid this confusing diagnostic we opt to leave
* that pointer alone instead.
*/
// free(ptr);
fail();
}
return data;
}function: xReallocArray
void* xReallocArray(void* ptr, size_t nmemb, size_t size) {
assert(nmemb > 0);
assert(size > 0);
if (SIZE_MAX / nmemb < size) {
fail();
}
return xRealloc(ptr, nmemb * size);
}function: xReallocArrayZero
void* xReallocArrayZero(void* ptr, size_t prevmemb, size_t newmemb, size_t size) {
assert((ptr == NULL) == (prevmemb == 0));
if (prevmemb == newmemb) {
return ptr;
}
void* ret = xReallocArray(ptr, newmemb, size);
if (newmemb > prevmemb) {
memset((unsigned char*)ret + prevmemb * size, '\0', (newmemb - prevmemb) * size);
}
return ret;
}function: xSnprintf
int xSnprintf(char* buf, size_t len, const char* fmt, ...) {
assert(len > 0);
va_list vl;
va_start(vl, fmt);
int n = vsnprintf(buf, len, fmt, vl);
va_end(vl);
if (n < 0 || (size_t)n >= len) {
fail();
}
return n;
}function: xStrdup
char* xStrdup(const char* str) {
char* data = strdup(str);
if (!data) {
fail();
}
return data;
}function: xStrndup
char* xStrndup(const char* str, size_t len) {
char* data = strndup(str, len);
if (!data) {
fail();
}
return data;
}XUtils.h
XUtils.h
function: compareRealNumbers
int compareRealNumbers(double a, double b);
function: countDigits
size_t countDigits(size_t n, size_t base);
function: countTrailingZeros
#if defined(HAVE_BUILTIN_CTZ)
static inline unsigned int countTrailingZeros(unsigned int x) {
return !x ? 32 : __builtin_ctz(x);
}
#else
unsigned int countTrailingZeros(unsigned int x);
#endiffunction: fail
ATTR_NORETURN void fail(void);
function: free_and_xStrdup
ATTR_NONNULL void free_and_xStrdup(char** ptr, const char* str);
function: full_write
ATTR_NONNULL ATTR_ACCESS3_R(2, 3) ssize_t full_write(int fd, const void* buf, size_t count);
function: full_write_str
ATTR_NONNULL
static inline ssize_t full_write_str(int fd, const char* str) {
return full_write(fd, str, strlen(str));
}function: skipEndOfLine
static inline bool skipEndOfLine(FILE* fp) {
char buffer[1024];
while (fgets(buffer, sizeof(buffer), fp)) {
if (strchr(buffer, '\n')) {
return true;
}
}
return false;
}function: String_cat
ATTR_NONNULL ATTR_RETNONNULL ATTR_MALLOC char* String_cat(const char* s1, const char* s2);
function: String_contains_i
bool String_contains_i(const char* s1, const char* s2, bool multi);
function: String_eq
ATTR_NONNULL
static inline bool String_eq(const char* s1, const char* s2) {
return strcmp(s1, s2) == 0;
}function: String_eq_nullable
static inline bool String_eq_nullable(const char* s1, const char* s2) {
if (s1 == s2)
return true;
if (s1 && s2)
return String_eq(s1, s2);
return false;
}function: String_freeArray
void String_freeArray(char** s);
function: String_readLine
ATTR_NONNULL ATTR_MALLOC char* String_readLine(FILE* fp);
function: String_safeStrncpy
ATTR_NONNULL ATTR_ACCESS3_W(1, 3) ATTR_ACCESS3_R(2, 3) size_t String_safeStrncpy(char* restrict dest, const char* restrict src, size_t size);
function: String_split
ATTR_NONNULL_N(1) ATTR_RETNONNULL char** String_split(const char* s, char sep, size_t* n);
function: String_startsWith
ATTR_NONNULL
static inline bool String_startsWith(const char* s, const char* match) {
return strncmp(s, match, strlen(match)) == 0;
}function: String_strchrnul
ATTR_NONNULL ATTR_RETNONNULL
static inline char* String_strchrnul(const char* s, int c) {
#ifdef HAVE_STRCHRNUL
return strchrnul(s, c);
#else
char* result = strchr(s, c);
if (result)
return result;
return strchr(s, '\0');
#endif
}function: String_trim
ATTR_NONNULL ATTR_RETNONNULL ATTR_MALLOC char* String_trim(const char* in);
function: sumPositiveValues
ATTR_NONNULL ATTR_ACCESS3_R(1, 2) double sumPositiveValues(const double* array, size_t count);
function: xAsprintf
ATTR_FORMAT(printf, 2, 3) ATTR_NONNULL_N(1, 2) int xAsprintf(char** strp, const char* fmt, ...);
function: xCalloc
ATTR_RETNONNULL ATTR_MALLOC ATTR_ALLOC_SIZE2(1, 2) void* xCalloc(size_t nmemb, size_t size);
function: xDirfd
static inline int xDirfd(DIR* dirp) {
int r = dirfd(dirp);
assert(r >= 0);
return r;
}function: xMalloc
ATTR_RETNONNULL ATTR_MALLOC ATTR_ALLOC_SIZE1(1) void* xMalloc(size_t size);
function: xMallocArray
ATTR_RETNONNULL ATTR_MALLOC ATTR_ALLOC_SIZE2(1, 2) void* xMallocArray(size_t nmemb, size_t size);
function: xReadfile
ATTR_NONNULL ATTR_ACCESS3_W(2, 3) ssize_t xReadfile(const char* pathname, void* buffer, size_t count);
function: xReadfileat
ATTR_NONNULL ATTR_ACCESS3_W(3, 4) ssize_t xReadfileat(openat_arg_t dirfd, const char* pathname, void* buffer, size_t count);
function: xRealloc
ATTR_RETNONNULL ATTR_ALLOC_SIZE1(2) void* xRealloc(void* ptr, size_t size);
function: xReallocArray
ATTR_RETNONNULL ATTR_ALLOC_SIZE2(2, 3) void* xReallocArray(void* ptr, size_t nmemb, size_t size);
function: xReallocArrayZero
ATTR_RETNONNULL ATTR_ALLOC_SIZE2(3, 4) void* xReallocArrayZero(void* ptr, size_t prevmemb, size_t newmemb, size_t size);
function: xSnprintf
ATTR_FORMAT(printf, 3, 4) ATTR_NONNULL_N(1, 3) ATTR_ACCESS3_W(1, 2) int xSnprintf(char* buf, size_t len, const char* fmt, ...);
function: xStrdup
ATTR_NONNULL ATTR_RETNONNULL ATTR_MALLOC char* xStrdup(const char* str);
function: xStrndup
ATTR_NONNULL ATTR_RETNONNULL ATTR_MALLOC ATTR_ACCESS3_R(1, 2) char* xStrndup(const char* str, size_t len);
global_variable: unitPrefixes
static const char unitPrefixes[] = { 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y', 'R', 'Q' };ZfsArcMeter.c
zfs/ZfsArcMeter.c
function: ZfsArcMeter_readStats
void ZfsArcMeter_readStats(Meter* this, const ZfsArcStats* stats) {
this->total = stats->max;
this->values[0] = stats->MFU;
this->values[1] = stats->MRU;
this->values[2] = stats->anon;
this->values[3] = stats->header;
this->values[4] = stats->other;
// "Hide" the last value so it can
// only be accessed by index and is not
// displayed by the Bar or Graph style
this->curItems = 5;
this->values[5] = stats->size;
}method: ZfsArcMeter_display
static void ZfsArcMeter_display(const Object* cast, RichString* out) {
const Meter* this = (const Meter*)cast;
if (this->values[5] > 0) {
char buffer[50];
Meter_humanUnit(buffer, this->total, sizeof(buffer));
RichString_appendAscii(out, CRT_colors[METER_VALUE], buffer);
Meter_humanUnit(buffer, this->values[5], sizeof(buffer));
RichString_appendAscii(out, CRT_colors[METER_TEXT], " Used:");
RichString_appendAscii(out, CRT_colors[METER_VALUE], buffer);
Meter_humanUnit(buffer, this->values[0], sizeof(buffer));
RichString_appendAscii(out, CRT_colors[METER_TEXT], " MFU:");
RichString_appendAscii(out, CRT_colors[ZFS_MFU], buffer);
Meter_humanUnit(buffer, this->values[1], sizeof(buffer));
RichString_appendAscii(out, CRT_colors[METER_TEXT], " MRU:");
RichString_appendAscii(out, CRT_colors[ZFS_MRU], buffer);
Meter_humanUnit(buffer, this->values[2], sizeof(buffer));
RichString_appendAscii(out, CRT_colors[METER_TEXT], " Anon:");
RichString_appendAscii(out, CRT_colors[ZFS_ANON], buffer);
Meter_humanUnit(buffer, this->values[3], sizeof(buffer));
RichString_appendAscii(out, CRT_colors[METER_TEXT], " Hdr:");
RichString_appendAscii(out, CRT_colors[ZFS_HEADER], buffer);
Meter_humanUnit(buffer, this->values[4], sizeof(buffer));
RichString_appendAscii(out, CRT_colors[METER_TEXT], " Oth:");
RichString_appendAscii(out, CRT_colors[ZFS_OTHER], buffer);
} else {
RichString_writeAscii(out, CRT_colors[METER_TEXT], " ");
RichString_appendAscii(out, CRT_colors[FAILED_READ], "Unavailable");
}
}method: ZfsArcMeter_updateValues
static void ZfsArcMeter_updateValues(Meter* this) {
char* buffer = this->txtBuffer;
size_t size = sizeof(this->txtBuffer);
int written;
Platform_setZfsArcValues(this);
written = Meter_humanUnit(buffer, this->values[5], size);
METER_BUFFER_CHECK(buffer, size, written);
METER_BUFFER_APPEND_CHR(buffer, size, '/');
Meter_humanUnit(buffer, this->total, size);
}struct: ZfsArcMeter_attributes
static const int ZfsArcMeter_attributes[] = {
ZFS_MFU, ZFS_MRU, ZFS_ANON, ZFS_HEADER, ZFS_OTHER
};struct: ZfsArcMeter_class
const MeterClass ZfsArcMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = ZfsArcMeter_display,
},
.updateValues = ZfsArcMeter_updateValues,
.defaultMode = TEXT_METERMODE,
.supportedModes = METERMODE_DEFAULT_SUPPORTED,
.maxItems = 6,
.total = 100.0,
.attributes = ZfsArcMeter_attributes,
.name = "ZFSARC",
.uiName = "ZFS ARC",
.caption = "ARC: "
};ZfsArcMeter.h
zfs/ZfsArcMeter.h
function: ZfsArcMeter_readStats
void ZfsArcMeter_readStats(Meter* this, const ZfsArcStats* stats);
variable: ZfsArcMeter_class
extern const MeterClass ZfsArcMeter_class;
ZfsArcStats.h
zfs/ZfsArcStats.h
struct: ZfsArcStats
typedef struct ZfsArcStats_ {
int enabled;
int isCompressed;
unsigned long long int min;
unsigned long long int max;
unsigned long long int size;
unsigned long long int MFU;
unsigned long long int MRU;
unsigned long long int anon;
unsigned long long int header;
unsigned long long int other;
unsigned long long int compressed;
unsigned long long int uncompressed;
} ZfsArcStats;ZfsCompressedArcMeter.c
zfs/ZfsCompressedArcMeter.c
function: ZfsCompressedArcMeter_display
static void ZfsCompressedArcMeter_display(const Object* cast, RichString* out) {
const Meter* this = (const Meter*)cast;
if (this->values[0] > 0) {
char buffer[50];
int len;
Meter_humanUnit(buffer, this->total, sizeof(buffer));
RichString_appendAscii(out, CRT_colors[METER_VALUE], buffer);
RichString_appendAscii(out, CRT_colors[METER_TEXT], " Uncompressed, ");
Meter_humanUnit(buffer, this->values[0], sizeof(buffer));
RichString_appendAscii(out, CRT_colors[METER_VALUE], buffer);
RichString_appendAscii(out, CRT_colors[METER_TEXT], " Compressed, ");
len = ZfsCompressedArcMeter_printRatioString(this, buffer, sizeof(buffer));
RichString_appendnAscii(out, CRT_colors[ZFS_RATIO], buffer, len);
RichString_appendAscii(out, CRT_colors[METER_TEXT], " Ratio");
} else {
RichString_writeAscii(out, CRT_colors[METER_TEXT], " ");
RichString_appendAscii(out, CRT_colors[FAILED_READ], "Compression Unavailable");
}
}function: ZfsCompressedArcMeter_printRatioString
static int ZfsCompressedArcMeter_printRatioString(const Meter* this, char* buffer, size_t size) {
if (this->values[0] > 0) {
return xSnprintf(buffer, size, "%.2f:1", this->total / this->values[0]);
}
return xSnprintf(buffer, size, "N/A");
}function: ZfsCompressedArcMeter_readStats
void ZfsCompressedArcMeter_readStats(Meter* this, const ZfsArcStats* stats) {
if ( stats->isCompressed ) {
this->total = stats->uncompressed;
this->values[0] = stats->compressed;
} else {
// For uncompressed ARC, report 1:1 ratio
this->total = stats->size;
this->values[0] = stats->size;
}
}function: ZfsCompressedArcMeter_updateValues
static void ZfsCompressedArcMeter_updateValues(Meter* this) {
Platform_setZfsCompressedArcValues(this);
ZfsCompressedArcMeter_printRatioString(this, this->txtBuffer, sizeof(this->txtBuffer));
}global variable: ZfsCompressedArcMeter_attributes
static const int ZfsCompressedArcMeter_attributes[] = {
ZFS_COMPRESSED
};struct: ZfsCompressedArcMeter_class
const MeterClass ZfsCompressedArcMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = ZfsCompressedArcMeter_display,
},
.updateValues = ZfsCompressedArcMeter_updateValues,
.defaultMode = TEXT_METERMODE,
.supportedModes = METERMODE_DEFAULT_SUPPORTED,
.maxItems = 1,
.total = 100.0,
.attributes = ZfsCompressedArcMeter_attributes,
.name = "ZFSCARC",
.uiName = "ZFS CARC",
.description = "ZFS CARC: Compressed ARC statistics",
.caption = "ARC: "
};ZfsCompressedArcMeter.h
zfs/ZfsCompressedArcMeter.h
function: ZfsCompressedArcMeter_readStats
void ZfsCompressedArcMeter_readStats(Meter* this, const ZfsArcStats* stats);
global variable declaration: ZfsCompressedArcMeter_class
extern const MeterClass ZfsCompressedArcMeter_class;