/proc是内核向用户态提供的一组fifo接口, 通过伪文件目录的形式调用接口
每一个进程相关的信息, 会被放到以pid命名的文件夹当中, ps等命令也是通过遍历/proc目录来获取进程的相关信息的.
一个stat文件内容如下所示, 下面self是/proc目录提供的一个快捷的查看自己进程信息的接口, 每一个进程访问/self时看到都是自己的信息.
#cat /proc/self/stat 3119 (cat) R 29973 3119 19885 34821 3119 4194304 107 0 0 0 0 0 0 0 20 0 1 0 5794695 5562368 176 18446744073709551615 94309027168256 94309027193225 140731267701520 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 94309027212368 94309027213920 94309053399040 140731267704821 140731267704841 140731267704841 140731267706859 0
会发现这些数据杂乱无章, 使用空格作为每一个数据的边界, 没有地方说明这些数据各自表达什么意思.
一般折腾找到了一篇文章里面给出了一个列表, 这个表里面说明了每一个数据的数据类型和其表达的含义, 见文章附录1
最后整理出一个有52个数据项每个数据项类型各不相同的结构体, 获取起来还是有点麻烦, 网上没有找到轮子, 所以自己写了一个
具体的结构体定义:
struct proc_stat { int pid; //process ID. char* comm; //可执行文件名称, 会用包围 char state; //进程状态 int ppid; //父进程pid int pgid; int session; //sid int tty_nr; int tpgid; unsigned int flags; long unsigned int minflt; long unsigned int cminflt; long unsigned int majflt; long unsigned int cmajflt; long unsigned int utime; long unsigned int stime; long int cutime; long int cstime; long int priority; long int nice; long int num_threads; long int itrealvalue; long long unsigned int starttime; long unsigned int vsize; long int rss; long unsigned int rsslim; long unsigned int startcode; long unsigned int endcode; long unsigned int startstack; long unsigned int kstkesp; long unsigned int kstkeip; long unsigned int signal; //The bitmap of pending signals long unsigned int blocked; long unsigned int sigignore; long unsigned int sigcatch; long unsigned int wchan; long unsigned int nswap; long unsigned int cnswap; int exit_signal; int processor; unsigned int rt_priority; unsigned int policy; long long unsigned int delayacct_blkio_ticks; long unsigned int guest_time; long int cguest_time; long unsigned int start_data; long unsigned int end_data; long unsigned int start_brk; long unsigned int arg_start; //参数起始地址 long unsigned int arg_end; //参数结束地址 long unsigned int env_start; //环境变量在内存中的起始地址 long unsigned int env_end; //环境变量的结束地址 int exit_code; //退出状态码 };
从文件中读入并格式化为结构体:
struct proc_stat get_proc_stat(int Pid) { FILE *f = NULL; struct proc_stat stat = {0}; char tmp[100] = "0"; stat.comm = tmp; char stat_path[20]; char* pstat_path = stat_path; if (Pid != -1) { sprintf(stat_path, "/proc/%d/stat", Pid); } else { pstat_path = "/proc/self/stat"; } if ((f = fopen(pstat_path, "r")) == NULL) { printf("open file error"); return stat; } fscanf(f, "%d ", &stat.pid); fscanf(f, "(%100s ", stat.comm); tmp[strlen(tmp)-1] = ''; fscanf(f, "%c ", &stat.state); fscanf(f, "%d ", &stat.ppid); fscanf(f, "%d ", &stat.pgid); fscanf ( f, "%d %d %d %u %lu %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %llu %lu %ld %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %d %d %u %u %llu %lu %ld %lu %lu %lu %lu %lu %lu %lu %d", &stat.session, &stat.tty_nr, &stat.tpgid, &stat.flags, &stat.minflt, &stat.cminflt, &stat.majflt, &stat.cmajflt, &stat.utime, &stat.stime, &stat.cutime, &stat.cstime, &stat.priority, &stat.nice, &stat.num_threads, &stat.itrealvalue, &stat.starttime, &stat.vsize, &stat.rss, &stat.rsslim, &stat.startcode, &stat.endcode, &stat.startstack, &stat.kstkesp, &stat.kstkeip, &stat.signal, &stat.blocked, &stat.sigignore, &stat.sigcatch, &stat.wchan, &stat.nswap, &stat.cnswap, &stat.exit_signal, &stat.processor, &stat.rt_priority, &stat.policy, &stat.delayacct_blkio_ticks, &stat.guest_time, &stat.cguest_time, &stat.start_data, &stat.end_data, &stat.start_brk, &stat.arg_start, &stat.arg_end, &stat.env_start, &stat.env_end, &stat.exit_code ); fclose(f); return stat; }
和我们需要获取的数据做了一下对比, 可以获取以下数据
ppid
父进程id
pgid
进程组id
sid
进程会话id
start_time
父进程开始运行的时间
run_time
父进程已经运行的时间
/proc/[pid]/exe