// proc.h // emacs, this is written in -*-c++-*- (who?) // // This program is free software. See the file COPYING for details. // Author: Mattias Engdeg?rd, 1997-1999 // #ifndef PROC_H #define PROC_H #include "config.h" #ifdef SOLARIS #include // kstat_ctl_t #endif #ifndef USING_PCH #include #include #include #include #include #endif class Procinfo; int read_file(char *name, char *buf, int max); int read_file_addNULL(char *name, void *buf, int max); void check_system_requirement(); int get_kernel_version(); //#define F_PID 0x00000000 enum fields { F_PID = 0, #ifdef LINUX F_TGID, #endif F_PPID, F_PGID, F_SID, F_TTY, #ifdef LINUX F_TPGID, #endif #ifdef MOSIX F_MIGR, F_LOCKED, F_NMIGS, F_NOMOVE, F_RPID, #endif F_USER, F_GROUP, F_UID, F_EUID, #ifdef LINUX F_SUID, F_FSUID, #endif F_GID, F_EGID, #ifdef LINUX F_SGID, F_FSGID, #endif F_PRI, F_NICE, F_PLCY, F_RPRI, #ifdef LINUX F_TMS, F_AFFCPU, F_SLPAVG, #endif F_NLWP, #ifdef SOLARIS F_ARCH, #endif F_MAJFLT, F_MINFLT, #ifdef LINUX F_TRS, F_DRS, F_STACK, #endif F_SIZE, // VSIZE F_SWAP, // Linux not correct F_MEM, F_RSS, #ifdef LINUX F_SHARE, F_DT, F_IOW, F_IOR, #endif F_STAT, F_FLAGS, F_WCHAN, F_WCPU, F_CPU, /* %CPU */ F_PMEM, // F_PMEM: %MEM F_START, F_TIME, F_CPUNUM, F_CMD, F_PROCESSNAME, // NEW F_CWD, F_ROOT, //? F_CMDLINE, F_END = -1 }; class Details; #ifdef LINUX class Sockinfo { public: enum proto_t { TCP, UDP }; proto_t proto; unsigned char st; unsigned char tr; unsigned local_addr; unsigned rem_addr; unsigned short local_port; unsigned short rem_port; unsigned tx_queue; unsigned rx_queue; unsigned tm_when; unsigned rexmits; int uid; //?? int pid; int timeout; int inode; }; class SockInode { public: SockInode(int descr, unsigned long ino) : fd(descr), inode(ino){}; int fd; unsigned long inode; }; class UnixSocket { public: unsigned long inode; QString name; unsigned flags; unsigned char type; // SOCK_STREAM or SOCK_DGRAM unsigned char state; // SS_FREE, SS_UNCONNECTED, SS_CONNECTING, // SS_CONNECTED, SS_DISCONNECTING }; #endif // LINUX // COMMON class Mapsinfo { public: unsigned long from, to; unsigned long offset; unsigned long inode; QString filename; // null if name unknown char perm[4]; // "rwx[ps]"; last is private/shared flag unsigned minor, major; }; #define OPEN_READ 1 #define OPEN_WRITE 2 class Fileinfo { public: Fileinfo(int descr, QString name, int open_mode = 0) : fd(descr), filename(name), mode(open_mode){}; int fd; QString filename; // "major:minor inode" in Linux 2.0, // texual description in Solaris 2.6 unsigned mode; // bits from OPEN_* above (Linux only) }; class NameValue { public: NameValue(){}; // NameValue(const NameValue &nv){ name=nv.name; value=nv.value; }; NameValue(const char *n, const char *val) : name(n), value(val){}; QString name; QString value; }; class Category { public: Category(const char *heading, const char *explain) : name(heading), help(explain), reversed(false), flag_int_value(false){}; virtual ~Category(); virtual int alignment() = 0; virtual QString string(Procinfo *p) = 0; virtual int width() = 0; virtual int compare(Procinfo *a, Procinfo *b); const char *name; const char *help; int index; int id; bool reversed; // testing bool flag_int_value; // testing: for total sum , cat_memory , cat_int }; // COMMON class Cat_int : public Category { public: Cat_int(const char *heading, const char *explain, int w, int Procinfo::*member); virtual int alignment() { return Qt::AlignRight; }; virtual QString string(Procinfo *p); virtual int width() { return field_width; }; virtual int compare(Procinfo *a, Procinfo *b); protected: int Procinfo::*int_member; int field_width; }; // COMMON for memory usage class Cat_memory : public Category { public: Cat_memory(const char *heading, const char *explain, int w, unsigned long Procinfo::*member); virtual int alignment() { return Qt::AlignRight; }; virtual QString string(Procinfo *p); virtual int width() { return field_width; }; virtual int compare(Procinfo *a, Procinfo *b); protected: unsigned long Procinfo::*uintl_member; int field_width; }; class Cat_uintl : public Category { public: Cat_uintl(const char *heading, const char *explain, int w, unsigned long Procinfo::*member); virtual int alignment() { return Qt::AlignRight; }; virtual QString string(Procinfo *p); virtual int width() { return field_width; }; virtual int compare(Procinfo *a, Procinfo *b); protected: unsigned long Procinfo::*uintl_member; int field_width; }; class Cat_hex : public Cat_uintl { public: Cat_hex(const char *heading, const char *explain, int w, unsigned long Procinfo::*member); virtual QString string(Procinfo *p); }; class Cat_swap : public Category { public: Cat_swap(const char *heading, const char *explain); virtual int alignment() { return Qt::AlignRight; }; virtual QString string(Procinfo *p); virtual int width() { return 8; }; virtual int compare(Procinfo *a, Procinfo *b); }; class Cat_string : public Category { public: Cat_string(const char *heading, const char *explain, QString Procinfo::*member = 0); virtual int alignment() { return Qt::AlignLeft; }; virtual QString string(Procinfo *p); virtual int width() { return -9; }; virtual int gap() { return 8; }; protected: QString Procinfo::*str_member; }; class Cat_user : public Cat_string { public: Cat_user(const char *heading, const char *explain); virtual QString string(Procinfo *p); }; class Cat_group : public Cat_string { public: Cat_group(const char *heading, const char *explain); virtual QString string(Procinfo *p); }; class Cat_wchan : public Cat_string { public: Cat_wchan(const char *heading, const char *explain); virtual QString string(Procinfo *p); }; class Cat_dir : public Cat_string { public: Cat_dir(const char *heading, const char *explain, const char *dirname, QString Procinfo::*member); virtual QString string(Procinfo *p); protected: const char *dir; QString Procinfo::*cache; }; class Cat_cmdline : public Cat_string { public: Cat_cmdline(const char *heading, const char *explain); virtual QString string(Procinfo *p); }; class Cat_state : public Category { public: Cat_state(const char *heading, const char *explain); virtual int alignment() { return Qt::AlignLeft; }; virtual QString string(Procinfo *p); virtual int width() { return 6; }; virtual int gap() { return 8; }; }; class Cat_policy : public Category { public: Cat_policy(const char *heading, const char *explain); virtual int alignment() { return Qt::AlignLeft; }; virtual QString string(Procinfo *p); virtual int width() { return 3; }; virtual int gap() { return 8; }; virtual int compare(Procinfo *a, Procinfo *b); }; class Cat_rtprio : public Category { public: Cat_rtprio(const char *heading, const char *explain); virtual int alignment() { return Qt::AlignRight; }; virtual QString string(Procinfo *p); virtual int width() { return 5; }; virtual int compare(Procinfo *a, Procinfo *b); }; #ifdef LINUX class Cat_tms : public Category { public: Cat_tms(const char *heading, const char *explain); virtual int alignment() { return Qt::AlignRight; }; virtual QString string(Procinfo *p); virtual int width() { return 5; }; virtual int compare(Procinfo *a, Procinfo *b); }; class Cat_affcpu : public Category { public: Cat_affcpu(const char *heading, const char *explain); virtual int alignment() { return Qt::AlignRight; }; virtual QString string(Procinfo *p); virtual int width() { return 8; }; // virtual int compare(Procinfo *a, Procinfo *b); }; #endif class Cat_time : public Category { public: Cat_time(const char *heading, const char *explain); virtual int alignment() { return Qt::AlignRight; }; virtual QString string(Procinfo *p); virtual int width() { return 7; }; virtual int compare(Procinfo *a, Procinfo *b); }; class Cat_start : public Category { public: Cat_start(const char *heading, const char *explain); virtual int alignment() { return Qt::AlignRight; }; virtual QString string(Procinfo *p); virtual int width() { return 8; }; virtual int compare(Procinfo *a, Procinfo *b); }; class Cat_percent : public Category { public: Cat_percent(const char *heading, const char *explain, int w, float Procinfo::*member); virtual int alignment() { return Qt::AlignRight; }; virtual QString string(Procinfo *p); virtual int width() { return field_width; }; virtual int compare(Procinfo *a, Procinfo *b); protected: float Procinfo::*float_member; int field_width; }; class Cat_tty : public Cat_string { public: Cat_tty(const char *heading, const char *explain); virtual QString string(Procinfo *p); }; #define CPU_TIMES(cpu, kind) cpu_times_vec[cpu * CPUTIMES + kind] class Proc; class Procinfo // Process Infomation { public: Procinfo(Proc *system_proc, int pid, int thread_id = -1); #ifdef SOLARIS // Procinfo(int pid); //solaris ! // Procinfo(int pid, int thread); //solaris ! int readproc(int pid, int lwp); #endif ~Procinfo(); Procinfo *ref() { refcnt++; return this; }; void deref() { if (!--refcnt) delete this; }; Proc *proc; inline void calculate_cpu(); int readproc(); bool isThread(); void read_fd(int fdnum, char *path); bool read_fds(); bool read_maps(); bool read_environ(); #ifdef SOLARIS void read_pmap_maps(); #endif #ifdef MOSIX static void check_for_mosix(); static Svec mosix_nodes(); #endif int get_policy(); int get_rtprio(); #ifdef LINUX double get_tms(); unsigned long get_affcpu(); QVector sock_inodes; // socket inodes or NULL if not read #endif int pid; bool clone; bool first_run; // for optimization char hashstr[128 * 8]; // cache int hashlen; int hashcmp(char *str); QString command; // COMMAND QString cmdline; // COMMAND_LINE QString username; // QString groupname; // QString cwd; // null if not read QString root; // null if not read bool accepted; int test_stop; // for test int session; // ??? int uid, euid; int gid, egid; char state; int ppid; // Parent's PID int pgrp; dev_t tty; // tty major:minor device int type; // TESTING X,NETWORK,FILE_OPEN,TERMINAL(tty),THREAD, int nthreads; // number of threads : LWP(Solaris), task(Linux) int tgid; // thread leader's id #ifdef LINUX double tms; // slice time int slpavg; unsigned long affcpu; int suid, fsuid; int sgid, fsgid; int tpgid; unsigned long cminflt; unsigned long cmajflt; #endif unsigned long io_read; // byte, testing unsigned long io_write; // testing unsigned long io_read_KBps; // K byte/sec unsigned long io_write_KBps; // K byte/sec unsigned long io_read_prev, io_write_prev; unsigned long flags; //? unsigned long minflt; unsigned long majflt; long utime; long old_utime; // initial value = -1 ; long cutime; int priority; int nice; unsigned long starttime; // start time since run in epoch? Linux : jiffies // since boot , solaris unsigned long wchan; QString wchan_str; // Memory unsigned long mem; // user Memory define unsigned long size; // SIZE: total memory (K) unsigned long resident; // RSS: pages in resident set (non-swapped) (K) #ifdef LINUX unsigned long share; // shared memory pages (mmaped) (K) unsigned long trs; // text resident set size (K) unsigned long lrs; // shared-lib resident set size (K) unsigned long drs; // data resident set size (K) unsigned long dt; // dirty pages (number of pages, not K), obsolute in Kernel 2.6 unsigned long stack; // stack size (K) #endif #ifdef SOLARIS int addr_bits; // address bits (32 or 64) char policy_name[2]; // two first letters of scheduling class #endif struct timeval tv; // time when the snapshot was taken struct timeval old_tv; // // Posix.1b scheduling int policy; // -1 = uninitialized int rtprio; // 0-99, higher can pre-empt lower (-1 = uninitialized) // Linux: the cpu used most of the time of the process // Solaris: the cpu on which the process last ran int which_cpu; // computed %cpu and %mem since last update float wcpu, old_wcpu; // %WCPUwheight cpu float pcpu; // %CPU: percent cpu after last update float pmem; // %MEM QVector fd_files; // file names list QVector maps; // maps list QVector environ; // environment char *envblock; // malloc()ed environment data block #ifdef SOLARIS unsigned long env_ofs; #endif Details *detail; // details window or NULL (backlink) unsigned int generation; // timestamp bool selected : 1; // true if selected in current view bool hidekids : 1; // true if children are hidden in tree view bool lastchild : 1; // true if last (visible) child in tree view short level; // distance from process root QVector children; // real child processes static const int MAX_CMD_LEN = 512; char refcnt; // virtual child for Table_Tree QVector table_children; int table_child_seq; int clear_gen; int child_seq_prev; int parent_row; // virtual parent for tree table #ifdef MOSIX bool isremote; int from; int where; int remotepid; QString migr; // String explaining migration "node>" or ">node" int nmigs; int locked; QString cantmove; static bool mosix_running; // true if MOSIX is running #endif }; typedef QHash Proclist; class SysHistory { public: int idx; time_t time; // saved time, epoch... int current_gen; float load_cpu; // %CPU total ; green float load_mem; // %mem ; yellow? float load_io; // %SYS_IO ; BLUE float load_net; // ;blue? orange? Proclist procs; ~SysHistory(); }; // for A System // cf. Procinfo is for a Process // class Proc { public: Proc(); ~Proc(); void commonPostInit(); // COMMON void read_proc_all(); // test void refresh(); static void init_static(); int read_system(); int countCpu(); void read_loadavg(); int read_pid_tasks(int pid); Category *cat_by_name(const char *s); int field_id_by_name(const char *s); #ifdef LINUX /* from /proc/net/{tcp,udp,unix} */ QHash socks; // tcp/udp sockets QHash usocks; // unix domain sockets bool socks_current; // true if the socks list is current bool usocks_current; // true if the usocks list is current bool read_socket_list(Sockinfo::proto_t proto, const char *pseudofile); void read_sockets(); bool read_usocket_list(); void read_usockets(); void invalidate_sockets(); #endif #ifdef SOLARIS static kstat_ctl_t *kc; // NULL if kstat not opened #endif QHash categories; Proclist procs; // processes indexed by pid // TESTING QString supasswd; // test int syshistoryMAX; Proclist *hprocs; // temp_hprocs list Proclist *mprocs; // QList history; void setHistory(int tick); Proclist getHistory(int pos); int qps_pid; // test float loadQps; // TEST static int update_msec; // class int num_cpus; // current number of CPUs int old_num_cpus; // previous number of CPUs long num_network_process; // number of network(socket) process long num_opened_files; // number of opened normal(not socket) files int num_process; // number of process long dt_total; // long dt_used; // cpu used time in clktick long read_byte; // test long write_byte; // test long io_byte; // test file_io float load_cpu; // %CPU total float loadavg[3]; // 1,5,15 minutes load avgs unsigned int clk_tick; // the number of clock ticks per second. unsigned int boot_time; // boot time in seconds since the Epoch int mem_total, mem_free; // (Kb) int swap_total, swap_free; // in kB int mem_shared, mem_buffers, mem_cached; // Linux // the following are pointers to matrices indexed by kind (above) and // cpu unsigned *cpu_times_vec; unsigned *old_cpu_times_vec; // accessors for (old_)cpu_times_vec unsigned &cpu_times(int cpu, int kind) { return cpu_times_vec[cpu * CPUTIMES + kind]; } unsigned &old_cpu_times(int cpu, int kind) { return old_cpu_times_vec[cpu * CPUTIMES + kind]; } #ifdef LINUX // from /proc/stat unsigned long *per_cpu_times; // vector of num_cpus times unsigned long *old_per_cpu_times; // vector of num_cpus times #endif // Solaris #defines CPU_xxx so we must avoid them enum { CPUTIME_USER, #ifdef LINUX CPUTIME_NICE, #endif CPUTIME_SYSTEM, #ifdef SOLARIS CPUTIME_WAIT, #endif CPUTIME_IDLE, CPUTIMES }; //#define CPU_TIMES(cpu, kind) cpu_times_vec[cpu * CPUTIMES + kind] unsigned int current_gen; int maxSizeHistory; }; class Procview : public Proc { public: Procview(); QString filterstr; static bool flag_show_file_path; static bool flag_pcpu_single; static bool flag_cumulative; static int compare(Procinfo *const *a, Procinfo *const *b); static int compare_backwards(Procinfo *const *a, Procinfo *const *b); void refresh(); bool accept_proc(Procinfo *p); // COMMON void linearize_tree(QVector *ps, int level, int prow, bool flag_hide = false); void build_tree(Proclist &); void rebuild(); void set_fields(); void set_fields_list(int fields[]); void addField(char *name); // interface void addField(int FIELD_ID, int where = -1); // base interface void removeField(int FIELD_ID); int findCol(int FIELD_ID); void moveColumn(int col, int place); void deduce_fields(); void fieldArrange(); void update_customfield(); // void setSortColumn(int col, bool r = false); void setTreeMode(bool b); void saveCOMMANDFIELD(); #ifndef GTK Procinfo *getProcinfoByPID(int pid) { return procs.value(pid, NULL); }; #endif QVector linear_procs; // this is linear_proc_list for viewer #ifdef LINUX QVector linear_socks; // Linux Testing #endif // QList<> tags_kernel; // root_procs contains processes without parent; normally only init, but // we cannot rely on this (Solaris has several parentless processes). // Also, if the view is restricted, all processes whose parent isn't in // the table. QVector root_procs; // table_root_procs; for viewer QVector cats; // for table Category *sortcat; Category *sortcat_linear; // testing int sort_column; // index of bool reversed; // true if sorted backwards static bool treeview; // true if viewed in tree form bool enable; // tmp enum procstates { ALL, OWNED, NROOT, RUNNING, HIDDEN, NETWORK }; enum fieldstates { USER = HIDDEN + 1, JOBS, MEM, SCHED, CUSTOM }; int viewproc; int viewfields; int idxF_CMD; ////Test QStringList customfields; static int custom_fields[64]; // lists of fields to be used for different views, terminated by -1: static int mini_fields[]; // for mobile static int basic_fields[]; static int jobs_fields[]; static int mem_fields[]; #ifdef LINUX static int sched_fields[]; #endif #ifdef MOSIX static int user_fields_mosix[]; static int jobs_fields_mosix[]; static int mem_fields_mosix[]; #endif static float avg_factor; // exponential factor for averaging static const int cpu_avg_time = 30 * 1000; // averaging time for WCPU (ms) private: static Category *static_sortcat; // kludge: to be used by compare }; #endif // PROC_H