最近在做一个项目,需要内核监控一个本机用户进程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是调用<span style="font-family: song, Verdana;">sysctl从内核中获取进程信息。
<span style="font-family: Arial, Helvetica, sans-serif;">入核了!</span>
<span style="font-family: Arial, Helvetica, sans-serif;">static SYSCTL_NODE(_kern_proc, KERN_PROC_PROC, proc, CTLFLAG_RD | CTLFLAG_MPSAFE,</span>
sysctl_kern_proc, "Return process table, no threads");
通过sysctl的定义,我们发现实际的处理函数为
sysctl_kern_proc。
随后的调用关系就是sysctl_kern_proc -> sysctl_out_proc -> kern_proc_out -> fill_kinfo_proc
从 <span style="font-family: Arial, Helvetica, sans-serif;">sysctl_out_proc开始,进程变量struct proc *p是作为一个参数传递数据。因此,只要我们能够得到p,就可以调用以后的函数获得它的信息。</span>
<span style="font-family:Arial, Helvetica, sans-serif;">最后写的函数</span>
<span style="font-family:Arial, Helvetica, sans-serif;"></span><pre name="code" class="cpp">int get_kinfo_by_comm(char *comm, struct kinfo_proc *ki)
{
struct proc *p;
int find = 0;
sx_slock(&allproc_lock);
FOREACH_PROC_IN_SYSTEM(p) {
if (strcmp(p->p_comm, comm) == 0) {
find = 1;
break;
}
}
sx_sunlock(&allproc_lock);
if (find) {
PROC_LOCK_ASSERT(p, MA_OWNED);
MPASS(FIRST_THREAD_IN_PROC(p) != NULL);
fill_kinfo_proc(p, ki);
return 0;
}
return 1;
}
该函数使用p的commands, 反找相应的p,然后调用
fill_kinfo_proc
把proc中的信息存在kinfo中。