Add IO priority support ('i' key)

This commit is contained in:
Hisham Muhammad 2012-10-04 23:59:45 +00:00
parent e6c6d7fbf7
commit 47e881f460
14 changed files with 285 additions and 72 deletions

View File

@ -50,7 +50,7 @@ Panel* AffinityPanel_new(ProcessList* pl, Affinity* affinity) {
} else { } else {
mode = false; mode = false;
} }
Panel_add(this, (Object*) CheckItem_new(strdup(number), NULL, mode)); Panel_add(this, (Object*) CheckItem_new(strdup(number), NULL, mode));
} }
return this; return this;
} }

2
CRT.c
View File

@ -129,7 +129,7 @@ static void CRT_handleSIGSEGV(int sgn) {
fprintf(stderr, "\n\nhtop " VERSION " aborting. Please report bug at http://htop.sf.net\n"); fprintf(stderr, "\n\nhtop " VERSION " aborting. Please report bug at http://htop.sf.net\n");
#ifdef HAVE_EXECINFO_H #ifdef HAVE_EXECINFO_H
size_t size = backtrace(backtraceArray, sizeof(backtraceArray) / sizeof(void *)); 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); backtrace_symbols_fd(backtraceArray, size, 2);
fprintf(stderr, "\nAdditionally, in order to make the above backtrace useful,"); 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, "\nplease also run the following command to generate a disassembly of your binary:");

View File

@ -1,6 +1,7 @@
What's new in version 1.0.2 What's new in version 1.0.2
* Add IO priority support ('i' key)
* Avoid deleting .htoprc if it is a symlink * Avoid deleting .htoprc if it is a symlink
* BUGFIX: Fix crashes when process list is empty * BUGFIX: Fix crashes when process list is empty

41
IOPriority.c Normal file
View File

@ -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 <jens@axboe.dk>
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)
}*/

43
IOPriority.h Normal file
View File

@ -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 <jens@axboe.dk>
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

43
IOPriorityPanel.c Normal file
View File

@ -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 );
}

20
IOPriorityPanel.h Normal file
View File

@ -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

View File

@ -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 \ DisplayOptionsPanel.c FunctionBar.c Hashtable.c Header.c htop.c ListItem.c \
LoadAverageMeter.c MemoryMeter.c Meter.c MetersPanel.c Object.c Panel.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 \ 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 \ 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 \ myhtopheaders = AvailableColumnsPanel.h AvailableMetersPanel.h \
CategoriesPanel.h CheckItem.h ClockMeter.h ColorsPanel.h ColumnsPanel.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 \ 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 \ BatteryMeter.h Meter.h MetersPanel.h Object.h Panel.h ProcessList.h RichString.h \
ScreenManager.h Settings.h SignalsPanel.h String.h \ ScreenManager.h Settings.h SignalsPanel.h String.h \
SwapMeter.h TasksMeter.h TraceScreen.h UptimeMeter.h UsersTable.h Vector.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 SUFFIXES = .h

View File

