diff --git a/Makefile b/Makefile index b262c0a24e..b247097811 100644 --- a/Makefile +++ b/Makefile @@ -137,6 +137,7 @@ UPROGS=\ $U/_mkdir\ $U/_rm\ $U/_sh\ + $U/_sleep\ $U/_stressfs\ $U/_usertests\ $U/_grind\ @@ -145,6 +146,7 @@ UPROGS=\ $U/_logstress\ $U/_forphan\ $U/_dorphan\ + $U/_ps\ fs.img: mkfs/mkfs README $(UPROGS) mkfs/mkfs fs.img README $(UPROGS) diff --git a/kernel/defs.h b/kernel/defs.h index 122d9cae89..da0a09c52f 100644 --- a/kernel/defs.h +++ b/kernel/defs.h @@ -96,6 +96,7 @@ void sched(void); void sleep(void*, struct spinlock*); void userinit(void); int kwait(uint64); +int kps(uint64, int); void wakeup(void*); void yield(void); int either_copyout(int user_dst, uint64 dst, void *src, uint64 len); diff --git a/kernel/proc.c b/kernel/proc.c index 22a5401903..06f7339fdc 100644 --- a/kernel/proc.c +++ b/kernel/proc.c @@ -4,6 +4,7 @@ #include "riscv.h" #include "spinlock.h" #include "proc.h" +#include "ps.h" #include "defs.h" struct cpu cpus[NCPU]; @@ -688,3 +689,40 @@ procdump(void) printf("\n"); } } + +// Copy process info to userspace. +// Iterate through proc table and copy RUNNABLE/RUNNING/SLEEPING processes. +// Returns number of processes copied, or -1 on error. +int +kps(uint64 addr, int max) +{ + if(max < 0 || max > 256) + return -1; + + struct proc *cur = myproc(); + struct proc *p; + int n = 0; + + for(p = proc; p < &proc[NPROC] && n < max; p++){ + struct pinfo pi; + int include = 0; + + acquire(&p->lock); + if(p->state == SLEEPING || p->state == RUNNABLE || p->state == RUNNING){ + pi.pid = p->pid; + pi.state = p->state; + pi.sz = p->sz; + safestrcpy(pi.name, p->name, sizeof(pi.name)); + include = 1; + } + release(&p->lock); + + if(include){ + if(copyout(cur->pagetable, addr + n * sizeof(pi), (char *)&pi, sizeof(pi)) < 0) + return -1; + n++; + } + } + + return n; +} diff --git a/kernel/ps.h b/kernel/ps.h new file mode 100644 index 0000000000..966e9850da --- /dev/null +++ b/kernel/ps.h @@ -0,0 +1,18 @@ +#ifndef _KERNEL_PS_H_ +#define _KERNEL_PS_H_ + +#define PS_NAME_LEN 16 + +// Matches enum procstate in proc.h +#define PS_SLEEPING 2 +#define PS_RUNNABLE 3 +#define PS_RUNNING 4 + +struct pinfo { + int pid; + int state; + uint64 sz; + char name[PS_NAME_LEN]; +}; + +#endif diff --git a/kernel/syscall.c b/kernel/syscall.c index 076d9659a3..794ea867d0 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -101,6 +101,7 @@ extern uint64 sys_unlink(void); extern uint64 sys_link(void); extern uint64 sys_mkdir(void); extern uint64 sys_close(void); +extern uint64 sys_ps(void); // An array mapping syscall numbers from syscall.h // to the function that handles the system call. @@ -126,6 +127,7 @@ static uint64 (*syscalls[])(void) = { [SYS_link] sys_link, [SYS_mkdir] sys_mkdir, [SYS_close] sys_close, +[SYS_ps] sys_ps, }; void diff --git a/kernel/syscall.h b/kernel/syscall.h index 3dd926d668..50217dbcfd 100644 --- a/kernel/syscall.h +++ b/kernel/syscall.h @@ -20,3 +20,4 @@ #define SYS_link 19 #define SYS_mkdir 20 #define SYS_close 21 +#define SYS_ps 22 diff --git a/kernel/sysproc.c b/kernel/sysproc.c index 419e727985..29b06c8bce 100644 --- a/kernel/sysproc.c +++ b/kernel/sysproc.c @@ -36,6 +36,17 @@ sys_wait(void) return kwait(p); } +uint64 +sys_ps(void) +{ + uint64 p; + int max; + + argaddr(0, &p); + argint(1, &max); + return kps(p, max); +} + uint64 sys_sbrk(void) { diff --git a/user/ps.c b/user/ps.c new file mode 100644 index 0000000000..abee6c145b --- /dev/null +++ b/user/ps.c @@ -0,0 +1,39 @@ +#include "kernel/types.h" +#include "kernel/ps.h" +#include "user/user.h" + +#define MAX_PROCS 64 + +static char * +state_name(int s) +{ + switch(s){ + case PS_SLEEPING: + return "sleep"; + case PS_RUNNABLE: + return "runnable"; + case PS_RUNNING: + return "running"; + default: + return "?"; + } +} + +int +main(void) +{ + struct pinfo list[MAX_PROCS]; + int n = ps(list, MAX_PROCS); + + if(n < 0){ + fprintf(2, "ps: syscall failed\n"); + exit(1); + } + + printf("PID\tSTATE\t\tSIZE(KB)\tNAME\n"); + for(int i = 0; i < n; i++){ + printf("%d\t%s\t\t%ld\t\t%s\n", list[i].pid, state_name(list[i].state), list[i].sz / 1024, list[i].name); + } + + exit(0); +} diff --git a/user/sleep.c b/user/sleep.c new file mode 100644 index 0000000000..2a93b71857 --- /dev/null +++ b/user/sleep.c @@ -0,0 +1,18 @@ +#include "kernel/types.h" +#include "user/user.h" + +int +main(int argc, char *argv[]) +{ + int i; + + if(argc < 2){ + fprintf(2, "usage: sleep seconds\n"); + exit(1); + } + i = atoi(argv[1]); + if(i < 0) + i = 0; + pause(i * 100); + exit(0); +} diff --git a/user/user.h b/user/user.h index ac84de9609..6e334f6cad 100644 --- a/user/user.h +++ b/user/user.h @@ -1,5 +1,6 @@ #define SBRK_ERROR ((char *)-1) +struct pinfo; struct stat; // system calls @@ -24,6 +25,7 @@ int getpid(void); char* sys_sbrk(int,int); int pause(int); int uptime(void); +int ps(struct pinfo*, int); // ulib.c int stat(const char*, struct stat*); diff --git a/user/usys.pl b/user/usys.pl index c5d4c3a750..65e729ba71 100755 --- a/user/usys.pl +++ b/user/usys.pl @@ -42,3 +42,4 @@ sub entry { entry("sbrk"); entry("pause"); entry("uptime"); +entry("ps");