Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8de6f45af1 | ||
|
|
dc9153fcb9 | ||
|
|
4d7493893d | ||
|
|
0c477a6c84 | ||
|
|
7d47335b4f |
6
Makefile
6
Makefile
@ -188,7 +188,11 @@ UPROGS=\
|
|||||||
$U/_grind\
|
$U/_grind\
|
||||||
$U/_wc\
|
$U/_wc\
|
||||||
$U/_zombie\
|
$U/_zombie\
|
||||||
$U/_alarmtest\
|
$U/_sleep\
|
||||||
|
$U/_pingpong\
|
||||||
|
$U/_primes\
|
||||||
|
$U/_find\
|
||||||
|
$U/_xargs\
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
36
README
36
README
@ -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
|
||||||
|
|||||||
@ -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.
|
|
||||||
|
|
||||||
@ -1 +1 @@
|
|||||||
LAB=traps
|
LAB=util
|
||||||
|
|||||||
@ -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
86
grade-lab-util
Executable 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()
|
||||||
@ -80,7 +80,6 @@ int pipewrite(struct pipe*, uint64, int);
|
|||||||
void printf(char*, ...);
|
void printf(char*, ...);
|
||||||
void panic(char*) __attribute__((noreturn));
|
void panic(char*) __attribute__((noreturn));
|
||||||
void printfinit(void);
|
void printfinit(void);
|
||||||
void backtrace(void);
|
|
||||||
|
|
||||||
// proc.c
|
// proc.c
|
||||||
int cpuid(void);
|
int cpuid(void);
|
||||||
|
|||||||
@ -122,7 +122,6 @@ panic(char *s)
|
|||||||
printf("panic: ");
|
printf("panic: ");
|
||||||
printf(s);
|
printf(s);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
backtrace();
|
|
||||||
panicked = 1; // freeze uart output from other CPUs
|
panicked = 1; // freeze uart output from other CPUs
|
||||||
for(;;)
|
for(;;)
|
||||||
;
|
;
|
||||||
@ -134,14 +133,3 @@ printfinit(void)
|
|||||||
initlock(&pr.lock, "pr");
|
initlock(&pr.lock, "pr");
|
||||||
pr.locking = 1;
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -131,11 +131,6 @@ found:
|
|||||||
release(&p->lock);
|
release(&p->lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if((p->trapframe1 = (struct trapframe *)kalloc()) == 0){
|
|
||||||
freeproc(p);
|
|
||||||
release(&p->lock);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// An empty user page table.
|
// An empty user page table.
|
||||||
p->pagetable = proc_pagetable(p);
|
p->pagetable = proc_pagetable(p);
|
||||||
@ -150,8 +145,6 @@ found:
|
|||||||
memset(&p->context, 0, sizeof(p->context));
|
memset(&p->context, 0, sizeof(p->context));
|
||||||
p->context.ra = (uint64)forkret;
|
p->context.ra = (uint64)forkret;
|
||||||
p->context.sp = p->kstack + PGSIZE;
|
p->context.sp = p->kstack + PGSIZE;
|
||||||
p->alarm_hdlr = 0;
|
|
||||||
p->alarm_intrv = p->alarm_ticks = 0;
|
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
@ -165,9 +158,6 @@ freeproc(struct proc *p)
|
|||||||
if(p->trapframe)
|
if(p->trapframe)
|
||||||
kfree((void*)p->trapframe);
|
kfree((void*)p->trapframe);
|
||||||
p->trapframe = 0;
|
p->trapframe = 0;
|
||||||
if(p->trapframe1)
|
|
||||||
kfree((void*)p->trapframe1);
|
|
||||||
p->trapframe1 = 0;
|
|
||||||
if(p->pagetable)
|
if(p->pagetable)
|
||||||
proc_freepagetable(p->pagetable, p->sz);
|
proc_freepagetable(p->pagetable, p->sz);
|
||||||
p->pagetable = 0;
|
p->pagetable = 0;
|
||||||
|
|||||||
@ -100,12 +100,8 @@ struct proc {
|
|||||||
uint64 sz; // Size of process memory (bytes)
|
uint64 sz; // Size of process memory (bytes)
|
||||||
pagetable_t pagetable; // User page table
|
pagetable_t pagetable; // User page table
|
||||||
struct trapframe *trapframe; // data page for trampoline.S
|
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 context context; // swtch() here to run process
|
||||||
struct file *ofile[NOFILE]; // Open files
|
struct file *ofile[NOFILE]; // Open files
|
||||||
struct inode *cwd; // Current directory
|
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)
|
char name[16]; // Process name (debugging)
|
||||||
};
|
};
|
||||||
|
|||||||
@ -319,14 +319,6 @@ r_ra()
|
|||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint64
|
|
||||||
r_fp()
|
|
||||||
{
|
|
||||||
uint64 x;
|
|
||||||
asm volatile("mv %0, s0" : "=r" (x) );
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
// flush the TLB.
|
// flush the TLB.
|
||||||
static inline void
|
static inline void
|
||||||
sfence_vma()
|
sfence_vma()
|
||||||
|
|||||||
@ -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_sigalarm(void);
|
|
||||||
extern uint64 sys_sigreturn(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,8 +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_sigalarm] sys_sigalarm,
|
|
||||||
[SYS_sigreturn] sys_sigreturn,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|||||||
@ -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_sigalarm 22
|
|
||||||
#define SYS_sigreturn 23
|
|
||||||
|
|||||||
@ -55,9 +55,6 @@ sys_sleep(void)
|
|||||||
uint ticks0;
|
uint ticks0;
|
||||||
|
|
||||||
argint(0, &n);
|
argint(0, &n);
|
||||||
if(n < 0)
|
|
||||||
n = 0;
|
|
||||||
backtrace();
|
|
||||||
acquire(&tickslock);
|
acquire(&tickslock);
|
||||||
ticks0 = ticks;
|
ticks0 = ticks;
|
||||||
while(ticks - ticks0 < n){
|
while(ticks - ticks0 < n){
|
||||||
@ -92,28 +89,3 @@ sys_uptime(void)
|
|||||||
release(&tickslock);
|
release(&tickslock);
|
||||||
return xticks;
|
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;
|
|
||||||
}
|
|
||||||
@ -67,18 +67,6 @@ usertrap(void)
|
|||||||
syscall();
|
syscall();
|
||||||
} else if((which_dev = devintr()) != 0){
|
} else if((which_dev = devintr()) != 0){
|
||||||
// ok
|
// 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 {
|
} else {
|
||||||
printf("usertrap(): unexpected scause %p pid=%d\n", r_scause(), p->pid);
|
printf("usertrap(): unexpected scause %p pid=%d\n", r_scause(), p->pid);
|
||||||
printf(" sepc=%p stval=%p\n", r_sepc(), r_stval());
|
printf(" sepc=%p stval=%p\n", r_sepc(), r_stval());
|
||||||
|
|||||||
193
user/alarmtest.c
193
user/alarmtest.c
@ -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");
|
|
||||||
}
|
|
||||||
@ -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);
|
|
||||||
}
|
|
||||||
17
user/call.c
17
user/call.c
@ -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);
|
|
||||||
}
|
|
||||||
@ -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
74
user/find.c
Normal 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);
|
||||||
|
}
|
||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
27
user/pingpong.c
Normal 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
51
user/primes.c
Normal 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
17
user/sleep.c
Normal 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);
|
||||||
|
}
|
||||||
@ -22,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 sigalarm(int ticks, void (*handler)());
|
|
||||||
int sigreturn(void);
|
|
||||||
|
|
||||||
// ulib.c
|
// ulib.c
|
||||||
int stat(const char*, struct stat*);
|
int stat(const char*, struct stat*);
|
||||||
|
|||||||
@ -36,5 +36,3 @@ entry("getpid");
|
|||||||
entry("sbrk");
|
entry("sbrk");
|
||||||
entry("sleep");
|
entry("sleep");
|
||||||
entry("uptime");
|
entry("uptime");
|
||||||
entry("sigalarm");
|
|
||||||
entry("sigreturn");
|
|
||||||
|
|||||||
@ -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
59
user/xargs.c
Normal 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
6
user/xargstest.sh
Normal 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
|
||||||
Loading…
Reference in New Issue
Block a user