在proc根目录下,以数字命名的目录表示当前一个运行的进程,目录名即为进程的pid。其内的目录和文件给出了一些关于该进程的信息。
niutao@niutao-desktop:/proc/6584$ ls attr coredump_filter fd maps oom_score statm auxv cpuset fdinfo mem root status cgroup cwd io mounts sched task clear_refs environ limits mountstats smaps wchan cmdline exe loginuid oom_adj stat
1.cmdline文件:
该文件中包含的是该进程的命令行参数,包括进程的启动路径(argv[0])。也就是说例如你在命令行上运行一个hello程序:
niutao@niutao-desktop:~$ cat hello.c #include<stdio.h> #include<wait.h> int main() { int i; for(i=0;i<100;i++) { printf("Hello world\n"); sleep(2); } return 0; } niutao@niutao-desktop:~$ gcc -o hello hello.c niutao@niutao-desktop:~$ ./hello one two niutao@niutao-desktop:~$ ps -A |grep hello 7282 pts/4 00:00:00 hello niutao@niutao-desktop:~$ cd /proc/7282/ niutao@niutao-desktop:/proc/7282$ cat cmdline ./helloonetwoniutao@niutao-desktop:/proc/7282$
niutao@niutao-desktop:~/c$ cat readcmd.c #include<stdio.h> #include<string.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int main(int args,char *argv[]) { FILE *fp; char path[80]; unsigned char ch; snprintf(path,80,"/home/niutao/cmdline"); if((fp=fopen(path,"r"))==NULL) { perror("fopen"); return 0; } while(!feof(fp)) { ch=fgetc(fp); printf("%c %d\n",ch,ch); } fclose(fp); return 0; } niutao@niutao-desktop:~/c$ gcc -o readcmd readcmd.c niutao@niutao-desktop:~/c$ ./readcmd . 46 / 47 h 104 e 101 l 108 l 108 o 111 0 o 111 n 110 e 101 0 t 116 w 119 o 111 0 � 255 niutao@niutao-desktop:~/c$
3.cmd目录链接:
该目录链接指向该进程运行的当前路径。该符号链接虽然使用ls命令查看其权限是对所有用户都有权限,但实际中是只有启动该进程的用户才具有读写的权限,其他用户不具有一切权限。该链接指向该进程运行的当前路径,例如我们在用户目录下启动该进程,那么cwd就指向用户目录。
4.environ文件:
包含该进程运行的环境变量。我们常用的一些环境变量都包含在该文件中,例如PATH,HOME,PWD等。所以如果我们想在一个进程中获取这些环境变量而又不想使用getenv(),getpwd函数的时候,我们就可以通过直接读取该进程的该文件以直接获得环境变量。下面是一个程序实现这个过程:
#include<stdio.h> #include<unistd.h> #include<string.h> #include<sys/types.h> #include <fcntl.h> int main(int args,char *argv[]) { FILE *fp; int pid; char path[80]; int i=0; unsigned char buff[1024]; unsigned char *p=NULL; unsigned char ch; if(args<2) { printf("no argument\n"); return 0; } pid=getpid(); snprintf(path,80,"/proc/%d/environ",pid); if((fp=fopen(path,"r"))==NULL) { perror("fopen"); return 0; } while(!feof(fp)) { if((ch=fgetc(fp))!=‘\0′) { buff[i]=ch; i++; continue; } buff[i]=‘\0′; if((p=strstr(buff,argv[1]))!=NULL) { printf(“%s\n”,p+strlen(argv[1])+1); return 0; } i=0; memset(buff,‘\0′,1024); } fclose(fp); return 0; } niutao@niutao-desktop:~/c$ gcc -o getenv getenv.c niutao@niutao-desktop:~/c$ ./getenv HOME /home/niutao
6.maps文件和smaps文件
maps 文件是可执行文件或者库文件对应的内存映像,而smaps文件显示的是该进程这些可执行文件或者库文件内存映像在内存中的大小等信息。在 GNOME桌面下的gnome-system-monitor中,我们选中一个进程,右键Memory Maps,其中显示的内容就来自这两个文件的信息。
首先我们来看maps文件:
niutao@niutao-desktop:/proc/6740$ cat maps 08048000-080ef000 r-xp 00000000 08:0d 636485 /bin/bash 080ef000-080f5000 rw-p 000a6000 08:0d 636485 /bin/bash 080f5000-08337000 rw-p 080f5000 00:00 0 [heap] b7c91000-b7cd0000 r--p 00000000 08:0d 1183449 /usr/lib/locale/en_US.utf8/LC_CTYPE b7cd0000-b7cd9000 r-xp 00000000 08:0d 1111788 /lib/tls/i686/cmov/libnss_files-2.7.so b7cd9000-b7cdb000 rw-p 00008000 08:0d 1111788 /lib/tls/i686/cmov/libnss_files-2.7.so b7cdb000-b7ce3000 r-xp 00000000 08:0d 1111790 /lib/tls/i686/cmov/libnss_nis-2.7.so b7ce3000-b7ce5000 rw-p 00007000 08:0d 1111790 /lib/tls/i686/cmov/libnss_nis-2.7.so 。。。。
niutao@niutao-desktop:/proc/6740$ cat smaps 08048000-080ef000 r-xp 00000000 08:0d 636485 /bin/bash Size: 668 kB Rss: 584 kB Shared_Clean: 584 kB Shared_Dirty: 0 kB Private_Clean: 0 kB Private_Dirty: 0 kB Referenced: 584 kB 080ef000-080f5000 rw-p 000a6000 08:0d 636485 /bin/bash Size: 24 kB Rss: 24 kB Shared_Clean: 0 kB Shared_Dirty: 0 kB Private_Clean: 0 kB Private_Dirty: 24 kB Referenced: 24 kB 。。。。
7.fd目录fdinfo目录
fd目录包含了所有该进程使用的文件描述符,而fdinfo目录包含的是对应的fd目录中进程打开文件的操作权限。
niutao@niutao-desktop:/proc/6772/fd$ ls -l lrwx------ 1 niutao niutao 64 2008-10-22 21:32 0 -> /dev/pts/5 lrwx------ 1 niutao niutao 64 2008-10-22 21:32 1 -> /dev/pts/5 lrwx------ 1 niutao niutao 64 2008-10-22 21:32 2 -> /dev/pts/5 niutao@niutao-desktop:/proc/6772/fd$ cd ../fdinfo/ niutao@niutao-desktop:/proc/6772/fdinfo$ cat 0 pos: 0 flags: 02我 们可以看出fd目录中包含的是进程打开文件的链接,这里我们就可以看到我们经常提到的标准输入(0),标准输出(1),标准错误输出(2)。那么 fdinfo中包含的文件的含义,我们可以从这两个方面探索。一个是内核中的 proc_fd_info函数(/fs/proc/base.c),fdinfo目录中的文件中的内容正是由这个函数写的,而flags对应的是文件结 构体(struct file)的f_flags域(知识我呢件的访问权限)。另一个是我们可以通过查看fd目录中包含的符号链接文件指向的文件的权限得知其(fdinfo目 录中文件内容)含义:
niutao@niutao-desktop:/proc/6772/fd$ ls -l /dev/pts/5 crw--w---- 1 niutao tty 136, 5 2008-10-22 21:32 /dev/pts/5
8.root符号链接文件
该文件指向的是根目录(/)。
9.stat文件
该文件的内容反应的是该进程的PCB(task_struct结构)的一些数据域的信息。下面我们来具体看一下它的含义。首先我们在终端上启动gedit程 序,然后使用系统监视器(gnome-system-monitor)查看gedit进程的pid为11942,然后我们读取它的stat文件
niutao@niutao-desktop:/proc/11942$ cat stat 11942 (gedit) S 7293 11942 7293 34820 11942 4202496 5017 0 0 0 80 10 0 0 20 0 1 0 1292037 61636608 4481 4294967295 134512640 135099420 3216990608 3216990068 3085931536 0 0 4096 0 0 0 0 17 0 0 0 0 0 0
sprintf(buffer, "%d (%s) %c %d %d %d %d %d %u %lu \ %lu %lu %lu %lu %lu %ld %ld %ld %ld %d 0 %llu %lu %ld %lu %lu %lu %lu %lu \ %lu %lu %lu %lu %lu %lu %lu %lu %d %d %u %u %llu %lu %ld\n", task_pid_nr_ns(task, ns), /*进程(包括轻量级进程,即线程)号(task->pid)*/ tcomm, /*应用程序的名字(task->comm)*/ state,/*进程的状态信息(task->state),具体参见http://blog.chinaunix.net/u2/73528/showart_1106510.html*/ ppid,/*父进程ID*/ pgid,/*线程组ID*/ sid,/*会话组ID*/ tty_nr,/*该进程的tty终端的设备号,INT(34817/256)=主设备号,(34817-主设备号)=次设备号*/ tty_pgrp,/*终端的进程组号,当前运行在该进程所在终端的前台进程(包括shell 应用程序)的PID*/ task->flags,/*进程标志位,查看该进程的特性(定义在/include/kernel/sched.h中)*/ min_flt,/*累计进程的次缺页数(Copy on Write页和匿名页)*/ cmin_flt,/*该进程所有的子进程发生的次缺页的次数*/ maj_flt,/*主缺页数(从映射文件或交换设备读入的页面数)*/ cmaj_flt,/*该进程所有的子进程发生的主缺页的次数*/ cputime_to_clock_t(utime),/*该进程在用户态运行的时间,单位为jiffies*/ cputime_to_clock_t(stime),/*该进程在核心态运行的时间,单位为jiffies*/ cputime_to_clock_t(cutime),/*该进程所有的子进程在用户态运行的时间总和,单位为jiffies*/ cputime_to_clock_t(cstime),/*该进程所有的子进程在内核态运行的时间的总和,单位为jiffies*/ priority,/*进程的动态优先级*/ nice,/*进程的静态优先级*/. num_threads,/*该进程所在的线程组里线程的个数*/. start_time,/*该进程创建的时间*/. vsize,/*该进程的虚拟地址空间大小*/. mm ? get_mm_rss(mm) : 0,/*该进程当前驻留物理地址空间的大小*/. rsslim,/*该进程能驻留物理地址空间的最大值*/. mm ? mm->start_code : 0,/*该进程在虚拟地址空间的代码段的起始地址*/. mm ? mm->end_code : 0,/*该进程在虚拟地址空间的代码段的结束地址*/. mm ? mm->start_stack : 0,/*该进程在虚拟地址空间的栈的结束地址*/. esp,/*esp(32 位堆栈指针) 的当前值, 与在进程的内核堆栈页得到的一致*/. eip,/*指向将要执行的指令的指针, EIP(32 位指令指针)的当前值*/. /* The signal information here is obsolete. * It must be decimal for Linux 2.0 compatibility. * Use /proc/#/status for real-time signals. */ task->pending.signal.sig[0] & 0x7fffffffUL,/*待处理信号的位图,记录发送给进程的普通信号*/. task->blocked.sig[0] & 0x7fffffffUL,/*阻塞信号的位图*/. sigign .sig[0] & 0x7fffffffUL,/*忽略的信号的位图*/. sigcatch .sig[0] & 0x7fffffffUL,/*被俘获的信号的位图*/. wchan,/*如果该进程是睡眠状态,该值给出调度的调用点*/. 0UL,/*被swapped的页数,当前没用*/. 0UL,/*所有子进程被swapped的页数的和,当前没用*/. task->exit_signal,/*该进程结束时,向父进程所发送的信号*/. task_cpu(task),/*运行在哪个CPU上*/. task->rt_priority,/*实时进程的相对优先级别*/. task->policy,/*进程的调度策略,0=非实时进程,1=FIFO实时进程;2=RR实时进程*/. (unsigned long long)delayacct_blkio_ticks(task),/**/. cputime_to_clock_t(gtime),/**/. cputime_to_clock_t(cgtime));/**/.
bashniutao@niutao-desktop:/proc/7293$ cat stat 7293 (bash) S 7095 7293 7293 34820 7293 4194304 2902 40892 1 166 16 2 600 64 20 0 1 0 509398 6619136 918 4294967295 134512640 135194160 3214795824 3214792344 3086427152 0 0 3686404 1266761467 0 0 0 17 0 0 0 0 0 0
10.statm文件
描述进程的内存状态。
niutao@niutao-desktop:/proc/6950$ cat statm 12992 4432 3213 144 0 1028 0 niutao@niutao-desktop:/proc/6950$下面我们来详细解释该文件中内容的含义。首先我们可以在内核中搜索到该文件的内容是由函数proc_pid_statm()函数写入的:(/fs/proc/array.c)
int proc_pid_statm(struct task_struct *task, char *buffer) { int size = 0, resident = 0, shared = 0, text = 0, lib = 0, data = 0; struct mm_struct *mm = get_task_mm(task); if (mm) { size = task_statm(mm, &shared, &text, &data, &resident); mmput(mm); } return sprintf(buffer, "%d %d %d %d %d %d %d\n", size, resident, shared, text, lib, data, 0); } /*fs/proc/task_mmu.c*/ int task_statm(struct mm_struct *mm, int *shared, int *text, int *data, int *resident) { *shared = get_mm_counter(mm, file_rss); *text = (PAGE_ALIGN(mm->end_code) - (mm->start_code & PAGE_MASK)) >> PAGE_SHIFT; *data = mm->total_vm - mm->shared_vm; *resident = *shared + get_mm_counter(mm, anon_rss); return mm->total_vm; }
11.status文件:
用可读的方式描述进程的状态
niutao@niutao-desktop:/proc/9744$ cat status Name: gedit /*进程的程序名*/ State: S (sleeping) /*进程的状态信息,具体参见http://blog.chinaunix.net/u2/73528/showart_1106510.html*/ Tgid: 9744 /*线程组号*/ Pid: 9744 /*进程pid*/ PPid: 7672 /*父进程的pid*/ TracerPid: 0 /*跟踪进程的pid*/ Uid: 1000 1000 1000 1000 /*uid euid suid fsuid*/ Gid: 1000 1000 1000 1000 /*gid egid sgid fsgid*/ FDSize: 256 /*文件描述符的最大个数,file->fds*/ Groups: 0 4 20 24 25 29 30 44 46 107 109 115 124 1000 /*启动该进程的用户所属的组的id*/ VmPeak: 60184 kB /*进程地址空间的大小*/ VmSize: 60180 kB /*进程虚拟地址空间的大小reserved_vm:进程在预留或特殊的内存间的物理页*/ VmLck: 0 kB /*进程已经锁住的物理内存的大小.锁住的物理内存不能交换到硬盘*/ VmHWM: 18020 kB /*文件内存映射和匿名内存映射的大小*/ VmRSS: 18020 kB /*应用程序正在使用的物理内存的大小,就是用ps命令的参数rss的值 (rss)*/ VmData: 12240 kB /*程序数据段的大小(所占虚拟内存的大小),存放初始化了的数据*/ VmStk: 84 kB /*进程在用户态的栈的大小*/ VmExe: 576 kB /*程序所拥有的可执行虚拟内存的大小,代码段,不包括任务使用的库 */ VmLib: 21072 kB /*被映像到任务的虚拟内存空间的库的大小*/ VmPTE: 56 kB /*该进程的所有页表的大小*/ Threads: 1 /*共享使用该信号描述符的任务的个数*/ SigQ: 0/8183 /*待处理信号的个数/目前最大可以处理的信号的个数*/ SigPnd: 0000000000000000 /*屏蔽位,存储了该线程的待处理信号*/ ShdPnd: 0000000000000000 /*屏蔽位,存储了该线程组的待处理信号*/ SigBlk: 0000000000000000 /*存放被阻塞的信号*/ SigIgn: 0000000000001000 /*存放被忽略的信号*/ SigCgt: 0000000180000000 /*存放被俘获到的信号*/ CapInh: 0000000000000000 /*能被当前进程执行的程序的继承的能力*/ CapPrm: 0000000000000000 /*进程能够使用的能力,可以包含CapEff中没有的能力,这些能力是被进程自己临时放弃的*/ CapEff: 0000000000000000 /*是CapPrm的一个子集,进程放弃没有必要的能力有利于提高安全性*/ Cpus_allowed: 01 /*可以执行该进程的CPU掩码集*/ Mems_allowed: 1 /**/ voluntary_ctxt_switches: 1241 /*进程主动切换的次数*/ nonvoluntary_ctxt_switches: 717 /*进程被动切换的次数*/
int proc_pid_status(struct task_struct *task, char *buffer) { char *orig = buffer; struct mm_struct *mm = get_task_mm(task); buffer = task_name(task, buffer); buffer = task_state(task, buffer); if (mm) { buffer = task_mem(mm, buffer); mmput(mm); } buffer = task_sig(task, buffer); buffer = task_cap(task, buffer); buffer = cpuset_task_status_allowed(task, buffer); #if defined(CONFIG_S390) buffer = task_show_regs(task, buffer); #endif buffer = task_context_switch_counts(task, buffer); return buffer - orig; }
12.mounts文件
该文件包含该系统挂在的文件系统的信息。该文件在/proc下和每个进程文件夹下都有,并且内容一样。
niutao@niutao-desktop:/proc/1$ cat mounts rootfs / rootfs rw 0 0 none /sys sysfs rw,nosuid,nodev,noexec 0 0 none /proc proc rw,nosuid,nodev,noexec 0 0 udev /dev tmpfs rw,relatime 0 0 fusectl /sys/fs/fuse/connections fusectl rw,relatime 0 0 /dev/disk/by-uuid/f9f21592-a8a3-4e61-ac3d-0c7b7aa2cd42 / ext3 rw,relatime,errors=remount-ro,data=ordered 0 0 /dev/disk/by-uuid/f9f21592-a8a3-4e61-ac3d-0c7b7aa2cd42 /dev/.static/dev ext3 rw,relatime,errors=remount-ro,data=ordered 0 0 ....
13.io文件
niutao@niutao-desktop:/proc/1$ cat io rchar: 14699 /*task_struct->rchar*/ wchar: 20553017 /*task_struct->wchar*/ syscr: 350 /*task_struct->syscr*/ syscw: 1128 /*task_struct->syscw,*/ read_bytes: 1605632 /*task_struct->ioac.read_bytes*/ write_bytes: 0 /*task_struct->ioac.write_bytes*/ cancelled_write_bytes: 0 /*task_struct->ioac.cancelled_write_bytes*/
from:
http://www.kerneltravel.net/?p=285
http://www.kerneltravel.net/?p=287
http://www.kerneltravel.net/?p=291
http://www.kerneltravel.net/?p=294