"vscode:/vscode.git/clone" did not exist on "bdf68e257ca5aecbfac1bee4a55c64c97a3022f9"
Commit a7c2aedc authored by Hisham Muhammad's avatar Hisham Muhammad
Browse files

Improve construction of tree view, properly nesting threads.

Add CPU affinity screen ('a' key).
BUGFIX: Correct display of TPGID field.
Add TGID field.
parent 46631b59
What's new in version 0.6.7
What's new in version 0.7
* CPU affinity configuration ('a' key)
* Improve display of tree view, properly nesting
threads of the same app based on TGID.
* BUGFIX: Correct display of TPGID field
* Add TGID field
* BUGFIX: Don't crash with invalid command-line flags * BUGFIX: Don't crash with invalid command-line flags
(thanks to Nico Golde for the report) (thanks to Nico Golde for the report)
* Fix GCC 4.3 compilation issues * Fix GCC 4.3 compilation issues
......
...@@ -16,7 +16,8 @@ in the source distribution for its full text. ...@@ -16,7 +16,8 @@ in the source distribution for its full text.
typedef struct CheckItem_ { typedef struct CheckItem_ {
Object super; Object super;
char* text; char* text;
bool* value; bool value;
bool* ref;
} CheckItem; } CheckItem;
}*/ }*/
...@@ -27,13 +28,14 @@ char* CHECKITEM_CLASS = "CheckItem"; ...@@ -27,13 +28,14 @@ char* CHECKITEM_CLASS = "CheckItem";
#define CHECKITEM_CLASS NULL #define CHECKITEM_CLASS NULL
#endif #endif
CheckItem* CheckItem_new(char* text, bool* value) { CheckItem* CheckItem_new(char* text, bool* ref, bool value) {
CheckItem* this = malloc(sizeof(CheckItem)); CheckItem* this = malloc(sizeof(CheckItem));
Object_setClass(this, CHECKITEM_CLASS); Object_setClass(this, CHECKITEM_CLASS);
((Object*)this)->display = CheckItem_display; ((Object*)this)->display = CheckItem_display;
((Object*)this)->delete = CheckItem_delete; ((Object*)this)->delete = CheckItem_delete;
this->text = text; this->text = text;
this->value = value; this->value = value;
this->ref = ref;
return this; return this;
} }
...@@ -45,11 +47,25 @@ void CheckItem_delete(Object* cast) { ...@@ -45,11 +47,25 @@ void CheckItem_delete(Object* cast) {
free(this); free(this);
} }
void CheckItem_set(CheckItem* this, bool value) {
if (this->ref)
*(this->ref) = value;
else
this->value = value;
}
bool CheckItem_get(CheckItem* this) {
if (this->ref)
return *(this->ref);
else
return this->value;
}
void CheckItem_display(Object* cast, RichString* out) { void CheckItem_display(Object* cast, RichString* out) {
CheckItem* this = (CheckItem*)cast; CheckItem* this = (CheckItem*)cast;
assert (this != NULL); assert (this != NULL);
RichString_write(out, CRT_colors[CHECK_BOX], "["); RichString_write(out, CRT_colors[CHECK_BOX], "[");
if (*(this->value)) if (CheckItem_get(this))
RichString_append(out, CRT_colors[CHECK_MARK], "x"); RichString_append(out, CRT_colors[CHECK_MARK], "x");
else else
RichString_append(out, CRT_colors[CHECK_MARK], " "); RichString_append(out, CRT_colors[CHECK_MARK], " ");
......
...@@ -18,7 +18,8 @@ in the source distribution for its full text. ...@@ -18,7 +18,8 @@ in the source distribution for its full text.
typedef struct CheckItem_ { typedef struct CheckItem_ {
Object super; Object super;
char* text; char* text;
bool* value; bool value;
bool* ref;
} CheckItem; } CheckItem;
...@@ -28,10 +29,14 @@ extern char* CHECKITEM_CLASS; ...@@ -28,10 +29,14 @@ extern char* CHECKITEM_CLASS;
#define CHECKITEM_CLASS NULL #define CHECKITEM_CLASS NULL
#endif #endif
CheckItem* CheckItem_new(char* text, bool* value); CheckItem* CheckItem_new(char* text, bool* ref, bool value);
void CheckItem_delete(Object* cast); void CheckItem_delete(Object* cast);
void CheckItem_set(CheckItem* this, bool value);
bool CheckItem_get(CheckItem* this);
void CheckItem_display(Object* cast, RichString* out); void CheckItem_display(Object* cast, RichString* out);
#endif #endif
...@@ -23,7 +23,6 @@ typedef struct ColorsPanel_ { ...@@ -23,7 +23,6 @@ typedef struct ColorsPanel_ {
Settings* settings; Settings* settings;
ScreenManager* scr; ScreenManager* scr;
bool check[5];
} ColorsPanel; } ColorsPanel;
}*/ }*/
...@@ -50,10 +49,9 @@ ColorsPanel* ColorsPanel_new(Settings* settings, ScreenManager* scr) { ...@@ -50,10 +49,9 @@ ColorsPanel* ColorsPanel_new(Settings* settings, ScreenManager* scr) {
Panel_setHeader(super, "Colors"); Panel_setHeader(super, "Colors");
for (int i = 0; ColorSchemes[i] != NULL; i++) { for (int i = 0; ColorSchemes[i] != NULL; i++) {
Panel_add(super, (Object*) CheckItem_new(String_copy(ColorSchemes[i]), &(this->check[i]))); Panel_add(super, (Object*) CheckItem_new(String_copy(ColorSchemes[i]), NULL, false));
this->check[i] = false;
} }
this->check[settings->colorScheme] = true; CheckItem_set((CheckItem*)Panel_get(super, settings->colorScheme), true);
return this; return this;
} }
...@@ -75,10 +73,9 @@ HandlerResult ColorsPanel_EventHandler(Panel* super, int ch) { ...@@ -75,10 +73,9 @@ HandlerResult ColorsPanel_EventHandler(Panel* super, int ch) {
case 0x0d: case 0x0d:
case KEY_ENTER: case KEY_ENTER:
case ' ': case ' ':
for (int i = 0; ColorSchemes[i] != NULL; i++) { for (int i = 0; ColorSchemes[i] != NULL; i++)
this->check[i] = false; CheckItem_set((CheckItem*)Panel_get(super, i), false);
} CheckItem_set((CheckItem*)Panel_get(super, mark), true);
this->check[mark] = true;
this->settings->colorScheme = mark; this->settings->colorScheme = mark;
result = HANDLED; result = HANDLED;
} }
......
...@@ -25,7 +25,6 @@ typedef struct ColorsPanel_ { ...@@ -25,7 +25,6 @@ typedef struct ColorsPanel_ {
Settings* settings; Settings* settings;
ScreenManager* scr; ScreenManager* scr;
bool check[5];
} ColorsPanel; } ColorsPanel;
......
...@@ -28,17 +28,17 @@ DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager* ...@@ -28,17 +28,17 @@ DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager*
this->settings = settings; this->settings = settings;
this->scr = scr; this->scr = scr;
super->eventHandler = DisplayOptionsPanel_EventHandler; super->eventHandler = DisplayOptionsPanel_eventHandler;
Panel_setHeader(super, "Display options"); Panel_setHeader(super, "Display options");
Panel_add(super, (Object*) CheckItem_new(String_copy("Tree view"), &(settings->pl->treeView))); Panel_add(super, (Object*) CheckItem_new(String_copy("Tree view"), &(settings->pl->treeView), false));
Panel_add(super, (Object*) CheckItem_new(String_copy("Shadow other users' processes"), &(settings->pl->shadowOtherUsers))); Panel_add(super, (Object*) CheckItem_new(String_copy("Shadow other users' processes"), &(settings->pl->shadowOtherUsers), false));
Panel_add(super, (Object*) CheckItem_new(String_copy("Hide kernel threads"), &(settings->pl->hideKernelThreads))); Panel_add(super, (Object*) CheckItem_new(String_copy("Hide kernel threads"), &(settings->pl->hideKernelThreads), false));
Panel_add(super, (Object*) CheckItem_new(String_copy("Hide userland threads"), &(settings->pl->hideUserlandThreads))); Panel_add(super, (Object*) CheckItem_new(String_copy("Hide userland threads"), &(settings->pl->hideUserlandThreads), false));
Panel_add(super, (Object*) CheckItem_new(String_copy("Highlight program \"basename\""), &(settings->pl->highlightBaseName))); Panel_add(super, (Object*) CheckItem_new(String_copy("Highlight program \"basename\""), &(settings->pl->highlightBaseName), false));
Panel_add(super, (Object*) CheckItem_new(String_copy("Highlight megabytes in memory counters"), &(settings->pl->highlightMegabytes))); Panel_add(super, (Object*) CheckItem_new(String_copy("Highlight megabytes in memory counters"), &(settings->pl->highlightMegabytes), false));
Panel_add(super, (Object*) CheckItem_new(String_copy("Leave a margin around header"), &(settings->header->margin))); Panel_add(super, (Object*) CheckItem_new(String_copy("Leave a margin around header"), &(settings->header->margin), false));
Panel_add(super, (Object*) CheckItem_new(String_copy("Split System Time into System/IO-Wait/Hard-IRQ/Soft-IRQ"), &(settings->pl->expandSystemTime))); Panel_add(super, (Object*) CheckItem_new(String_copy("Split System Time into System/IO-Wait/Hard-IRQ/Soft-IRQ"), &(settings->pl->expandSystemTime), false));
return this; return this;
} }
...@@ -49,7 +49,7 @@ void DisplayOptionsPanel_delete(Object* object) { ...@@ -49,7 +49,7 @@ void DisplayOptionsPanel_delete(Object* object) {
free(this); free(this);
} }
HandlerResult DisplayOptionsPanel_EventHandler(Panel* super, int ch) { HandlerResult DisplayOptionsPanel_eventHandler(Panel* super, int ch) {
DisplayOptionsPanel* this = (DisplayOptionsPanel*) super; DisplayOptionsPanel* this = (DisplayOptionsPanel*) super;
HandlerResult result = IGNORED; HandlerResult result = IGNORED;
...@@ -60,7 +60,7 @@ HandlerResult DisplayOptionsPanel_EventHandler(Panel* super, int ch) { ...@@ -60,7 +60,7 @@ HandlerResult DisplayOptionsPanel_EventHandler(Panel* super, int ch) {
case 0x0d: case 0x0d:
case KEY_ENTER: case KEY_ENTER:
case ' ': case ' ':
*(selected->value) = ! *(selected->value); CheckItem_set(selected, ! (CheckItem_get(selected)) );
result = HANDLED; result = HANDLED;
} }
......
...@@ -25,7 +25,7 @@ DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager* ...@@ -25,7 +25,7 @@ DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager*
void DisplayOptionsPanel_delete(Object* object); void DisplayOptionsPanel_delete(Object* object);
HandlerResult DisplayOptionsPanel_EventHandler(Panel* super, int ch); HandlerResult DisplayOptionsPanel_eventHandler(Panel* super, int ch);
#endif #endif
...@@ -17,7 +17,7 @@ DisplayOptionsPanel.c FunctionBar.c Hashtable.c Header.c htop.c ListItem.c \ ...@@ -17,7 +17,7 @@ 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 \
Process.c ProcessList.c RichString.c ScreenManager.c Settings.c \ Process.c ProcessList.c RichString.c ScreenManager.c Settings.c \
SignalItem.c SignalsPanel.c String.c SwapMeter.c TasksMeter.c TraceScreen.c \ SignalItem.c SignalsPanel.c String.c SwapMeter.c TasksMeter.c TraceScreen.c \
UptimeMeter.c UsersTable.c Vector.c AvailableColumnsPanel.c UptimeMeter.c UsersTable.c Vector.c AvailableColumnsPanel.c AffinityPanel.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 \
...@@ -26,7 +26,7 @@ Hashtable.h Header.h htop.h ListItem.h LoadAverageMeter.h MemoryMeter.h \ ...@@ -26,7 +26,7 @@ Hashtable.h Header.h htop.h ListItem.h LoadAverageMeter.h MemoryMeter.h \
Meter.h MetersPanel.h Object.h Panel.h ProcessList.h RichString.h \ Meter.h MetersPanel.h Object.h Panel.h ProcessList.h RichString.h \
ScreenManager.h Settings.h SignalItem.h SignalsPanel.h String.h \ ScreenManager.h Settings.h SignalItem.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 Process.h AffinityPanel.h
SUFFIXES = .h SUFFIXES = .h
......
...@@ -25,6 +25,7 @@ in the source distribution for its full text. ...@@ -25,6 +25,7 @@ in the source distribution for its full text.
#include <string.h> #include <string.h>
#include <stdbool.h> #include <stdbool.h>
#include <pwd.h> #include <pwd.h>
#include <sched.h>
// This works only with glibc 2.1+. On earlier versions // This works only with glibc 2.1+. On earlier versions
// the behavior is similar to have a hardcoded page size. // the behavior is similar to have a hardcoded page size.
...@@ -41,7 +42,7 @@ typedef enum ProcessField_ { ...@@ -41,7 +42,7 @@ typedef enum ProcessField_ {
STIME, CUTIME, CSTIME, PRIORITY, NICE, ITREALVALUE, STARTTIME, VSIZE, RSS, RLIM, STARTCODE, ENDCODE, STIME, CUTIME, CSTIME, PRIORITY, NICE, ITREALVALUE, STARTTIME, VSIZE, RSS, RLIM, STARTCODE, ENDCODE,
STARTSTACK, KSTKESP, KSTKEIP, SIGNAL, BLOCKED, SSIGIGNORE, SIGCATCH, WCHAN, NSWAP, CNSWAP, EXIT_SIGNAL, STARTSTACK, KSTKESP, KSTKEIP, SIGNAL, BLOCKED, SSIGIGNORE, SIGCATCH, WCHAN, NSWAP, CNSWAP, EXIT_SIGNAL,
PROCESSOR, M_SIZE, M_RESIDENT, M_SHARE, M_TRS, M_DRS, M_LRS, M_DT, ST_UID, PERCENT_CPU, PERCENT_MEM, PROCESSOR, M_SIZE, M_RESIDENT, M_SHARE, M_TRS, M_DRS, M_LRS, M_DT, ST_UID, PERCENT_CPU, PERCENT_MEM,
USER, TIME, NLWP, USER, TIME, NLWP, TGID
#ifdef HAVE_OPENVZ #ifdef HAVE_OPENVZ
VEID, VPID, VEID, VPID,
#endif #endif
...@@ -65,7 +66,8 @@ typedef struct Process_ { ...@@ -65,7 +66,8 @@ typedef struct Process_ {
unsigned int pgrp; unsigned int pgrp;
unsigned int session; unsigned int session;
unsigned int tty_nr; unsigned int tty_nr;
unsigned int tpgid; unsigned int tgid;
int tpgid;
unsigned long int flags; unsigned long int flags;
#ifdef DEBUG #ifdef DEBUG
unsigned long int minflt; unsigned long int minflt;
...@@ -127,7 +129,7 @@ char* PROCESS_CLASS = "Process"; ...@@ -127,7 +129,7 @@ char* PROCESS_CLASS = "Process";
#endif #endif
char *Process_fieldNames[] = { char *Process_fieldNames[] = {
"", "PID", "Command", "STATE", "PPID", "PGRP", "SESSION", "TTY_NR", "TPGID", "FLAGS", "MINFLT", "CMINFLT", "MAJFLT", "CMAJFLT", "UTIME", "STIME", "CUTIME", "CSTIME", "PRIORITY", "NICE", "ITREALVALUE", "STARTTIME", "VSIZE", "RSS", "RLIM", "STARTCODE", "ENDCODE", "STARTSTACK", "KSTKESP", "KSTKEIP", "SIGNAL", "BLOCKED", "SIGIGNORE", "SIGCATCH", "WCHAN", "NSWAP", "CNSWAP", "EXIT_SIGNAL", "PROCESSOR", "M_SIZE", "M_RESIDENT", "M_SHARE", "M_TRS", "M_DRS", "M_LRS", "M_DT", "ST_UID", "PERCENT_CPU", "PERCENT_MEM", "USER", "TIME", "NLWP", "", "PID", "Command", "STATE", "PPID", "PGRP", "SESSION", "TTY_NR", "TPGID", "FLAGS", "MINFLT", "CMINFLT", "MAJFLT", "CMAJFLT", "UTIME", "STIME", "CUTIME", "CSTIME", "PRIORITY", "NICE", "ITREALVALUE", "STARTTIME", "VSIZE", "RSS", "RLIM", "STARTCODE", "ENDCODE", "STARTSTACK", "KSTKESP", "KSTKEIP", "SIGNAL", "BLOCKED", "SIGIGNORE", "SIGCATCH", "WCHAN", "NSWAP", "CNSWAP", "EXIT_SIGNAL", "PROCESSOR", "M_SIZE", "M_RESIDENT", "M_SHARE", "M_TRS", "M_DRS", "M_LRS", "M_DT", "ST_UID", "PERCENT_CPU", "PERCENT_MEM", "USER", "TIME", "NLWP", "TGID",
#ifdef HAVE_OPENVZ #ifdef HAVE_OPENVZ
"VEID", "VPID", "VEID", "VPID",
#endif #endif
...@@ -193,6 +195,16 @@ void Process_setPriority(Process* this, int priority) { ...@@ -193,6 +195,16 @@ void Process_setPriority(Process* this, int priority) {
} }
} }
unsigned long Process_getAffinity(Process* this) {
unsigned long mask = 0;
sched_getaffinity(this->pid, sizeof(unsigned long), (cpu_set_t*) &mask);
return mask;
}
void Process_setAffinity(Process* this, unsigned long mask) {
sched_setaffinity(this->pid, sizeof(unsigned long), (cpu_set_t*) &mask);
}
void Process_sendSignal(Process* this, int signal) { void Process_sendSignal(Process* this, int signal) {
kill(this->pid, signal); kill(this->pid, signal);
} }
...@@ -281,7 +293,8 @@ void Process_writeField(Process* this, RichString* str, ProcessField field) { ...@@ -281,7 +293,8 @@ void Process_writeField(Process* this, RichString* str, ProcessField field) {
case PGRP: snprintf(buffer, n, "%5u ", this->pgrp); break; case PGRP: snprintf(buffer, n, "%5u ", this->pgrp); break;
case SESSION: snprintf(buffer, n, "%5u ", this->session); break; case SESSION: snprintf(buffer, n, "%5u ", this->session); break;
case TTY_NR: snprintf(buffer, n, "%5u ", this->tty_nr); break; case TTY_NR: snprintf(buffer, n, "%5u ", this->tty_nr); break;
case TPGID: snprintf(buffer, n, "%5u ", this->tpgid); break; case TGID: snprintf(buffer, n, "%5u ", this->tgid); break;
case TPGID: snprintf(buffer, n, "%5d ", this->tpgid); break;
case PROCESSOR: snprintf(buffer, n, "%3d ", this->processor+1); break; case PROCESSOR: snprintf(buffer, n, "%3d ", this->processor+1); break;
case NLWP: snprintf(buffer, n, "%4ld ", this->nlwp); break; case NLWP: snprintf(buffer, n, "%4ld ", this->nlwp); break;
case COMM: { case COMM: {
...@@ -462,7 +475,8 @@ char* Process_printField(ProcessField field) { ...@@ -462,7 +475,8 @@ char* Process_printField(ProcessField field) {
case PGRP: return " PGRP "; case PGRP: return " PGRP ";
case SESSION: return " SESN "; case SESSION: return " SESN ";
case TTY_NR: return " TTY "; case TTY_NR: return " TTY ";
case TPGID: return " TGID "; case TGID: return " TGID ";
case TPGID: return "TPGID ";
case COMM: return "Command "; case COMM: return "Command ";
case STATE: return "S "; case STATE: return "S ";
case PRIORITY: return "PRI "; case PRIORITY: return "PRI ";
......
...@@ -28,6 +28,7 @@ in the source distribution for its full text. ...@@ -28,6 +28,7 @@ in the source distribution for its full text.
#include <string.h> #include <string.h>
#include <stdbool.h> #include <stdbool.h>
#include <pwd.h> #include <pwd.h>
#include <sched.h>
// This works only with glibc 2.1+. On earlier versions // This works only with glibc 2.1+. On earlier versions
// the behavior is similar to have a hardcoded page size. // the behavior is similar to have a hardcoded page size.
...@@ -43,7 +44,7 @@ typedef enum ProcessField_ { ...@@ -43,7 +44,7 @@ typedef enum ProcessField_ {
STIME, CUTIME, CSTIME, PRIORITY, NICE, ITREALVALUE, STARTTIME, VSIZE, RSS, RLIM, STARTCODE, ENDCODE, STIME, CUTIME, CSTIME, PRIORITY, NICE, ITREALVALUE, STARTTIME, VSIZE, RSS, RLIM, STARTCODE, ENDCODE,
STARTSTACK, KSTKESP, KSTKEIP, SIGNAL, BLOCKED, SSIGIGNORE, SIGCATCH, WCHAN, NSWAP, CNSWAP, EXIT_SIGNAL, STARTSTACK, KSTKESP, KSTKEIP, SIGNAL, BLOCKED, SSIGIGNORE, SIGCATCH, WCHAN, NSWAP, CNSWAP, EXIT_SIGNAL,
PROCESSOR, M_SIZE, M_RESIDENT, M_SHARE, M_TRS, M_DRS, M_LRS, M_DT, ST_UID, PERCENT_CPU, PERCENT_MEM, PROCESSOR, M_SIZE, M_RESIDENT, M_SHARE, M_TRS, M_DRS, M_LRS, M_DT, ST_UID, PERCENT_CPU, PERCENT_MEM,
USER, TIME, NLWP, USER, TIME, NLWP, TGID,
#ifdef HAVE_OPENVZ #ifdef HAVE_OPENVZ
VEID, VPID, VEID, VPID,
#endif #endif
...@@ -67,7 +68,8 @@ typedef struct Process_ { ...@@ -67,7 +68,8 @@ typedef struct Process_ {
unsigned int pgrp; unsigned int pgrp;
unsigned int session; unsigned int session;
unsigned int tty_nr; unsigned int tty_nr;
unsigned int tpgid; unsigned int tgid;
int tpgid;
unsigned long int flags; unsigned long int flags;
#ifdef DEBUG #ifdef DEBUG
unsigned long int minflt; unsigned long int minflt;
...@@ -141,6 +143,10 @@ void Process_toggleTag(Process* this); ...@@ -141,6 +143,10 @@ void Process_toggleTag(Process* this);
void Process_setPriority(Process* this, int priority); void Process_setPriority(Process* this, int priority);
unsigned long Process_getAffinity(Process* this);
void Process_setAffinity(Process* this, unsigned long mask);
void Process_sendSignal(Process* this, int signal); void Process_sendSignal(Process* this, int signal);
#define ONE_K 1024 #define ONE_K 1024
......
...@@ -333,7 +333,7 @@ static void ProcessList_buildTree(ProcessList* this, int pid, int level, int ind ...@@ -333,7 +333,7 @@ static void ProcessList_buildTree(ProcessList* this, int pid, int level, int ind
for (int i = Vector_size(this->processes) - 1; i >= 0; i--) { for (int i = Vector_size(this->processes) - 1; i >= 0; i--) {
Process* process = (Process*) (Vector_get(this->processes, i)); Process* process = (Process*) (Vector_get(this->processes, i));
if (process->ppid == pid) { if (process->tgid == pid || (process->tgid == process->pid && process->ppid == pid)) {
Process* process = (Process*) (Vector_take(this->processes, i)); Process* process = (Process*) (Vector_take(this->processes, i));
Vector_add(children, process); Vector_add(children, process);
} }
...@@ -360,26 +360,34 @@ void ProcessList_sort(ProcessList* this) { ...@@ -360,26 +360,34 @@ void ProcessList_sort(ProcessList* this) {
if (!this->treeView) { if (!this->treeView) {
Vector_sort(this->processes); Vector_sort(this->processes);
} else { } else {
// Save settings
int direction = this->direction; int direction = this->direction;
int sortKey = this->sortKey; int sortKey = this->sortKey;
// Sort by PID
this->sortKey = PID; this->sortKey = PID;
this->direction = 1; this->direction = 1;
Vector_sort(this->processes); Vector_sort(this->processes);
// Restore settings
this->sortKey = sortKey; this->sortKey = sortKey;
this->direction = direction; this->direction = direction;
// Take PID 1 as root and add to the new listing
int vsize = Vector_size(this->processes); int vsize = Vector_size(this->processes);
Process* init = (Process*) (Vector_take(this->processes, 0)); Process* init = (Process*) (Vector_take(this->processes, 0));
assert(init->pid == 1); assert(init->pid == 1);
init->indent = 0; init->indent = 0;
Vector_add(this->processes2, init); Vector_add(this->processes2, init);
// Recursively empty list
ProcessList_buildTree(this, init->pid, 0, 0, direction); ProcessList_buildTree(this, init->pid, 0, 0, direction);
// Add leftovers
while (Vector_size(this->processes)) { while (Vector_size(this->processes)) {
Process* p = (Process*) (Vector_take(this->processes, 0)); Process* p = (Process*) (Vector_take(this->processes, 0));
p->indent = 0; p->indent = 0;
Vector_add(this->processes2, p); Vector_add(this->processes2, p);
ProcessList_buildTree(this, p->pid, 0, 0, direction);
} }
assert(Vector_size(this->processes2) == vsize); (void)vsize; assert(Vector_size(this->processes2) == vsize); (void)vsize;
assert(Vector_size(this->processes) == 0); assert(Vector_size(this->processes) == 0);
// Swap listings around
Vector* t = this->processes; Vector* t = this->processes;
this->processes = this->processes2; this->processes = this->processes2;
this->processes2 = t; this->processes2 = t;
...@@ -408,7 +416,7 @@ static int ProcessList_readStatFile(ProcessList* this, Process *proc, FILE *f, c ...@@ -408,7 +416,7 @@ static int ProcessList_readStatFile(ProcessList* this, Process *proc, FILE *f, c
#ifdef DEBUG_PROC #ifdef DEBUG_PROC
int num = ProcessList_read(this, location, int num = ProcessList_read(this, location,
"%c %u %u %u %u %u %lu %lu %lu %lu " "%c %u %u %u %u %d %lu %lu %lu %lu "
"%lu %lu %lu %ld %ld %ld %ld %ld %ld " "%lu %lu %lu %ld %ld %ld %ld %ld %ld "
"%lu %lu %ld %lu %lu %lu %lu %lu " "%lu %lu %ld %lu %lu %lu %lu %lu "
"%lu %lu %lu %lu %lu %lu %lu %lu " "%lu %lu %lu %lu %lu %lu %lu %lu "
...@@ -426,7 +434,7 @@ static int ProcessList_readStatFile(ProcessList* this, Process *proc, FILE *f, c ...@@ -426,7 +434,7 @@ static int ProcessList_readStatFile(ProcessList* this, Process *proc, FILE *f, c
#else #else
long int uzero; long int uzero;
int num = ProcessList_read(this, location, int num = ProcessList_read(this, location,
"%c %u %u %u %u %u %lu %lu %lu %lu " "%c %u %u %u %u %d %lu %lu %lu %lu "
"%lu %lu %lu %ld %ld %ld %ld %ld %ld " "%lu %lu %lu %ld %ld %ld %ld %ld %ld "
"%lu %lu %ld %lu %lu %lu %lu %lu " "%lu %lu %ld %lu %lu %lu %lu %lu "
"%lu %lu %lu %lu %lu %lu %lu %lu " "%lu %lu %lu %lu %lu %lu %lu %lu "
...@@ -454,10 +462,12 @@ static int ProcessList_readStatFile(ProcessList* this, Process *proc, FILE *f, c ...@@ -454,10 +462,12 @@ static int ProcessList_readStatFile(ProcessList* this, Process *proc, FILE *f, c
bool ProcessList_readStatusFile(ProcessList* this, Process* proc, char* dirname, char* name) { bool ProcessList_readStatusFile(ProcessList* this, Process* proc, char* dirname, char* name) {
char statusfilename[MAX_NAME+1]; char statusfilename[MAX_NAME+1];
statusfilename[MAX_NAME] = '\0'; statusfilename[MAX_NAME] = '\0';
/*
bool success = false; bool success = false;
char buffer[256]; char buffer[256];
buffer[255] = '\0'; buffer[255] = '\0';
// We need to parse the status file just for tgid, which is missing in stat.
snprintf(statusfilename, MAX_NAME, "%s/%s/status", dirname, name); snprintf(statusfilename, MAX_NAME, "%s/%s/status", dirname, name);
FILE* status = ProcessList_fopen(this, statusfilename, "r"); FILE* status = ProcessList_fopen(this, statusfilename, "r");
if (status) { if (status) {
...@@ -465,12 +475,11 @@ bool ProcessList_readStatusFile(ProcessList* this, Process* proc, char* dirname, ...@@ -465,12 +475,11 @@ bool ProcessList_readStatusFile(ProcessList* this, Process* proc, char* dirname,
char* ok = fgets(buffer, 255, status); char* ok = fgets(buffer, 255, status);
if (!ok) if (!ok)
break; break;
if (String_startsWith(buffer, "Uid:")) { if (String_startsWith(buffer, "Tgid:")) {
int uid1, uid2, uid3, uid4; int tgid;
// TODO: handle other uid's. int ok = ProcessList_read(this, buffer, "Tgid:\t%d", &tgid);
int ok = ProcessList_read(this, buffer, "Uid:\t%d\t%d\t%d\t%d", &uid1, &uid2, &uid3, &uid4);
if (ok >= 1) { if (ok >= 1) {
proc->st_uid = uid1; proc->tgid = tgid;
success = true; success = true;
} }
break; break;
...@@ -478,8 +487,6 @@ bool ProcessList_readStatusFile(ProcessList* this, Process* proc, char* dirname, ...@@ -478,8 +487,6 @@ bool ProcessList_readStatusFile(ProcessList* this, Process* proc, char* dirname,
} }
fclose(status); fclose(status);
} }
if (!success) {
*/
snprintf(statusfilename, MAX_NAME, "%s/%s", dirname, name); snprintf(statusfilename, MAX_NAME, "%s/%s", dirname, name);
struct stat sstat; struct stat sstat;
int statok = stat(statusfilename, &sstat); int statok = stat(statusfilename, &sstat);
...@@ -487,10 +494,6 @@ bool ProcessList_readStatusFile(ProcessList* this, Process* proc, char* dirname, ...@@ -487,10 +494,6 @@ bool ProcessList_readStatusFile(ProcessList* this, Process* proc, char* dirname,
return false; return false;
proc->st_uid = sstat.st_uid; proc->st_uid = sstat.st_uid;
return true; return true;
/*
} else
return true;
*/
} }
void ProcessList_processEntries(ProcessList* this, char* dirname, int parent, float period) { void ProcessList_processEntries(ProcessList* this, char* dirname, int parent, float period) {
...@@ -521,10 +524,8 @@ void ProcessList_processEntries(ProcessList* this, char* dirname, int parent, fl ...@@ -521,10 +524,8 @@ void ProcessList_processEntries(ProcessList* this, char* dirname, int parent, fl
char subdirname[MAX_NAME+1]; char subdirname[MAX_NAME+1];
snprintf(subdirname, MAX_NAME, "%s/%s/task", dirname, name); snprintf(subdirname, MAX_NAME, "%s/%s/task", dirname, name);
if (access(subdirname, X_OK) == 0) {
ProcessList_processEntries(this, subdirname, pid, period); ProcessList_processEntries(this, subdirname, pid, period);
} }
}
FILE* status; FILE* status;
char statusfilename[MAX_NAME+1]; char statusfilename[MAX_NAME+1];
......
...@@ -27,7 +27,7 @@ SignalsPanel* SignalsPanel_new(int x, int y, int w, int h) { ...@@ -27,7 +27,7 @@ SignalsPanel* SignalsPanel_new(int x, int y, int w, int h) {
((Object*)this)->delete = SignalsPanel_delete; ((Object*)this)->delete = SignalsPanel_delete;
this->signals = Signal_getSignalTable(); this->signals = Signal_getSignalTable();
super->eventHandler = SignalsPanel_EventHandler; super->eventHandler = SignalsPanel_eventHandler;
int sigCount = Signal_getSignalCount(); int sigCount = Signal_getSignalCount();
for(int i = 0; i < sigCount; i++) for(int i = 0; i < sigCount; i++)
Panel_set(super, i, (Object*) this->signals[i]); Panel_set(super, i, (Object*) this->signals[i]);
...@@ -51,7 +51,7 @@ void SignalsPanel_reset(SignalsPanel* this) { ...@@ -51,7 +51,7 @@ void SignalsPanel_reset(SignalsPanel* this) {
this->state = 0; this->state = 0;
} }
HandlerResult SignalsPanel_EventHandler(Panel* super, int ch) { HandlerResult SignalsPanel_eventHandler(Panel* super, int ch) {
SignalsPanel* this = (SignalsPanel*) super; SignalsPanel* this = (SignalsPanel*) super;
int size = Panel_getSize(super); int size = Panel_getSize(super);
......
...@@ -27,6 +27,6 @@ void SignalsPanel_delete(Object* object); ...@@ -27,6 +27,6 @@ void SignalsPanel_delete(Object* object);
void SignalsPanel_reset(SignalsPanel* this); void SignalsPanel_reset(SignalsPanel* this);
HandlerResult SignalsPanel_EventHandler(Panel* super, int ch); HandlerResult SignalsPanel_eventHandler(Panel* super, int ch);
#endif #endif
...@@ -77,6 +77,9 @@ If none is tagged, sends to the currently selected process. ...@@ -77,6 +77,9 @@ If none is tagged, sends to the currently selected process.
.B F10, q .B F10, q
Quit Quit
.TP .TP
.B a (on multiprocessor machines)
Set CPU affinity: mark which CPUs a process is allowed to use.
.TP
.B u .B u
Show only processes owned by a specified user. Show only processes owned by a specified user.
.TP .TP
......
...@@ -25,6 +25,7 @@ in the source distribution for its full text. ...@@ -25,6 +25,7 @@ in the source distribution for its full text.
#include "CategoriesPanel.h" #include "CategoriesPanel.h"
#include "SignalsPanel.h" #include "SignalsPanel.h"
#include "TraceScreen.h" #include "TraceScreen.h"
#include "AffinityPanel.h"
#include "config.h" #include "config.h"
#include "debug.h" #include "debug.h"
...@@ -104,6 +105,9 @@ void showHelp(ProcessList* pl) { ...@@ -104,6 +105,9 @@ void showHelp(ProcessList* pl) {
mvaddstr(15, 0, " F9 k: kill process/tagged processes P: sort by CPU%"); mvaddstr(15, 0, " F9 k: kill process/tagged processes P: sort by CPU%");
mvaddstr(16, 0, " + [ F7: lower priority (+ nice) M: sort by MEM%"); mvaddstr(16, 0, " + [ F7: lower priority (+ nice) M: sort by MEM%");
mvaddstr(17, 0, " - ] F8: higher priority (root only) T: sort by TIME"); mvaddstr(17, 0, " - ] F8: higher priority (root only) T: sort by TIME");
if (pl->processorCount > 1)
mvaddstr(18, 0, " a: set CPU affinity F4 I: invert sort order");
else
mvaddstr(18, 0, " F4 I: invert sort order"); mvaddstr(18, 0, " F4 I: invert sort order");
mvaddstr(19, 0, " F2 S: setup F6 >: select sort column"); mvaddstr(19, 0, " F2 S: setup F6 >: select sort column");
mvaddstr(20, 0, " F1 h: show this help screen"); mvaddstr(20, 0, " F1 h: show this help screen");
...@@ -120,6 +124,8 @@ void showHelp(ProcessList* pl) { ...@@ -120,6 +124,8 @@ void showHelp(ProcessList* pl) {
mvaddstr(16, 0, " + [ F7"); mvaddstr(16,40, " M"); mvaddstr(16, 0, " + [ F7"); mvaddstr(16,40, " M");
mvaddstr(17, 0, " - ] F8"); mvaddstr(17,40, " T"); mvaddstr(17, 0, " - ] F8"); mvaddstr(17,40, " T");
mvaddstr(18,40, " F4 I"); mvaddstr(18,40, " F4 I");
if (pl->processorCount > 1)
mvaddstr(18, 0, " a:");
mvaddstr(19, 0, " F2 S"); mvaddstr(19,40, " F6 >"); mvaddstr(19, 0, " F2 S"); mvaddstr(19,40, " F6 >");
mvaddstr(20, 0, " F1 h"); mvaddstr(20, 0, " F1 h");
mvaddstr(21, 0, " F10 q"); mvaddstr(21,40, " s"); mvaddstr(21, 0, " F10 q"); mvaddstr(21,40, " s");
...@@ -169,7 +175,7 @@ static HandlerResult pickWithEnter(Panel* panel, int ch) { ...@@ -169,7 +175,7 @@ static HandlerResult pickWithEnter(Panel* panel, int ch) {
static Object* pickFromList(Panel* panel, Panel* list, int x, int y, char** keyLabels, FunctionBar* prevBar) { static Object* pickFromList(Panel* panel, Panel* list, int x, int y, char** keyLabels, FunctionBar* prevBar) {
char* fuKeys[2] = {"Enter", "Esc"}; char* fuKeys[2] = {"Enter", "Esc"};
int fuEvents[2] = {13, 27}; int fuEvents[2] = {13, 27};
if (!panel->eventHandler) if (!list->eventHandler)
Panel_setEventHandler(list, pickWithEnter); Panel_setEventHandler(list, pickWithEnter);
ScreenManager* scr = ScreenManager_new(0, y, 0, -1, HORIZONTAL, false); ScreenManager* scr = ScreenManager_new(0, y, 0, -1, HORIZONTAL, false);
ScreenManager_add(scr, list, FunctionBar_new(2, keyLabels, fuKeys, fuEvents), x - 1); ScreenManager_add(scr, list, FunctionBar_new(2, keyLabels, fuKeys, fuEvents), x - 1);
...@@ -592,6 +598,36 @@ int main(int argc, char** argv) { ...@@ -592,6 +598,36 @@ int main(int argc, char** argv) {
refreshTimeout = 0; refreshTimeout = 0;
break; break;
} }
case 'a':
{
if (pl->processorCount == 1)
break;
Process* p = (Process*) Panel_getSelected(panel);
unsigned long curr = Process_getAffinity(p);
Panel* affinityPanel = AffinityPanel_new(pl->processorCount, curr);
char* fuFunctions[2] = {"Toggle ", "Done "};
pickFromList(panel, affinityPanel, 15, headerHeight, fuFunctions, defaultBar);
unsigned long new = AffinityPanel_getAffinity(affinityPanel);
bool anyTagged = false;
for (int i = 0; i < Panel_getSize(panel); i++) {
Process* p = (Process*) Panel_get(panel, i);
if (p->tag) {
Process_setAffinity(p, new);
anyTagged = true;
}
}
if (!anyTagged) {
Process* p = (Process*) Panel_getSelected(panel);
Process_setAffinity(p, new);
}
((Object*)affinityPanel)->delete((Object*)affinityPanel);
Panel_setRichHeader(panel, ProcessList_printHeader(pl));
refreshTimeout = 0;
break;
}
case KEY_F(10): case KEY_F(10):
case 'q': case 'q':
quit = 1; quit = 1;
......
...@@ -29,6 +29,7 @@ in the source distribution for its full text. ...@@ -29,6 +29,7 @@ in the source distribution for its full text.
#include "CategoriesPanel.h" #include "CategoriesPanel.h"
#include "SignalsPanel.h" #include "SignalsPanel.h"
#include "TraceScreen.h" #include "TraceScreen.h"
#include "AffinityPanel.h"
#include "config.h" #include "config.h"
#include "debug.h" #include "debug.h"
......
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