Compare commits

..

5 Commits

Author SHA1 Message Date
catfood
8de6f45af1 lab util grade 100 2023-01-05 17:03:50 +08:00
Frans Kaashoek
dc9153fcb9 Fix year 2022-09-19 09:27:22 -04:00
Frans Kaashoek
4d7493893d 2022 submission site 2022-08-28 10:18:51 -04:00
Frans Kaashoek
0c477a6c84 Merge branch 'riscv' into util 2022-08-25 13:52:48 -04:00
Frans Kaashoek
7d47335b4f Util lab 2022-08-23 14:40:09 -04:00
29 changed files with 349 additions and 400 deletions

View File

@ -188,8 +188,11 @@ UPROGS=\
$U/_grind\ $U/_grind\
$U/_wc\ $U/_wc\
$U/_zombie\ $U/_zombie\
$U/_trace\ $U/_sleep\
$U/_sysinfotest\ $U/_pingpong\
$U/_primes\
$U/_find\
$U/_xargs\

36
README
View File

@ -6,7 +6,7 @@ ACKNOWLEDGMENTS
xv6 is inspired by John Lions's Commentary on UNIX 6th Edition (Peer xv6 is inspired by John Lions's Commentary on UNIX 6th Edition (Peer
to Peer Communications; ISBN: 1-57398-013-7; 1st edition (June 14, to Peer Communications; ISBN: 1-57398-013-7; 1st edition (June 14,
2000)). See also https://pdos.csail.mit.edu/6.1810/, which provides 2000)). See also https://pdos.csail.mit.edu/6.828/, which provides
pointers to on-line resources for v6. pointers to on-line resources for v6.
The following people have made contributions: Russ Cox (context switching, The following people have made contributions: Russ Cox (context switching,
@ -14,31 +14,29 @@ locking), Cliff Frey (MP), Xiao Yu (MP), Nickolai Zeldovich, and Austin
Clements. Clements.
We are also grateful for the bug reports and patches contributed by We are also grateful for the bug reports and patches contributed by
Takahiro Aoyagi, Silas Boyd-Wickizer, Anton Burtsev, carlclone, Ian Takahiro Aoyagi, Silas Boyd-Wickizer, Anton Burtsev, Ian Chen, Dan
Chen, Dan Cross, Cody Cutler, Mike CAT, Tej Chajed, Asami Doi, Cross, Cody Cutler, Mike CAT, Tej Chajed, Asami Doi, eyalz800, Nelson
eyalz800, Nelson Elhage, Saar Ettinger, Alice Ferrazzi, Nathaniel Elhage, Saar Ettinger, Alice Ferrazzi, Nathaniel Filardo, flespark,
Filardo, flespark, Peter Froehlich, Yakir Goaron, Shivam Handa, Matt Peter Froehlich, Yakir Goaron, Shivam Handa, Matt Harvey, Bryan Henry,
Harvey, Bryan Henry, jaichenhengjie, Jim Huang, Matúš Jókay, John jaichenhengjie, Jim Huang, Matúš Jókay, Alexander Kapshuk, Anders
Jolly, Alexander Kapshuk, Anders Kaseorg, kehao95, Wolfgang Keller, Kaseorg, kehao95, Wolfgang Keller, Jungwoo Kim, Jonathan Kimmitt,
Jungwoo Kim, Jonathan Kimmitt, Eddie Kohler, Vadim Kolontsov, Austin Eddie Kohler, Vadim Kolontsov, Austin Liew, l0stman, Pavan
Liew, l0stman, Pavan Maddamsetti, Imbar Marinescu, Yandong Mao, Matan Maddamsetti, Imbar Marinescu, Yandong Mao, Matan Shabtay, Hitoshi
Shabtay, Hitoshi Mitake, Carmi Merimovich, Mark Morrissey, mtasm, Joel Mitake, Carmi Merimovich, Mark Morrissey, mtasm, Joel Nider,
Nider, Hayato Ohhashi, OptimisticSide, Harry Porter, Greg Price, Jude OptimisticSide, Greg Price, Jude Rich, Ayan Shafqat, Eldar Sehayek,
Rich, segfault, Ayan Shafqat, Eldar Sehayek, Yongming Shen, Fumiya Yongming Shen, Fumiya Shigemitsu, Cam Tenny, tyfkda, Warren Toomey,
Shigemitsu, Cam Tenny, tyfkda, Warren Toomey, Stephen Tu, Rafael Ubal, Stephen Tu, Rafael Ubal, Amane Uehara, Pablo Ventura, Xi Wang, Keiichi
Amane Uehara, Pablo Ventura, Xi Wang, WaheedHafez, Keiichi Watanabe, Watanabe, Nicolas Wolovick, wxdao, Grant Wu, Jindong Zhang, Icenowy
Nicolas Wolovick, wxdao, Grant Wu, Jindong Zhang, Icenowy Zheng, Zheng, ZhUyU1997, and Zou Chang Wei.
ZhUyU1997, and Zou Chang Wei.
The code in the files that constitute xv6 is The code in the files that constitute xv6 is
Copyright 2006-2022 Frans Kaashoek, Robert Morris, and Russ Cox. Copyright 2006-2020 Frans Kaashoek, Robert Morris, and Russ Cox.
ERROR REPORTS ERROR REPORTS
Please send errors and suggestions to Frans Kaashoek and Robert Morris Please send errors and suggestions to Frans Kaashoek and Robert Morris
(kaashoek,rtm@mit.edu). The main purpose of xv6 is as a teaching (kaashoek,rtm@mit.edu). The main purpose of xv6 is as a teaching
operating system for MIT's 6.1810, so we are more interested in operating system for MIT's 6.S081, so we are more interested in
simplifications and clarifications than new features. simplifications and clarifications than new features.
BUILDING AND RUNNING XV6 BUILDING AND RUNNING XV6

View File

@ -1,17 +0,0 @@
Q: Looking at the backtrace output, which function called syscall?
A: usertrap
Q: What is the value of p->trapframe->a7 and what does that value represent?
A: a7 is 0x7. It represents the number of syscall SYS_exec.
Q: What was the previous mode that the CPU was in?
A: $sstatus is now 0x22, which is 0b0000_0010_0010, with SPP(bit-8) 0, so its previous privilege is User Mode.
Q: Write down the assembly instruction the kernel is panicing at. Which register corresponds to the varialable num?
A: The kernel is panicing at instruct `lw a3,0(zero)` at 0x80001ff6. The register corresponding to the variable num is a3.
Q: Why does the kernel crash? Hint: look at figure 3-3 in the text; is address 0 mapped in the kernel address space? Is that confirmed by the value in scause above?
A: $scause is 0xd(13) which corresponds to 'Load page fault'. According to figure 3-3, this address is not mapped in the kernel address space, so this causes page fault.
Q: What is the name of the binary that was running when the kernel paniced? What is its process id (pid)?
A: The name of the binary is "initcode", and its pid is 1.

View File

@ -1 +1 @@
LAB=syscall LAB=util

View File

@ -1,69 +0,0 @@
#!/usr/bin/env python3
import re
from gradelib import *
r = Runner(save("xv6.out"))
@test(5, "answers-syscall.txt")
def test_answers():
# just a simple sanity check, will be graded manually
check_answers("answers-syscall.txt")
@test(5, "trace 32 grep")
def test_trace_32_grep():
r.run_qemu(shell_script([
'trace 32 grep hello README'
]))
r.match('^\\d+: syscall read -> 1023')
r.match('^\\d+: syscall read -> 961')
r.match('^\\d+: syscall read -> 321')
r.match('^\\d+: syscall read -> 0')
@test(5, "trace all grep")
def test_trace_all_grep():
r.run_qemu(shell_script([
'trace 2147483647 grep hello README'
]))
r.match('^\\d+: syscall trace -> 0')
r.match('^\\d+: syscall exec -> 3')
r.match('^\\d+: syscall open -> 3')
r.match('^\\d+: syscall read -> 1023')
r.match('^\\d+: syscall read -> 961')
r.match('^\\d+: syscall read -> 321')
r.match('^\\d+: syscall read -> 0')
r.match('^\\d+: syscall close -> 0')
@test(5, "trace nothing")
def test_trace_nothing():
r.run_qemu(shell_script([
'grep hello README'
]))
r.match(no=[".* syscall .*"])
@test(5, "trace children")
def test_trace_children():
r.run_qemu(shell_script([
'trace 2 usertests forkforkfork'
]))
r.match('3: syscall fork -> 4')
r.match('^5: syscall fork -> \\d+')
r.match('^6: syscall fork -> \\d+')
r.match('^\\d+: syscall fork -> -1')
r.match('^ALL TESTS PASSED')
@test(14, "sysinfotest")
def test_sysinfotest():
r.run_qemu(shell_script([
'sysinfotest'
]))
r.match('^sysinfotest: OK', no=[".* FAIL .*"])
@test(1, "time")
def test_time():
check_time()
run_tests()

86
grade-lab-util Executable file
View File

@ -0,0 +1,86 @@
#!/usr/bin/env python3
import re
from gradelib import *
r = Runner(save("xv6.out"))
@test(5, "sleep, no arguments")
def test_sleep_no_args():
r.run_qemu(shell_script([
'sleep'
]))
r.match(no=["exec .* failed", "$ sleep\n$"])
@test(5, "sleep, returns")
def test_sleep_no_args():
r.run_qemu(shell_script([
'sleep',
'echo OK'
]))
r.match('^OK$', no=["exec .* failed", "$ sleep\n$"])
@test(10, "sleep, makes syscall")
def test_sleep():
r.run_qemu(shell_script([
'sleep 10',
'echo FAIL'
]), stop_breakpoint('sys_sleep'))
r.match('\\$ sleep 10', no=['FAIL'])
@test(20, "pingpong")
def test_pingpong():
r.run_qemu(shell_script([
'pingpong', 'echo OK'
]))
r.match('^\\d+: received ping$', '^\\d+: received pong$', '^OK$')
@test(20, "primes")
def test_primes():
r.run_qemu(shell_script([
'primes', 'echo OK'
]))
args = ['prime %d' % i for i in [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31]]
args.append('^OK$')
r.match(*args)
@test(10, "find, in current directory")
def test_find_curdir():
fn = random_str()
r.run_qemu(shell_script([
'echo > %s' % fn,
'find . %s' % fn
]))
r.match('./%s' % fn)
@test(10, "find, recursive")
def test_find_recursive():
needle = random_str()
dirs = [random_str() for _ in range(3)]
r.run_qemu(shell_script([
'mkdir %s' % dirs[0],
'echo > %s/%s' % (dirs[0], needle),
'mkdir %s/%s' % (dirs[0], dirs[1]),
'echo > %s/%s/%s' % (dirs[0], dirs[1], needle),
'mkdir %s' % dirs[2],
'echo > %s/%s' % (dirs[2], needle),
'find . %s' % needle
]))
r.match('./%s/%s' % (dirs[0], needle),
'./%s/%s/%s' % (dirs[0], dirs[1], needle),
'./%s/%s' % (dirs[2], needle))
@test(19, "xargs")
def test_xargs():
r.run_qemu(shell_script([
'sh < xargstest.sh',
'echo DONE',
], 'DONE'))
matches = re.findall("hello", r.qemu.output)
assert_equal(len(matches), 3, "Number of appearances of 'hello'")
@test(1, "time")
def test_time():
check_time()
run_tests()

View File

@ -63,7 +63,6 @@ void ramdiskrw(struct buf*);
void* kalloc(void); void* kalloc(void);
void kfree(void *); void kfree(void *);
void kinit(void); void kinit(void);
int size_of_freemem(void);
// log.c // log.c
void initlog(int, struct superblock*); void initlog(int, struct superblock*);
@ -107,7 +106,6 @@ void yield(void);
int either_copyout(int user_dst, uint64 dst, void *src, uint64 len); int either_copyout(int user_dst, uint64 dst, void *src, uint64 len);
int either_copyin(void *dst, int user_src, uint64 src, uint64 len); int either_copyin(void *dst, int user_src, uint64 src, uint64 len);
void procdump(void); void procdump(void);
int number_of_process(void);
// swtch.S // swtch.S
void swtch(struct context*, struct context*); void swtch(struct context*, struct context*);

View File

@ -80,18 +80,3 @@ kalloc(void)
memset((char*)r, 5, PGSIZE); // fill with junk memset((char*)r, 5, PGSIZE); // fill with junk
return (void*)r; return (void*)r;
} }
int
size_of_freemem(void)
{
struct run *r;
int count = 0;
acquire(&kmem.lock);
r = kmem.freelist;
while (r) {
count ++;
r = r->next;
}
release(&kmem.lock);
return count * PGSIZE;
}

