最近在做一个项目,需要内核监控一个本机用户进程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,就可以调用以后的函数获得它的信息。最后写的函数
点击(此处)折叠或打开
- 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;
- }