@ -26,6 +26,7 @@ in the source distribution for its full text.
#include <sched.h> #include <sched.h>
#include <time.h> #include <time.h>
#include <assert.h> #include <assert.h>
#include <sys/syscall.h>
#ifdef HAVE_LIBHWLOC #ifdef HAVE_LIBHWLOC
#include <hwloc/linux.h> #include <hwloc/linux.h>
@ -41,6 +42,7 @@ in the source distribution for its full text.
/*{ /*{
#include "Object.h" #include "Object.h"
#include "Affinity.h" #include "Affinity.h"
#include "IOPriority.h"
#include <sys/types.h> #include <sys/types.h>
#ifndef Process_isKernelThread #ifndef Process_isKernelThread
@ -73,6 +75,7 @@ typedef enum ProcessField_ {
#ifdef HAVE_CGROUP #ifdef HAVE_CGROUP
CGROUP, CGROUP,
#endif #endif
IO_PRIORITY,
LAST_PROCESSFIELD LAST_PROCESSFIELD
} ProcessField; } ProcessField;
@ -111,6 +114,7 @@ typedef struct Process_ {
long int priority; long int priority;
long int nice; long int nice;
long int nlwp; long int nlwp;
IOPriority ioPriority;
char starttime_show[8]; char starttime_show[8];
time_t starttime_ctime; time_t starttime_ctime;
#ifdef DEBUG #ifdef DEBUG
@ -199,6 +203,7 @@ const char *Process_fieldNames[] = {
#ifdef HAVE_CGROUP #ifdef HAVE_CGROUP
"CGROUP", "CGROUP",
#endif #endif
"IO_PRIORITY",
"*** report bug! ***" "*** report bug! ***"
}; };
@ -224,6 +229,7 @@ const char *Process_fieldTitles[] = {
#ifdef HAVE_CGROUP #ifdef HAVE_CGROUP
" CGROUP ", " CGROUP ",
#endif #endif
"IO ",
"*** report bug! ***" "*** report bug! ***"
}; };
@ -507,7 +513,24 @@ static void Process_writeField(Process* this, RichString* str, ProcessField fiel
#ifdef HAVE_CGROUP #ifdef HAVE_CGROUP
case CGROUP: snprintf(buffer, n, "%-10s ", this->cgroup); break; case CGROUP: snprintf(buffer, n, "%-10s ", this->cgroup); break;
#endif #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: default:
snprintf(buffer, n, "- "); snprintf(buffer, n, "- ");
} }
@ -572,6 +595,31 @@ bool Process_setPriority(Process* this, int priority) {
return (err == 0); 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 #ifdef HAVE_LIBHWLOC
Affinity* Process_getAffinity(Process* this) { Affinity* Process_getAffinity(Process* this) {
@ -631,8 +679,8 @@ bool Process_setAffinity(Process* this, Affinity* affinity) {
#endif #endif
void Process_sendSignal(Process* this, int sgn) { void Process_sendSignal(Process* this, size_t sgn) {
kill(this->pid, sgn); kill(this->pid, (int) sgn);
} }
int Process_pidCompare(const void* v1, const void* v2) { int Process_pidCompare(const void* v1, const void* v2) {
@ -729,7 +777,8 @@ int Process_compare(const void* v1, const void* v2) {
case CGROUP: case CGROUP:
return strcmp(p1->cgroup ? p1->cgroup : "", p2->cgroup ? p2->cgroup : ""); return strcmp(p1->cgroup ? p1->cgroup : "", p2->cgroup ? p2->cgroup : "");
#endif #endif
case IO_PRIORITY:
return Process_effectiveIOPriority(p1) - Process_effectiveIOPriority(p2);
default: default:
return (p1->pid - p2->pid); return (p1->pid - p2->pid);
} }

View File

@ -21,6 +21,7 @@ in the source distribution for its full text.
#include "Object.h" #include "Object.h"
#include "Affinity.h" #include "Affinity.h"
#include "IOPriority.h"
#include <sys/types.h> #include <sys/types.h>
#ifndef Process_isKernelThread #ifndef Process_isKernelThread
@ -53,6 +54,7 @@ typedef enum ProcessField_ {
#ifdef HAVE_CGROUP #ifdef HAVE_CGROUP
CGROUP, CGROUP,
#endif #endif
IO_PRIORITY,
LAST_PROCESSFIELD LAST_PROCESSFIELD
} ProcessField; } ProcessField;
@ -91,6 +93,7 @@ typedef struct Process_ {
long int priority; long int priority;
long int nice; long int nice;
long int nlwp; long int nlwp;
IOPriority ioPriority;
char starttime_show[8]; char starttime_show[8];
time_t starttime_ctime; time_t starttime_ctime;
#ifdef DEBUG #ifdef DEBUG
@ -175,6 +178,22 @@ void Process_toggleTag(Process* this);
bool Process_setPriority(Process* this, int priority); 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 #ifdef HAVE_LIBHWLOC
Affinity* Process_getAffinity(Process* this); Affinity* Process_getAffinity(Process* this);
@ -189,7 +208,7 @@ bool Process_setAffinity(Process* this, Affinity* affinity);
#endif #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); int Process_pidCompare(const void* v1, const void* v2);

View File

@ -268,7 +268,7 @@ void ProcessList_printHeader(ProcessList* this, RichString* header) {
ProcessField* fields = this->fields; ProcessField* fields = this->fields;
for (int i = 0; fields[i]; i++) { for (int i = 0; fields[i]; i++) {
const char* field = Process_fieldTitles[fields[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); RichString_append(header, CRT_colors[PANEL_HIGHLIGHT_FOCUS], field);
else else
RichString_append(header, CRT_colors[PANEL_HEADER_FOCUS], field); RichString_append(header, CRT_colors[PANEL_HEADER_FOCUS], field);
@ -681,6 +681,7 @@ static bool ProcessList_processEntries(ProcessList* this, const char* dirname, P
unsigned long long int lasttimes = (process->utime + process->stime); unsigned long long int lasttimes = (process->utime + process->stime);
if (! ProcessList_readStatFile(process, dirname, name, command)) if (! ProcessList_readStatFile(process, dirname, name, command))
goto errorReadingProcess; goto errorReadingProcess;
Process_updateIOPriority(process);
float percent_cpu = (process->utime + process->stime - lasttimes) / period * 100.0; float percent_cpu = (process->utime + process->stime - lasttimes) / period * 100.0;
process->percent_cpu = MAX(MIN(percent_cpu, cpus*100.0), 0.0); process->percent_cpu = MAX(MIN(percent_cpu, cpus*100.0), 0.0);
if (isnan(process->percent_cpu)) process->percent_cpu = 0.0; if (isnan(process->percent_cpu)) process->percent_cpu = 0.0;

View File

@ -2,7 +2,7 @@
# Process this file with autoconf to produce a configure script. # Process this file with autoconf to produce a configure script.
AC_PREREQ(2.65) 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 # The following two lines are required by hwloc scripts
AC_USE_SYSTEM_EXTENSIONS AC_USE_SYSTEM_EXTENSIONS

112
htop.c
View File

@ -22,6 +22,7 @@ in the source distribution for its full text.
#include "TraceScreen.h" #include "TraceScreen.h"
#include "OpenFilesScreen.h" #include "OpenFilesScreen.h"
#include "AffinityPanel.h" #include "AffinityPanel.h"
#include "IOPriorityPanel.h"
#include <unistd.h> #include <unistd.h>
#include <math.h> #include <math.h>
@ -124,18 +125,18 @@ static void showHelp(ProcessList* pl) {
mvaddstr(12, 0, " F4 \\: incremental name filtering K: hide/show kernel threads"); mvaddstr(12, 0, " F4 \\: incremental name filtering K: hide/show kernel threads");
mvaddstr(13, 0, " Space: tag processes F: cursor follows process"); mvaddstr(13, 0, " Space: tag processes F: cursor follows process");
mvaddstr(14, 0, " U: untag all processes + -: expand/collapse tree"); mvaddstr(14, 0, " U: untag all processes + -: expand/collapse tree");
mvaddstr(15, 0, " F9 k: kill process/tagged processes P: sort by CPU%"); 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) M: sort by MEM%"); mvaddstr(16, 0, " ] F7: higher priority (root only) i: set IO priority");
mvaddstr(17, 0, " [ F8: lower priority (+ nice) T: sort by TIME"); mvaddstr(17, 0, " [ F8: lower priority (+ nice) I: invert sort order");
#if (HAVE_LIBHWLOC || HAVE_NATIVE_AFFINITY) #if (HAVE_LIBHWLOC || HAVE_NATIVE_AFFINITY)
if (pl->cpuCount > 1) 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 else
#endif #endif
mvaddstr(18, 0, " I: invert sort order"); mvaddstr(18, 0, " F6 >: select sort column");
mvaddstr(19, 0, " F2 S: setup 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 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 s: trace syscalls with strace"); mvaddstr(21, 0, " F10 q: quit");
attrset(CRT_colors[HELP_BOLD]); attrset(CRT_colors[HELP_BOLD]);
mvaddstr( 9, 0, " Arrows"); mvaddstr( 9,40, " F5 t"); mvaddstr( 9, 0, " Arrows"); mvaddstr( 9,40, " F5 t");
@ -144,17 +145,17 @@ static void showHelp(ProcessList* pl) {
mvaddstr(12, 0, " F4 \\"); mvaddstr(12,40, " K"); mvaddstr(12, 0, " F4 \\"); mvaddstr(12,40, " K");
mvaddstr(13, 0, " Space"); mvaddstr(13,40, " F"); mvaddstr(13, 0, " Space"); mvaddstr(13,40, " F");
mvaddstr(14, 0, " U"); mvaddstr(14,40, " + -"); mvaddstr(14, 0, " U"); mvaddstr(14,40, " + -");
mvaddstr(15, 0, " F9 k"); mvaddstr(15,40, " P"); mvaddstr(15, 0, " F9 k"); mvaddstr(15,40, "P M T");
mvaddstr(16, 0, " ] F7"); mvaddstr(16,40, " M"); mvaddstr(16, 0, " ] F7"); mvaddstr(16,40, " i");
mvaddstr(17, 0, " [ F8"); mvaddstr(17,40, " T"); mvaddstr(17, 0, " [ F8"); mvaddstr(17,40, " I");
mvaddstr(18,40, " I"); mvaddstr(18,40, " F6 >");
#if (HAVE_LIBHWLOC || HAVE_NATIVE_AFFINITY) #if (HAVE_LIBHWLOC || HAVE_NATIVE_AFFINITY)
if (pl->cpuCount > 1) if (pl->cpuCount > 1)
mvaddstr(18, 0, " a:"); mvaddstr(18, 0, " a:");
#endif #endif
mvaddstr(19, 0, " F2 S"); mvaddstr(19,40, " F6 >"); mvaddstr(19, 0, " F2 S"); mvaddstr(19,40, " l");
mvaddstr(20, 0, " ? F1 h"); mvaddstr(20,40, " l"); mvaddstr(20, 0, " ? F1 h"); mvaddstr(20,40, " s");
mvaddstr(21, 0, " F10 q"); mvaddstr(21,40, " s"); mvaddstr(21, 0, " F10 q");
attrset(CRT_colors[DEFAULT_COLOR]); attrset(CRT_colors[DEFAULT_COLOR]);
attrset(CRT_colors[HELP_BOLD]); attrset(CRT_colors[HELP_BOLD]);
@ -178,20 +179,30 @@ static void Setup_run(Settings* settings, const Header* header) {
ScreenManager_delete(scr); 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 ok = true;
bool anyTagged = false; bool anyTagged = false;
for (int i = 0; i < Panel_size(panel); i++) { for (int i = 0; i < Panel_size(panel); i++) {
Process* p = (Process*) Panel_get(panel, i); Process* p = (Process*) Panel_get(panel, i);
if (p->tag) { if (p->tag) {
ok = Process_setPriority(p, p->nice + delta) && ok; ok = fn(p, arg) && ok;
anyTagged = true; anyTagged = true;
} }
} }
if (!anyTagged) { if (!anyTagged) {
Process* p = (Process*) Panel_getSelected(panel); Process* p = (Process*) Panel_getSelected(panel);
if (p) 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) if (!ok)
beep(); beep();
return anyTagged; return anyTagged;
@ -764,20 +775,6 @@ int main(int argc, char** argv) {
if (!killPanel) { if (!killPanel) {
killPanel = (Panel*) SignalsPanel_new(0, 0, 0, 0); killPanel = (Panel*) SignalsPanel_new(0, 0, 0, 0);
} }
bool anyTagged = false;
pid_t selectedPid = 0;
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);
if (p) selectedPid = p->pid;
if (selectedPid == 0) break;
}
SignalsPanel_reset((SignalsPanel*) killPanel); SignalsPanel_reset((SignalsPanel*) killPanel);
const char* fuFunctions[] = {"Send ", "Cancel ", NULL}; const char* fuFunctions[] = {"Send ", "Cancel ", NULL};
ListItem* sgn = (ListItem*) pickFromVector(panel, killPanel, 15, headerHeight, fuFunctions, defaultBar, header); ListItem* sgn = (ListItem*) pickFromVector(panel, killPanel, 15, headerHeight, fuFunctions, defaultBar, header);
@ -786,18 +783,7 @@ int main(int argc, char** argv) {
Panel_setHeader(panel, "Sending..."); Panel_setHeader(panel, "Sending...");
Panel_draw(panel, true); Panel_draw(panel, true);
refresh(); refresh();
if (anyTagged) { foreachProcess(panel, (ForeachProcessFn) Process_sendSignal, (size_t) sgn->key, NULL);
for (int i = 0; i < Panel_size(panel); i++) {
Process* p = (Process*) Panel_get(panel, i);
if (p->tag) {
Process_sendSignal(p, sgn->key);
}
}
} else {
Process* p = (Process*) Panel_getSelected(panel);
if (p->pid == selectedPid)
Process_sendSignal(p, sgn->key);
}
napms(500); napms(500);
} }
} }
@ -822,21 +808,8 @@ int main(int argc, char** argv) {
void* set = pickFromVector(panel, affinityPanel, 15, headerHeight, fuFunctions, defaultBar, header); void* set = pickFromVector(panel, affinityPanel, 15, headerHeight, fuFunctions, defaultBar, header);
if (set) { if (set) {
Affinity* affinity = AffinityPanel_getAffinity(affinityPanel); Affinity* affinity = AffinityPanel_getAffinity(affinityPanel);
bool anyTagged = false; bool ok = foreachProcess(panel, (ForeachProcessFn) Process_setAffinity, (size_t) affinity, NULL);
bool ok = true; if (!ok) beep();
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);
if (p) ok = Process_setAffinity(p, affinity) && ok;
}
if (!ok)
beep();
Affinity_delete(affinity); Affinity_delete(affinity);
} }
Panel_delete((Object*)affinityPanel); Panel_delete((Object*)affinityPanel);
@ -878,6 +851,25 @@ int main(int argc, char** argv) {
refreshTimeout = 0; refreshTimeout = 0;
break; 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': case 'I':
{ {
refreshTimeout = 0; refreshTimeout = 0;
@ -914,6 +906,8 @@ int main(int argc, char** argv) {
case KEY_F(5): case KEY_F(5):
refreshTimeout = 0; refreshTimeout = 0;
pl->treeView = !pl->treeView; pl->treeView = !pl->treeView;
if (pl->treeView) pl->direction = 1;
ProcessList_printHeader(pl, Panel_getHeader(panel));
ProcessList_expandTree(pl); ProcessList_expandTree(pl);
settings->changed = true; settings->changed = true;
if (following != -1) continue; if (following != -1) continue;

2
htop.h
View File

@ -15,6 +15,8 @@ in the source distribution for its full text.
#define COPYRIGHT "(C) 2004-2011 Hisham Muhammad" #define COPYRIGHT "(C) 2004-2011 Hisham Muhammad"
typedef bool(*ForeachProcessFn)(Process*, size_t);
typedef struct IncBuffer_; typedef struct IncBuffer_;
int main(int argc, char** argv); int main(int argc, char** argv);