最近在做一个项目,需要内核监控一个本机用户进程cpu占用率, 当时考虑有以下几种方法:
1. 使用ps命令获取

方法简单,直接执行命令,再过滤就行。但是从内核调用命令,查了一下,好像Linux可以使用call_usermodehelper,使内核调用用户态的程序,具体的解释在这里~ http://www.cnblogs.com/hoys/archive/2012/03/13/2395232.html。 但是对FreeBSD而言,好像就没有这样的好用的接口。
2. 
直接调用函数

既然ps是一个用户命令,实际起作用的应该是内核的动作,如果直接调用内核相应的函数,问题不就解决了?好像这是正解,继续分析~

首先,看了下ps的实现原理:

 ps -- process status, 它的主要文件是usr\src\usr.bin\procstat\Procstat.c, 在main函数中,我们看到ps实际上是通过函数 p = procstat_getprocs(prstat, KERN_PROC_PROC, 0, &cnt);

来打印进程信息的。而函数 procstat_getprocs是调用sysctl从内核中获取进程信息,继续跟踪~
入核了!
static SYSCTL_NODE(_kern_proc, KERN_PROC_PROC, proc, CTLFLAG_RD | CTLFLAG_MPSAFE,sysctl_kern_proc, "Return process table, no threads");发现该sysctl实际的处理函数为sysctl_kern_proc。
随后的调用关系就是sysctl_kern_proc -> sysctl_out_proc -> kern_proc_out -> fill_kinfo_proc。
注意!从
sysctl_out_proc开始,进程变量struct proc *p是作为一个参数传递数据。因此,只要我们能够得到进程变量p,就可以调用以后的函数获得它的信息。最后写的函数


点击(此处)折叠或打开

  1. int get_kinfo_by_comm(char *comm, struct kinfo_proc *ki) 
  2. {
  3.     struct proc *p; int find = 0;
  4.     sx_slock(&allproc_lock); 
  5.     FOREACH_PROC_IN_SYSTEM(p) { 
  6.     if (strcmp(p->p_comm, comm) == 0) { 
  7.         find = 1; break; 
  8.     } 
  9.     }
  10.     sx_sunlock(&allproc_lock); 
  11.     if (find) { 
  12.         PROC_LOCK_ASSERT(p, MA_OWNED); 
  13.         MPASS(FIRST_THREAD_IN_PROC(p) != NULL);
  14.         fill_kinfo_proc(p, ki); 
  15.         return 0;
  16.     }
  17.     return 1;
  18. }
该函数使用进程变量p的commands, 遍历系统中所有的进程,找到相应的p,然后调用fill_kinfo_proc把proc中的信息存在kinfo中。
02-12 09:47