View File

@ -311,7 +311,7 @@ fork(void)
safestrcpy(np->name, p->name, sizeof(p->name)); safestrcpy(np->name, p->name, sizeof(p->name));
pid = np->pid; pid = np->pid;
np->tracemask = p->tracemask;
release(&np->lock); release(&np->lock);
acquire(&wait_lock); acquire(&wait_lock);
@ -681,14 +681,3 @@ procdump(void)
printf("\n"); printf("\n");
} }
} }
int
number_of_process(void)
{
struct proc *p;
int count = 0;
for (p = proc; p < &proc[NPROC]; p ++) {
if (p->state != UNUSED) count ++;
}
return count;
}

View File

@ -104,5 +104,4 @@ struct proc {
struct file *ofile[NOFILE]; // Open files struct file *ofile[NOFILE]; // Open files
struct inode *cwd; // Current directory struct inode *cwd; // Current directory
char name[16]; // Process name (debugging) char name[16]; // Process name (debugging)
int tracemask; // mask for syscall trace
}; };

View File

@ -101,8 +101,6 @@ extern uint64 sys_unlink(void);
extern uint64 sys_link(void); extern uint64 sys_link(void);
extern uint64 sys_mkdir(void); extern uint64 sys_mkdir(void);
extern uint64 sys_close(void); extern uint64 sys_close(void);
extern uint64 sys_trace(void);
extern uint64 sys_sysinfo(void);
// An array mapping syscall numbers from syscall.h // An array mapping syscall numbers from syscall.h
// to the function that handles the system call. // to the function that handles the system call.
@ -128,33 +126,6 @@ static uint64 (*syscalls[])(void) = {
[SYS_link] sys_link, [SYS_link] sys_link,
[SYS_mkdir] sys_mkdir, [SYS_mkdir] sys_mkdir,
[SYS_close] sys_close, [SYS_close] sys_close,
[SYS_trace] sys_trace,
[SYS_sysinfo] sys_sysinfo,
};
char syscall_name[][8] = {
[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",
}; };
void void
@ -168,8 +139,6 @@ syscall(void)
// Use num to lookup the system call function for num, call it, // Use num to lookup the system call function for num, call it,
// and store its return value in p->trapframe->a0 // and store its return value in p->trapframe->a0
p->trapframe->a0 = syscalls[num](); p->trapframe->a0 = syscalls[num]();
if ((1 << num) & p->tracemask)
printf("%d: syscall %s -> %d\n", p->pid, syscall_name[num], p->trapframe->a0);
} else { } else {
printf("%d %s: unknown sys call %d\n", printf("%d %s: unknown sys call %d\n",
p->pid, p->name, num); p->pid, p->name, num);

View File

@ -20,5 +20,3 @@
#define SYS_link 19 #define SYS_link 19
#define SYS_mkdir 20 #define SYS_mkdir 20
#define SYS_close 21 #define SYS_close 21
#define SYS_trace 22
#define SYS_sysinfo 23

View File

@ -1,4 +0,0 @@
struct sysinfo {
uint64 freemem; // amount of free memory (bytes)
uint64 nproc; // number of process
};

View File

@ -5,7 +5,6 @@
#include "memlayout.h" #include "memlayout.h"
#include "spinlock.h" #include "spinlock.h"
#include "proc.h" #include "proc.h"
#include "sysinfo.h"
uint64 uint64
sys_exit(void) sys_exit(void)
@ -56,8 +55,6 @@ sys_sleep(void)
uint ticks0; uint ticks0;
argint(0, &n); argint(0, &n);
if(n < 0)
n = 0;
acquire(&tickslock); acquire(&tickslock);
ticks0 = ticks; ticks0 = ticks;
while(ticks - ticks0 < n){ while(ticks - ticks0 < n){
@ -92,31 +89,3 @@ sys_uptime(void)
release(&tickslock); release(&tickslock);
return xticks; return xticks;
} }
uint64
sys_trace(void)
{
int mask;
argint(0, &mask);
acquire(&myproc()->lock);
myproc()->tracemask = mask;
release(&myproc()->lock);
return 0;
}
uint64
sys_sysinfo(void)
{
struct sysinfo info;
uint64 addr;
argaddr(0, &addr);
info.nproc = number_of_process();
info.freemem = size_of_freemem();
acquire(&myproc()->lock);
if(copyout(myproc()->pagetable, addr, (char *)&info, sizeof(info)) < 0){
release(&myproc()->lock);
return -1;
}
release(&myproc()->lock);
return 0;
}

View File

@ -1 +1 @@
3 6

View File

@ -1,6 +1,5 @@
#include "kernel/types.h" #include "kernel/types.h"
#include "kernel/stat.h" #include "kernel/stat.h"
#include "kernel/fcntl.h"
#include "user/user.h" #include "user/user.h"
char buf[512]; char buf[512];
@ -33,7 +32,7 @@ main(int argc, char *argv[])
} }
for(i = 1; i < argc; i++){ for(i = 1; i < argc; i++){
if((fd = open(argv[i], O_RDONLY)) < 0){ if((fd = open(argv[i], 0)) < 0){
fprintf(2, "cat: cannot open %s\n", argv[i]); fprintf(2, "cat: cannot open %s\n", argv[i]);
exit(1); exit(1);
} }

74
user/find.c Normal file
View File

@ -0,0 +1,74 @@
#include "kernel/types.h"
#include "user/user.h"
#include "kernel/stat.h"
#include "kernel/fs.h"
int fmtname(const char *path) {
int p;
for(p=strlen(path); p >= 0 && *(path + p) != '/'; p--);
p++;
return p;
}
void find(const char *path, const char* target) {
char buf[512], *p;
int fd;
struct dirent de;
struct stat st;
if((fd = open(path, 0)) < 0){
fprintf(2, "find: cannot open %s\n", path);
return;
}
if(fstat(fd, &st) < 0){
fprintf(2, "find: cannot stat %s\n", path);
close(fd);
return;
}
switch(st.type){
case T_DEVICE:
case T_FILE:
if (strcmp(path + fmtname(path), target) == 0) {
printf("%s\n", path);
}
break;
case T_DIR:
if (strcmp(path + fmtname(path), target) == 0) {
printf("%s\n", path);
}
if(strlen(path) + 1 + DIRSIZ + 1 > sizeof buf){
printf("find: path too long\n");
break;
}
strcpy(buf, path);
p = buf+strlen(buf);
*p++ = '/';
while(read(fd, &de, sizeof(de)) == sizeof(de)){
if(de.inum == 0)
continue;
if (strcmp(de.name, ".") == 0 || strcmp(de.name, "..") == 0)
continue;
memmove(p, de.name, DIRSIZ);
p[DIRSIZ] = 0;
if(stat(buf, &st) < 0){
printf("find: cannot stat %s\n", buf);
continue;
}
find(buf, target);
}
break;
}
close(fd);
}
int main(int argc, char** argv) {
if (argc != 3) {
printf("\x1b[31mInvalid arguments\x1b[0m\n");
printf("\x1b[32musage\x1b[0m: find <base directory> <file name to find>\n");
exit(0);
}
find(argv[1], argv[2]);
exit(0);
}

View File

@ -2,7 +2,6 @@
#include "kernel/types.h" #include "kernel/types.h"
#include "kernel/stat.h" #include "kernel/stat.h"
#include "kernel/fcntl.h"
#include "user/user.h" #include "user/user.h"
char buf[1024]; char buf[1024];
@ -52,7 +51,7 @@ main(int argc, char *argv[])
} }
for(i = 2; i < argc; i++){ for(i = 2; i < argc; i++){
if((fd = open(argv[i], O_RDONLY)) < 0){ if((fd = open(argv[i], 0)) < 0){
printf("grep: cannot open %s\n", argv[i]); printf("grep: cannot open %s\n", argv[i]);
exit(1); exit(1);
} }

View File

@ -2,7 +2,6 @@
#include "kernel/stat.h" #include "kernel/stat.h"
#include "user/user.h" #include "user/user.h"
#include "kernel/fs.h" #include "kernel/fs.h"
#include "kernel/fcntl.h"
char* char*
fmtname(char *path) fmtname(char *path)
@ -31,7 +30,7 @@ ls(char *path)
struct dirent de; struct dirent de;
struct stat st; struct stat st;
if((fd = open(path, O_RDONLY)) < 0){ if((fd = open(path, 0)) < 0){
fprintf(2, "ls: cannot open %s\n", path); fprintf(2, "ls: cannot open %s\n", path);
return; return;
} }

27
user/pingpong.c Normal file
View File

@ -0,0 +1,27 @@
#include "kernel/types.h"
#include "user/user.h"
int main(int argc, char** argv) {
int p[2]; // hell, read from p[0] and write to p[1] no matter in pa/ch
if (pipe(p) == -1) exit(1);
uint8 senddata[] = {0xAC};
uint8 recvdata[] = {0};
int pid = fork();
if (pid == 0) {
// child
if (read(p[0], recvdata, 1) != 1) printf("error child read\n");
close(p[0]);
printf("%d: received ping\n", getpid());
if (write(p[1], senddata, 1) != 1) printf("error child write\n");
close(p[1]);
exit(0);
}
else {
if (write(p[1], senddata, 1) != 1) printf("error parent write\n");
close(p[1]);
if (read(p[0], recvdata, 1) != 1) printf("error parent read\n");
printf("%d: received pong\n", getpid());
close(p[0]);
exit(0);
}
}

51
user/primes.c Normal file
View File

@ -0,0 +1,51 @@
#include "kernel/types.h"
#include "user/user.h"
void pipeline(int leftfd) {
int pipefd[2];
int p; read(leftfd, &p, sizeof(p));
printf("prime %d\n", p);
int n;
int has_right = 0;
while (read(leftfd, &n, sizeof(n)) > 0) {
if (n % p != 0) {
if (!has_right) {
has_right = 1;
pipe(pipefd);
if (fork() == 0) {
close(pipefd[1]);
pipeline(pipefd[0]);
} else {
close(pipefd[0]);
}
}
write(pipefd[1], &n, sizeof(n));
}
}
close(leftfd);
if (has_right) {
close(pipefd[1]);
while(wait(0) != -1);
}
exit(0);
}
int main(int argc, char** argv) {
int pipefd[2];
pipe(pipefd);
int pid = fork();
if (pid != 0) {
close(pipefd[0]); // no need to read in the feeding proc
for (int i = 2; i <= 35; ++ i) {
write(pipefd[1], &i, sizeof(i));
}
close(pipefd[1]);
while(wait(0) != -1);
exit(0);
}
else {
close(pipefd[1]); // pipeline proc will have its own write pipe
pipeline(pipefd[0]);
}
exit(0);
}

17
user/sleep.c Normal file
View File

@ -0,0 +1,17 @@
#include "kernel/types.h"
#include "user/user.h"
int main(int argc, char** argv) {
if (argc != 2) {
printf("\x1b[31mUnexpected argument\x1b[0m\n");
printf("usage: sleep <ticks>\n");
exit(0);
}
int ticks = atoi(argv[1]);
int ret = sleep(ticks);
if (ret) {
printf("\x1b[31mFailed to sleep\x1b[0m\n");
exit(-1);
}
exit(0);
}

View File

@ -1,153 +0,0 @@
#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;
int status;
int pid;
sinfo(&info);
nproc = info.nproc;
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);
}
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);
}
}
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);
}

