Compare commits

..

6 Commits
util ... mmap

Author SHA1 Message Date
ridethepig
d66082b414 make grade 140/140 2023-02-07 03:43:47 +00:00
ridethepig
294e926e52 forktest failed 2023-02-06 16:05:34 +00:00
Frans Kaashoek
9cc6b83453 mmap lab 2022-11-26 10:58:00 -05:00
Frans Kaashoek
4b46c0c6eb Use O_RDONLY instead of 0 2022-09-11 13:51:11 -04:00
Robert Morris
463ae0abc3 handle negative arguments to sleep() a little better 2022-09-09 09:17:37 -04:00
Frans Kaashoek
f5b93ef12f Update acks
61810
2022-08-25 14:20:52 -04:00
28 changed files with 642 additions and 350 deletions

16
.vscode/c_cpp_properties.json vendored Normal file
View File

@ -0,0 +1,16 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**"
],
"defines": ["LAB_MMAP"],
"compilerPath": "/usr/bin/gcc",
"cStandard": "gnu17",
"cppStandard": "gnu++17",
"intelliSenseMode": "linux-gcc-x64"
}
],
"version": 4
}

View File

@ -106,7 +106,7 @@ endif
ifdef KCSAN
CFLAGS += -DKCSAN
KCSANFLAG = -fsanitize=thread
KCSANFLAG = -fsanitize=thread -fno-inline
endif
# Disable PIE when possible (for Ubuntu 16.10 toolchain)
@ -188,11 +188,7 @@ UPROGS=\
$U/_grind\
$U/_wc\
$U/_zombie\
$U/_sleep\
$U/_pingpong\
$U/_primes\
$U/_find\
$U/_xargs\
$U/_mmaptest\

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.828/, which provides
2000)). See also https://pdos.csail.mit.edu/6.1810/, which provides
pointers to on-line resources for v6.
The following people have made contributions: Russ Cox (context switching,
@ -14,29 +14,31 @@ 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, 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.
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.
The code in the files that constitute xv6 is
Copyright 2006-2020 Frans Kaashoek, Robert Morris, and Russ Cox.
Copyright 2006-2022 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.S081, so we are more interested in
operating system for MIT's 6.1810, so we are more interested in
simplifications and clarifications than new features.
BUILDING AND RUNNING XV6

View File

@ -1 +1 @@
LAB=util
LAB=mmap

57
grade-lab-mmap Executable file
View File

@ -0,0 +1,57 @@
#!/usr/bin/env python3
import re
from gradelib import *
r = Runner(save("xv6.out"))
@test(0, "running mmaptest")
def test_mmaptest():
r.run_qemu(shell_script([
'mmaptest'
]), timeout=180)
@test(20, "mmaptest: mmap f", parent=test_mmaptest)
def test_mmaptest_mmap_f():
r.match('^test mmap f: OK$')
@test(10, "mmaptest: mmap private", parent=test_mmaptest)
def test_mmaptest_mmap_private():
r.match('^test mmap private: OK$')
@test(10, "mmaptest: mmap read-only", parent=test_mmaptest)
def test_mmaptest_mmap_readonly():
r.match('^test mmap read-only: OK$')
@test(10, "mmaptest: mmap read/write", parent=test_mmaptest)
def test_mmaptest_mmap_readwrite():
r.match('^test mmap read/write: OK$')
@test(10, "mmaptest: mmap dirty", parent=test_mmaptest)
def test_mmaptest_mmap_dirty():
r.match('^test mmap dirty: OK$')
@test(10, "mmaptest: not-mapped unmap", parent=test_mmaptest)
def test_mmaptest_mmap_unmap():
r.match('^test not-mapped unmap: OK$')
@test(10, "mmaptest: two files", parent=test_mmaptest)
def test_mmaptest_mmap_two():
r.match('^test mmap two files: OK$')
@test(40, "mmaptest: fork_test", parent=test_mmaptest)
def test_mmaptest_fork_test():
r.match('^fork_test OK$')
@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()

View File

@ -1,86 +0,0 @@
#!/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

@ -187,3 +187,6 @@ void virtio_disk_intr(void);
// number of elements in fixed-size array
#define NELEM(x) (sizeof(x)/sizeof((x)[0]))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))

View File

@ -3,3 +3,13 @@
#define O_RDWR 0x002
#define O_CREATE 0x200
#define O_TRUNC 0x400
#ifdef LAB_MMAP
#define PROT_NONE 0x0
#define PROT_READ 0x1
#define PROT_WRITE 0x2
#define PROT_EXEC 0x4
#define MAP_SHARED 0x01
#define MAP_PRIVATE 0x02
#endif

View File

@ -5,6 +5,15 @@
#include "spinlock.h"
#include "proc.h"
#include "defs.h"
#include "fcntl.h"
#include "sleeplock.h"
#include "fs.h"
#include "file.h"
static struct vma vma_pool[NMAXVMA];
static struct spinlock lock_vma_pool;
uint64 do_munmap(uint64 addr, int length);
uint64 do_mmap(struct proc* p, int length, int prot, int flags, int fd);
struct cpu cpus[NCPU];
@ -33,7 +42,7 @@ void
proc_mapstacks(pagetable_t kpgtbl)
{
struct proc *p;
initlock(&lock_vma_pool, "vma_pool");
for(p = proc; p < &proc[NPROC]; p++) {
char *pa = kalloc();
if(pa == 0)
@ -318,6 +327,31 @@ fork(void)
np->parent = p;
release(&wait_lock);
acquire(&np->lock);
for (int i = 0; i < NMAXVMA; ++ i) {
if (p->map_region[i]) {
struct vma* newvma = 0;
acquire(&lock_vma_pool);
for (int i = 0; i < NMAXVMA; ++ i) {
if (vma_pool[i].length == 0) {
newvma = &vma_pool[i];
break;
}
}
if (!newvma || newvma->length)
panic("mmap: vma pool run out");
newvma->f = filedup(p->map_region[i]->f);
newvma->addr = p->map_region[i]->addr;
newvma->prot = p->map_region[i]->prot;
newvma->length = p->map_region[i]->length;
newvma->flag = p->map_region[i]->flag;
newvma->offset = p->map_region[i]->offset;
release(&lock_vma_pool);
np->map_region[i] = newvma;
}
}
release(&np->lock);
acquire(&np->lock);
np->state = RUNNABLE;
release(&np->lock);
@ -351,6 +385,13 @@ exit(int status)
if(p == initproc)
panic("init exiting");
// clear mmaps
for (int i = 0; i < NMAXVMA; ++ i) {
if (p->map_region[i]) {
do_munmap(p->map_region[i]->addr, p->map_region[i]->length);
}
}
// Close all open files.
for(int fd = 0; fd < NOFILE; fd++){
if(p->ofile[fd]){
@ -681,3 +722,131 @@ procdump(void)
printf("\n");
}
}
uint64 do_mmap(struct proc* p, int length, int prot, int flags, int fd)
{
uint64 addr;
struct vma* newvma = 0;
if (fd < 0 || fd > NOFILE || p->ofile[fd] == 0){
return -1;
}
if (!p->ofile[fd]->writable && (prot & PROT_WRITE) && (flags != MAP_PRIVATE)) {
return -1;
}
// find vacant addr space
addr = MMAP_START;
for (int i = 0; i < NMAXVMA; ++ i) {
// in case some va has been occupied by some other vma but not accessed
if (p->map_region[i]) {
int _tmp = PGROUNDUP(p->map_region[i]->addr + length);
addr = _tmp > addr ? _tmp : addr;
}
}
acquire(&lock_vma_pool);
for (int i = 0; i < NMAXVMA; ++ i) {
if (vma_pool[i].length == 0) {
newvma = &vma_pool[i];
break;
}
}
if (!newvma || newvma->length)
panic("mmap: vma pool run out");
newvma->f = p->ofile[fd];
newvma->addr = addr;
newvma->prot = prot;
newvma->length = length;
newvma->flag = flags;
newvma->offset = 0;
release(&lock_vma_pool);
filedup(newvma->f);
for (int i = 0; i < NMAXVMA; ++ i) {
if (p->map_region[i] == 0) {
p->map_region[i] = newvma;
break;
}
}
return addr;
}
// void *mmap(void *addr, int length, int prot, int flags, int fd, int offset);
// int munmap(void *addr, int length);
uint64 sys_mmap(void)
{
uint64 addr;
int length, prot, flags, fd, offset;
argaddr(0, &addr);
argint(1, &length);
argint(2, &prot);
argint(3, &flags);
argint(4, &fd);
argint(5, &offset);
// some preliminary check
if (addr != 0 || offset != 0) panic("Unsupported non-zero value for arg addr and off");
return do_mmap(myproc(), length, prot, flags, fd);
}
uint64 do_munmap(uint64 addr, int length)
{
struct vma* vma0 = 0;
struct proc* p = myproc();
int imap = 0;
for (int i = 0; i < NMAXVMA; ++ i) {
if(p->map_region[i]
&& p->map_region[i]->addr <= addr
&& addr < p->map_region[i]->addr + p->map_region[i]->length) {
vma0 = p->map_region[i];
imap = i;
break;
}
}
if (vma0 == 0) {
printf("failed to ummap %p\n", addr);
return -1;
}
// remove all relavant pages
// by reading the test code, no need to worry about non-aligned unmap
// or those unmaps which would break a vma into parts
uint64 vma_end = PGROUNDUP(vma0->addr + vma0->length);
uint64 free_start = MAX(PGROUNDDOWN(addr), vma0->addr);
uint64 free_end = MIN(PGROUNDUP(addr + length), vma_end);
for (uint64 va0 = free_start; va0 < free_end; va0 += PGSIZE) {
if (walkaddr(p->pagetable, va0)){
if (vma0->flag == MAP_SHARED) {
begin_op();
ilock(vma0->f->ip);
// int wrsz =
writei(vma0->f->ip, 1, va0, va0 + vma0->offset - vma0->addr, PGSIZE); // ? no sure if to write whole page
// printf("Write %d bytes from %p @offset=%d(off=%x,addr=%x)\n", wrsz, va0, va0 + vma0->offset - vma0->addr, vma0->offset, vma0->addr);
iunlock(vma0->f->ip);
end_op();
}
uvmunmap(p->pagetable, va0, 1, 1);
}
}
if (free_start <= vma0->addr && free_end >= vma_end) {
// all released
fileclose(vma0->f);
memset(vma0, 0, sizeof(struct vma));
p->map_region[imap] = 0;
} else if (free_end >= vma_end) {
vma0->length = free_start - vma0->addr;
} else if (free_start <= vma0->addr) {
vma0->length -= free_end - vma0->addr;
vma0->offset += free_end - vma0->addr;
vma0->addr = free_end;
} else {
panic("unsupported unmap type");
}
return 0;
}
uint64 sys_munmap(void)
{
uint64 addr;
int length;
argaddr(0, &addr);
argint(1, &length);
return do_munmap(addr, length);
}

View File

@ -81,6 +81,18 @@ struct trapframe {
enum procstate { UNUSED, USED, SLEEPING, RUNNABLE, RUNNING, ZOMBIE };
struct vma {
uint64 addr;
uint length;
uint prot;
uint flag;
uint offset;
struct file* f;
};
#define NMAXVMA 20
#define MMAP_START (0x40000000)
// Per-process state
struct proc {
struct spinlock lock;
@ -103,5 +115,6 @@ struct proc {
struct context context; // swtch() here to run process
struct file *ofile[NOFILE]; // Open files
struct inode *cwd; // Current directory
struct vma* map_region[NMAXVMA];
char name[16]; // Process name (debugging)
};

View File

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

View File

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

View File

@ -55,6 +55,8 @@ sys_sleep(void)
uint ticks0;
argint(0, &n);
if(n < 0)
n = 0;
acquire(&tickslock);
ticks0 = ticks;
while(ticks - ticks0 < n){

View File

@ -5,6 +5,10 @@
#include "spinlock.h"
#include "proc.h"
#include "defs.h"
#include "fcntl.h"
#include "sleeplock.h"
#include "fs.h"
#include "file.h"
struct spinlock tickslock;
uint ticks;
@ -65,9 +69,36 @@ usertrap(void)
intr_on();
syscall();
} else if(r_scause() == 13){
int va0 = r_stval();
struct vma* vma0 = 0;
for (int i = 0; i < NMAXVMA; ++ i) {
if(p->map_region[i]
&& p->map_region[i]->addr <= va0
&& va0 < p->map_region[i]->addr + p->map_region[i]->length) {
vma0 = p->map_region[i];
break;
}
}
if (vma0 == 0) {
goto bad;
}
uint64 phy_addr = (uint64)kalloc();
uint pgflag = PTE_U | (vma0->prot << 1);
// save some code... there is PTE_R/W/X = PROT_READ/WRITE/EXEC << 1
mappages(p->pagetable, va0, PGSIZE, phy_addr, pgflag);
memset((void*)phy_addr, 0, PGSIZE);
begin_op();
ilock(vma0->f->ip);
// int rdsz =
readi(vma0->f->ip, 0, phy_addr, va0 + vma0->offset - vma0->addr, PGSIZE);
// printf("Load %d bytes to %p @offset=%d\n", rdsz, va0,va0 + vma0->offset - vma0->addr);
iunlock(vma0->f->ip);
end_op();
} else if((which_dev = devintr()) != 0){
// ok
} else {
bad:
printf("usertrap(): unexpected scause %p pid=%d\n", r_scause(), p->pid);
printf(" sepc=%p stval=%p\n", r_sepc(), r_stval());
setkilled(p);

View File

@ -179,8 +179,10 @@ uvmunmap(pagetable_t pagetable, uint64 va, uint64 npages, int do_free)
for(a = va; a < va + npages*PGSIZE; a += PGSIZE){
if((pte = walk(pagetable, a, 0)) == 0)
panic("uvmunmap: walk");
if((*pte & PTE_V) == 0)
if((*pte & PTE_V) == 0){
printf("%p\n", va);
panic("uvmunmap: not mapped");
}
if(PTE_FLAGS(*pte) == PTE_V)
panic("uvmunmap: not a leaf");
if(do_free){

View File

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

View File

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

View File

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

297
user/mmaptest.c Normal file
View File

@ -0,0 +1,297 @@
#include "kernel/param.h"
#include "kernel/fcntl.h"
#include "kernel/types.h"
#include "kernel/stat.h"
#include "kernel/riscv.h"
#include "kernel/fs.h"
#include "user/user.h"
void mmap_test();
void fork_test();
char buf[BSIZE];
#define MAP_FAILED ((char *) -1)
int
main(int argc, char *argv[])
{
mmap_test();
fork_test();
printf("mmaptest: all tests succeeded\n");
exit(0);
}
char *testname = "???";
void
err(char *why)
{
printf("mmaptest: %s failed: %s, pid=%d\n", testname, why, getpid());
exit(1);
}
//
// check the content of the two mapped pages.
//
void
_v1(char *p)
{
int i;
for (i = 0; i < PGSIZE*2; i++) {
if (i < PGSIZE + (PGSIZE/2)) {
if (p[i] != 'A') {
printf("mismatch at %d, wanted 'A', got 0x%x\n", i, p[i]);
err("v1 mismatch (1)");
}
} else {
if (p[i] != 0) {
printf("mismatch at %d, wanted zero, got 0x%x\n", i, p[i]);
err("v1 mismatch (2)");
}
}
}
}
//
// create a file to be mapped, containing
// 1.5 pages of 'A' and half a page of zeros.
//
void
makefile(const char *f)
{
int i;
int n = PGSIZE/BSIZE;
unlink(f);
int fd = open(f, O_WRONLY | O_CREATE);
if (fd == -1)
err("open");
memset(buf, 'A', BSIZE);
// write 1.5 page
for (i = 0; i < n + n/2; i++) {
if (write(fd, buf, BSIZE) != BSIZE)
err("write 0 makefile");
}
if (close(fd) == -1)
err("close");
}
void
mmap_test(void)
{
int fd;
int i;
const char * const f = "mmap.dur";
printf("mmap_test starting\n");
testname = "mmap_test";
//
// create a file with known content, map it into memory, check that
// the mapped memory has the same bytes as originally written to the
// file.
//
makefile(f);
if ((fd = open(f, O_RDONLY)) == -1)
err("open");
printf("test mmap f\n");
//
// this call to mmap() asks the kernel to map the content
// of open file fd into the address space. the first
// 0 argument indicates that the kernel should choose the
// virtual address. the second argument indicates how many
// bytes to map. the third argument indicates that the
// mapped memory should be read-only. the fourth argument
// indicates that, if the process modifies the mapped memory,
// that the modifications should not be written back to
// the file nor shared with other processes mapping the
// same file (of course in this case updates are prohibited
// due to PROT_READ). the fifth argument is the file descriptor
// of the file to be mapped. the last argument is the starting
// offset in the file.
//
char *p = mmap(0, PGSIZE*2, PROT_READ, MAP_PRIVATE, fd, 0);
if (p == MAP_FAILED)
err("mmap (1)");
_v1(p);
if (munmap(p, PGSIZE*2) == -1)
err("munmap (1)");
printf("test mmap f: OK\n");
printf("test mmap private\n");
// should be able to map file opened read-only with private writable
// mapping
p = mmap(0, PGSIZE*2, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
if (p == MAP_FAILED)
err("mmap (2)");
if (close(fd) == -1)
err("close");
_v1(p);
for (i = 0; i < PGSIZE*2; i++)
p[i] = 'Z';
if (munmap(p, PGSIZE*2) == -1)
err("munmap (2)");
printf("test mmap private: OK\n");
printf("test mmap read-only\n");
// check that mmap doesn't allow read/write mapping of a
// file opened read-only.
if ((fd = open(f, O_RDONLY)) == -1)
err("open");
p = mmap(0, PGSIZE*3, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (p != MAP_FAILED)
err("mmap call should have failed");
if (close(fd) == -1)
err("close");
printf("test mmap read-only: OK\n");
printf("test mmap read/write\n");
// check that mmap does allow read/write mapping of a
// file opened read/write.
if ((fd = open(f, O_RDWR)) == -1)
err("open");
p = mmap(0, PGSIZE*3, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (p == MAP_FAILED)
err("mmap (3)");
if (close(fd) == -1)
err("close");
// check that the mapping still works after close(fd).
_v1(p);
// write the mapped memory.
for (i = 0; i < PGSIZE*2; i++)
p[i] = 'Z';
// unmap just the first two of three pages of mapped memory.
if (munmap(p, PGSIZE*2) == -1)
err("munmap (3)");
printf("test mmap read/write: OK\n");
printf("test mmap dirty\n");
// check that the writes to the mapped memory were
// written to the file.
if ((fd = open(f, O_RDWR)) == -1)
err("open");
for (i = 0; i < PGSIZE + (PGSIZE/2); i++){
char b;
if (read(fd, &b, 1) != 1)
err("read (1)");
if (b != 'Z')
err("file does not contain modifications");
}
if (close(fd) == -1)
err("close");
printf("test mmap dirty: OK\n");
printf("test not-mapped unmap\n");
// unmap the rest of the mapped memory.
if (munmap(p+PGSIZE*2, PGSIZE) == -1)
err("munmap (4)");
printf("test not-mapped unmap: OK\n");
printf("test mmap two files\n");
//
// mmap two files at the same time.
//
int fd1;
if((fd1 = open("mmap1", O_RDWR|O_CREATE)) < 0)
err("open mmap1");
if(write(fd1, "12345", 5) != 5)
err("write mmap1");
char *p1 = mmap(0, PGSIZE, PROT_READ, MAP_PRIVATE, fd1, 0);
if(p1 == MAP_FAILED)
err("mmap mmap1");
close(fd1);
unlink("mmap1");
int fd2;
if((fd2 = open("mmap2", O_RDWR|O_CREATE)) < 0)
err("open mmap2");
if(write(fd2, "67890", 5) != 5)
err("write mmap2");
char *p2 = mmap(0, PGSIZE, PROT_READ, MAP_PRIVATE, fd2, 0);
if(p2 == MAP_FAILED)
err("mmap mmap2");
close(fd2);
unlink("mmap2");
if(memcmp(p1, "12345", 5) != 0)
err("mmap1 mismatch");
if(memcmp(p2, "67890", 5) != 0)
err("mmap2 mismatch");
munmap(p1, PGSIZE);
if(memcmp(p2, "67890", 5) != 0)
err("mmap2 mismatch (2)");
munmap(p2, PGSIZE);
printf("test mmap two files: OK\n");
printf("mmap_test: ALL OK\n");
}
//
// mmap a file, then fork.
// check that the child sees the mapped file.
//
void
fork_test(void)
{
int fd;
int pid;
const char * const f = "mmap.dur";
printf("fork_test starting\n");
testname = "fork_test";
// mmap the file twice.
makefile(f);
if ((fd = open(f, O_RDONLY)) == -1)
err("open");
unlink(f);
char *p1 = mmap(0, PGSIZE*2, PROT_READ, MAP_SHARED, fd, 0);
if (p1 == MAP_FAILED)
err("mmap (4)");
char *p2 = mmap(0, PGSIZE*2, PROT_READ, MAP_SHARED, fd, 0);
if (p2 == MAP_FAILED)
err("mmap (5)");
// read just 2nd page.
if(*(p1+PGSIZE) != 'A')
err("fork mismatch (1)");
if((pid = fork()) < 0)
err("fork");
if (pid == 0) {
_v1(p1);
munmap(p1, PGSIZE); // just the first page
exit(0); // tell the parent that the mapping looks OK.
}
int status = -1;
wait(&status);
if(status != 0){
printf("fork_test failed\n");
exit(1);
}
// check that the parent's mappings are still there.
_v1(p1);
_v1(p2);
printf("fork_test OK\n");
}

View File

@ -1,27 +0,0 @@
#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);
}
}

View File

@ -1,51 +0,0 @@
#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);
}

View File

@ -1,17 +0,0 @@
#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,6 +22,8 @@ int getpid(void);
char* sbrk(int);
int sleep(int);
int uptime(void);
void *mmap(void *addr, int length, int prot, int flags, int fd, int offset);
int munmap(void *addr, int length);
// ulib.c
int stat(const char*, struct stat*);

View File

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

View File

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

View File

@ -1,59 +0,0 @@
#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);
}

View File

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