diff --git a/Makefile b/Makefile index 8bc60d9..034219f 100644 --- a/Makefile +++ b/Makefile @@ -195,6 +195,7 @@ UPROGS=\ $U/_find\ $U/_xargs\ $U/_trace\ + $U/_sysinfotest\ diff --git a/kernel/defs.h b/kernel/defs.h index f3f5fef..2c07dbe 100644 --- a/kernel/defs.h +++ b/kernel/defs.h @@ -63,6 +63,7 @@ void ramdiskrw(struct buf *); void *kalloc(void); void kfree(void *); void kinit(void); +int freemem(void); // log.c void initlog(int, struct superblock *); @@ -106,6 +107,7 @@ void yield(void); int either_copyout(int user_dst, uint64 dst, void *src, uint64 len); int either_copyin(void *dst, int user_src, uint64 src, uint64 len); void procdump(void); +int proc_size(void); // swtch.S void swtch(struct context *, struct context *); diff --git a/kernel/kalloc.c b/kernel/kalloc.c index 0699e7e..8509864 100644 --- a/kernel/kalloc.c +++ b/kernel/kalloc.c @@ -7,6 +7,7 @@ #include "memlayout.h" #include "spinlock.h" #include "riscv.h" +#include "proc.h" #include "defs.h" void freerange(void *pa_start, void *pa_end); @@ -80,3 +81,17 @@ kalloc(void) memset((char*)r, 5, PGSIZE); // fill with junk return (void*)r; } + +int +freemem(void) +{ + struct run* p = kmem.freelist; + uint64 num = 0; + while (p) { + num += 1; + p = p->next; + } + return num * PGSIZE; +} + + diff --git a/kernel/proc.c b/kernel/proc.c index db97edc..863b57d 100644 --- a/kernel/proc.c +++ b/kernel/proc.c @@ -691,3 +691,13 @@ procdump(void) printf("\n"); } } + +int +proc_size() +{ + int i =0, n = 0; + for (; i < NPROC; ++i) { + if (proc[i].state != UNUSED) n += 1; + } + return n; +} diff --git a/kernel/syscall.c b/kernel/syscall.c index 9d267af..ad511e1 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -8,9 +8,9 @@ #include "defs.h" // 保留系统调用别名 -char* syscalls_name[24] = {"", "fork", "exit", "wait", "pipe", "read", "kill", "exec", +char* syscalls_name[25] = {"", "fork", "exit", "wait", "pipe", "read", "kill", "exec", "fstat", "chdir", "dup", "getpid", "sbrk", "sleep", "uptime", - "open", "write", "mknod", "unlink", "link", "mkdir", "close", "trace"}; + "open", "write", "mknod", "unlink", "link", "mkdir", "close", "trace", "sysinfo"}; // Fetch the uint64 at addr from the current process. int @@ -107,6 +107,7 @@ extern uint64 sys_link(void); extern uint64 sys_mkdir(void); extern uint64 sys_close(void); extern uint64 sys_trace(void); +extern uint64 sys_sysinfo(void); // An array mapping syscall numbers from syscall.h // to the function that handles the system call. @@ -133,6 +134,7 @@ static uint64 (*syscalls[])(void) = { [SYS_mkdir] sys_mkdir, [SYS_close] sys_close, [SYS_trace] sys_trace, +[SYS_sysinfo] sys_sysinfo, }; void diff --git a/kernel/syscall.h b/kernel/syscall.h index cc112b9..0dfedc7 100644 --- a/kernel/syscall.h +++ b/kernel/syscall.h @@ -21,3 +21,4 @@ #define SYS_mkdir 20 #define SYS_close 21 #define SYS_trace 22 +#define SYS_sysinfo 23 diff --git a/kernel/sysinfo.h b/kernel/sysinfo.h new file mode 100644 index 0000000..670db98 --- /dev/null +++ b/kernel/sysinfo.h @@ -0,0 +1,6 @@ +#include "kernel/types.h" +struct sysinfo { + uint64 freemem; + uint64 nproc; + uint64 unused_proc_num; +}; diff --git a/kernel/sysproc.c b/kernel/sysproc.c index 46af86b..ddad0ea 100644 --- a/kernel/sysproc.c +++ b/kernel/sysproc.c @@ -5,6 +5,7 @@ #include "memlayout.h" #include "spinlock.h" #include "proc.h" +#include "sysinfo.h" uint64 sys_exit(void) @@ -101,3 +102,19 @@ sys_trace(void) myproc()->tracemask = n; return 0; } + +uint64 +sys_sysinfo(void) +{ + struct sysinfo info; + uint64 addr; + argaddr(0, &addr); + if (addr < 0) return -1; + struct proc* p = myproc(); + info.nproc = proc_size(); + info.freemem = freemem(); + info.unused_proc_num = NPROC - info.nproc; + if (copyout(p->pagetable, addr, (char*)&info, sizeof(info)) < 0) + return -1; + return 0; +} diff --git a/user/sysinfotest.c b/user/sysinfotest.c new file mode 100644 index 0000000..c6d6f6f --- /dev/null +++ b/user/sysinfotest.c @@ -0,0 +1,164 @@ +#include "kernel/types.h" +#include "kernel/riscv.h" +/*#include "kernel/sysinfo.h"*/ +#include "user/user.h" + + +void +sinfo(struct sysinfo *info) { + if (sysinfo(info) < 0) { + printf("FAIL: sysinfo failed"); + exit(1); + } +} + +// +// use sbrk() to count how many free physical memory pages there are. +// +int +countfree() +{ + uint64 sz0 = (uint64)sbrk(0); + struct sysinfo info; + int n = 0; + + while(1){ + if((uint64)sbrk(PGSIZE) == 0xffffffffffffffff){ + break; + } + n += PGSIZE; + } + sinfo(&info); + if (info.freemem != 0) { + printf("FAIL: there is no free mem, but sysinfo.freemem=%d\n", + info.freemem); + exit(1); + } + sbrk(-((uint64)sbrk(0) - sz0)); + return n; +} + +void +testmem() { + struct sysinfo info; + uint64 n = countfree(); + + sinfo(&info); + + if (info.freemem!= n) { + printf("FAIL: free mem %d (bytes) instead of %d\n", info.freemem, n); + exit(1); + } + + if((uint64)sbrk(PGSIZE) == 0xffffffffffffffff){ + printf("sbrk failed"); + exit(1); + } + + sinfo(&info); + + if (info.freemem != n-PGSIZE) { + printf("FAIL: free mem %d (bytes) instead of %d\n", n-PGSIZE, info.freemem); + exit(1); + } + + if((uint64)sbrk(-PGSIZE) == 0xffffffffffffffff){ + printf("sbrk failed"); + exit(1); + } + + sinfo(&info); + + if (info.freemem != n) { + printf("FAIL: free mem %d (bytes) instead of %d\n", n, info.freemem); + exit(1); + } +} + +void +testcall() { + struct sysinfo info; + + if (sysinfo(&info) < 0) { + printf("FAIL: sysinfo failed\n"); + exit(1); + } + + if (sysinfo((struct sysinfo *) 0xeaeb0b5b00002f5e) != 0xffffffffffffffff) { + printf("FAIL: sysinfo succeeded with bad argument\n"); + exit(1); + } +} + +void testproc() { + struct sysinfo info; + uint64 nproc, unused_proc_num; + int status; + int pid; + + sinfo(&info); + nproc = info.nproc; + unused_proc_num = info.unused_proc_num; + + pid = fork(); + if(pid < 0){ + printf("sysinfotest: fork failed\n"); + exit(1); + } + if(pid == 0){ + sinfo(&info); + if(info.nproc != nproc+1) { + printf("sysinfotest: FAIL nproc is %d instead of %d\n", info.nproc, nproc+1); + exit(1); + } + + if(info.unused_proc_num != unused_proc_num-1) { + printf("sysinfotest: FAIL unused_proc_num is %d instead of %d\n", info.unused_proc_num, unused_proc_num-1); + exit(1); + } + exit(0); + } + wait(&status); + sinfo(&info); + if(info.nproc != nproc) { + printf("sysinfotest: FAIL nproc is %d instead of %d\n", info.nproc, nproc); + exit(1); + } + if(info.unused_proc_num != unused_proc_num) { + printf("sysinfotest: FAIL unused_proc_num is %d instead of %d\n", info.unused_proc_num, unused_proc_num); + exit(1); + } +} + +void testbad() { + int pid = fork(); + int xstatus; + + if(pid < 0){ + printf("sysinfotest: fork failed\n"); + exit(1); + } + if(pid == 0){ + sinfo(0x0); + exit(0); + } + wait(&xstatus); + if(xstatus == -1) // kernel killed child? + exit(0); + else { + printf("sysinfotest: testbad succeeded %d\n", xstatus); + exit(xstatus); + } +} + +int +main(int argc, char *argv[]) +{ + printf("sysinfotest: start\n"); + testcall(); + testmem(); + testproc(); + printf("sysinfotest: OK\n"); + exit(0); +} + diff --git a/user/user.h b/user/user.h index 36603a0..2af28d8 100644 --- a/user/user.h +++ b/user/user.h @@ -1,4 +1,5 @@ #include "kernel/types.h" +#include "kernel/sysinfo.h" struct stat; // system calls @@ -24,6 +25,7 @@ char *sbrk(int); int sleep(int); int uptime(void); int trace(int); +int sysinfo(struct sysinfo*); // ulib.c int stat(const char *, struct stat *); diff --git a/user/usys.pl b/user/usys.pl index 9c97b05..bc109fd 100755 --- a/user/usys.pl +++ b/user/usys.pl @@ -37,3 +37,4 @@ entry("sbrk"); entry("sleep"); entry("uptime"); entry("trace"); +entry("sysinfo");