You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
qps-packaging/src/proc_common.cpp

1121 lines
27 KiB

/*
* fm-search-uri.c
* This file is part of qps -- Qt-based visual process status monitor
*
* Copyright 2015 Hong Jen Yee (PCMan) <pcman.tw@gmail.com>
* Copyright 2012-2014 Andriy Grytsenko (LStranger) <andrej@rep.kiev.ua>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
// for Non-ASCII locale
//#include <global.h>
//#include <qtextcodec.h>
// extern QTextCodec * codec ;
//#define UniString(str) codec->toUnicode(str)
int flag_24_ok; // we presume a kernel 2.4.x
#include <grp.h>
#include <pwd.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
// COMMON
bool Procview::treeview = 0; // true
bool Procview::flag_show_file_path = false;
bool Procview::flag_cumulative = false; // times cumulative with children's
bool Procview::flag_pcpu_single = false; // %CPU= pcpu/num_cpus
// COMMON: basic field
int Procview::mini_fields[] = {F_PID, F_STAT, F_MEM, F_CPU, F_CMDLINE, F_END};
// COMMON?
// return username from /etc/passwd
char *userName(int uid, int euid)
{
char buff[128];
struct passwd *pw = getpwuid(uid);
if (!pw)
{
// dont have name !
sprintf(buff, "%d", uid);
}
else
strcpy(buff, pw->pw_name);
if (uid != euid)
strcat(buff, euid == 0 ? "*" : "+");
return strdup(buff);
}
// return group name (possibly numeric)
char *groupName(int gid, int egid)
{
char *p;
struct group *gr = getgrgid(gid);
if (!gr)
{
p = (char *)malloc(11);
sprintf(p, "%d", gid);
}
else
p = strdup(gr->gr_name);
// s.append("*");
return p;
}
Category::~Category() {}
int Category::compare(Procinfo *a, Procinfo *b)
{
return string(a).compare(string(b));
}
Cat_int::Cat_int(const QString &heading, const QString &explain, int w,
int Procinfo::*member)
: Category(heading, explain), int_member(member), field_width(w)
{
}
QString Cat_int::string(Procinfo *p)
{
QString s;
s.setNum(p->*int_member);
return s;
}
int Cat_int::compare(Procinfo *a, Procinfo *b)
{
// qsort() only cares about the sign of the number returned by the
// comparison function; only a subtraction is necessary
return a->*int_member - b->*int_member;
}
// COMMON
Cat_percent::Cat_percent(const QString &heading, const QString &explain, int w,
float Procinfo::*member)
: Category(heading, explain), float_member(member), field_width(w)
{
}
QString Cat_percent::string(Procinfo *p)
{
QString s;
s.sprintf("%01.2f", (double)(p->*float_member));
return s;
}
int Cat_percent::compare(Procinfo *a, Procinfo *b)
{
float at = a->*float_member, bt = b->*float_member;
return at < bt ? 1 : (at > bt ? -1 : 0);
}
// added 2006/05/07
Cat_memory::Cat_memory(const QString &heading, const QString &explain, int w,
unsigned long Procinfo::*member)
: Category(heading, explain), uintl_member(member), field_width(w)
{
}
QString Cat_memory::string(Procinfo *p)
{
QString s;
char buff[128];
long sizeK, sizeM;
sizeK = p->*uintl_member;
sizeM = sizeK / 1024;
/* if ( sizeM > 1024 )
{
sprintf(buff,"%dM",sizeM/1024);
}
else */
if (sizeM > 0)
{
sprintf(buff, "%ldM", sizeM);
}
else
sprintf(buff, "%ldK", sizeK);
if (sizeK == 0)
s = "0";
else
s = buff;
return s;
}
int Cat_memory::compare(Procinfo *a, Procinfo *b)
{
int bu = b->*uintl_member, au = a->*uintl_member;
return bu >= au ? (bu == au ? 0 : 1) : -1;
}
Cat_uintl::Cat_uintl(const QString &heading, const QString &explain, int w,
unsigned long Procinfo::*member)
: Category(heading, explain), uintl_member(member), field_width(w)
{
}
QString Cat_uintl::string(Procinfo *p)
{
QString s;
s.setNum(p->*uintl_member);
return s;
}
int Cat_uintl::compare(Procinfo *a, Procinfo *b)
{
int bu = b->*uintl_member, au = a->*uintl_member;
return bu >= au ? (bu == au ? 0 : 1) : -1;
}
Cat_hex::Cat_hex(const QString &heading, const QString &explain, int w,
unsigned long Procinfo::*member)
: Cat_uintl(heading, explain, w, member)
{
}
// QString.sprintf 2x speed than glibc.sprintf (by fasthyun@magicn.com)
// but QString structuring & destructring eat more time
QString Cat_hex::string(Procinfo *p)
{
QString s;
s.sprintf("%8x", (unsigned)(p->*uintl_member));
return s;
}
// COMMON,
Cat_swap::Cat_swap(const QString &heading, const QString &explain)
: Category(heading, explain)
{
}
QString Cat_swap::string(Procinfo *p)
{
QString s;
// It can actually happen that size < resident (Sun under Solaris 2.6)
// Possible with Linux ?
long sizeK, sizeM;
sizeK = p->size > p->resident ? p->size - p->resident : 0;
sizeM = sizeK / 1024;
if (sizeM > 0)
s = QString::number(sizeM) + "M";
else
s = QString::number(sizeK) + "K";
if (sizeK == 0)
s = "0";
return s;
}
int Cat_swap::compare(Procinfo *a, Procinfo *b)
{
return (b->size - b->resident) - (a->size - a->resident);
}
Cat_string::Cat_string(const QString &heading, const QString &explain,
QString Procinfo::*member)
: Category(heading, explain), str_member(member)
{
}
QString Cat_string::string(Procinfo *p) { return p->*str_member; }
Cat_user::Cat_user(const QString &heading, const QString &explain)
: Cat_string(heading, explain)
{
}
QString Cat_user::string(Procinfo *p)
{
if (p->uid == p->euid)
return Uidstr::userName(p->uid);
else
{
QString s = Uidstr::userName(p->uid);
s.append(p->euid == 0 ? "*" : "+");
return s;
}
}
Cat_group::Cat_group(const QString &heading, const QString &explain)
: Cat_string(heading, explain)
{
}
QString Cat_group::string(Procinfo *p)
{
if (p->gid == p->egid)
return Uidstr::groupName(p->gid);
else
{
QString s = Uidstr::groupName(p->gid);
s.append("*");
return s;
}
}
Cat_wchan::Cat_wchan(const QString &heading, const QString &explain)
: Cat_string(heading, explain)
{
}
QString Cat_wchan::string(Procinfo *p)
{
#ifdef LINUX
return p->wchan_str;
#else
return Wchan::name(p->wchan);
#endif
}
Cat_cmdline::Cat_cmdline(const QString &heading, const QString &explain)
: Cat_string(heading, explain)
{
}
QString Cat_cmdline::string(Procinfo *p)
{
if (p->cmdline.isEmpty())
{
QString s("(");
s.append(p->command);
s.append(")");
return s;
}
else
{
if (Procview::flag_show_file_path)
return p->cmdline;
else
{
QString s(p->cmdline);
int i = s.indexOf(' ');
if (i < 0)
i = s.length();
if (i > 0)
{
i = s.lastIndexOf('/', i - 1);
if (i >= 0)
s.remove(0, i + 1);
}
return s;
}
}
}
// hmm COMMON? almost same...but Solaris's zombie process...
Cat_start::Cat_start(const QString &heading, const QString &explain)
: Category(heading, explain)
{
}
// don't let your confidence be shaken, just learn what you can from this young
// master.
QString Cat_start::string(Procinfo *p)
{
#ifdef SOLARIS
if (p->state == 'Z')
return "-"; // Solaris zombies have no valid start time
#endif
Proc *proc = p->proc;
// time_t start = boot_time + p->starttime / (unsigned)HZ;
QString s;
// time_t start = proc->boot_time + p->starttime / proc->clk_tick;
time_t start = p->starttime;
char *ct = ctime(&start); // ctime(sec)
time_t sec = p->starttime - proc->boot_time; // secs
// if(p->tv.tv_sec - start < 86400) {
if (sec < 86400)
{ // 24hours
ct[16] = '\0';
s = ct + 11; // Hour:minu
}
else
{
ct[10] = '\0';
s = ct + 4; // Date
}
return s;
}
int Cat_start::compare(Procinfo *a, Procinfo *b)
{
unsigned long bs = b->starttime, as = a->starttime;
return bs >= as ? (bs == as ? 0 : 1) : -1;
}
/* ======================== Procview ============================ */
float Procview::avg_factor = 1.0;
Procview::Procview()
{
// Proc::Proc(); //call once more ?
cats.clear();
reversed = false;
viewproc = ALL;
treeview = true;
idxF_CMD = 0; // **** important ****
viewfields = USER;
set_fields();
sortcat = 0; // categories[F_PID];
sort_column = -1;
sortcat_linear = NULL;
enable = true;
maxSizeHistory = 1200;
refresh(); // before reading Watchdog list
}
// COMMON:
// Description :
// View mode : ALL , OWNER, NO-ROOOT , HIDDEN, NETWORK
bool Procview::accept_proc(Procinfo *p)
{
QString pid;
static int my_uid = getuid();
bool result;
result = true;
// BAD
if (false and viewproc == NETWORK)
{
/*
p->read_fds();
if(p->sock_inodes.size()==0)
result=false;
for(int i=0;i<p->sock_inodes.size();i++)
{
SockInode *sn=p->sock_inodes[i];
Sockinfo *si=Procinfo::socks.value(sn->inode,NULL);
if(si)
{
si->pid=p->pid;
linear_socks.append(si);
}
}
*/
}
else if (viewproc == ALL)
result = true;
else if (viewproc == OWNED)
result = (p->uid == my_uid);
else if (viewproc == NROOT)
result = (p->uid != 0);
else if (viewproc == RUNNING)
result = strchr("ORDW", p->state) != 0;
/*
if ( viewproc == HIDDEN)
{
result=false;
for(int j=0;j<hidden_process.size();j++)
if(hidden_process[j]==p->command)
result=true ;
}
else
{
for(int j=0;j<hidden_process.size();j++)
if(hidden_process[j]==p->command)
result=false;
} */
if (result == false)
return false; // dont go further !! for better speed
/// if(search_box==NULL) return result;
if (filterstr == "")
return result;
if (filterstr == "*")
return true;
// Notice:
// 1. some process name maybe different CMDLINE. ex) Xorg
if (p->cmdline.contains(filterstr,
Qt::CaseInsensitive)) // search_box->text()
return true;
if (p->command.contains(filterstr, Qt::CaseInsensitive))
return true;
if (p->username.contains(filterstr, Qt::CaseInsensitive))
return true;
pid = pid.setNum(p->pid); //=QString::number(p->pid);
if (pid.contains(filterstr, Qt::CaseInsensitive))
return true;
/// printf("search_Box =%s , %s
/// \n",search_box->text().toAscii().data(),p->command.toAscii().data());
return false;
}
extern "C" {
typedef int (*compare_func)(const void *, const void *);
}
/*
template<class T>
void Svec<T>::sort(int (*compare)(const T *a, const T *b))
{
qsort(vect, used, sizeof(T), (compare_func)compare);
}
*/
// table view - sort
void Procview::linearize_tree(QVector<Procinfo *> *ps, int level, int prow,
bool hide)
{
static_sortcat = sortcat;
// ps->sort(reversed ? compare_backwards : compare);
if (reversed)
qsort(ps->data(), ps->size(), sizeof(Procinfo *),
(compare_func)compare_backwards);
else
qsort(ps->data(), ps->size(), sizeof(Procinfo *),
(compare_func)compare);
int size = ps->size();
// printf("level=%d prow=%d size=%d\n",level,prow,size);
for (int i = 0; i < size; i++)
{
Procinfo *p = (*ps)[i];
// if (p->pid<6 ) printf("pid=%d level=%d
// parent_row=%d\n",p->pid,p->pid,p->parent_row);
p->level = level;
p->lastchild = false;
p->table_child_seq = i; // ************* where using ? -> sequence
p->parent_row = prow;
if (!hide)
linear_procs.append(p); // need !!
if (p->table_children.size()) // and !p->hidekids)
linearize_tree(&p->table_children, level + 1,
linear_procs.size() - 1, hide | p->hidekids);
}
if (size > 0)
(*ps)[size - 1]->lastchild = true;
}
/// basic,memory,job fields
void Procview::set_fields_list(int fields[])
{
cats.clear();
for (int i = 0; fields[i] != F_END; i++)
{
if (fields[i] == F_CPUNUM and Proc::num_cpus < 2)
continue; // not correctly work
Category *c = categories.value(fields[i], NULL);
if (c)
{
// printf("name=%s\n",c->name);
cats.append(c);
}
}
return;
}
// return the column number of a field, or -1 if not displayed
int Procview::findCol(int field_id)
{
for (int i = 0; i < cats.size(); i++)
if (cats[i]->id == field_id)
return i;
return -1;
}
// basis
// called by
// void Procview::fieldArrange();
// qps();
//
void Procview::addField(int Fid, int where)
{
// where=-1;
// printf("Fid =%d where=%d\n",Fid,where);
// where=pstable->clickedColumn();
if (where == 0)
{
// if (pstable->treeMode()) where=1;
}
if (Fid == F_PROCESSNAME)
where = 0;
if (Fid == F_CMDLINE)
where = cats.size(); // always should be the last column
if (where < 0)
{
// this is default
where = cats.size();
}
if (where > cats.size()) // CMD_LINE ! ??????
where = 1;
Category *newcat = categories[Fid];
// printf("name =%s where=%d\n",newcat->name,where);
if (cats.indexOf(newcat) < 0) // if not in the list ****
cats.insert(where, newcat);
}
// add a category to last by name
void Procview::addField(char *name) // interface
{
// QString str=sl[i];
int id = field_id_by_name(name);
if (id >= 0)
addField(id); // add to last
return;
Category *cat = cat_by_name(name);
if (cat)
cats.append(cat);
}
void Procview::removeField(int field_id)
{
for (int i = 0; i < cats.size();)
{
// printf("Fid=%d cats[%d].id=%d
//\n",field_id,i,cats[i]->id);
if (true)
{
if (cats[i]->id == field_id)
{
// if(cats[i]->id==F_CMD and !treeview)
// idxF_CMD=-1;
cats.remove(i);
break;
}
else
i++;
}
}
// printf("Fid=%d cats.size=%d\n",field_id,cats.size());
}
// called by
// 1. write_settings()
// DEL? -> not yet
void Procview::update_customfield()
{
int i;
// printf("update custom_fields\n");
customfields.clear();
for (i = 0; i < cats.size(); i++)
customfields.append(cats[i]->name);
// DEL
if (false and treeview)
{
int idx = customfields.indexOf("COMMAND"); // == removeField(F_CMD);
if (idx >= 0)
customfields.removeAt(idx);
if (idxF_CMD >= 0)
{
/* if(customfields.size()<=idxF_CMD)
customfields.append(categories[F_CMD]->name);
else */
customfields.insert(idxF_CMD, categories[F_CMD]->name);
}
}
return;
}
// Description : FIELD movement by mouse drag
// From col To place
void Procview::moveColumn(int col, int place)
{
int i;
int f_size = cats.size();
if (col < 0 or place < 0 or f_size <= col or f_size <= place)
{
printf("QPS code bugs!! : moveColumn() col=%d place=%d "
"cats.size=%d\n",
col, place, cats.size());
return;
}
if (treeview == true)
{
// *** important : F_PROCESSNAME field should be the first in
// TreeMode!
/// if(place==0) return;
if (cats[col]->index == F_PROCESSNAME)
place = 0;
}
// COMMAND_LINE field should always be the last field
// if(cats[place]->index==F_CMDLINE) return;
if (cats[col]->index == F_CMDLINE)
place = cats.size() - 1;
Category *cat = cats[col]; // SEGFAULT POSSIBLE!
cats.insert(place, cat); // insert
if (place < col)
col++;
cats.remove(col); // remove idx
// refresh();
/// update_customfield();
}
// always called when linear to tree
// DEL
void Procview::saveCOMMANDFIELD() {}
// call by
// void Pstable::moveCol(int col, int place)
// void Pstable::setTreeMode(bool treemode)
// void Procview::set_fields()
// TODO: checkField();
void Procview::fieldArrange()
{
if (treeview == true)
{
// Tree Mode
// If ProcessName isn't the leftmost column, move it to
// leftmost
// *** important : F_PROCESSNAME field should be the first in
// TreeMode!
if (cats[0]->index != F_PROCESSNAME)
{
// find F_PROCESSNAME
for (int i = 1; i < cats.size(); i++)
{
if (cats[i]->index == F_PROCESSNAME)
moveColumn(i, 0);
}
}
// PID sort for convenience (default)
/*
if(false and cats[i]->index == F_PID )
{
reversed = false;
sortcat = cats[i];
//// pstable->setSortedCol(i);
} */
// Linear_Mode:
}
if (true)
{
for (int i = 0; i < cats.size(); i++)
{
if (cats[i]->index == F_CMDLINE)
{
// COMMAND_LINE field should always be the last
// field
if (i == (cats.size() - 1))
moveColumn(i, 0);
else
{
}
}
}
}
}
void Procview::setTreeMode(bool b)
{
if (treeview == false)
{
if (sortcat_linear == NULL)
sortcat_linear = sortcat;
else
sortcat = sortcat_linear;
}
}
void Procview::setSortColumn(int col, bool r)
{
// qDebug("xxx error? col>=cats.size() %d",col);
if (col >= cats.size())
{
qDebug("hmmm error? col>=cats.size() %d", col);
return;
}
// if(!procview->treeview) just reverse the lines
if (col == sort_column)
reversed = !reversed;
else
reversed = false;
sortcat = cats[col];
sort_column = col;
}
Category *Procview::static_sortcat = 0;
int Procview::compare(Procinfo *const *a, Procinfo *const *b)
{
if (static_sortcat == 0)
return 0;
int r = static_sortcat->compare(*a, *b);
return (r == 0) ? ((*a)->pid > (*b)->pid ? 1 : -1) : r;
}
int Procview::compare_backwards(Procinfo *const *a, Procinfo *const *b)
{
if (static_sortcat == 0)
return 0;
int r = static_sortcat->compare(*b, *a);
return (r == 0) ? ((*b)->pid > (*a)->pid ? 1 : -1) : r;
}
// COMMON
Category *Proc::cat_by_name( const QString &s )
{
if ( ! s.isNull() )
{
// java style
QHashIterator<int, Category *> i(categories);
while (i.hasNext())
{
i.next();
const QString &p = i.value()->name;
int index = p.indexOf( QRegExp( "\\S" ) );
if ( p.indexOf( s, index ) == index )
return i.value();
// cout << i.key() << ": " << i.value() << endl;
}
}
return 0;
}
// COMMON
// call by
int Proc::field_id_by_name(const QString &s)
{
if ( ! s.isNull() )
{
// STL style
QHash<int, Category *>::iterator i = categories.begin();
while (i != categories.end())
{
if ( i.value()->name == s )
return i.key(); // cout << i.key() << ": " <<
// i.value() << endl;
++i;
}
}
return -1;
}
// postInit
void Proc::commonPostInit()
{
// java style
/*
QHashIterator<int,Category *> i(categories); // a little suck!
while (i.hasNext()) {
i.next();
i.value()->index=i.key();
i.value()->id=i.key();
}*/
// STL style , set id
QHash<int, Category *>::iterator i = categories.begin();
while (i != categories.end())
{
i.value()->index = i.key();
i.value()->id = i.key();
// cout << i.key() << ": " << i.value() << endl;
++i;
}
num_opened_files = 0; // test
num_process = 0; // 64bit
num_network_process = 0; // 64bit
dt_total = 0; // diff system tick
dt_used = 0; // for infobar
loadavg[0] = loadavg[1] = loadavg[2] =
0.0; // CPU load avg 1min,5min,15minute
Proc::num_cpus = 0;
Proc::old_num_cpus = 0;
Proc::mem_total = 0;
Proc::mem_free = 0;
Proc::mem_buffers = 0;
Proc::mem_cached = 0;
// mem_shared = 0; // only linux kernel 2.4.x???
Proc::swap_total = 0;
Proc::swap_free = 0;
Proc::qps_pid = -1;
Proc::loadQps = 0.0;
Proc::cpu_times_vec = 0; // array.
Proc::old_cpu_times_vec = 0;
Proc::boot_time = 0;
Proc::clk_tick = 100; // for most system
current_gen = 0; // !
mprocs = NULL;
hprocs = NULL;
clk_tick =
sysconf(_SC_CLK_TCK); //****** The number of clock ticks per second.
//
// printf("Qps: hz=%d\n",clk_tick);
/// Procinfo::init_static();
}
// COMMON?
// called by Procview::rebuild()
// using procs, makes root_procs for TABLE_View
void Procview::build_tree(Proclist &procs)
{
Procinfo *p;
int proc_n = 0;
// children clear
root_procs.clear();
QHash<int, Procinfo *>::iterator i;
for (i = procs.begin(); i != procs.end();)
{
Procinfo *p = i.value();
p->table_children.clear();
if ((p->accepted = accept_proc(p)))
proc_n++;
++i;
}
Proc::num_process = proc_n; // count process
// find parent of a process
for (i = procs.begin(); i != procs.end(); ++i)
{
p = i.value(); // always not NULL
if (p->accepted)
{
Procinfo *parent = 0;
int virtual_parent_pid;
if (p->isThread())
virtual_parent_pid = p->tgid; // thread's leader ID.
else
virtual_parent_pid = p->ppid;
if (p->pid < p->ppid)
{
// this occurs !! a reporter mailed to me
}
parent = procs.value(virtual_parent_pid,
NULL); // if pid not found, then return NULL.
// printf("thread_leader=0 (%d)
//%s\n",p->tgid,p->command.ascii());
if (treeview and parent and parent->accepted)
{
// p->table_child_seq=parent->table_children.size();
parent->table_children.append(p);
}
else
{
// 1.init(pid=1) process
// 2.some process which parent not accepted
// 3.(null) thread has TGID=0,PPID=0
// 4.when not tree mode
root_procs.append(p);
}
}
}
}
// COMMON
// BOTTLENECK No.3 0.5%
// re-sort the process list , ::rebuild() for Table
// called by Pstable::refresh()
void Procview::rebuild()
{
linear_procs.clear(); // Svec<Procinfo *> procs in Proview
#ifdef LINUX
linear_socks.clear();
#endif
// Procinfo *pi = getProcinfoByPID(Procinfo::qps_pid);
// if(pi) Procinfo::loadQps=pi->pcpu;
// printf("rebuild\n");
/* if(mprocs)
{
build_tree(*mprocs);
}
else */
build_tree(Proc::procs);
linearize_tree(&root_procs, 0, -1);
}
#include <math.h> // log()
// COMMON: CORE
// Description: update the process list BottleNeck 1.5%
// read /proc/*
// called by Procview::refresh(), every UPDATE .
void Proc::refresh()
{
current_gen++;
// TEST for Process History
SysHistory *s = new SysHistory;
history.append(s);
hprocs = &(s->procs);
// init
/// num_opened_files=0;
Proc::num_process = 0;
Proc::num_network_process = 0;
Proc::read_loadavg();
Proc::read_system(); // **** should be every refresh !!
// s->load_cpu=(float)Proc::dt_used/Proc::dt_total; //after
// read_system();
s->load_cpu = load_cpu; // after read_system();
s->time = time(NULL); // save current time in seconds since epoch
// TODO: clean
// Procinfo::read_sockets(); // for future, BottleNect 2%
read_byte = 0;
write_byte = 0;
io_byte = 0; //!!!
/// Proc::read_sockets(); // test
read_proc_all(); // Linux, Solaris...
// s->load_io=(float)(read_byte + write_byte ); // (50*1024*1024);
// //dt_total;
if (io_byte != 0)
{
s->load_io = log10(io_byte) * 2; // 9000 -> 3point
// printf("DEBUG: rw=[%d,%d] %d, %f\n",read_byte,
// write_byte,io_byte,s->load_io);
}
else
s->load_io = 0;
// remove non-existing processes, remove Procinfos of nonexisting
// processes
QHash<int, Procinfo *>::iterator i;
for (i = procs.begin(); i != procs.end();)
{
Procinfo *p = i.value();
if (p->generation != current_gen)
{
// printf("delete %d\n",p->pid);
i = procs.erase(i);
delete p;
}
else
{
// p->table_children.clear(); // for rebuild()
// p->accepted=accept_proc(p);
++i;
}
}
// TESTING
while (history.size() >= maxSizeHistory)
{
// if(history.isEmpty()==false)
delete history.takeFirst();
}
}
// COMMON
// read new process info
void Procview::refresh()
{
/****************************************************************/
/* Procview.procs has the procinfo
*/
/****************************************************************/
if (enable)
{
// printf("Procview::refresh()\n");
Proc::refresh(); // read "/proc/*", then update the process list
}
}
SysHistory::~SysHistory()
{
for (const auto *p : qAsConst(procs))
{
delete p;
}
procs.clear(); // remove all (key,val)
}
/* check
Category *Proc::cat_by_name(const char *s)
{
if( s )
{
for( int i = 0; i < categories.size(); i++ )
if( strcmp(categories[i]->name, s) == 0 )
return categories[i];
}
return 0;
}
int Proc::field_id_by_name(const char *s)
{
if( s )
{
for( int i = 0; i < categories.size(); i++ )
if( strcmp(categories[i]->name, s) == 0 )
return i;
}
return -1;
}
*/