我们首先再proc
结构体中添加一个数据字段,用于保存trace
的参数。并在sys_trace()
的实现中实现参数的保存
// kernel/proc.h
struct proc {
// ...
int trace_mask; // trace系统调用参数
};
// kernel/sysproc.c
uint64
sys_trace(void)
{
// 获取系统调用的参数
argint(0, &(myproc()->trace_mask));
return 0;
}
由于struct proc
中增加了一个新的变量,当fork
的时候我们也需要将这个变量传递到子进程中
//kernel/proc.c
int
fork(void)
{
// ...
safestrcpy(np->name, p->name, sizeof(p->name));
//将trace_mask拷贝到子进程
np->trace_mask = p->trace_mask;
pid = np->pid;
// ...
return pid;
}
接下来应当考虑如何进行系统调用追踪了,根据提示,这将在syscall()
函数中实现。
void
syscall(void)
{
int num;
struct proc *p = myproc();
num = p->trapframe->a7; // 系统调用编号,参见书中4.3节
if(num > 0 && num < NELEM(syscalls) && syscalls[num]) {
p->trapframe->a0 = syscalls[num](); // 执行系统调用,然后将返回值存入a0
// 系统调用是否匹配
if ((1 << num) & p->trace_mask)
printf("%d: syscall %s -> %d\\n", p->pid, syscalls_name[num], p->trapframe->a0);
} else {
printf("%d %s: unknown sys call %d\\n",
p->pid, p->name, num);
p->trapframe->a0 = -1;
}
}
还需要在syscall.c中定义一些变量
// ...
extern uint64 sys_trace(void);
static uint64 (*syscalls[])(void) = {
// ...
[SYS_trace] sys_trace,
};
static char *syscalls_name[] = {
[SYS_fork] "fork",
[SYS_exit] "exit",
[SYS_wait] "wait",
[SYS_pipe] "pipe",
[SYS_read] "read",
[SYS_kill] "kill",
[SYS_exec] "exec",
[SYS_fstat] "fstat",
[SYS_chdir] "chdir",
[SYS_dup] "dup",
[SYS_getpid] "getpid",
[SYS_sbrk] "sbrk",
[SYS_sleep] "sleep",
[SYS_uptime] "uptime",
[SYS_open] "open",
[SYS_write] "write",
[SYS_mknod] "mknod",
[SYS_unlink] "unlink",
[SYS_link] "link",
[SYS_mkdir] "mkdir",
[SYS_close] "close",
[SYS_trace] "trace",
};
我们在 kernel/proc.c 中新增函数 nproc
如下,通过该函数以获取可用进程数目:
uint64
nproc(void)
{
struct proc *p;
uint64 num = 0;
for (p = proc; p < &proc[NPROC]; p++)
{
acquire(&p->lock);
if (p->state != UNUSED)
{
num++;
}
release(&p->lock);
}
return num;
}
接下来我们来实现获取空闲内存数量的函数。可用空间的判断在kernel/kalloc.c文件中。这里定义了一个链表,每个链表都指向上一个可用空间,这里的 kmem
就是一个保存最后链表的变量。
struct run {
struct run *next;
};
struct {
struct spinlock lock;
struct run *freelist;
} kmem;
在 kernel/kalloc.c 中新增函数 free_mem
,以获取空闲内存数量:
uint64
free_mem(void)
{
struct run *r;
uint64 num = 0;
acquire(&kmem.lock);
r = kmem.freelist;
while (r)
{
num++;
r = r->next;
}
release(&kmem.lock);
return num * PGSIZE;
}
我们在 kernel/sysproc.c 文件中添加 sys_sysinfo
函数的具体实现如下:
uint64
sys_sysinfo(void)
{
uint64 addr;
struct sysinfo info;
struct proc *p = myproc();
// 使用argint获取用户空间地址
argint(0, (int*)&addr);
// 检查地址是否有效
if (addr == 0)
return -1;
info.freemem = free_mem();
info.nproc = nproc();
if (copyout(p->pagetable, addr, (char *)&info, sizeof(info)) < 0)
return -1;
return 0;
}
最后在 user 目录下添加一个 sysinfo.c 用户程序:
#include "kernel/param.h"
#include "kernel/types.h"
#include "kernel/sysinfo.h"
#include "user/user.h"
int
main(int argc, char *argv[])
{
// param error
if (argc != 1)
{
fprintf(2, "Usage: %s need not param\\n", argv[0]);
exit(1);
}
struct sysinfo info;
sysinfo(&info);
// print the sysinfo
printf("free space: %d\\nused process: %d\\n", info.freemem, info.nproc);
exit(0);
}