From 2004bbc3ef28ada3acca05f5d5fa9108121a6784 Mon Sep 17 00:00:00 2001 From: Daniel Lange Date: Mon, 11 Apr 2016 13:00:32 +0200 Subject: Imported Upstream version 1.0.2 --- AffinityPanel.c | 2 +- CRT.c | 16 ++++- CRT.h | 2 + ChangeLog | 10 +++ DisplayOptionsPanel.c | 1 + IOPriority.c | 41 ++++++++++++ IOPriority.h | 43 ++++++++++++ IOPriorityPanel.c | 43 ++++++++++++ IOPriorityPanel.h | 20 ++++++ Makefile.am | 8 +-- Makefile.in | 52 ++++++++++++--- Panel.c | 12 +++- Process.c | 85 +++++++++++++++++++----- Process.h | 21 +++++- ProcessList.c | 36 +++++++--- ProcessList.h | 4 +- Settings.c | 7 +- String.c | 2 +- config.h | 6 +- configure | 20 +++--- configure.ac | 2 +- htop.1 | 9 ++- htop.1.in | 7 +- htop.c | 181 ++++++++++++++++++++++++++++++-------------------- htop.h | 2 + 25 files changed, 495 insertions(+), 137 deletions(-) create mode 100644 IOPriority.c create mode 100644 IOPriority.h create mode 100644 IOPriorityPanel.c create mode 100644 IOPriorityPanel.h diff --git a/AffinityPanel.c b/AffinityPanel.c index 729eec4..8c406fb 100644 --- a/AffinityPanel.c +++ b/AffinityPanel.c @@ -50,7 +50,7 @@ Panel* AffinityPanel_new(ProcessList* pl, Affinity* affinity) { } else { mode = false; } - Panel_add(this, (Object*) CheckItem_new(strdup(number), NULL, mode)); + Panel_add(this, (Object*) CheckItem_new(strdup(number), NULL, mode)); } return this; } diff --git a/CRT.c b/CRT.c index 621adfc..6cc979f 100644 --- a/CRT.c +++ b/CRT.c @@ -11,8 +11,10 @@ in the source distribution for its full text. #include "String.h" #include +#include #include #include +#include #ifdef HAVE_EXECINFO_H #include #endif @@ -129,8 +131,13 @@ static void CRT_handleSIGSEGV(int sgn) { fprintf(stderr, "\n\nhtop " VERSION " aborting. Please report bug at http://htop.sf.net\n"); #ifdef HAVE_EXECINFO_H size_t size = backtrace(backtraceArray, sizeof(backtraceArray) / sizeof(void *)); - fprintf(stderr, "Backtrace: \n"); + fprintf(stderr, "\n Please include in your report the following backtrace: \n"); backtrace_symbols_fd(backtraceArray, size, 2); + fprintf(stderr, "\nAdditionally, in order to make the above backtrace useful,"); + fprintf(stderr, "\nplease also run the following command to generate a disassembly of your binary:"); + fprintf(stderr, "\n\n objdump -d `which htop` > ~/htop.objdump"); + fprintf(stderr, "\n\nand then attach the file ~/htop.objdump to your bug report."); + fprintf(stderr, "\n\nThank you for helping to improve htop!\n\n"); #endif #else fprintf(stderr, "\n\nhtop " VERSION " aborting. Unsupported platform.\n"); @@ -193,6 +200,13 @@ void CRT_done() { endwin(); } +void CRT_fatalError(const char* note) { + char* sysMsg = strerror(errno); + CRT_done(); + fprintf(stderr, "%s: %s\n", note, sysMsg); + exit(2); +} + int CRT_readKey() { nocbreak(); cbreak(); diff --git a/CRT.h b/CRT.h index 1fe3d24..7916b16 100644 --- a/CRT.h +++ b/CRT.h @@ -119,6 +119,8 @@ void CRT_init(int delay, int colorScheme); void CRT_done(); +void CRT_fatalError(const char* note); + int CRT_readKey(); void CRT_disableDelay(); diff --git a/ChangeLog b/ChangeLog index 568ec87..a866a6a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,14 @@ +What's new in version 1.0.2 + +* Add IO priority support ('i' key) +* Avoid deleting .htoprc if it is a symlink +* Fail gracefully when /proc is not mounted + (thanks to Philipp Hagemeister) +* Option to update process names on every refresh + (thanks to Rob Hoelz) +* BUGFIX: Fix crashes when process list is empty + What's new in version 1.0.1 * Move .htoprc to XDG-compliant path ~/.config/htop/htoprc, diff --git a/DisplayOptionsPanel.c b/DisplayOptionsPanel.c index bf521a8..7ec035b 100644 --- a/DisplayOptionsPanel.c +++ b/DisplayOptionsPanel.c @@ -83,5 +83,6 @@ DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager* Panel_add(super, (Object*) CheckItem_new(strdup("Leave a margin around header"), &(settings->header->margin), false)); Panel_add(super, (Object*) CheckItem_new(strdup("Detailed CPU time (System/IO-Wait/Hard-IRQ/Soft-IRQ/Steal/Guest)"), &(settings->pl->detailedCPUTime), false)); Panel_add(super, (Object*) CheckItem_new(strdup("Count CPUs from 0 instead of 1"), &(settings->pl->countCPUsFromZero), false)); + Panel_add(super, (Object*) CheckItem_new(strdup("Update process names on every refresh"), &(settings->pl->updateProcessNames), false)); return this; } diff --git a/IOPriority.c b/IOPriority.c new file mode 100644 index 0000000..7b19743 --- /dev/null +++ b/IOPriority.c @@ -0,0 +1,41 @@ +/* +htop - IOPriority.c +(C) 2004-2012 Hisham H. Muhammad +Released under the GNU GPL, see the COPYING file +in the source distribution for its full text. + +Based on ionice, +Copyright (C) 2005 Jens Axboe +Released under the terms of the GNU General Public License version 2 +*/ + +#include "IOPriority.h" + +/*{ + +enum { + IOPRIO_CLASS_NONE, + IOPRIO_CLASS_RT, + IOPRIO_CLASS_BE, + IOPRIO_CLASS_IDLE, +}; + +#define IOPRIO_WHO_PROCESS 1 + +#define IOPRIO_CLASS_SHIFT (13) +#define IOPRIO_PRIO_MASK ((1UL << IOPRIO_CLASS_SHIFT) - 1) + +#define IOPriority_class(ioprio_) ((int) ((ioprio_) >> IOPRIO_CLASS_SHIFT) ) +#define IOPriority_data(ioprio_) ((int) ((ioprio_) & IOPRIO_PRIO_MASK) ) + +typedef int IOPriority; + +#define IOPriority_tuple(class_, data_) (((class_) << IOPRIO_CLASS_SHIFT) | data_) + +#define IOPriority_error 0xffffffff + +#define IOPriority_None IOPriority_tuple(IOPRIO_CLASS_NONE, 0) +#define IOPriority_Idle IOPriority_tuple(IOPRIO_CLASS_IDLE, 0) + +}*/ + diff --git a/IOPriority.h b/IOPriority.h new file mode 100644 index 0000000..d69e30d --- /dev/null +++ b/IOPriority.h @@ -0,0 +1,43 @@ +/* Do not edit this file. It was automatically generated. */ + +#ifndef HEADER_IOPriority +#define HEADER_IOPriority +/* +htop - IOPriority.h +(C) 2004-2012 Hisham H. Muhammad +Released under the GNU GPL, see the COPYING file +in the source distribution for its full text. + +Based on ionice, +Copyright (C) 2005 Jens Axboe +Released under the terms of the GNU General Public License version 2 +*/ + + +enum { + IOPRIO_CLASS_NONE, + IOPRIO_CLASS_RT, + IOPRIO_CLASS_BE, + IOPRIO_CLASS_IDLE, +}; + +#define IOPRIO_WHO_PROCESS 1 + +#define IOPRIO_CLASS_SHIFT (13) +#define IOPRIO_PRIO_MASK ((1UL << IOPRIO_CLASS_SHIFT) - 1) + +#define IOPriority_class(ioprio_) ((int) ((ioprio_) >> IOPRIO_CLASS_SHIFT) ) +#define IOPriority_data(ioprio_) ((int) ((ioprio_) & IOPRIO_PRIO_MASK) ) + +typedef int IOPriority; + +#define IOPriority_tuple(class_, data_) (((class_) << IOPRIO_CLASS_SHIFT) | data_) + +#define IOPriority_error 0xffffffff + +#define IOPriority_None IOPriority_tuple(IOPRIO_CLASS_NONE, 0) +#define IOPriority_Idle IOPriority_tuple(IOPRIO_CLASS_IDLE, 0) + + + +#endif diff --git a/IOPriorityPanel.c b/IOPriorityPanel.c new file mode 100644 index 0000000..bc80b7d --- /dev/null +++ b/IOPriorityPanel.c @@ -0,0 +1,43 @@ +/* +htop - IOPriorityPanel.c +(C) 2004-2012 Hisham H. Muhammad +Released under the GNU GPL, see the COPYING file +in the source distribution for its full text. +*/ + +#include "IOPriorityPanel.h" + +/*{ +#include "Panel.h" +#include "IOPriority.h" +#include "ListItem.h" +}*/ + +Panel* IOPriorityPanel_new(IOPriority currPrio) { + Panel* this = Panel_new(1, 1, 1, 1, LISTITEM_CLASS, true, ListItem_compare); + + 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); + 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]; + snprintf(name, sizeof(name)-1, "%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; +} + +IOPriority IOPriorityPanel_getIOPriority(Panel* this) { + return (IOPriority) ( ((ListItem*) Panel_getSelected(this))->key ); +} diff --git a/IOPriorityPanel.h b/IOPriorityPanel.h new file mode 100644 index 0000000..f87af4e --- /dev/null +++ b/IOPriorityPanel.h @@ -0,0 +1,20 @@ +/* Do not edit this file. It was automatically generated. */ + +#ifndef HEADER_IOPriorityPanel +#define HEADER_IOPriorityPanel +/* +htop - IOPriorityPanel.h +(C) 2004-2012 Hisham H. Muhammad +Released under the GNU GPL, see the COPYING file +in the source distribution for its full text. +*/ + +#include "Panel.h" +#include "IOPriority.h" +#include "ListItem.h" + +Panel* IOPriorityPanel_new(IOPriority currPrio); + +IOPriority IOPriorityPanel_getIOPriority(Panel* this); + +#endif diff --git a/Makefile.am b/Makefile.am index a1ff7d6..05a72e7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -18,18 +18,18 @@ ClockMeter.c ColorsPanel.c ColumnsPanel.c CPUMeter.c CRT.c \ DisplayOptionsPanel.c FunctionBar.c Hashtable.c Header.c htop.c ListItem.c \ LoadAverageMeter.c MemoryMeter.c Meter.c MetersPanel.c Object.c Panel.c \ BatteryMeter.c Process.c ProcessList.c RichString.c ScreenManager.c Settings.c \ -SignalsPanel.c String.c SwapMeter.c TasksMeter.c TraceScreen.c \ +IOPriorityPanel.c SignalsPanel.c String.c SwapMeter.c TasksMeter.c TraceScreen.c \ UptimeMeter.c UsersTable.c Vector.c AvailableColumnsPanel.c AffinityPanel.c \ -HostnameMeter.c OpenFilesScreen.c Affinity.c +HostnameMeter.c OpenFilesScreen.c Affinity.c IOPriority.c myhtopheaders = AvailableColumnsPanel.h AvailableMetersPanel.h \ CategoriesPanel.h CheckItem.h ClockMeter.h ColorsPanel.h ColumnsPanel.h \ -CPUMeter.h CRT.h DisplayOptionsPanel.h FunctionBar.h \ +IOPriorityPanel.h CPUMeter.h CRT.h DisplayOptionsPanel.h FunctionBar.h \ Hashtable.h Header.h htop.h ListItem.h LoadAverageMeter.h MemoryMeter.h \ BatteryMeter.h Meter.h MetersPanel.h Object.h Panel.h ProcessList.h RichString.h \ ScreenManager.h Settings.h SignalsPanel.h String.h \ SwapMeter.h TasksMeter.h TraceScreen.h UptimeMeter.h UsersTable.h Vector.h \ -Process.h AffinityPanel.h HostnameMeter.h OpenFilesScreen.h Affinity.h +Process.h AffinityPanel.h HostnameMeter.h OpenFilesScreen.h Affinity.h IOPriority.h SUFFIXES = .h diff --git a/Makefile.in b/Makefile.in index 554029e..b818ec9 100644 --- a/Makefile.in +++ b/Makefile.in @@ -74,13 +74,15 @@ am__objects_2 = htop-AvailableMetersPanel.$(OBJEXT) \ htop-Panel.$(OBJEXT) htop-BatteryMeter.$(OBJEXT) \ htop-Process.$(OBJEXT) htop-ProcessList.$(OBJEXT) \ htop-RichString.$(OBJEXT) htop-ScreenManager.$(OBJEXT) \ - htop-Settings.$(OBJEXT) htop-SignalsPanel.$(OBJEXT) \ - htop-String.$(OBJEXT) htop-SwapMeter.$(OBJEXT) \ - htop-TasksMeter.$(OBJEXT) htop-TraceScreen.$(OBJEXT) \ - htop-UptimeMeter.$(OBJEXT) htop-UsersTable.$(OBJEXT) \ - htop-Vector.$(OBJEXT) htop-AvailableColumnsPanel.$(OBJEXT) \ + htop-Settings.$(OBJEXT) htop-IOPriorityPanel.$(OBJEXT) \ + htop-SignalsPanel.$(OBJEXT) htop-String.$(OBJEXT) \ + htop-SwapMeter.$(OBJEXT) htop-TasksMeter.$(OBJEXT) \ + htop-TraceScreen.$(OBJEXT) htop-UptimeMeter.$(OBJEXT) \ + htop-UsersTable.$(OBJEXT) htop-Vector.$(OBJEXT) \ + htop-AvailableColumnsPanel.$(OBJEXT) \ htop-AffinityPanel.$(OBJEXT) htop-HostnameMeter.$(OBJEXT) \ - htop-OpenFilesScreen.$(OBJEXT) htop-Affinity.$(OBJEXT) + htop-OpenFilesScreen.$(OBJEXT) htop-Affinity.$(OBJEXT) \ + htop-IOPriority.$(OBJEXT) am_htop_OBJECTS = $(am__objects_1) $(am__objects_2) htop_OBJECTS = $(am_htop_OBJECTS) htop_LDADD = $(LDADD) @@ -270,18 +272,18 @@ ClockMeter.c ColorsPanel.c ColumnsPanel.c CPUMeter.c CRT.c \ DisplayOptionsPanel.c FunctionBar.c Hashtable.c Header.c htop.c ListItem.c \ LoadAverageMeter.c MemoryMeter.c Meter.c MetersPanel.c Object.c Panel.c \ BatteryMeter.c Process.c ProcessList.c RichString.c ScreenManager.c Settings.c \ -SignalsPanel.c String.c SwapMeter.c TasksMeter.c TraceScreen.c \ +IOPriorityPanel.c SignalsPanel.c String.c SwapMeter.c TasksMeter.c TraceScreen.c \ UptimeMeter.c UsersTable.c Vector.c AvailableColumnsPanel.c AffinityPanel.c \ -HostnameMeter.c OpenFilesScreen.c Affinity.c +HostnameMeter.c OpenFilesScreen.c Affinity.c IOPriority.c myhtopheaders = AvailableColumnsPanel.h AvailableMetersPanel.h \ CategoriesPanel.h CheckItem.h ClockMeter.h ColorsPanel.h ColumnsPanel.h \ -CPUMeter.h CRT.h DisplayOptionsPanel.h FunctionBar.h \ +IOPriorityPanel.h CPUMeter.h CRT.h DisplayOptionsPanel.h FunctionBar.h \ Hashtable.h Header.h htop.h ListItem.h LoadAverageMeter.h MemoryMeter.h \ BatteryMeter.h Meter.h MetersPanel.h Object.h Panel.h ProcessList.h RichString.h \ ScreenManager.h Settings.h SignalsPanel.h String.h \ SwapMeter.h TasksMeter.h TraceScreen.h UptimeMeter.h UsersTable.h Vector.h \ -Process.h AffinityPanel.h HostnameMeter.h OpenFilesScreen.h Affinity.h +Process.h AffinityPanel.h HostnameMeter.h OpenFilesScreen.h Affinity.h IOPriority.h SUFFIXES = .h BUILT_SOURCES = $(myhtopheaders) @@ -414,6 +416,8 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htop-Hashtable.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htop-Header.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htop-HostnameMeter.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htop-IOPriority.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htop-IOPriorityPanel.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htop-ListItem.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htop-LoadAverageMeter.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htop-MemoryMeter.Po@am__quote@ @@ -822,6 +826,20 @@ htop-Settings.obj: Settings.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(htop_CFLAGS) $(CFLAGS) -c -o htop-Settings.obj `if test -f 'Settings.c'; then $(CYGPATH_W) 'Settings.c'; else $(CYGPATH_W) '$(srcdir)/Settings.c'; fi` +htop-IOPriorityPanel.o: IOPriorityPanel.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(htop_CFLAGS) $(CFLAGS) -MT htop-IOPriorityPanel.o -MD -MP -MF $(DEPDIR)/htop-IOPriorityPanel.Tpo -c -o htop-IOPriorityPanel.o `test -f 'IOPriorityPanel.c' || echo '$(srcdir)/'`IOPriorityPanel.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/htop-IOPriorityPanel.Tpo $(DEPDIR)/htop-IOPriorityPanel.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='IOPriorityPanel.c' object='htop-IOPriorityPanel.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(htop_CFLAGS) $(CFLAGS) -c -o htop-IOPriorityPanel.o `test -f 'IOPriorityPanel.c' || echo '$(srcdir)/'`IOPriorityPanel.c + +htop-IOPriorityPanel.obj: IOPriorityPanel.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(htop_CFLAGS) $(CFLAGS) -MT htop-IOPriorityPanel.obj -MD -MP -MF $(DEPDIR)/htop-IOPriorityPanel.Tpo -c -o htop-IOPriorityPanel.obj `if test -f 'IOPriorityPanel.c'; then $(CYGPATH_W) 'IOPriorityPanel.c'; else $(CYGPATH_W) '$(srcdir)/IOPriorityPanel.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/htop-IOPriorityPanel.Tpo $(DEPDIR)/htop-IOPriorityPanel.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='IOPriorityPanel.c' object='htop-IOPriorityPanel.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(htop_CFLAGS) $(CFLAGS) -c -o htop-IOPriorityPanel.obj `if test -f 'IOPriorityPanel.c'; then $(CYGPATH_W) 'IOPriorityPanel.c'; else $(CYGPATH_W) '$(srcdir)/IOPriorityPanel.c'; fi` + htop-SignalsPanel.o: SignalsPanel.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(htop_CFLAGS) $(CFLAGS) -MT htop-SignalsPanel.o -MD -MP -MF $(DEPDIR)/htop-SignalsPanel.Tpo -c -o htop-SignalsPanel.o `test -f 'SignalsPanel.c' || echo '$(srcdir)/'`SignalsPanel.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/htop-SignalsPanel.Tpo $(DEPDIR)/htop-SignalsPanel.Po @@ -1004,6 +1022,20 @@ htop-Affinity.obj: Affinity.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(htop_CFLAGS) $(CFLAGS) -c -o htop-Affinity.obj `if test -f 'Affinity.c'; then $(CYGPATH_W) 'Affinity.c'; else $(CYGPATH_W) '$(srcdir)/Affinity.c'; fi` +htop-IOPriority.o: IOPriority.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(htop_CFLAGS) $(CFLAGS) -MT htop-IOPriority.o -MD -MP -MF $(DEPDIR)/htop-IOPriority.Tpo -c -o htop-IOPriority.o `test -f 'IOPriority.c' || echo '$(srcdir)/'`IOPriority.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/htop-IOPriority.Tpo $(DEPDIR)/htop-IOPriority.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='IOPriority.c' object='htop-IOPriority.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(htop_CFLAGS) $(CFLAGS) -c -o htop-IOPriority.o `test -f 'IOPriority.c' || echo '$(srcdir)/'`IOPriority.c + +htop-IOPriority.obj: IOPriority.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(htop_CFLAGS) $(CFLAGS) -MT htop-IOPriority.obj -MD -MP -MF $(DEPDIR)/htop-IOPriority.Tpo -c -o htop-IOPriority.obj `if test -f 'IOPriority.c'; then $(CYGPATH_W) 'IOPriority.c'; else $(CYGPATH_W) '$(srcdir)/IOPriority.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/htop-IOPriority.Tpo $(DEPDIR)/htop-IOPriority.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='IOPriority.c' object='htop-IOPriority.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(htop_CFLAGS) $(CFLAGS) -c -o htop-IOPriority.obj `if test -f 'IOPriority.c'; then $(CYGPATH_W) 'IOPriority.c'; else $(CYGPATH_W) '$(srcdir)/IOPriority.c'; fi` + mostlyclean-libtool: -rm -f *.lo diff --git a/Panel.c b/Panel.c index b090c52..d0f69bf 100644 --- a/Panel.c +++ b/Panel.c @@ -199,8 +199,10 @@ Object* Panel_remove(Panel* this, int i) { Object* Panel_getSelected(Panel* this) { assert (this != NULL); - - return Vector_get(this->items, this->selected); + if (Vector_size(this->items) > 0) + return Vector_get(this->items, this->selected); + else + return NULL; } void Panel_moveSelectedUp(Panel* this) { @@ -248,7 +250,11 @@ void Panel_draw(Panel* this, bool focus) { int scrollH = this->scrollH; int y = this->y; int x = this->x; int first = this->scrollV; - int last = MIN(itemCount, this->scrollV + MIN(itemCount, this->h)); + if (itemCount > this->h && first > itemCount - this->h) { + first = itemCount - this->h; + this->scrollV = first; + } + int last = MIN(itemCount, first + MIN(itemCount, this->h)); if (this->selected < first) { first = this->selected; this->scrollV = first; diff --git a/Process.c b/Process.c index 1ae96e1..99e9f13 100644 --- a/Process.c +++ b/Process.c @@ -26,6 +26,7 @@ in the source distribution for its full text. #include #include #include +#include #ifdef HAVE_LIBHWLOC #include @@ -41,6 +42,7 @@ in the source distribution for its full text. /*{ #include "Object.h" #include "Affinity.h" +#include "IOPriority.h" #include #ifndef Process_isKernelThread @@ -73,6 +75,7 @@ typedef enum ProcessField_ { #ifdef HAVE_CGROUP CGROUP, #endif + IO_PRIORITY, LAST_PROCESSFIELD } ProcessField; @@ -111,6 +114,7 @@ typedef struct Process_ { long int priority; long int nice; long int nlwp; + IOPriority ioPriority; char starttime_show[8]; time_t starttime_ctime; #ifdef DEBUG @@ -199,11 +203,12 @@ const char *Process_fieldNames[] = { #ifdef HAVE_CGROUP "CGROUP", #endif + "IO_PRIORITY", "*** report bug! ***" }; const char *Process_fieldTitles[] = { - "", " PID ", "Command ", "S ", " PPID ", " PGRP ", " SESN ", + "", " PID ", "Command ", "S ", " PPID ", " PGRP ", " SESN ", " TTY ", " TPGID ", "- ", "- ", "- ", "- ", "- ", " UTIME+ ", " STIME+ ", " CUTIME+ ", " CSTIME+ ", "PRI ", " NI ", "- ", "START ", "- ", "- ", "- ", "- ", "- ", "- ", @@ -224,6 +229,7 @@ const char *Process_fieldTitles[] = { #ifdef HAVE_CGROUP " CGROUP ", #endif + "IO ", "*** report bug! ***" }; @@ -239,17 +245,21 @@ void Process_getMaxPid() { fscanf(file, "%32d", &maxPid); fclose(file); if (maxPid > 99999) { - Process_fieldTitles[PID] = " PID "; - Process_fieldTitles[PPID] = " PPID "; - Process_fieldTitles[TPGID] = " TPGID "; - Process_fieldTitles[TGID] = " TGID "; + Process_fieldTitles[PID] = " PID "; + Process_fieldTitles[PPID] = " PPID "; + Process_fieldTitles[TPGID] = " TPGID "; + Process_fieldTitles[TGID] = " TGID "; + Process_fieldTitles[PGRP] = " PGRP "; + Process_fieldTitles[SESSION] = " SESN "; Process_pidFormat = "%7u "; Process_tpgidFormat = "%7d "; } else { - Process_fieldTitles[PID] = " PID "; - Process_fieldTitles[PPID] = " PPID "; - Process_fieldTitles[TPGID] = "TPGID "; - Process_fieldTitles[TGID] = " TGID "; + Process_fieldTitles[PID] = " PID "; + Process_fieldTitles[PPID] = " PPID "; + Process_fieldTitles[TPGID] = "TPGID "; + Process_fieldTitles[TGID] = " TGID "; + Process_fieldTitles[PGRP] = " PGRP "; + Process_fieldTitles[SESSION] = " SESN "; Process_pidFormat = "%5u "; Process_tpgidFormat = "%5d "; } @@ -311,7 +321,7 @@ static void Process_printTime(RichString* str, unsigned long long t) { double jiffytime = 1.0 / jiffy; double realTime = t * jiffytime; - int iRealTime = (int) realTime; + unsigned long long iRealTime = (unsigned long long) realTime; unsigned long long hours = iRealTime / 3600; int minutes = (iRealTime / 60) % 60; @@ -375,8 +385,8 @@ static void Process_writeField(Process* this, RichString* str, ProcessField fiel switch (field) { case PID: snprintf(buffer, n, Process_pidFormat, this->pid); break; case PPID: snprintf(buffer, n, Process_pidFormat, this->ppid); break; - case PGRP: snprintf(buffer, n, "%5u ", this->pgrp); break; - case SESSION: snprintf(buffer, n, "%5u ", this->session); break; + case PGRP: snprintf(buffer, n, Process_pidFormat, this->pgrp); break; + case SESSION: snprintf(buffer, n, Process_pidFormat, this->session); break; case TTY_NR: snprintf(buffer, n, "%5u ", this->tty_nr); break; case TGID: snprintf(buffer, n, Process_pidFormat, this->tgid); break; case TPGID: snprintf(buffer, n, Process_tpgidFormat, this->tpgid); break; @@ -507,7 +517,24 @@ static void Process_writeField(Process* this, RichString* str, ProcessField fiel #ifdef HAVE_CGROUP case CGROUP: snprintf(buffer, n, "%-10s ", this->cgroup); break; #endif - + case IO_PRIORITY: { + int klass = IOPriority_class(this->ioPriority); + if (klass == IOPRIO_CLASS_NONE) { + // see note [1] above + snprintf(buffer, n, "B%1d ", (int) (this->nice + 20) / 5); + } else if (klass == IOPRIO_CLASS_BE) { + snprintf(buffer, n, "B%1d ", IOPriority_data(this->ioPriority)); + } else if (klass == IOPRIO_CLASS_RT) { + attr = CRT_colors[PROCESS_HIGH_PRIORITY]; + snprintf(buffer, n, "R%1d ", IOPriority_data(this->ioPriority)); + } else if (this->ioPriority == IOPriority_Idle) { + attr = CRT_colors[PROCESS_LOW_PRIORITY]; + snprintf(buffer, n, "id "); + } else { + snprintf(buffer, n, "?? "); + } + break; + } default: snprintf(buffer, n, "- "); } @@ -572,6 +599,31 @@ bool Process_setPriority(Process* this, int priority) { return (err == 0); } +bool Process_changePriorityBy(Process* this, size_t delta) { + return Process_setPriority(this, this->nice + delta); +} + +IOPriority Process_updateIOPriority(Process* this) { + IOPriority ioprio = syscall(SYS_ioprio_get, IOPRIO_WHO_PROCESS, this->pid); + this->ioPriority = ioprio; + return ioprio; +} + +bool Process_setIOPriority(Process* this, IOPriority ioprio) { + syscall(SYS_ioprio_set, IOPRIO_WHO_PROCESS, this->pid, ioprio); + return (Process_updateIOPriority(this) == ioprio); +} + +/* +[1] Note that before kernel 2.6.26 a process that has not asked for +an io priority formally uses "none" as scheduling class, but the +io scheduler will treat such processes as if it were in the best +effort class. The priority within the best effort class will be +dynamically derived from the cpu nice level of the process: +io_priority = (cpu_nice + 20) / 5. -- From ionice(1) man page +*/ +#define Process_effectiveIOPriority(p_) (IOPriority_class(p_->ioPriority) == IOPRIO_CLASS_NONE ? IOPriority_tuple(IOPRIO_CLASS_BE, (p_->nice + 20) / 5) : p_->ioPriority) + #ifdef HAVE_LIBHWLOC Affinity* Process_getAffinity(Process* this) { @@ -631,8 +683,8 @@ bool Process_setAffinity(Process* this, Affinity* affinity) { #endif -void Process_sendSignal(Process* this, int sgn) { - kill(this->pid, sgn); +void Process_sendSignal(Process* this, size_t sgn) { + kill(this->pid, (int) sgn); } int Process_pidCompare(const void* v1, const void* v2) { @@ -729,7 +781,8 @@ int Process_compare(const void* v1, const void* v2) { case CGROUP: return strcmp(p1->cgroup ? p1->cgroup : "", p2->cgroup ? p2->cgroup : ""); #endif - + case IO_PRIORITY: + return Process_effectiveIOPriority(p1) - Process_effectiveIOPriority(p2); default: return (p1->pid - p2->pid); } diff --git a/Process.h b/Process.h index 2c3e0c3..c5f5934 100644 --- a/Process.h +++ b/Process.h @@ -21,6 +21,7 @@ in the source distribution for its full text. #include "Object.h" #include "Affinity.h" +#include "IOPriority.h" #include #ifndef Process_isKernelThread @@ -53,6 +54,7 @@ typedef enum ProcessField_ { #ifdef HAVE_CGROUP CGROUP, #endif + IO_PRIORITY, LAST_PROCESSFIELD } ProcessField; @@ -91,6 +93,7 @@ typedef struct Process_ { long int priority; long int nice; long int nlwp; + IOPriority ioPriority; char starttime_show[8]; time_t starttime_ctime; #ifdef DEBUG @@ -175,6 +178,22 @@ void Process_toggleTag(Process* this); bool Process_setPriority(Process* this, int priority); +bool Process_changePriorityBy(Process* this, size_t delta); + +IOPriority Process_updateIOPriority(Process* this); + +bool Process_setIOPriority(Process* this, IOPriority ioprio); + +/* +[1] Note that before kernel 2.6.26 a process that has not asked for +an io priority formally uses "none" as scheduling class, but the +io scheduler will treat such processes as if it were in the best +effort class. The priority within the best effort class will be +dynamically derived from the cpu nice level of the process: +extern io_priority; +*/ +#define Process_effectiveIOPriority(p_) (IOPriority_class(p_->ioPriority) == IOPRIO_CLASS_NONE ? IOPriority_tuple(IOPRIO_CLASS_BE, (p_->nice + 20) / 5) : p_->ioPriority) + #ifdef HAVE_LIBHWLOC Affinity* Process_getAffinity(Process* this); @@ -189,7 +208,7 @@ bool Process_setAffinity(Process* this, Affinity* affinity); #endif -void Process_sendSignal(Process* this, int sgn); +void Process_sendSignal(Process* this, size_t sgn); int Process_pidCompare(const void* v1, const void* v2); diff --git a/ProcessList.c b/ProcessList.c index 1f47408..04adac5 100644 --- a/ProcessList.c +++ b/ProcessList.c @@ -114,6 +114,7 @@ typedef struct ProcessList_ { uid_t userId; bool filtering; const char* incFilter; + Hashtable* pidWhiteList; int cpuCount; int totalTasks; @@ -152,6 +153,7 @@ typedef struct ProcessList_ { bool highlightThreads; bool detailedCPUTime; bool countCPUsFromZero; + bool updateProcessNames; const char **treeStr; } ProcessList; @@ -180,18 +182,21 @@ const char *ProcessList_treeStrUtf8[TREE_STR_COUNT] = { "\xe2\x94\x80", // TREE_STR_SHUT ─ }; -ProcessList* ProcessList_new(UsersTable* usersTable) { +ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList) { ProcessList* this; this = calloc(sizeof(ProcessList), 1); this->processes = Vector_new(PROCESS_CLASS, true, DEFAULT_SIZE, Process_compare); this->processTable = Hashtable_new(140, false); this->usersTable = usersTable; + this->pidWhiteList = pidWhiteList; /* tree-view auxiliary buffers */ this->processes2 = Vector_new(PROCESS_CLASS, true, DEFAULT_SIZE, Process_compare); FILE* file = fopen(PROCSTATFILE, "r"); - assert(file != NULL); + if (file == NULL) { + CRT_fatalError("Cannot open " PROCSTATFILE); + } char buffer[256]; int cpus = -1; do { @@ -235,7 +240,9 @@ ProcessList* ProcessList_new(UsersTable* usersTable) { this->highlightMegabytes = false; this->detailedCPUTime = false; this->countCPUsFromZero = false; + this->updateProcessNames = false; this->treeStr = NULL; + this->following = -1; return this; } @@ -265,7 +272,7 @@ void ProcessList_printHeader(ProcessList* this, RichString* header) { ProcessField* fields = this->fields; for (int i = 0; fields[i]; i++) { const char* field = Process_fieldTitles[fields[i]]; - if (this->sortKey == fields[i]) + if (!this->treeView && this->sortKey == fields[i]) RichString_append(header, CRT_colors[PANEL_HIGHLIGHT_FOCUS], field); else RichString_append(header, CRT_colors[PANEL_HEADER_FOCUS], field); @@ -598,6 +605,7 @@ static void ProcessList_readVServerData(Process* process, const char* dirname, c static bool ProcessList_readCmdlineFile(Process* process, const char* dirname, const char* name) { if (Process_isKernelThread(process)) return true; + char filename[MAX_NAME+1]; snprintf(filename, MAX_NAME, "%s/%s/cmdline", dirname, name); FILE* file = fopen(filename, "r"); @@ -616,6 +624,7 @@ static bool ProcessList_readCmdlineFile(Process* process, const char* dirname, c fclose(file); free(process->comm); process->comm = strdup(command); + return true; } @@ -676,7 +685,8 @@ static bool ProcessList_processEntries(ProcessList* this, const char* dirname, P unsigned long long int lasttimes = (process->utime + process->stime); if (! ProcessList_readStatFile(process, dirname, name, command)) goto errorReadingProcess; - int percent_cpu = (process->utime + process->stime - lasttimes) / period * 100.0; + Process_updateIOPriority(process); + float percent_cpu = (process->utime + process->stime - lasttimes) / period * 100.0; process->percent_cpu = MAX(MIN(percent_cpu, cpus*100.0), 0.0); if (isnan(process->percent_cpu)) process->percent_cpu = 0.0; process->percent_mem = (process->m_resident * PAGE_SIZE_KB) / (double)(this->totalMem) * 100.0; @@ -704,6 +714,11 @@ static bool ProcessList_processEntries(ProcessList* this, const char* dirname, P goto errorReadingProcess; ProcessList_add(this, process); + } else { + if (this->updateProcessNames) { + if (! ProcessList_readCmdlineFile(process, dirname, name)) + goto errorReadingProcess; + } } if (process->state == 'Z') { @@ -752,7 +767,9 @@ void ProcessList_scan(ProcessList* this) { unsigned long long int swapFree = 0; FILE* file = fopen(PROCMEMINFOFILE, "r"); - assert(file != NULL); + if (file == NULL) { + CRT_fatalError("Cannot open " PROCMEMINFOFILE); + } int cpus = this->cpuCount; { char buffer[128]; @@ -790,7 +807,9 @@ void ProcessList_scan(ProcessList* this) { fclose(file); file = fopen(PROCSTATFILE, "r"); - assert(file != NULL); + if (file == NULL) { + CRT_fatalError("Cannot open " PROCSTATFILE); + } for (int i = 0; i <= cpus; i++) { char buffer[256]; int cpuid; @@ -915,7 +934,7 @@ void ProcessList_rebuildPanel(ProcessList* this, bool flags, int following, bool } int currPos = Panel_getSelectedIndex(this->panel); - pid_t currPid = following ? following : 0; + pid_t currPid = following != -1 ? following : 0; int currScrollV = this->panel->scrollV; Panel_prune(this->panel); @@ -927,7 +946,8 @@ void ProcessList_rebuildPanel(ProcessList* this, bool flags, int following, bool if ( (!p->show) || (userOnly && (p->st_uid != userId)) - || (filtering && !(String_contains_i(p->comm, incFilter))) ) + || (filtering && !(String_contains_i(p->comm, incFilter))) + || (this->pidWhiteList && !Hashtable_get(this->pidWhiteList, p->pid)) ) hidden = true; if (!hidden) { diff --git a/ProcessList.h b/ProcessList.h index d7a5ef9..34bd5e8 100644 --- a/ProcessList.h +++ b/ProcessList.h @@ -97,6 +97,7 @@ typedef struct ProcessList_ { uid_t userId; bool filtering; const char* incFilter; + Hashtable* pidWhiteList; int cpuCount; int totalTasks; @@ -135,6 +136,7 @@ typedef struct ProcessList_ { bool highlightThreads; bool detailedCPUTime; bool countCPUsFromZero; + bool updateProcessNames; const char **treeStr; } ProcessList; @@ -144,7 +146,7 @@ extern const char *ProcessList_treeStrAscii[TREE_STR_COUNT]; extern const char *ProcessList_treeStrUtf8[TREE_STR_COUNT]; -ProcessList* ProcessList_new(UsersTable* usersTable); +ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList); void ProcessList_delete(ProcessList* this); diff --git a/Settings.c b/Settings.c index f2573e8..fd200a7 100644 --- a/Settings.c +++ b/Settings.c @@ -124,6 +124,8 @@ static bool Settings_read(Settings* this, char* fileName, int cpuCount) { this->pl->detailedCPUTime = atoi(option[1]); } else if (String_eq(option[0], "cpu_count_from_zero")) { this->pl->countCPUsFromZero = atoi(option[1]); + } else if (String_eq(option[0], "update_process_names")) { + this->pl->updateProcessNames = atoi(option[1]); } else if (String_eq(option[0], "delay")) { this->delay = atoi(option[1]); } else if (String_eq(option[0], "color_scheme")) { @@ -183,6 +185,7 @@ bool Settings_write(Settings* this) { fprintf(fd, "header_margin=%d\n", (int) this->header->margin); fprintf(fd, "detailed_cpu_time=%d\n", (int) this->pl->detailedCPUTime); fprintf(fd, "cpu_count_from_zero=%d\n", (int) this->pl->countCPUsFromZero); + fprintf(fd, "update_process_names=%d\n", (int) this->pl->updateProcessNames); fprintf(fd, "color_scheme=%d\n", (int) this->colorScheme); fprintf(fd, "delay=%d\n", (int) this->delay); fprintf(fd, "left_meters="); @@ -239,7 +242,9 @@ Settings* Settings_new(ProcessList* pl, Header* header, int cpuCount) { mkdir(htopDir, 0700); free(htopDir); free(configDir); - if (access(legacyDotfile, R_OK) != 0) { + struct stat st; + lstat(legacyDotfile, &st); + if (access(legacyDotfile, R_OK) != 0 || S_ISLNK(st.st_mode)) { free(legacyDotfile); legacyDotfile = NULL; } diff --git a/String.c b/String.c index adb6749..173932c 100644 --- a/String.c +++ b/String.c @@ -118,7 +118,7 @@ char* String_getToken(const char* line, const unsigned short int numMatch) { count++; if(inWord == 1){ - if (count == numMatch && line[i] != ' ' && line[i] != '\0' && line[i] != '\n' && line[i] != EOF) { + if (count == numMatch && line[i] != ' ' && line[i] != '\0' && line[i] != '\n' && line[i] != (char)EOF) { match[foundCount] = line[i]; foundCount++; } diff --git a/config.h b/config.h index 24abfcb..9852b8c 100644 --- a/config.h +++ b/config.h @@ -146,7 +146,7 @@ #define PACKAGE_NAME "htop" /* Define to the full name and version of this package. */ -#define PACKAGE_STRING "htop 1.0.1" +#define PACKAGE_STRING "htop 1.0.2" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "htop" @@ -155,7 +155,7 @@ #define PACKAGE_URL "" /* Define to the version of this package. */ -#define PACKAGE_VERSION "1.0.1" +#define PACKAGE_VERSION "1.0.2" /* Path of proc filesystem */ #define PROCDIR "/proc" @@ -189,7 +189,7 @@ /* Version number of package */ -#define VERSION "1.0.1" +#define VERSION "1.0.2" /* Define to 1 if on MINIX. */ /* #undef _MINIX */ diff --git a/configure b/configure index 18aa703..7d910e1 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.65 for htop 1.0.1. +# Generated by GNU Autoconf 2.65 for htop 1.0.2. # # Report bugs to . # @@ -562,8 +562,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='htop' PACKAGE_TARNAME='htop' -PACKAGE_VERSION='1.0.1' -PACKAGE_STRING='htop 1.0.1' +PACKAGE_VERSION='1.0.2' +PACKAGE_STRING='htop 1.0.2' PACKAGE_BUGREPORT='loderunner@users.sourceforge.net' PACKAGE_URL='' @@ -1286,7 +1286,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures htop 1.0.1 to adapt to many kinds of systems. +\`configure' configures htop 1.0.2 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1357,7 +1357,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of htop 1.0.1:";; + short | recursive ) echo "Configuration of htop 1.0.2:";; esac cat <<\_ACEOF @@ -1471,7 +1471,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -htop configure 1.0.1 +htop configure 1.0.2 generated by GNU Autoconf 2.65 Copyright (C) 2009 Free Software Foundation, Inc. @@ -1896,7 +1896,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by htop $as_me 1.0.1, which was +It was created by htop $as_me 1.0.2, which was generated by GNU Autoconf 2.65. Invocation command line was $ $0 $@ @@ -4130,7 +4130,7 @@ fi # Define the identity of the package. PACKAGE='htop' - VERSION='1.0.1' + VERSION='1.0.2' cat >>confdefs.h <<_ACEOF @@ -13153,7 +13153,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by htop $as_me 1.0.1, which was +This file was extended by htop $as_me 1.0.2, which was generated by GNU Autoconf 2.65. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -13219,7 +13219,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -htop config.status 1.0.1 +htop config.status 1.0.2 configured by $0, generated by GNU Autoconf 2.65, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index 639d048..ff6901b 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ(2.65) -AC_INIT([htop],[1.0.1],[loderunner@users.sourceforge.net]) +AC_INIT([htop],[1.0.2],[loderunner@users.sourceforge.net]) # The following two lines are required by hwloc scripts AC_USE_SYSTEM_EXTENSIONS diff --git a/htop.1 b/htop.1 index 6b201c6..ae654d0 100644 --- a/htop.1 +++ b/htop.1 @@ -1,4 +1,4 @@ -.TH "HTOP" "1" "2011" "htop 1.0.1" "Utils" +.TH "HTOP" "1" "2011" "htop 1.0.2" "Utils" .SH "NAME" htop \- interactive process viewer .SH "SYNOPSIS" @@ -29,12 +29,15 @@ Start htop in monochrome mode \fB\-h \-\-help Display a help message and exit .TP -\fB\-u \-\-user=USERNAME\fR -Show only the processes of a given user +\fB\-p \-\-pid=PID,PID...\fR +Show only the given PIDs .TP \fB\-s \-\-sort\-key COLUMN\fR Sort by this column (use \-\-sort\-key help for a column list) .TP +\fB\-u \-\-user=USERNAME\fR +Show only the processes of a given user +.TP \fB\-v \-\-version Output version information and exit .PP diff --git a/htop.1.in b/htop.1.in index fa7682b..bd8b909 100644 --- a/htop.1.in +++ b/htop.1.in @@ -29,12 +29,15 @@ Start htop in monochrome mode \fB\-h \-\-help Display a help message and exit .TP -\fB\-u \-\-user=USERNAME\fR -Show only the processes of a given user +\fB\-p \-\-pid=PID,PID...\fR +Show only the given PIDs .TP \fB\-s \-\-sort\-key COLUMN\fR Sort by this column (use \-\-sort\-key help for a column list) .TP +\fB\-u \-\-user=USERNAME\fR +Show only the processes of a given user +.TP \fB\-v \-\-version Output version information and exit .PP diff --git a/htop.c b/htop.c index dd76071..44aa857 100644 --- a/htop.c +++ b/htop.c @@ -22,6 +22,7 @@ in the source distribution for its full text. #include "TraceScreen.h" #include "OpenFilesScreen.h" #include "AffinityPanel.h" +#include "IOPriorityPanel.h" #include #include @@ -51,11 +52,12 @@ static void printVersionFlag() { static void printHelpFlag() { fputs("htop " VERSION " - " COPYRIGHT "\n" "Released under the GNU GPL.\n\n" - "-C --no-color Use a monochrome color scheme\n" - "-d --delay=DELAY Set the delay between updates, in tenths of seconds\n" - "-h --help Print this help screen\n" - "-s --sort-key=COLUMN Sort by COLUMN (try --sort-key=help for a list)\n" - "-u --user=USERNAME Show only processes of a given user\n" + "-C --no-color Use a monochrome color scheme\n" + "-d --delay=DELAY Set the delay between updates, in tenths of seconds\n" + "-h --help Print this help screen\n" + "-s --sort-key=COLUMN Sort by COLUMN (try --sort-key=help for a list)\n" + "-u --user=USERNAME Show only processes of a given user\n" + "-p --pid=PID,[,PID,PID...] Show only the given PIDs\n" "-v --version Print version info\n" "\n" "Long options may be passed with a single dash.\n\n" @@ -123,18 +125,18 @@ static void showHelp(ProcessList* pl) { mvaddstr(12, 0, " F4 \\: incremental name filtering K: hide/show kernel threads"); mvaddstr(13, 0, " Space: tag processes F: cursor follows process"); mvaddstr(14, 0, " U: untag all processes + -: expand/collapse tree"); - mvaddstr(15, 0, " F9 k: kill process/tagged processes P: sort by CPU%"); - mvaddstr(16, 0, " ] F7: higher priority (root only) M: sort by MEM%"); - mvaddstr(17, 0, " [ F8: lower priority (+ nice) T: sort by TIME"); + mvaddstr(15, 0, " F9 k: kill process/tagged processes P M T: sort by CPU%, MEM% or TIME"); + mvaddstr(16, 0, " ] F7: higher priority (root only) i: set IO priority"); + mvaddstr(17, 0, " [ F8: lower priority (+ nice) I: invert sort order"); #if (HAVE_LIBHWLOC || HAVE_NATIVE_AFFINITY) if (pl->cpuCount > 1) - mvaddstr(18, 0, " a: set CPU affinity I: invert sort order"); + mvaddstr(18, 0, " a: set CPU affinity F6 >: select sort column"); else #endif - mvaddstr(18, 0, " I: invert sort order"); - mvaddstr(19, 0, " F2 S: setup F6 >: select sort column"); - mvaddstr(20, 0, " F1 h: show this help screen l: list open files with lsof"); - mvaddstr(21, 0, " F10 q: quit s: trace syscalls with strace"); + mvaddstr(18, 0, " F6 >: select sort column"); + mvaddstr(19, 0, " F2 S: setup l: list open files with lsof"); + mvaddstr(20, 0, " F1 h: show this help screen s: trace syscalls with strace"); + mvaddstr(21, 0, " F10 q: quit"); attrset(CRT_colors[HELP_BOLD]); mvaddstr( 9, 0, " Arrows"); mvaddstr( 9,40, " F5 t"); @@ -143,17 +145,17 @@ static void showHelp(ProcessList* pl) { mvaddstr(12, 0, " F4 \\"); mvaddstr(12,40, " K"); mvaddstr(13, 0, " Space"); mvaddstr(13,40, " F"); mvaddstr(14, 0, " U"); mvaddstr(14,40, " + -"); - mvaddstr(15, 0, " F9 k"); mvaddstr(15,40, " P"); - mvaddstr(16, 0, " ] F7"); mvaddstr(16,40, " M"); - mvaddstr(17, 0, " [ F8"); mvaddstr(17,40, " T"); - mvaddstr(18,40, " F4 I"); + mvaddstr(15, 0, " F9 k"); mvaddstr(15,40, "P M T"); + mvaddstr(16, 0, " ] F7"); mvaddstr(16,40, " i"); + mvaddstr(17, 0, " [ F8"); mvaddstr(17,40, " I"); + mvaddstr(18,40, " F6 >"); #if (HAVE_LIBHWLOC || HAVE_NATIVE_AFFINITY) if (pl->cpuCount > 1) mvaddstr(18, 0, " a:"); #endif - mvaddstr(19, 0, " F2 S"); mvaddstr(19,40, " F6 >"); - mvaddstr(20, 0, " ? F1 h"); mvaddstr(20,40, " l"); - mvaddstr(21, 0, " F10 q"); mvaddstr(21,40, " s"); + mvaddstr(19, 0, " F2 S"); mvaddstr(19,40, " l"); + mvaddstr(20, 0, " ? F1 h"); mvaddstr(20,40, " s"); + mvaddstr(21, 0, " F10 q"); attrset(CRT_colors[DEFAULT_COLOR]); attrset(CRT_colors[HELP_BOLD]); @@ -177,20 +179,30 @@ static void Setup_run(Settings* settings, const Header* header) { ScreenManager_delete(scr); } -static bool changePriority(Panel* panel, int delta) { +typedef bool(*ForeachProcessFn)(Process*, size_t); + +static bool foreachProcess(Panel* panel, ForeachProcessFn fn, int arg, bool* wasAnyTagged) { bool ok = true; bool anyTagged = false; for (int i = 0; i < Panel_size(panel); i++) { Process* p = (Process*) Panel_get(panel, i); if (p->tag) { - ok = Process_setPriority(p, p->nice + delta) && ok; + ok = fn(p, arg) && ok; anyTagged = true; } } if (!anyTagged) { Process* p = (Process*) Panel_getSelected(panel); - ok = Process_setPriority(p, p->nice + delta) && ok; + if (p) ok = fn(p, arg) && ok; } + if (wasAnyTagged) + *wasAnyTagged = anyTagged; + return ok; +} + +static bool changePriority(Panel* panel, int delta) { + bool anyTagged; + bool ok = foreachProcess(panel, (ForeachProcessFn) Process_changePriorityBy, delta, &anyTagged); if (!ok) beep(); return anyTagged; @@ -207,7 +219,16 @@ static Object* pickFromVector(Panel* panel, Panel* list, int x, int y, const cha ScreenManager_add(scr, panel, NULL, -1); Panel* panelFocus; int ch; + bool unfollow = false; + if (header->pl->following == -1) { + Process* p = (Process*)Panel_getSelected(panel); + header->pl->following = p ? p->pid : -1; + unfollow = true; + } ScreenManager_run(scr, &panelFocus, &ch); + if (unfollow) { + header->pl->following = -1; + } ScreenManager_delete(scr); Panel_move(panel, 0, y); Panel_resize(panel, COLS, LINES-y-1); @@ -260,6 +281,9 @@ int main(int argc, char** argv) { uid_t userId = 0; int usecolors = 1; TreeType treeType = TREE_TYPE_AUTO; + char *argCopy; + char *pid; + Hashtable *pidWhiteList = NULL; int opt, opti=0; static struct option long_opts[] = @@ -271,6 +295,7 @@ int main(int argc, char** argv) { {"user", required_argument, 0, 'u'}, {"no-color", no_argument, 0, 'C'}, {"no-colour",no_argument, 0, 'C'}, + {"pid", required_argument, 0, 'p'}, {0,0,0,0} }; int sortKey = 0; @@ -284,7 +309,7 @@ int main(int argc, char** argv) { setlocale(LC_CTYPE, ""); /* Parse arguments */ - while ((opt = getopt_long(argc, argv, "hvCs:d:u:", long_opts, &opti))) { + while ((opt = getopt_long(argc, argv, "hvCs:d:u:p:", long_opts, &opti))) { if (opt == EOF) break; switch (opt) { case 'h': @@ -323,6 +348,22 @@ int main(int argc, char** argv) { break; case 'C': usecolors=0; + break; + case 'p': + argCopy = strdup(optarg); + pid = strtok(argCopy, ","); + + if( !pidWhiteList ) { + pidWhiteList = Hashtable_new(8, false); + } + + while( pid ) { + unsigned int num_pid = atoi(pid); + Hashtable_put(pidWhiteList, num_pid, (void *) 1); + pid = strtok(NULL, ","); + } + free(argCopy); + break; default: exit(1); @@ -347,7 +388,7 @@ int main(int argc, char** argv) { ProcessList* pl = NULL; UsersTable* ut = UsersTable_new(); - pl = ProcessList_new(ut); + pl = ProcessList_new(ut, pidWhiteList); Process_getMaxPid(); Header* header = Header_new(pl); @@ -440,7 +481,8 @@ int main(int argc, char** argv) { gettimeofday(&tv, NULL); newTime = ((double)tv.tv_sec * 10) + ((double)tv.tv_usec / 100000); recalculate = (newTime - oldTime > CRT_delay); - int following = follow ? ((Process*)Panel_getSelected(panel))->pid : -1; + Process* p = (Process*)Panel_getSelected(panel); + int following = (follow && p) ? p->pid : -1; if (recalculate) oldTime = newTime; if (doRefresh) { @@ -481,6 +523,7 @@ int main(int argc, char** argv) { doRefresh = false; int size = Panel_size(panel); if (ch == KEY_F(3)) { + if (Panel_size(panel) == 0) continue; int here = Panel_getSelectedIndex(panel); int i = here+1; while (i != here) { @@ -541,11 +584,12 @@ int main(int argc, char** argv) { continue; } if (isdigit((char)ch)) { + if (Panel_size(panel) == 0) continue; pid_t pid = ch-48 + acc; for (int i = 0; i < ProcessList_size(pl) && ((Process*) Panel_getSelected(panel))->pid != pid; i++) Panel_setSelected(panel, i); acc = pid * 10; - if (acc > 100000) + if (acc > 10000000) acc = 0; continue; } else { @@ -644,13 +688,16 @@ int main(int argc, char** argv) { case ' ': { Process* p = (Process*) Panel_getSelected(panel); + if (!p) break; Process_toggleTag(p); Panel_onKey(panel, KEY_DOWN); break; } case 's': { - TraceScreen* ts = TraceScreen_new((Process*) Panel_getSelected(panel)); + Process* p = (Process*) Panel_getSelected(panel); + if (!p) break; + TraceScreen* ts = TraceScreen_new(p); TraceScreen_run(ts); TraceScreen_delete(ts); clear(); @@ -661,7 +708,9 @@ int main(int argc, char** argv) { } case 'l': { - OpenFilesScreen* ts = OpenFilesScreen_new((Process*) Panel_getSelected(panel)); + Process* p = (Process*) Panel_getSelected(panel); + if (!p) break; + OpenFilesScreen* ts = OpenFilesScreen_new(p); OpenFilesScreen_run(ts); OpenFilesScreen_delete(ts); clear(); @@ -714,6 +763,7 @@ int main(int argc, char** argv) { case '-': { Process* p = (Process*) Panel_getSelected(panel); + if (!p) break; p->showChildren = !p->showChildren; refreshTimeout = 0; doRecalculate = true; @@ -725,19 +775,6 @@ int main(int argc, char** argv) { if (!killPanel) { killPanel = (Panel*) SignalsPanel_new(0, 0, 0, 0); } - bool anyTagged = false; - pid_t selectedPid; - for (int i = 0; i < Panel_size(panel); i++) { - Process* p = (Process*) Panel_get(panel, i); - if (p->tag) { - anyTagged = true; - break; - } - } - if (!anyTagged) { - Process* p = (Process*) Panel_getSelected(panel); - selectedPid = p->pid; - } SignalsPanel_reset((SignalsPanel*) killPanel); const char* fuFunctions[] = {"Send ", "Cancel ", NULL}; ListItem* sgn = (ListItem*) pickFromVector(panel, killPanel, 15, headerHeight, fuFunctions, defaultBar, header); @@ -746,19 +783,7 @@ int main(int argc, char** argv) { Panel_setHeader(panel, "Sending..."); Panel_draw(panel, true); refresh(); - if (anyTagged) { - for (int i = 0; i < Panel_size(panel); i++) { - Process* p = (Process*) Panel_get(panel, i); - if (p->tag) { - Process_sendSignal(p, sgn->key); - anyTagged = true; - } - } - } else { - Process* p = (Process*) Panel_getSelected(panel); - if (p->pid == selectedPid) - Process_sendSignal(p, sgn->key); - } + foreachProcess(panel, (ForeachProcessFn) Process_sendSignal, (size_t) sgn->key, NULL); napms(500); } } @@ -772,7 +797,9 @@ int main(int argc, char** argv) { if (pl->cpuCount == 1) break; - Affinity* affinity = Process_getAffinity((Process*) Panel_getSelected(panel)); + Process* p = (Process*) Panel_getSelected(panel); + if (!p) break; + Affinity* affinity = Process_getAffinity(p); if (!affinity) break; Panel* affinityPanel = AffinityPanel_new(pl, affinity); Affinity_delete(affinity); @@ -781,21 +808,8 @@ int main(int argc, char** argv) { void* set = pickFromVector(panel, affinityPanel, 15, headerHeight, fuFunctions, defaultBar, header); if (set) { Affinity* affinity = AffinityPanel_getAffinity(affinityPanel); - bool anyTagged = false; - bool ok = true; - for (int i = 0; i < Panel_size(panel); i++) { - Process* p = (Process*) Panel_get(panel, i); - if (p->tag) { - ok = Process_setAffinity(p, affinity) && ok; - anyTagged = true; - } - } - if (!anyTagged) { - Process* p = (Process*) Panel_getSelected(panel); - ok = Process_setAffinity(p, affinity) && ok; - } - if (!ok) - beep(); + bool ok = foreachProcess(panel, (ForeachProcessFn) Process_setAffinity, (size_t) affinity, NULL); + if (!ok) beep(); Affinity_delete(affinity); } Panel_delete((Object*)affinityPanel); @@ -837,6 +851,25 @@ int main(int argc, char** argv) { refreshTimeout = 0; break; } + case 'i': + { + Process* p = (Process*) Panel_getSelected(panel); + if (!p) break; + IOPriority ioprio = p->ioPriority; + Panel* ioprioPanel = IOPriorityPanel_new(ioprio); + const char* fuFunctions[] = {"Set ", "Cancel ", NULL}; + void* set = pickFromVector(panel, ioprioPanel, 21, headerHeight, fuFunctions, defaultBar, header); + if (set) { + IOPriority ioprio = IOPriorityPanel_getIOPriority(ioprioPanel); + bool ok = foreachProcess(panel, (ForeachProcessFn) Process_setIOPriority, (size_t) ioprio, NULL); + if (!ok) + beep(); + } + Panel_delete((Object*)ioprioPanel); + ProcessList_printHeader(pl, Panel_getHeader(panel)); + refreshTimeout = 0; + break; + } case 'I': { refreshTimeout = 0; @@ -873,8 +906,11 @@ int main(int argc, char** argv) { case KEY_F(5): refreshTimeout = 0; pl->treeView = !pl->treeView; + if (pl->treeView) pl->direction = 1; + ProcessList_printHeader(pl, Panel_getHeader(panel)); ProcessList_expandTree(pl); settings->changed = true; + if (following != -1) continue; break; case 'H': doRecalculate = true; @@ -915,5 +951,8 @@ int main(int argc, char** argv) { ((Object*)killPanel)->delete((Object*)killPanel); UsersTable_delete(ut); Settings_delete(settings); + if(pidWhiteList) { + Hashtable_delete(pidWhiteList); + } return 0; } diff --git a/htop.h b/htop.h index 227f36d..8d8ed7e 100644 --- a/htop.h +++ b/htop.h @@ -15,6 +15,8 @@ in the source distribution for its full text. #define COPYRIGHT "(C) 2004-2011 Hisham Muhammad" +typedef bool(*ForeachProcessFn)(Process*, size_t); + typedef struct IncBuffer_; int main(int argc, char** argv); -- cgit v1.2.3