Compare commits

..

5 Commits
traps ... util

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
31 changed files with 348 additions and 442 deletions

View File

@ -188,7 +188,11 @@ UPROGS=\
$U/_grind\
$U/_wc\
$U/_zombie\
$U/_alarmtest\
$U/_sleep\
$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
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.
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.
We are also grateful for the bug reports and patches contributed by
Takahiro Aoyagi, Silas Boyd-Wickizer, Anton Burtsev, carlclone, Ian
Chen, Dan Cross, Cody Cutler, Mike CAT, Tej Chajed, Asami Doi,
eyalz800, Nelson Elhage, Saar Ettinger, Alice Ferrazzi, Nathaniel
Filardo, flespark, Peter Froehlich, Yakir Goaron, Shivam Handa, Matt
Harvey, Bryan Henry, jaichenhengjie, Jim Huang, Matúš Jókay, John
Jolly, Alexander Kapshuk, Anders Kaseorg, kehao95, Wolfgang Keller,
Jungwoo Kim, Jonathan Kimmitt, Eddie Kohler, Vadim Kolontsov, Austin
Liew, l0stman, Pavan Maddamsetti, Imbar Marinescu, Yandong Mao, Matan
Shabtay, Hitoshi Mitake, Carmi Merimovich, Mark Morrissey, mtasm, Joel
Nider, Hayato Ohhashi, OptimisticSide, Harry Porter, Greg Price, Jude
Rich, segfault, Ayan Shafqat, Eldar Sehayek, Yongming Shen, Fumiya
Shigemitsu, Cam Tenny, tyfkda, Warren Toomey, Stephen Tu, Rafael Ubal,
Amane Uehara, Pablo Ventura, Xi Wang, WaheedHafez, Keiichi Watanabe,
Nicolas Wolovick, wxdao, Grant Wu, Jindong Zhang, Icenowy Zheng,
ZhUyU1997, and Zou Chang Wei.
Takahiro Aoyagi, Silas Boyd-Wickizer, Anton Burtsev, Ian Chen, Dan
Cross, Cody Cutler, Mike CAT, Tej Chajed, Asami Doi, eyalz800, Nelson
Elhage, Saar Ettinger, Alice Ferrazzi, Nathaniel Filardo, flespark,
Peter Froehlich, Yakir Goaron, Shivam Handa, Matt Harvey, Bryan Henry,
jaichenhengjie, Jim Huang, Matúš Jókay, Alexander Kapshuk, Anders
Kaseorg, kehao95, Wolfgang Keller, Jungwoo Kim, Jonathan Kimmitt,
Eddie Kohler, Vadim Kolontsov, Austin Liew, l0stman, Pavan
Maddamsetti, Imbar Marinescu, Yandong Mao, Matan Shabtay, Hitoshi
Mitake, Carmi Merimovich, Mark Morrissey, mtasm, Joel Nider,
OptimisticSide, Greg Price, Jude Rich, Ayan Shafqat, Eldar Sehayek,
Yongming Shen, Fumiya Shigemitsu, Cam Tenny, tyfkda, Warren Toomey,
Stephen Tu, Rafael Ubal, Amane Uehara, Pablo Ventura, Xi Wang, Keiichi
Watanabe, Nicolas Wolovick, wxdao, Grant Wu, Jindong Zhang, Icenowy
Zheng, ZhUyU1997, and Zou Chang Wei.
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
Please send errors and suggestions to Frans Kaashoek and Robert Morris
(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.
BUILDING AND RUNNING XV6

View File

@ -1,33 +0,0 @@
Q: Which registers contain arguments to functions? For example, which register holds 13 in main's call to printf?
A: The base integer calling convention provides eight argument registers, a0-a7, the first two of which are also used to return values. Register a2 holds 13.
Q: Where is the call to function f in the assembly code for main? Where is the call to g?
A: There is no call to function f for main, the value of f(8) (which is 12) is calculated at compile time and hard-coded into the executable.
The call to g is inlined into f, at address 0x14.
Q: At what address is the function printf located?
A: The function printf is located at address 0x642.
Q: What value is in the register ra just after the jalr to printf in main?
A: The address of the next instruction after return, aka 0x38.
Q:
---
Run the following code.
unsigned int i = 0x00646c72;
printf("H%x Wo%s", 57616, &i);
What is the output? Here's an ASCII table that maps bytes to characters.
The output depends on that fact that the RISC-V is little-endian. If the RISC-V were instead big-endian what would you set i to in order to yield the same output? Would you need to change 57616 to a different value?
---
A: The output is, He110 World(with no whitespace or new line).
If big endian, the new i should be 0x726c6400; and there is no need to change 56716.
Q:
---
In the following code, what is going to be printed after 'y='? (note: the answer is not a specific value.) Why does this happen?
printf("x=%d y=%d", 3);
---
A: The value that register a2 holds when the caller calls printf. By default, the third argument passed to a procedure is stored in a2.

View File

@ -1 +1 @@
LAB=traps
LAB=util

View File

@ -1,74 +0,0 @@
#!/usr/bin/env python3
import os
import re
import subprocess
from gradelib import *
r = Runner(save("xv6.out"))
@test(5, "answers-traps.txt")
def test_answers():
# just a simple sanity check, will be graded manually
check_answers("answers-traps.txt")
BACKTRACE_RE = r"^(0x000000008[0-9a-f]+)"
def addr2line():
for f in ['riscv64-unknown-elf-addr2line', 'riscv64-linux-gnu-addr2line', 'addr2line', ]:
try:
devnull = open(os.devnull)
subprocess.Popen([f], stdout=devnull, stderr=devnull).communicate()
return f
except OSError:
continue
raise AssertionError('Cannot find the addr2line program')
@test(10, "backtrace test")
def test_backtracetest():
r.run_qemu(shell_script([
'bttest'
]))
a2l = addr2line()
matches = re.findall(BACKTRACE_RE, r.qemu.output, re.MULTILINE)
assert_equal(len(matches), 3)
files = ['sysproc.c', 'syscall.c', 'trap.c']
for f, m in zip(files, matches):
result = subprocess.run([a2l, '-e', 'kernel/kernel', m], stdout=subprocess.PIPE)
if not f in result.stdout.decode("utf-8"):
raise AssertionError('Trace is incorrect; no %s' % f)
@test(0, "running alarmtest")
def test_alarmtest():
r.run_qemu(shell_script([
'alarmtest'
]))
@test(20, "alarmtest: test0", parent=test_alarmtest)
def test_alarmtest_test0():
r.match('^test0 passed$')
@test(20, "alarmtest: test1", parent=test_alarmtest)
def test_alarmtest_test1():
r.match('^\\.?test1 passed$')
@test(10, "alarmtest: test2", parent=test_alarmtest)
def test_alarmtest_test2():
r.match('^\\.?test2 passed$')
@test(10, "alarmtest: test3", parent=test_alarmtest)
def test_alarmtest_test3():
r.match('^test3 passed$')
@test(19, "usertests")
def test_usertests():
r.run_qemu(shell_script([
'usertests -q'
]), timeout=300)
r.match('^ALL TESTS PASSED$')
@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

@ -80,7 +80,6 @@ int pipewrite(struct pipe*, uint64, int);
void printf(char*, ...);
void panic(char*) __attribute__((noreturn));
void printfinit(void);
void backtrace(void);
// proc.c
int cpuid(void);

View File

@ -122,7 +122,6 @@ panic(char *s)
printf("panic: ");
printf(s);
printf("\n");
backtrace();
panicked = 1; // freeze uart output from other CPUs
for(;;)
;
@ -134,14 +133,3 @@ printfinit(void)
initlock(&pr.lock, "pr");
pr.locking = 1;
}
void backtrace(void)
{
printf("backtrace:\n");
uint64 fp = r_fp();
uint64 fp_pg = PGROUNDDOWN(fp);
while (PGROUNDDOWN(fp) == fp_pg) {
printf("%p\n", (*(uint64*)(fp-8)));
fp = *(uint64*)(fp-16);
}
}