View File

@ -1,27 +0,0 @@
#include "kernel/param.h"
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
int
main(int argc, char *argv[])
{
int i;
char *nargv[MAXARG];
if(argc < 3 || (argv[1][0] < '0' || argv[1][0] > '9')){
fprintf(2, "Usage: %s mask command\n", argv[0]);
exit(1);
}
if (trace(atoi(argv[1])) < 0) {
fprintf(2, "%s: trace failed\n", argv[0]);
exit(1);
}
for(i = 2; i < argc && i < MAXARG; i++){
nargv[i-2] = argv[i];
}
exec(nargv[0], nargv);
exit(0);
}

View File

@ -1,5 +1,4 @@
struct stat; struct stat;
struct sysinfo;
// system calls // system calls
int fork(void); int fork(void);
@ -23,8 +22,6 @@ int getpid(void);
char* sbrk(int); char* sbrk(int);
int sleep(int); int sleep(int);
int uptime(void); int uptime(void);
int trace(int);
int sysinfo(struct sysinfo*);
// ulib.c // ulib.c
int stat(const char*, struct stat*); int stat(const char*, struct stat*);

View File

@ -36,5 +36,3 @@ entry("getpid");
entry("sbrk"); entry("sbrk");
entry("sleep"); entry("sleep");
entry("uptime"); entry("uptime");
entry("trace");
entry("sysinfo");

