blob: 74c3302a7872a16d9b8f4b51af0976d1876a456b [file] [log] [blame]
Hisham Muhammadd6231ba2006-03-04 18:16:49 +00001/*
2htop - ProcessList.c
3(C) 2004,2005 Hisham H. Muhammad
4Released under the GNU GPL, see the COPYING file
5in the source distribution for its full text.
6*/
7
Hisham Muhammadd6231ba2006-03-04 18:16:49 +00008#include "ProcessList.h"
Hisham Muhammadd6231ba2006-03-04 18:16:49 +00009
Hisham Muhammad84281bd2011-12-26 21:35:57 +000010#include "CRT.h"
11#include "String.h"
Hisham Muhammad84281bd2011-12-26 21:35:57 +000012
Hisham Muhammadd6231ba2006-03-04 18:16:49 +000013#include <stdlib.h>
Hisham Muhammad84281bd2011-12-26 21:35:57 +000014#include <string.h>
Hisham Muhammadd6231ba2006-03-04 18:16:49 +000015
16/*{
Hisham Muhammad84281bd2011-12-26 21:35:57 +000017#include "Vector.h"
18#include "Hashtable.h"
19#include "UsersTable.h"
20#include "Panel.h"
21#include "Process.h"
Hisham Muhammad3383d8e2015-01-21 23:27:31 -020022#include "Settings.h"
Hisham Muhammad64862292010-08-24 23:20:38 +000023
Hisham Muhammadd6231ba2006-03-04 18:16:49 +000024#ifndef MAX_NAME
Hisham Muhammad86d63132006-03-24 03:39:04 +000025#define MAX_NAME 128
26#endif
27
28#ifndef MAX_READ
Hisham Muhammad5d48ab82006-07-11 06:13:32 +000029#define MAX_READ 2048
Hisham Muhammadd6231ba2006-03-04 18:16:49 +000030#endif
31
Hisham Muhammadd6231ba2006-03-04 18:16:49 +000032typedef struct ProcessList_ {
Hisham Muhammad3383d8e2015-01-21 23:27:31 -020033 Settings* settings;
34
Hisham Muhammada853faa2006-05-30 13:45:40 +000035 Vector* processes;
36 Vector* processes2;
Hisham Muhammadd6231ba2006-03-04 18:16:49 +000037 Hashtable* processTable;
Hisham Muhammadd6231ba2006-03-04 18:16:49 +000038 UsersTable* usersTable;
39
Hisham Muhammadbfd86a62011-12-01 12:31:57 +000040 Panel* panel;
Hisham Muhammad1a604a02012-02-02 23:45:40 +000041 int following;
Hisham Muhammadbfd86a62011-12-01 12:31:57 +000042 uid_t userId;
Hisham Muhammadbfd86a62011-12-01 12:31:57 +000043 const char* incFilter;
Hisham Muhammade6c6d7f2012-08-10 21:54:41 +000044 Hashtable* pidWhiteList;
Hisham Muhammadbfd86a62011-12-01 12:31:57 +000045
Hisham Muhammadbc87a8f2011-11-21 02:52:41 +000046 #ifdef HAVE_LIBHWLOC
Hisham Muhammadec17b702011-09-24 00:30:47 +000047 hwloc_topology_t topology;
48 bool topologyOk;
49 #endif
Hisham Muhammadd6231ba2006-03-04 18:16:49 +000050
Hisham Muhammad3383d8e2015-01-21 23:27:31 -020051 int cpuCount;
Hisham Muhammadd6231ba2006-03-04 18:16:49 +000052
53} ProcessList;
Hisham Muhammadca6b9232011-11-03 22:12:12 +000054
Hisham Muhammad3383d8e2015-01-21 23:27:31 -020055ProcessList* ProcessList_new(UsersTable* ut, Hashtable* pidWhiteList, uid_t userId);
Hisham Muhammadcda6bdd2014-11-27 17:48:38 -020056void ProcessList_delete(ProcessList* pl);
Hisham Muhammadeb229d92014-11-24 18:55:03 -020057void ProcessList_scan(ProcessList* pl);
58
Hisham Muhammadd6231ba2006-03-04 18:16:49 +000059}*/
60
Hisham Muhammad3383d8e2015-01-21 23:27:31 -020061ProcessList* ProcessList_init(ProcessList* this, UsersTable* usersTable, Hashtable* pidWhiteList, uid_t userId) {
Hisham Muhammad00b324b2012-12-05 15:12:20 +000062 this->processes = Vector_new(Class(Process), true, DEFAULT_SIZE);
Hisham Muhammad7ca10812011-11-18 06:08:56 +000063 this->processTable = Hashtable_new(140, false);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +000064 this->usersTable = usersTable;
Hisham Muhammade6c6d7f2012-08-10 21:54:41 +000065 this->pidWhiteList = pidWhiteList;
Hisham Muhammad3383d8e2015-01-21 23:27:31 -020066 this->userId = userId;
Hisham Muhammadd6231ba2006-03-04 18:16:49 +000067
Hisham Muhammadeb229d92014-11-24 18:55:03 -020068 // tree-view auxiliary buffers
Hisham Muhammad00b324b2012-12-05 15:12:20 +000069 this->processes2 = Vector_new(Class(Process), true, DEFAULT_SIZE);
Hisham Muhammad86d63132006-03-24 03:39:04 +000070
Hisham Muhammadeb229d92014-11-24 18:55:03 -020071 // set later by platform-specific code
72 this->cpuCount = 0;
Hisham Muhammadec17b702011-09-24 00:30:47 +000073
Hisham Muhammadbc87a8f2011-11-21 02:52:41 +000074#ifdef HAVE_LIBHWLOC
Hisham Muhammadec17b702011-09-24 00:30:47 +000075 this->topologyOk = false;
76 int topoErr = hwloc_topology_init(&this->topology);
77 if (topoErr == 0) {
78 topoErr = hwloc_topology_load(this->topology);
Hisham Muhammad3fbd1ef2014-04-21 19:17:46 -030079 }
80 if (topoErr == 0) {
Hisham Muhammadec17b702011-09-24 00:30:47 +000081 this->topologyOk = true;
82 }
83#endif
Hisham Muhammadd6231ba2006-03-04 18:16:49 +000084
Hisham Muhammad05a78c82012-03-30 01:20:32 +000085 this->following = -1;
Hisham Muhammadd6231ba2006-03-04 18:16:49 +000086
87 return this;
88}
89
Hisham Muhammadcda6bdd2014-11-27 17:48:38 -020090void ProcessList_done(ProcessList* this) {
Hisham Muhammadd6231ba2006-03-04 18:16:49 +000091 Hashtable_delete(this->processTable);
Hisham Muhammada853faa2006-05-30 13:45:40 +000092 Vector_delete(this->processes);
93 Vector_delete(this->processes2);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +000094}
95
Hisham Muhammadbfd86a62011-12-01 12:31:57 +000096void ProcessList_setPanel(ProcessList* this, Panel* panel) {
97 this->panel = panel;
98}
99
Hisham Muhammadd8e14802010-11-22 12:40:20 +0000100void ProcessList_printHeader(ProcessList* this, RichString* header) {
101 RichString_prune(header);
Hisham Muhammad3383d8e2015-01-21 23:27:31 -0200102 ProcessField* fields = this->settings->fields;
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000103 for (int i = 0; fields[i]; i++) {
Hisham Muhammad3383d8e2015-01-21 23:27:31 -0200104 const char* field = Process_fields[fields[i]].title;
105 if (!field) field = "- ";
106 if (!this->settings->treeView && this->settings->sortKey == fields[i])
Hisham Muhammadd8e14802010-11-22 12:40:20 +0000107 RichString_append(header, CRT_colors[PANEL_HIGHLIGHT_FOCUS], field);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000108 else
Hisham Muhammadd8e14802010-11-22 12:40:20 +0000109 RichString_append(header, CRT_colors[PANEL_HEADER_FOCUS], field);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000110 }
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000111}
112
Hisham Muhammadeb229d92014-11-24 18:55:03 -0200113void ProcessList_add(ProcessList* this, Process* p) {
Hisham Muhammadfebe2592006-11-08 20:12:57 +0000114 assert(Vector_indexOf(this->processes, p, Process_pidCompare) == -1);
115 assert(Hashtable_get(this->processTable, p->pid) == NULL);
Hisham Muhammad64862292010-08-24 23:20:38 +0000116
Hisham Muhammada853faa2006-05-30 13:45:40 +0000117 Vector_add(this->processes, p);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000118 Hashtable_put(this->processTable, p->pid, p);
Hisham Muhammad64862292010-08-24 23:20:38 +0000119
Hisham Muhammadfebe2592006-11-08 20:12:57 +0000120 assert(Vector_indexOf(this->processes, p, Process_pidCompare) != -1);
121 assert(Hashtable_get(this->processTable, p->pid) != NULL);
Hisham Muhammad3d62edb2006-11-12 21:53:56 +0000122 assert(Hashtable_count(this->processTable) == Vector_count(this->processes));
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000123}
124
Hisham Muhammadeb229d92014-11-24 18:55:03 -0200125void ProcessList_remove(ProcessList* this, Process* p) {
Hisham Muhammadfebe2592006-11-08 20:12:57 +0000126 assert(Vector_indexOf(this->processes, p, Process_pidCompare) != -1);
127 assert(Hashtable_get(this->processTable, p->pid) != NULL);
128 Process* pp = Hashtable_remove(this->processTable, p->pid);
Hisham Muhammad8adc7ac2006-11-08 21:49:52 +0000129 assert(pp == p); (void)pp;
Hisham Muhammada227b202007-04-05 19:53:23 +0000130 unsigned int pid = p->pid;
Hisham Muhammad8f230922010-02-25 01:37:31 +0000131 int idx = Vector_indexOf(this->processes, p, Process_pidCompare);
132 assert(idx != -1);
133 if (idx >= 0) Vector_remove(this->processes, idx);
Hisham Muhammad8adc7ac2006-11-08 21:49:52 +0000134 assert(Hashtable_get(this->processTable, pid) == NULL); (void)pid;
Hisham Muhammad3d62edb2006-11-12 21:53:56 +0000135 assert(Hashtable_count(this->processTable) == Vector_count(this->processes));
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000136}
137
Hisham Muhammad8f230922010-02-25 01:37:31 +0000138Process* ProcessList_get(ProcessList* this, int idx) {
139 return (Process*) (Vector_get(this->processes, idx));
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000140}
141
142int ProcessList_size(ProcessList* this) {
Hisham Muhammada853faa2006-05-30 13:45:40 +0000143 return (Vector_size(this->processes));
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000144}
145
Hisham Muhammad9eb91212010-06-17 19:02:03 +0000146static void ProcessList_buildTree(ProcessList* this, pid_t pid, int level, int indent, int direction, bool show) {
Hisham Muhammad00b324b2012-12-05 15:12:20 +0000147 Vector* children = Vector_new(Class(Process), false, DEFAULT_SIZE);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000148
Hisham Muhammadfebe2592006-11-08 20:12:57 +0000149 for (int i = Vector_size(this->processes) - 1; i >= 0; i--) {
Hisham Muhammada853faa2006-05-30 13:45:40 +0000150 Process* process = (Process*) (Vector_get(this->processes, i));
Hisham Muhammada7c2aed2007-11-08 23:23:01 +0000151 if (process->tgid == pid || (process->tgid == process->pid && process->ppid == pid)) {
Hisham Muhammad8f230922010-02-25 01:37:31 +0000152 process = (Process*) (Vector_take(this->processes, i));
Hisham Muhammada853faa2006-05-30 13:45:40 +0000153 Vector_add(children, process);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000154 }
155 }
Hisham Muhammada853faa2006-05-30 13:45:40 +0000156 int size = Vector_size(children);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000157 for (int i = 0; i < size; i++) {
Hisham Muhammada853faa2006-05-30 13:45:40 +0000158 Process* process = (Process*) (Vector_get(children, i));
Hisham Muhammadd8e14802010-11-22 12:40:20 +0000159 if (!show)
160 process->show = false;
Hisham Muhammadd8e14802010-11-22 12:40:20 +0000161 int s = this->processes2->items;
162 if (direction == 1)
163 Vector_add(this->processes2, process);
164 else
165 Vector_insert(this->processes2, 0, process);
166 assert(this->processes2->items == s+1); (void)s;
167 int nextIndent = indent | (1 << level);
Hisham Muhammad5effb122010-11-24 12:00:34 +0000168 ProcessList_buildTree(this, process->pid, level+1, (i < size - 1) ? nextIndent : indent, direction, show ? process->showChildren : false);
Hisham Muhammadca6b9232011-11-03 22:12:12 +0000169 if (i == size - 1)
170 process->indent = -nextIndent;
171 else
172 process->indent = nextIndent;
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000173 }
Hisham Muhammada853faa2006-05-30 13:45:40 +0000174 Vector_delete(children);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000175}
176
177void ProcessList_sort(ProcessList* this) {
Hisham Muhammad3383d8e2015-01-21 23:27:31 -0200178 if (!this->settings->treeView) {
Hisham Muhammad7ca10812011-11-18 06:08:56 +0000179 Vector_insertionSort(this->processes);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000180 } else {
Hisham Muhammada7c2aed2007-11-08 23:23:01 +0000181 // Save settings
Hisham Muhammad3383d8e2015-01-21 23:27:31 -0200182 int direction = this->settings->direction;
183 int sortKey = this->settings->sortKey;
Hisham Muhammada7c2aed2007-11-08 23:23:01 +0000184 // Sort by PID
Hisham Muhammad3383d8e2015-01-21 23:27:31 -0200185 this->settings->sortKey = PID;
186 this->settings->direction = 1;
Hisham Muhammad7ca10812011-11-18 06:08:56 +0000187 Vector_quickSort(this->processes);
Hisham Muhammada7c2aed2007-11-08 23:23:01 +0000188 // Restore settings
Hisham Muhammad3383d8e2015-01-21 23:27:31 -0200189 this->settings->sortKey = sortKey;
190 this->settings->direction = direction;
Hisham Muhammada7c2aed2007-11-08 23:23:01 +0000191 // Take PID 1 as root and add to the new listing
Hisham Muhammad3d62edb2006-11-12 21:53:56 +0000192 int vsize = Vector_size(this->processes);
Hisham Muhammada853faa2006-05-30 13:45:40 +0000193 Process* init = (Process*) (Vector_take(this->processes, 0));
Hisham Muhammadeb229d92014-11-24 18:55:03 -0200194 if (!init) return;
Hisham Muhammada2f6eea2008-09-23 06:29:03 +0000195 // This assertion crashes on hardened kernels.
196 // I wonder how well tree view works on those systems.
197 // assert(init->pid == 1);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000198 init->indent = 0;
Hisham Muhammada853faa2006-05-30 13:45:40 +0000199 Vector_add(this->processes2, init);
Hisham Muhammada7c2aed2007-11-08 23:23:01 +0000200 // Recursively empty list
Hisham Muhammad9eb91212010-06-17 19:02:03 +0000201 ProcessList_buildTree(this, init->pid, 0, 0, direction, true);
Hisham Muhammada7c2aed2007-11-08 23:23:01 +0000202 // Add leftovers
Hisham Muhammad3d62edb2006-11-12 21:53:56 +0000203 while (Vector_size(this->processes)) {
204 Process* p = (Process*) (Vector_take(this->processes, 0));
205 p->indent = 0;
206 Vector_add(this->processes2, p);
Hisham Muhammad9eb91212010-06-17 19:02:03 +0000207 ProcessList_buildTree(this, p->pid, 0, 0, direction, p->showChildren);
Hisham Muhammad3d62edb2006-11-12 21:53:56 +0000208 }
209 assert(Vector_size(this->processes2) == vsize); (void)vsize;
210 assert(Vector_size(this->processes) == 0);
Hisham Muhammada7c2aed2007-11-08 23:23:01 +0000211 // Swap listings around
Hisham Muhammada853faa2006-05-30 13:45:40 +0000212 Vector* t = this->processes;
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000213 this->processes = this->processes2;
214 this->processes2 = t;
215 }
216}
217
Hisham Muhammad2338ad52008-03-14 18:50:49 +0000218
219ProcessField ProcessList_keyAt(ProcessList* this, int at) {
220 int x = 0;
Hisham Muhammad3383d8e2015-01-21 23:27:31 -0200221 ProcessField* fields = this->settings->fields;
Hisham Muhammad2338ad52008-03-14 18:50:49 +0000222 ProcessField field;
223 for (int i = 0; (field = fields[i]); i++) {
Hisham Muhammad3383d8e2015-01-21 23:27:31 -0200224 const char* title = Process_fields[field].title;
225 if (!title) title = "- ";
226 int len = strlen(title);
Hisham Muhammad2338ad52008-03-14 18:50:49 +0000227 if (at >= x && at <= x + len) {
228 return field;
229 }
230 x += len;
231 }
232 return COMM;
233}
Hisham Muhammad64862292010-08-24 23:20:38 +0000234
235void ProcessList_expandTree(ProcessList* this) {
236 int size = Vector_size(this->processes);
237 for (int i = 0; i < size; i++) {
238 Process* process = (Process*) Vector_get(this->processes, i);
239 process->showChildren = true;
240 }
241}
Hisham Muhammadbfd86a62011-12-01 12:31:57 +0000242
Hisham Muhammad3383d8e2015-01-21 23:27:31 -0200243void ProcessList_rebuildPanel(ProcessList* this) {
244 int following = this->following;
245 const char* incFilter = this->incFilter;
Hisham Muhammadbfd86a62011-12-01 12:31:57 +0000246
247 int currPos = Panel_getSelectedIndex(this->panel);
Hisham Muhammad3383d8e2015-01-21 23:27:31 -0200248 pid_t currPid = this->following != -1 ? this->following : 0;
Hisham Muhammadbfd86a62011-12-01 12:31:57 +0000249 int currScrollV = this->panel->scrollV;
Hisham Muhammadbfd86a62011-12-01 12:31:57 +0000250
251 Panel_prune(this->panel);
252 int size = ProcessList_size(this);
253 int idx = 0;
254 for (int i = 0; i < size; i++) {
255 bool hidden = false;
256 Process* p = ProcessList_get(this, i);
257
258 if ( (!p->show)
Hisham Muhammad3383d8e2015-01-21 23:27:31 -0200259 || (this->userId != (uid_t) -1 && (p->st_uid != this->userId))
Hisham Muhammad2a734052012-11-10 00:31:37 +0000260 || (incFilter && !(String_contains_i(p->comm, incFilter)))
Hisham Muhammade6c6d7f2012-08-10 21:54:41 +0000261 || (this->pidWhiteList && !Hashtable_get(this->pidWhiteList, p->pid)) )
Hisham Muhammadbfd86a62011-12-01 12:31:57 +0000262 hidden = true;
263
264 if (!hidden) {
265 Panel_set(this->panel, idx, (Object*)p);
Hisham Muhammad3383d8e2015-01-21 23:27:31 -0200266 if ((this->following == -1 && idx == currPos) || (this->following != -1 && p->pid == currPid)) {
Hisham Muhammadbfd86a62011-12-01 12:31:57 +0000267 Panel_setSelected(this->panel, idx);
268 this->panel->scrollV = currScrollV;
269 }
270 idx++;
271 }
272 }
273}
Hisham Muhammadeb229d92014-11-24 18:55:03 -0200274