View File

@ -131,11 +131,6 @@ found:
release(&p->lock);
return 0;
}
if((p->trapframe1 = (struct trapframe *)kalloc()) == 0){
freeproc(p);
release(&p->lock);
return 0;
}
// An empty user page table.
p->pagetable = proc_pagetable(p);
@ -150,8 +145,6 @@ found:
memset(&p->context, 0, sizeof(p->context));
p->context.ra = (uint64)forkret;
p->context.sp = p->kstack + PGSIZE;
p->alarm_hdlr = 0;
p->alarm_intrv = p->alarm_ticks = 0;
return p;
}
@ -165,9 +158,6 @@ freeproc(struct proc *p)
if(p->trapframe)
kfree((void*)p->trapframe);
p->trapframe = 0;
if(p->trapframe1)
kfree((void*)p->trapframe1);
p->trapframe1 = 0;
if(p->pagetable)
proc_freepagetable(p->pagetable, p->sz);
p->pagetable = 0;

View File

@ -100,12 +100,8 @@ struct proc {
uint64 sz; // Size of process memory (bytes)
pagetable_t pagetable; // User page table
struct trapframe *trapframe; // data page for trampoline.S
struct trapframe *trapframe1; // data page for trampoline.S
struct context context; // swtch() here to run process
struct file *ofile[NOFILE]; // Open files
struct inode *cwd; // Current directory
int alarm_intrv; // alarm interval
uint64 alarm_hdlr; // alarm handler
int alarm_ticks; // ticks after last alarm
char name[16]; // Process name (debugging)
};

View File

@ -319,14 +319,6 @@ r_ra()
return x;
}
static inline uint64
r_fp()
{
uint64 x;
asm volatile("mv %0, s0" : "=r" (x) );
return x;
}
// flush the TLB.
static inline void
sfence_vma()

View File

@ -101,8 +101,6 @@ extern uint64 sys_unlink(void);
extern uint64 sys_link(void);
extern uint64 sys_mkdir(void);
extern uint64 sys_close(void);
extern uint64 sys_sigalarm(void);
extern uint64 sys_sigreturn(void);
// An array mapping syscall numbers from syscall.h
// to the function that handles the system call.
@ -128,8 +126,6 @@ static uint64 (*syscalls[])(void) = {
[SYS_link] sys_link,
[SYS_mkdir] sys_mkdir,
[SYS_close] sys_close,
[SYS_sigalarm] sys_sigalarm,
[SYS_sigreturn] sys_sigreturn,
};
void

View File

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

View File

@ -55,9 +55,6 @@ sys_sleep(void)
uint ticks0;
argint(0, &n);
if(n < 0)
n = 0;
backtrace();
acquire(&tickslock);
ticks0 = ticks;
while(ticks - ticks0 < n){
@ -92,28 +89,3 @@ sys_uptime(void)
release(&tickslock);
return xticks;
}
uint64
sys_sigalarm(void)
{
int interval;
uint64 hdlr;
argint(0, &interval);
argaddr(1, &hdlr);
struct proc* p = myproc();
p->alarm_ticks = 0;
p->alarm_intrv = interval;
p->alarm_hdlr = hdlr;
return 0;
}
uint64
sys_sigreturn(void)
{
struct proc* p = myproc();
memmove(p->trapframe, p->trapframe1, sizeof(struct trapframe));
p->alarm_ticks = 0;
return p->trapframe->a0;
}

View File

@ -67,18 +67,6 @@ usertrap(void)
syscall();
} else if((which_dev = devintr()) != 0){
// ok
if (which_dev == 2) {
acquire(&p->lock);
if (p->alarm_intrv) {
if (p->alarm_ticks <= p->alarm_intrv)
p->alarm_ticks ++;
if (p->alarm_intrv == p->alarm_ticks) {
memmove(p->trapframe1, p->trapframe, sizeof(struct trapframe));
p->trapframe->epc = p->alarm_hdlr;
}
}
release(&p->lock);
}
} else {
printf("usertrap(): unexpected scause %p pid=%d\n", r_scause(), p->pid);
printf(" sepc=%p stval=%p\n", r_sepc(), r_stval());

View File

@ -1 +1 @@
4
6

View File

@ -1,193 +0,0 @@
//
// test program for the alarm lab.
// you can modify this file for testing,
// but please make sure your kernel
// modifications pass the original
// versions of these tests.
//
#include "kernel/param.h"
#include "kernel/types.h"
#include "kernel/stat.h"
#include "kernel/riscv.h"
#include "user/user.h"
void test0();
void test1();
void test2();
void test3();
void periodic();
void slow_handler();
void dummy_handler();
int
main(int argc, char *argv[])
{
test0();
test1();
test2();
test3();
exit(0);
}
volatile static int count;
void
periodic()
{
count = count + 1;
printf("alarm!\n");
sigreturn();
}
// tests whether the kernel calls
// the alarm handler even a single time.
void
test0()
{
int i;
printf("test0 start\n");
count = 0;
sigalarm(2, periodic);
for(i = 0; i < 1000*500000; i++){
if((i % 1000000) == 0)
write(2, ".", 1);
if(count > 0)
break;
}
sigalarm(0, 0);
if(count > 0){
printf("test0 passed\n");
} else {
printf("\ntest0 failed: the kernel never called the alarm handler\n");
}
}
void __attribute__ ((noinline)) foo(int i, int *j) {
if((i % 2500000) == 0) {
write(2, ".", 1);
}
*j += 1;
}
//
// tests that the kernel calls the handler multiple times.
//
// tests that, when the handler returns, it returns to
// the point in the program where the timer interrupt
// occurred, with all registers holding the same values they
// held when the interrupt occurred.
//
void
test1()
{
int i;
int j;
printf("test1 start\n");
count = 0;
j = 0;
sigalarm(2, periodic);
for(i = 0; i < 500000000; i++){
if(count >= 10)
break;
foo(i, &j);
}
if(count < 10){
printf("\ntest1 failed: too few calls to the handler\n");
} else if(i != j){
// the loop should have called foo() i times, and foo() should
// have incremented j once per call, so j should equal i.
// once possible source of errors is that the handler may
// return somewhere other than where the timer interrupt
// occurred; another is that that registers may not be
// restored correctly, causing i or j or the address ofj
// to get an incorrect value.
printf("\ntest1 failed: foo() executed fewer times than it was called\n");
} else {
printf("test1 passed\n");
}
}
//
// tests that kernel does not allow reentrant alarm calls.
void
test2()
{
int i;
int pid;
int status;
printf("test2 start\n");
if ((pid = fork()) < 0) {
printf("test2: fork failed\n");
}
if (pid == 0) {
count = 0;
sigalarm(2, slow_handler);
for(i = 0; i < 1000*500000; i++){
if((i % 1000000) == 0)
write(2, ".", 1);
if(count > 0)
break;
}
if (count == 0) {
printf("\ntest2 failed: alarm not called\n");
exit(1);
}
exit(0);
}
wait(&status);
if (status == 0) {
printf("test2 passed\n");
}
}
void
slow_handler()
{
count++;
printf("alarm!\n");
if (count > 1) {
printf("test2 failed: alarm handler called more than once\n");
exit(1);
}
for (int i = 0; i < 1000*500000; i++) {
asm volatile("nop"); // avoid compiler optimizing away loop
}
sigalarm(0, 0);
sigreturn();
}
//
// dummy alarm handler; after running immediately uninstall
// itself and finish signal handling
void
dummy_handler()
{
sigalarm(0, 0);
sigreturn();
}
//
// tests that the return from sys_sigreturn() does not
// modify the a0 register
void
test3()
{
uint64 a0;
sigalarm(1, dummy_handler);
printf("test3 start\n");
asm volatile("lui a5, 0");
asm volatile("addi a0, a5, 0xac" : : : "a0");
for(int i = 0; i < 500000000; i++)
;
asm volatile("mv %0, a0" : "=r" (a0) );
if(a0 != 0xac)
printf("test3 failed: register a0 changed\n");
else
printf("test3 passed\n");
}

View File

@ -1,10 +0,0 @@
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
int
main(int argc, char *argv[])
{
sleep(1);
exit(0);
}

View File

@ -1,17 +0,0 @@
#include "kernel/param.h"
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
int g(int x) {
return x+3;
}
int f(int x) {
return g(x);
}
void main(void) {
printf("%d %d\n", f(8)+1, 13);
exit(0);
}

View File

@ -1,6 +1,5 @@
#include "kernel/types.h"
#include "kernel/stat.h"
#include "kernel/fcntl.h"
#include "user/user.h"
char buf[512];
@ -33,7 +32,7 @@ main(int argc, char *argv[])
}
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]);
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/stat.h"
#include "kernel/fcntl.h"
#include "user/user.h"
char buf[1024];
@ -52,7 +51,7 @@ main(int argc, char *argv[])
}
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]);
exit(1);
}

View File

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

@ -22,8 +22,6 @@ int getpid(void);
char* sbrk(int);
int sleep(int);
int uptime(void);
int sigalarm(int ticks, void (*handler)());
int sigreturn(void);
// ulib.c
int stat(const char*, struct stat*);

View File

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

View File

@ -1,6 +1,5 @@
#include "kernel/types.h"
#include "kernel/stat.h"
#include "kernel/fcntl.h"
#include "user/user.h"
char buf[512];
@ -44,7 +43,7 @@ main(int argc, char *argv[])
}
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]);
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