View File

@ -1,6 +1,5 @@
#include "kernel/types.h" #include "kernel/types.h"
#include "kernel/stat.h" #include "kernel/stat.h"
#include "kernel/fcntl.h"
#include "user/user.h" #include "user/user.h"
char buf[512]; char buf[512];
@ -44,7 +43,7 @@ main(int argc, char *argv[])
} }
for(i = 1; i < argc; i++){ for(i = 1; i < argc; i++){
if((fd = open(argv[i], O_RDONLY)) < 0){ if((fd = open(argv[i], 0)) < 0){
printf("wc: cannot open %s\n", argv[i]); printf("wc: cannot open %s\n", argv[i]);
exit(1); exit(1);
} }

59
user/xargs.c Normal file
View File

@ -0,0 +1,59 @@
#include "kernel/param.h"
#include "kernel/types.h"
#include "user/user.h"
static inline int is_ws(const char ch) {
return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r';
}
int main(int argc, char** argv) {
int STDIN = 0;
char linebuf[1024];
char* p = linebuf;
char* _argv[MAXARG];
while (read(STDIN, p, 1) > 0) {
if (*p == '\n') {
int i;
int in_ws = 1;
for (i = 0; i < argc - 1; ++i) {
_argv[i] = argv[i + 1];
}
for (char* p0 = linebuf; p0 <= p; ++p0) {
if (is_ws(*p0)) {
if (!in_ws) {
in_ws = 1;
i++;
}
*p0 = '\0';
} else if (in_ws) {
in_ws = 0;
_argv[i] = p0;
}
if (i >= MAXARG) {
printf("warning: too many arguments");
break;
}
}
*p = '\0';
_argv[i] = 0;
// for (int j = 0; j < i; ++ j) {
// printf("%s\n", _argv[j]);
// }
if (fork() == 0) {
exec(_argv[0], _argv);
exit(0);
} else {
p = linebuf;
while (wait(0) != -1)
;
}
} else {
p++;
if (p >= linebuf + sizeof(linebuf)) {
printf("line buffer exceeded\n");
exit(0);
}
}
}
exit(0);
}

6
user/xargstest.sh Normal file
View File

@ -0,0 +1,6 @@
mkdir a
echo hello > a/b
mkdir c
echo hello > c/b
echo hello > b
find . b | xargs grep hello