Commit 47e881f4 authored by Hisham Muhammad's avatar Hisham Muhammad
Browse files

Add IO priority support ('i' key)

parent e6c6d7fb
......@@ -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");
#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:");
......
What's new in version 1.0.2
* Add IO priority support ('i' key)
* Avoid deleting .htoprc if it is a symlink
* BUGFIX: Fix crashes when process list is empty
......
/*
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)
}*/
/* 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
/*
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 );
}
/* 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
......@@ -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
......
......@@ -26,6 +26,7 @@ in the source distribution for its full text.
#include <sched.h>
#include <time.h>
#include <assert.h>
#include <sys/syscall.h>
#ifdef HAVE_LIBHWLOC
#include <hwloc/linux.h>
......@@ -41,6 +42,7 @@ in the source distribution for its full text.
/*{
#include "Object.h"
#include "Affinity.h"
#include "IOPriority.h"
#include <sys/types.h>
#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,6 +203,7 @@ const char *Process_fieldNames[] = {
#ifdef HAVE_CGROUP
"CGROUP",
#endif
"IO_PRIORITY",
"*** report bug! ***"
};
......@@ -224,6 +229,7 @@ const char *Process_fieldTitles[] = {
#ifdef HAVE_CGROUP
" CGROUP ",
#endif
"IO ",
"*** report bug! ***"
};
......@@ -507,7 +513,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 +595,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 +679,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 +777,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);
}
......
......@@ -21,6 +21,7 @@ in the source distribution for its full text.
#include "Object.h"
#include "Affinity.h"
#include "IOPriority.h"
#include <sys/types.h>
#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);
......
......@@ -268,7 +268,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);
......@@ -681,6 +681,7 @@ 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;
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;
......
......@@ -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
......
......@@ -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 <unistd.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(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");
......@@ -144,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, " 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]);
......@@ -178,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);
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)
beep();
return anyTagged;
......@@ -764,20 +775,6 @@ int main(int argc, char** argv) {
if (!killPanel) {
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);
const char* fuFunctions[] = {"Send ", "Cancel ", NULL};
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_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);
}
}
} 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);
}
}
......@@ -822,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);
if (p) 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);
......@@ -878,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;
......@@ -914,6 +906,8 @@ 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;
......
......@@ -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);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment