Compare commits

..

5 Commits
lock ... 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
37 changed files with 387 additions and 1322 deletions

View File

@ -106,7 +106,7 @@ endif
ifdef KCSAN ifdef KCSAN
CFLAGS += -DKCSAN CFLAGS += -DKCSAN
KCSANFLAG = -fsanitize=thread -fno-inline KCSANFLAG = -fsanitize=thread
endif endif
# Disable PIE when possible (for Ubuntu 16.10 toolchain) # Disable PIE when possible (for Ubuntu 16.10 toolchain)
@ -188,6 +188,11 @@ UPROGS=\
$U/_grind\ $U/_grind\
$U/_wc\ $U/_wc\
$U/_zombie\ $U/_zombie\
$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 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 +1 @@
LAB=lock LAB=util

View File

@ -1,58 +0,0 @@
#!/usr/bin/env python3
import re
from gradelib import *
r = Runner(save("xv6.out"))
@test(0, "running kalloctest")
def test_kalloctest():
r.run_qemu(shell_script([
'kalloctest'
]), timeout=200)
@test(10, "kalloctest: test1", parent=test_kalloctest)
def test_kalloctest_test1():
r.match('^test1 OK$')
@test(10, "kalloctest: test2", parent=test_kalloctest)
def test_kalloctest_test2():
r.match('^test2 OK$')
@test(10, "kalloctest: test3", parent=test_kalloctest)
def test_kalloctest_test3():
r.match('^test3 OK$')
@test(10, "kalloctest: sbrkmuch")
def test_sbrkmuch():
r.run_qemu(shell_script([
'usertests sbrkmuch'
]), timeout=90)
r.match('^ALL TESTS PASSED$')
@test(0, "running bcachetest")
def test_bcachetest():
r.run_qemu(shell_script([
'bcachetest'
]), timeout=90)
@test(10, "bcachetest: test0", parent=test_bcachetest)
def test_bcachetest_test0():
r.match('^test0: OK$')
@test(10, "bcachetest: test1", parent=test_bcachetest)
def test_bcachetest_test1():
r.match('^test1 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()

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

@ -33,34 +33,13 @@ struct {
struct buf head; struct buf head;
} bcache; } bcache;
#define NLOCK_BUCKETS 13
// #define ORIGINAL
struct spinlock hash_locks[NLOCK_BUCKETS];
static char lock_names [NLOCK_BUCKETS][20];
struct hash_tbl {
struct buf* buf;
struct hash_tbl *next;
} hash_tbl;
struct hash_tbl* hash_entry[NLOCK_BUCKETS];
struct hash_tbl hash_tbls[NBUF];
void void
binit(void) binit(void)
{ {
struct buf *b; struct buf *b;
initlock(&bcache.lock, "bcache"); initlock(&bcache.lock, "bcache");
for (int i = 0; i < NLOCK_BUCKETS; ++ i) {
snprintf(lock_names[i], 20, "bcache.lk%d", i);
initlock(&hash_locks[i], lock_names[i]);
hash_entry[i] = 0;
}
for (int i = 0; i < NBUF; ++ i) {
hash_tbls[i].buf = &bcache.buf[i];
hash_tbls[i].next = 0;
}
// Create linked list of buffers // Create linked list of buffers
bcache.head.prev = &bcache.head; bcache.head.prev = &bcache.head;
bcache.head.next = &bcache.head; bcache.head.next = &bcache.head;
@ -79,69 +58,12 @@ binit(void)
static struct buf* static struct buf*
bget(uint dev, uint blockno) bget(uint dev, uint blockno)
{ {
struct buf *b = 0; struct buf *b;
// acquire(&bcache.lock);
#ifndef ORIGINAL
int bucket = blockno % NLOCK_BUCKETS;
acquire(&hash_locks[bucket]);
struct hash_tbl* h = hash_entry[bucket];
struct hash_tbl* ph = 0;
while (h != 0) {
if (h->buf->dev == dev && h->buf->blockno == blockno) {
b = h->buf;
b->refcnt ++;
release(&hash_locks[bucket]);
// release(&bcache.lock);
acquiresleep(&b->lock);
return b;
}
h = h->next;
}
release(&hash_locks[bucket]);
// release the unfound bucket, or there'll be deadlock
acquire(&bcache.lock); acquire(&bcache.lock);
// after bcache.lock is aquired, only b->refcnt maybe out of our control
// so, have to aquire hash_locks[victim_bucket] before test refcnt
for(int i = 0; i < NBUF; ++ i){
b = &bcache.buf[i];
int victim_bucket = b->blockno % NLOCK_BUCKETS;
acquire(&hash_locks[victim_bucket]);
if(b->refcnt == 0) {
b->dev = dev;
b->blockno = blockno;
b->valid = 0;
b->refcnt = 1;
// try to release hash entry from the old bucket
h = hash_entry[victim_bucket];
ph = 0;
while (h != 0) {
if (h->buf->dev == b->dev && h->buf->blockno == b->blockno) {
if (ph) ph->next = h->next;
else hash_entry[victim_bucket] = h->next;
break;
}
ph = h;
h = h->next;
}
release(&hash_locks[victim_bucket]);
release(&bcache.lock);
// this should avoid deadlock and meanwhile guard the hashtable
// because after b is set, the only thing we need is hashtable rather than buf attributes
h = &hash_tbls[i];
acquire(&hash_locks[bucket]);
h->next = hash_entry[bucket];
hash_entry[bucket] = h;
release(&hash_locks[bucket]);
acquiresleep(&b->lock);
return b;
}
release(&hash_locks[victim_bucket]);
}
#else
// Is the block already cached? // Is the block already cached?
// for(b = bcache.head.next; b != &bcache.head; b = b->next){ for(b = bcache.head.next; b != &bcache.head; b = b->next){
for (b = &bcache.buf[0]; b < &bcache.buf[NBUF]; ++ b) {
if(b->dev == dev && b->blockno == blockno){ if(b->dev == dev && b->blockno == blockno){
b->refcnt++; b->refcnt++;
release(&bcache.lock); release(&bcache.lock);
@ -152,8 +74,7 @@ bget(uint dev, uint blockno)
// Not cached. // Not cached.
// Recycle the least recently used (LRU) unused buffer. // Recycle the least recently used (LRU) unused buffer.
// for(b = bcache.head.prev; b != &bcache.head; b = b->prev){ for(b = bcache.head.prev; b != &bcache.head; b = b->prev){
for(b = &bcache.buf[0]; b < &bcache.buf[NBUF]; ++ b){
if(b->refcnt == 0) { if(b->refcnt == 0) {
b->dev = dev; b->dev = dev;
b->blockno = blockno; b->blockno = blockno;
@ -164,7 +85,6 @@ bget(uint dev, uint blockno)
return b; return b;
} }
} }
#endif
panic("bget: no buffers"); panic("bget: no buffers");
} }
@ -201,25 +121,19 @@ brelse(struct buf *b)
releasesleep(&b->lock); releasesleep(&b->lock);
// if you use bcache lock, test0 fails without doubt acquire(&bcache.lock);
// the reason why this works is that, whenever b->refcnt is written or read
// its 'hash_locks[H(b->blockno)]' will always been locked
// the reason why b->blockno is valid is that, only when refcnt==0 could this field be written
// but here it must be non-zero before lock aquired
int bucket = b->blockno % NLOCK_BUCKETS;
acquire(&hash_locks[bucket]);
b->refcnt--; b->refcnt--;
// if (b->refcnt == 0) { if (b->refcnt == 0) {
// // no one is waiting for it. // no one is waiting for it.
// b->next->prev = b->prev; b->next->prev = b->prev;
// b->prev->next = b->next; b->prev->next = b->next;
// b->next = bcache.head.next; b->next = bcache.head.next;
// b->prev = &bcache.head; b->prev = &bcache.head;
// bcache.head.next->prev = b; bcache.head.next->prev = b;
// bcache.head.next = b; bcache.head.next = b;
// } }
release(&hash_locks[bucket]); release(&bcache.lock);
} }
void void

View File

@ -8,10 +8,6 @@ struct spinlock;
struct sleeplock; struct sleeplock;
struct stat; struct stat;
struct superblock; struct superblock;
#ifdef LAB_NET
struct mbuf;
struct sock;
#endif
// bio.c // bio.c
void binit(void); void binit(void);
@ -121,10 +117,6 @@ void initlock(struct spinlock*, char*);
void release(struct spinlock*); void release(struct spinlock*);
void push_off(void); void push_off(void);
void pop_off(void); void pop_off(void);
int atomic_read4(int *addr);
#ifdef LAB_LOCK
void freelock(struct spinlock*);
#endif
// sleeplock.c // sleeplock.c
void acquiresleep(struct sleeplock*); void acquiresleep(struct sleeplock*);
@ -195,44 +187,3 @@ void virtio_disk_intr(void);
// number of elements in fixed-size array // number of elements in fixed-size array
#define NELEM(x) (sizeof(x)/sizeof((x)[0])) #define NELEM(x) (sizeof(x)/sizeof((x)[0]))
#ifdef LAB_PGTBL
// vmcopyin.c
int copyin_new(pagetable_t, char *, uint64, uint64);
int copyinstr_new(pagetable_t, char *, uint64, uint64);
#endif
// stats.c
void statsinit(void);
void statsinc(void);
// sprintf.c
int snprintf(char*, int, char*, ...);
#ifdef KCSAN
void kcsaninit();
#endif
#ifdef LAB_NET
// pci.c
void pci_init();
// e1000.c
void e1000_init(uint32 *);
void e1000_intr(void);
int e1000_transmit(struct mbuf*);
// net.c
void net_rx(struct mbuf*);
void net_tx_udp(struct mbuf*, uint32, uint16, uint16);
// sysnet.c
void sockinit(void);
int sockalloc(struct file **, uint32, uint16, uint16);
void sockclose(struct sock *);
int sockread(struct sock *, uint64, int);
int sockwrite(struct sock *, uint64, int);
void sockrecvudp(struct mbuf*, uint32, uint16, uint16);
#endif

View File

@ -1,17 +1,10 @@
struct file { struct file {
#ifdef LAB_NET
enum { FD_NONE, FD_PIPE, FD_INODE, FD_DEVICE, FD_SOCK } type;
#else
enum { FD_NONE, FD_PIPE, FD_INODE, FD_DEVICE } type; enum { FD_NONE, FD_PIPE, FD_INODE, FD_DEVICE } type;
#endif
int ref; // reference count int ref; // reference count
char readable; char readable;
char writable; char writable;
struct pipe *pipe; // FD_PIPE struct pipe *pipe; // FD_PIPE
struct inode *ip; // FD_INODE and FD_DEVICE struct inode *ip; // FD_INODE and FD_DEVICE
#ifdef LAB_NET
struct sock *sock; // FD_SOCK
#endif
uint off; // FD_INODE uint off; // FD_INODE
short major; // FD_DEVICE short major; // FD_DEVICE
}; };
@ -45,4 +38,3 @@ struct devsw {
extern struct devsw devsw[]; extern struct devsw devsw[];
#define CONSOLE 1 #define CONSOLE 1
#define STATS 2

View File

@ -295,11 +295,11 @@ ilock(struct inode *ip)
struct buf *bp; struct buf *bp;
struct dinode *dip; struct dinode *dip;
if(ip == 0 || atomic_read4(&ip->ref) < 1) if(ip == 0 || ip->ref < 1)
panic("ilock"); panic("ilock");
acquiresleep(&ip->lock); acquiresleep(&ip->lock);
if(ip->valid == 0){ if(ip->valid == 0){
bp = bread(ip->dev, IBLOCK(ip->inum, sb)); bp = bread(ip->dev, IBLOCK(ip->inum, sb));
dip = (struct dinode*)bp->data + ip->inum%IPB; dip = (struct dinode*)bp->data + ip->inum%IPB;
@ -320,7 +320,7 @@ ilock(struct inode *ip)
void void
iunlock(struct inode *ip) iunlock(struct inode *ip)
{ {
if(ip == 0 || !holdingsleep(&ip->lock) || atomic_read4(&ip->ref) < 1) if(ip == 0 || !holdingsleep(&ip->lock) || ip->ref < 1)
panic("iunlock"); panic("iunlock");
releasesleep(&ip->lock); releasesleep(&ip->lock);
@ -416,6 +416,7 @@ bmap(struct inode *ip, uint bn)
brelse(bp); brelse(bp);
return addr; return addr;
} }
panic("bmap: out of range"); panic("bmap: out of range");
} }
@ -446,7 +447,7 @@ itrunc(struct inode *ip)
bfree(ip->dev, ip->addrs[NDIRECT]); bfree(ip->dev, ip->addrs[NDIRECT]);
ip->addrs[NDIRECT] = 0; ip->addrs[NDIRECT] = 0;
} }
ip->size = 0; ip->size = 0;
iupdate(ip); iupdate(ip);
} }

View File

@ -19,19 +19,14 @@ struct run {
}; };
struct { struct {
struct spinlock lock[NCPU]; struct spinlock lock;
struct run *freelist[NCPU]; struct run *freelist;
} kmem; } kmem;
static char kmem_lock_names [NCPU][10]; // ugly but have-to impl
void void
kinit() kinit()
{ {
for (int i = 0; i < NCPU; ++ i) { initlock(&kmem.lock, "kmem");
snprintf(kmem_lock_names[i], NELEM(kmem_lock_names[0]), "kmem%d", i);
initlock(&kmem.lock[i], kmem_lock_names[i]);
}
freerange(end, (void*)PHYSTOP); freerange(end, (void*)PHYSTOP);
} }
@ -60,13 +55,11 @@ kfree(void *pa)
memset(pa, 1, PGSIZE); memset(pa, 1, PGSIZE);
r = (struct run*)pa; r = (struct run*)pa;
push_off();
int _cpu = cpuid(); acquire(&kmem.lock);
acquire(&kmem.lock[_cpu]); r->next = kmem.freelist;
r->next = kmem.freelist[_cpu]; kmem.freelist = r;
kmem.freelist[_cpu] = r; release(&kmem.lock);
release(&kmem.lock[_cpu]);
pop_off();
} }
// Allocate one 4096-byte page of physical memory. // Allocate one 4096-byte page of physical memory.
@ -76,27 +69,13 @@ void *
kalloc(void) kalloc(void)
{ {
struct run *r; struct run *r;
push_off();
int _cpu = cpuid(); acquire(&kmem.lock);
acquire(&kmem.lock[_cpu]); r = kmem.freelist;
r = kmem.freelist[_cpu];
if(r) if(r)
kmem.freelist[_cpu] = r->next; kmem.freelist = r->next;
else { release(&kmem.lock);
for (int i = 0, found = 0; i < NCPU && !found; ++ i) {
if (i != _cpu) {
acquire(&kmem.lock[i]);
if (kmem.freelist[i]) {
r = kmem.freelist[i];
kmem.freelist[i] = r->next;
found = 1;
}
release(&kmem.lock[i]);
}
}
}
release(&kmem.lock[_cpu]);
pop_off();
if(r) if(r)
memset((char*)r, 5, PGSIZE); // fill with junk memset((char*)r, 5, PGSIZE); // fill with junk
return (void*)r; return (void*)r;

View File

@ -1,323 +0,0 @@
#include "types.h"
#include "param.h"
#include "memlayout.h"
#include "spinlock.h"
#include "riscv.h"
#include "proc.h"
#include "defs.h"
//
// Race detector using gcc's thread sanitizer. It delays all stores
// and loads and monitors if any other CPU is using the same address.
// If so, we have a race and print out the backtrace of the thread
// that raced and the thread that set the watchpoint.
//
//
// To run with kcsan:
// make clean
// make KCSAN=1 qemu
//
// The number of watch points.
#define NWATCH (NCPU)
// The number of cycles to delay stores, whatever that means on qemu.
//#define DELAY_CYCLES 20000
#define DELAY_CYCLES 200000
#define MAXTRACE 20
int
trace(uint64 *trace, int maxtrace)
{
uint64 i = 0;
push_off();
uint64 fp = r_fp();
uint64 ra, low = PGROUNDDOWN(fp) + 16, high = PGROUNDUP(fp);
while(!(fp & 7) && fp >= low && fp < high){
ra = *(uint64*)(fp - 8);
fp = *(uint64*)(fp - 16);
trace[i++] = ra;
if(i >= maxtrace)
break;
}
pop_off();
return i;
}
struct watch {
uint64 addr;
int write;
int race;
uint64 trace[MAXTRACE];
int tracesz;
};
struct {
struct spinlock lock;
struct watch points[NWATCH];
int on;
} tsan;
static struct watch*
wp_lookup(uint64 addr)
{
for(struct watch *w = &tsan.points[0]; w < &tsan.points[NWATCH]; w++) {
if(w->addr == addr) {
return w;
}
}
return 0;
}
static int
wp_install(uint64 addr, int write)
{
for(struct watch *w = &tsan.points[0]; w < &tsan.points[NWATCH]; w++) {
if(w->addr == 0) {
w->addr = addr;
w->write = write;
w->tracesz = trace(w->trace, MAXTRACE);
return 1;
}
}
panic("wp_install");
return 0;
}
static void
wp_remove(uint64 addr)
{
for(struct watch *w = &tsan.points[0]; w < &tsan.points[NWATCH]; w++) {
if(w->addr == addr) {
w->addr = 0;
w->tracesz = 0;
return;
}
}
panic("remove");
}
static void
printtrace(uint64 *t, int n)
{
int i;
for(i = 0; i < n; i++) {
printf("%p\n", t[i]);
}
}
static void
race(char *s, struct watch *w) {
uint64 t[MAXTRACE];
int n;
n = trace(t, MAXTRACE);
printf("== race detected ==\n");
printf("backtrace for racing %s\n", s);
printtrace(t, n);
printf("backtrace for watchpoint:\n");
printtrace(w->trace, w->tracesz);
printf("==========\n");
}
// cycle counter
static inline uint64
r_cycle()
{
uint64 x;
asm volatile("rdcycle %0" : "=r" (x) );
return x;
}
static void delay(void) __attribute__((noinline));
static void delay() {
uint64 stop = r_cycle() + DELAY_CYCLES;
uint64 c = r_cycle();
while(c < stop) {
c = r_cycle();
}
}
static void
kcsan_read(uint64 addr, int sz)
{
struct watch *w;
acquire(&tsan.lock);
if((w = wp_lookup(addr)) != 0) {
if(w->write) {
race("load", w);
}
release(&tsan.lock);
return;
}
release(&tsan.lock);
}
static void
kcsan_write(uint64 addr, int sz)
{
struct watch *w;
acquire(&tsan.lock);
if((w = wp_lookup(addr)) != 0) {
race("store", w);
release(&tsan.lock);
}
// no watchpoint; try to install one
if(wp_install(addr, 1)) {
release(&tsan.lock);
// XXX maybe read value at addr before and after delay to catch
// races of unknown origins (e.g., device).
delay();
acquire(&tsan.lock);
wp_remove(addr);
}
release(&tsan.lock);
}
// tsan.on will only have effect with "make KCSAN=1"
void
kcsaninit(void)
{
initlock(&tsan.lock, "tsan");
tsan.on = 1;
__sync_synchronize();
}
//
// Calls inserted by compiler into kernel binary, except for this file.
//
void
__tsan_init(void)
{
}
void
__tsan_read1(uint64 addr)
{
if(!tsan.on)
return;
// kcsan_read(addr, 1);
}
void
__tsan_read2(uint64 addr)
{
if(!tsan.on)
return;
kcsan_read(addr, 2);
}
void
__tsan_read4(uint64 addr)
{
if(!tsan.on)
return;
kcsan_read(addr, 4);
}
void
__tsan_read8(uint64 addr)
{
if(!tsan.on)
return;
kcsan_read(addr, 8);
}
void
__tsan_read_range(uint64 addr, uint64 size)
{
if(!tsan.on)
return;
kcsan_read(addr, size);
}
void
__tsan_write1(uint64 addr)
{
if(!tsan.on)
return;
// kcsan_write(addr, 1);
}
void
__tsan_write2(uint64 addr)
{
if(!tsan.on)
return;
kcsan_write(addr, 2);
}
void
__tsan_write4(uint64 addr)
{
if(!tsan.on)
return;
kcsan_write(addr, 4);
}
void
__tsan_write8(uint64 addr)
{
if(!tsan.on)
return;
kcsan_write(addr, 8);
}
void
__tsan_write_range(uint64 addr, uint64 size)
{
if(!tsan.on)
return;
kcsan_write(addr, size);
}
void
__tsan_atomic_thread_fence(int order)
{
__sync_synchronize();
}
uint32
__tsan_atomic32_load(uint *ptr, uint *val, int order)
{
uint t;
__atomic_load(ptr, &t, __ATOMIC_SEQ_CST);
return t;
}
void
__tsan_atomic32_store(uint *ptr, uint val, int order)
{
__atomic_store(ptr, &val, __ATOMIC_SEQ_CST);
}
// We don't use this
void
__tsan_func_entry(uint64 pc)
{
}
// We don't use this
void
__tsan_func_exit(void)
{
}

View File

@ -12,9 +12,6 @@ main()
{ {
if(cpuid() == 0){ if(cpuid() == 0){
consoleinit(); consoleinit();
#if defined(LAB_LOCK)
statsinit();
#endif
printfinit(); printfinit();
printf("\n"); printf("\n");
printf("xv6 kernel is booting\n"); printf("xv6 kernel is booting\n");
@ -31,18 +28,11 @@ main()
iinit(); // inode table iinit(); // inode table
fileinit(); // file table fileinit(); // file table
virtio_disk_init(); // emulated hard disk virtio_disk_init(); // emulated hard disk
#ifdef LAB_NET
pci_init();
sockinit();
#endif
userinit(); // first user process userinit(); // first user process
#ifdef KCSAN
kcsaninit();
#endif
__sync_synchronize(); __sync_synchronize();
started = 1; started = 1;
} else { } else {
while(atomic_read4((int *) &started) == 0) while(started == 0)
; ;
__sync_synchronize(); __sync_synchronize();
printf("hart %d starting\n", cpuid()); printf("hart %d starting\n", cpuid());

View File

@ -68,9 +68,6 @@ pipeclose(struct pipe *pi, int writable)
} }
if(pi->readopen == 0 && pi->writeopen == 0){ if(pi->readopen == 0 && pi->writeopen == 0){
release(&pi->lock); release(&pi->lock);
#ifdef LAB_LOCK
freelock(&pi->lock);
#endif
kfree((char*)pi); kfree((char*)pi);
} else } else
release(&pi->lock); release(&pi->lock);

View File

@ -295,14 +295,6 @@ r_sp()
return x; return x;
} }
static inline uint64
r_fp()
{
uint64 x;
asm volatile("mv %0, s0" : "=r" (x) );
return x;
}
// read and write tp, the thread pointer, which xv6 uses to hold // read and write tp, the thread pointer, which xv6 uses to hold
// this core's hartid (core number), the index into cpus[]. // this core's hartid (core number), the index into cpus[].
static inline uint64 static inline uint64
@ -352,9 +344,6 @@ typedef uint64 *pagetable_t; // 512 PTEs
#define PTE_X (1L << 3) #define PTE_X (1L << 3)
#define PTE_U (1L << 4) // user can access #define PTE_U (1L << 4) // user can access
// shift a physical address to the right place for a PTE. // shift a physical address to the right place for a PTE.
#define PA2PTE(pa) ((((uint64)pa) >> 12) << 10) #define PA2PTE(pa) ((((uint64)pa) >> 12) << 10)

View File

@ -8,52 +8,12 @@
#include "proc.h" #include "proc.h"
#include "defs.h" #include "defs.h"
#ifdef LAB_LOCK
#define NLOCK 500
static struct spinlock *locks[NLOCK];
struct spinlock lock_locks;
void
freelock(struct spinlock *lk)
{
acquire(&lock_locks);
int i;
for (i = 0; i < NLOCK; i++) {
if(locks[i] == lk) {
locks[i] = 0;
break;
}
}
release(&lock_locks);
}
static void
findslot(struct spinlock *lk) {
acquire(&lock_locks);
int i;
for (i = 0; i < NLOCK; i++) {
if(locks[i] == 0) {
locks[i] = lk;
release(&lock_locks);
return;
}
}
panic("findslot");
}
#endif
void void
initlock(struct spinlock *lk, char *name) initlock(struct spinlock *lk, char *name)
{ {
lk->name = name; lk->name = name;
lk->locked = 0; lk->locked = 0;
lk->cpu = 0; lk->cpu = 0;
#ifdef LAB_LOCK
lk->nts = 0;
lk->n = 0;
findslot(lk);
#endif
} }
// Acquire the lock. // Acquire the lock.
@ -65,21 +25,12 @@ acquire(struct spinlock *lk)
if(holding(lk)) if(holding(lk))
panic("acquire"); panic("acquire");
#ifdef LAB_LOCK
__sync_fetch_and_add(&(lk->n), 1);
#endif
// On RISC-V, sync_lock_test_and_set turns into an atomic swap: // On RISC-V, sync_lock_test_and_set turns into an atomic swap:
// a5 = 1 // a5 = 1
// s1 = &lk->locked // s1 = &lk->locked
// amoswap.w.aq a5, a5, (s1) // amoswap.w.aq a5, a5, (s1)
while(__sync_lock_test_and_set(&lk->locked, 1) != 0) { while(__sync_lock_test_and_set(&lk->locked, 1) != 0)
#ifdef LAB_LOCK ;
__sync_fetch_and_add(&(lk->nts), 1);
#else
;
#endif
}
// Tell the C compiler and the processor to not move loads or stores // Tell the C compiler and the processor to not move loads or stores
// past this point, to ensure that the critical section's memory // past this point, to ensure that the critical section's memory
@ -157,61 +108,3 @@ pop_off(void)
if(c->noff == 0 && c->intena) if(c->noff == 0 && c->intena)
intr_on(); intr_on();
} }
// Read a shared 32-bit value without holding a lock
int
atomic_read4(int *addr) {
uint32 val;
__atomic_load(addr, &val, __ATOMIC_SEQ_CST);
return val;
}
#ifdef LAB_LOCK
int
snprint_lock(char *buf, int sz, struct spinlock *lk)
{
int n = 0;
if(lk->n > 0) {
n = snprintf(buf, sz, "lock: %s: #test-and-set %d #acquire() %d\n",
lk->name, lk->nts, lk->n);
}
return n;
}
int
statslock(char *buf, int sz) {
int n;
int tot = 0;
acquire(&lock_locks);
n = snprintf(buf, sz, "--- lock kmem/bcache stats\n");
for(int i = 0; i < NLOCK; i++) {
if(locks[i] == 0)
break;
if(strncmp(locks[i]->name, "bcache", strlen("bcache")) == 0 ||
strncmp(locks[i]->name, "kmem", strlen("kmem")) == 0) {
tot += locks[i]->nts;
n += snprint_lock(buf +n, sz-n, locks[i]);
}
}
n += snprintf(buf+n, sz-n, "--- top 5 contended locks:\n");
int last = 100000000;
// stupid way to compute top 5 contended locks
for(int t = 0; t < 5; t++) {
int top = 0;
for(int i = 0; i < NLOCK; i++) {
if(locks[i] == 0)
break;
if(locks[i]->nts > locks[top]->nts && locks[i]->nts < last) {
top = i;
}
}
n += snprint_lock(buf+n, sz-n, locks[top]);
last = locks[top]->nts;
}
n += snprintf(buf+n, sz-n, "tot= %d\n", tot);
release(&lock_locks);
return n;
}
#endif

View File

@ -5,9 +5,5 @@ struct spinlock {
// For debugging: // For debugging:
char *name; // Name of lock. char *name; // Name of lock.
struct cpu *cpu; // The cpu holding the lock. struct cpu *cpu; // The cpu holding the lock.
#ifdef LAB_LOCK
int nts;
int n;
#endif
}; };

View File

@ -1,91 +0,0 @@
#include <stdarg.h>
#include "types.h"
#include "param.h"
#include "spinlock.h"
#include "sleeplock.h"
#include "fs.h"
#include "file.h"
#include "riscv.h"
#include "defs.h"
static char digits[] = "0123456789abcdef";
static int
sputc(char *s, char c)
{
*s = c;
return 1;
}
static int
sprintint(char *s, int xx, int base, int sign)
{
char buf[16];
int i, n;
uint x;
if(sign && (sign = xx < 0))
x = -xx;
else
x = xx;
i = 0;
do {
buf[i++] = digits[x % base];
} while((x /= base) != 0);
if(sign)
buf[i++] = '-';
n = 0;
while(--i >= 0)
n += sputc(s+n, buf[i]);
return n;
}
int
snprintf(char *buf, int sz, char *fmt, ...)
{
va_list ap;
int i, c;
int off = 0;
char *s;
if (fmt == 0)
panic("null fmt");
va_start(ap, fmt);
for(i = 0; off < sz && (c = fmt[i] & 0xff) != 0; i++){
if(c != '%'){
off += sputc(buf+off, c);
continue;
}
c = fmt[++i] & 0xff;
if(c == 0)
break;
switch(c){
case 'd':
off += sprintint(buf+off, va_arg(ap, int), 10, 1);
break;
case 'x':
off += sprintint(buf+off, va_arg(ap, int), 16, 1);
break;
case 's':
if((s = va_arg(ap, char*)) == 0)
s = "(null)";
for(; *s && off < sz; s++)
off += sputc(buf+off, *s);
break;
case '%':
off += sputc(buf+off, '%');
break;
default:
// Print unknown % sequence to draw attention.
off += sputc(buf+off, '%');
off += sputc(buf+off, c);
break;
}
}
return off;
}

View File

@ -38,11 +38,6 @@ start()
w_mideleg(0xffff); w_mideleg(0xffff);
w_sie(r_sie() | SIE_SEIE | SIE_STIE | SIE_SSIE); w_sie(r_sie() | SIE_SEIE | SIE_STIE | SIE_SSIE);
#ifdef KCSAN
// allow supervisor to read cycle counter register
w_mcounteren(r_mcounteren()|0x3);
#endif
// configure Physical Memory Protection to give supervisor mode // configure Physical Memory Protection to give supervisor mode
// access to all of physical memory. // access to all of physical memory.
w_pmpaddr0(0x3fffffffffffffull); w_pmpaddr0(0x3fffffffffffffull);

View File

@ -1,69 +0,0 @@
#include <stdarg.h>
#include "types.h"
#include "param.h"
#include "spinlock.h"
#include "sleeplock.h"
#include "fs.h"
#include "file.h"
#include "riscv.h"
#include "defs.h"
#define BUFSZ 4096
static struct {
struct spinlock lock;
char buf[BUFSZ];
int sz;
int off;
} stats;
int statscopyin(char*, int);
int statslock(char*, int);
int
statswrite(int user_src, uint64 src, int n)
{
return -1;
}
int
statsread(int user_dst, uint64 dst, int n)
{
int m;
acquire(&stats.lock);
if(stats.sz == 0) {
#ifdef LAB_PGTBL
stats.sz = statscopyin(stats.buf, BUFSZ);
#endif
#ifdef LAB_LOCK
stats.sz = statslock(stats.buf, BUFSZ);
#endif
}
m = stats.sz - stats.off;
if (m > 0) {
if(m > n)
m = n;
if(either_copyout(user_dst, dst, stats.buf+stats.off, m) != -1) {
stats.off += m;
}
} else {
m = -1;
stats.sz = 0;
stats.off = 0;
}
release(&stats.lock);
return m;
}
void
statsinit(void)
{
initlock(&stats.lock, "stats");
devsw[STATS].read = statsread;
devsw[STATS].write = statswrite;
}

View File

@ -55,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){

View File

@ -1 +1 @@
9 6

View File

@ -1,189 +0,0 @@
#include "kernel/fcntl.h"
#include "kernel/param.h"
#include "kernel/types.h"
#include "kernel/stat.h"
#include "kernel/riscv.h"
#include "kernel/fs.h"
#include "user/user.h"
void test0();
void test1();
#define SZ 4096
char buf[SZ];
int
main(int argc, char *argv[])
{
test0();
test1();
exit(0);
}
void
createfile(char *file, int nblock)
{
int fd;
char buf[BSIZE];
int i;
fd = open(file, O_CREATE | O_RDWR);
if(fd < 0){
printf("createfile %s failed\n", file);
exit(-1);
}
for(i = 0; i < nblock; i++) {
if(write(fd, buf, sizeof(buf)) != sizeof(buf)) {
printf("write %s failed\n", file);
exit(-1);
}
}
close(fd);
}
void
readfile(char *file, int nbytes, int inc)
{
char buf[BSIZE];
int fd;
int i;
if(inc > BSIZE) {
printf("readfile: inc too large\n");
exit(-1);
}
if ((fd = open(file, O_RDONLY)) < 0) {
printf("readfile open %s failed\n", file);
exit(-1);
}
for (i = 0; i < nbytes; i += inc) {
if(read(fd, buf, inc) != inc) {
printf("read %s failed for block %d (%d)\n", file, i, nbytes);
exit(-1);
}
}
close(fd);
}
int ntas(int print)
{
int n;
char *c;
if (statistics(buf, SZ) <= 0) {
fprintf(2, "ntas: no stats\n");
}
c = strchr(buf, '=');
n = atoi(c+2);
if(print)
printf("%s", buf);
return n;
}
// Test reading small files concurrently
void
test0()
{
char file[2];
char dir[2];
enum { N = 10, NCHILD = 3 };
int m, n;
dir[0] = '0';
dir[1] = '\0';
file[0] = 'F';
file[1] = '\0';
printf("start test0\n");
for(int i = 0; i < NCHILD; i++){
dir[0] = '0' + i;
mkdir(dir);
if (chdir(dir) < 0) {
printf("chdir failed\n");
exit(1);
}
unlink(file);
createfile(file, N);
if (chdir("..") < 0) {
printf("chdir failed\n");
exit(1);
}
}
m = ntas(0);
for(int i = 0; i < NCHILD; i++){
dir[0] = '0' + i;
int pid = fork();
if(pid < 0){
printf("fork failed");
exit(-1);
}
if(pid == 0){
if (chdir(dir) < 0) {
printf("chdir failed\n");
exit(1);
}
readfile(file, N*BSIZE, 1);
exit(0);
}
}
for(int i = 0; i < NCHILD; i++){
wait(0);
}
printf("test0 results:\n");
n = ntas(1);
if (n-m < 500)
printf("test0: OK\n");
else
printf("test0: FAIL\n");
}
// Test bcache evictions by reading a large file concurrently
void test1()
{
char file[3];
enum { N = 200, BIG=100, NCHILD=2 };
printf("start test1\n");
file[0] = 'B';
file[2] = '\0';
for(int i = 0; i < NCHILD; i++){
file[1] = '0' + i;
unlink(file);
if (i == 0) {
createfile(file, BIG);
} else {
createfile(file, 1);
}
}
for(int i = 0; i < NCHILD; i++){
file[1] = '0' + i;
int pid = fork();
if(pid < 0){
printf("fork failed");
exit(-1);
}
if(pid == 0){
if (i==0) {
for (i = 0; i < N; i++) {
readfile(file, BIG*BSIZE, BSIZE);
}
unlink(file);
exit(0);
} else {
for (i = 0; i < N*20; i++) {
readfile(file, 1, BSIZE);
}
unlink(file);
}
exit(0);
}
}
for(int i = 0; i < NCHILD; i++){
wait(0);
}
printf("test1 OK\n");
}

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

@ -18,7 +18,6 @@ main(void)
if(open("console", O_RDWR) < 0){ if(open("console", O_RDWR) < 0){
mknod("console", CONSOLE, 0); mknod("console", CONSOLE, 0);
mknod("statistics", STATS, 0);
open("console", O_RDWR); open("console", O_RDWR);
} }
dup(0); // stdout dup(0); // stdout

View File

@ -1,161 +0,0 @@
#include "kernel/param.h"
#include "kernel/types.h"
#include "kernel/stat.h"
#include "kernel/riscv.h"
#include "kernel/memlayout.h"
#include "kernel/fcntl.h"
#include "user/user.h"
#define NCHILD 2
#define N 100000
#define SZ 4096
void test1(void);
void test2(void);
void test3(void);
char buf[SZ];
int
main(int argc, char *argv[])
{
test1();
test2();
test3();
exit(0);
}
int ntas(int print)
{
int n;
char *c;
if (statistics(buf, SZ) <= 0) {
fprintf(2, "ntas: no stats\n");
}
c = strchr(buf, '=');
n = atoi(c+2);
if(print)
printf("%s", buf);
return n;
}
// Test concurrent kallocs and kfrees
void test1(void)
{
void *a, *a1;
int n, m;
printf("start test1\n");
m = ntas(0);
for(int i = 0; i < NCHILD; i++){
int pid = fork();
if(pid < 0){
printf("fork failed");
exit(-1);
}
if(pid == 0){
for(i = 0; i < N; i++) {
a = sbrk(4096);
*(int *)(a+4) = 1;
a1 = sbrk(-4096);
if (a1 != a + 4096) {
printf("wrong sbrk\n");
exit(-1);
}
}
exit(-1);
}
}
for(int i = 0; i < NCHILD; i++){
wait(0);
}
printf("test1 results:\n");
n = ntas(1);
if(n-m < 10)
printf("test1 OK\n");
else
printf("test1 FAIL\n");
}
//
// countfree() from usertests.c
//
int
countfree()
{
uint64 sz0 = (uint64)sbrk(0);
int n = 0;
while(1){
uint64 a = (uint64) sbrk(4096);
if(a == 0xffffffffffffffff){
break;
}
// modify the memory to make sure it's really allocated.
*(char *)(a + 4096 - 1) = 1;
n += 1;
}
sbrk(-((uint64)sbrk(0) - sz0));
return n;
}
// Test stealing
void test2() {
int free0 = countfree();
int free1;
int n = (PHYSTOP-KERNBASE)/PGSIZE;
printf("start test2\n");
printf("total free number of pages: %d (out of %d)\n", free0, n);
if(n - free0 > 1000) {
printf("test2 FAILED: cannot allocate enough memory");
exit(-1);
}
for (int i = 0; i < 50; i++) {
free1 = countfree();
if(i % 10 == 9)
printf(".");
if(free1 != free0) {
printf("test2 FAIL: losing pages\n");
exit(-1);
}
}
printf("\ntest2 OK\n");
}
// Test concurrent kalloc/kfree and stealing
void test3(void)
{
void *a, *a1;
printf("start test3\n");
for(int i = 0; i < NCHILD; i++){
int pid = fork();
if(pid < 0){
printf("fork failed");
exit(-1);
}
if(pid == 0){
if (i == 0) {
for(i = 0; i < N; i++) {
a = sbrk(4096);
*(int *)(a+4) = 1;
a1 = sbrk(-4096);
if (a1 != a + 4096) {
printf("wrong sbrk\n");
exit(-1);
}
}
printf("child done %d\n", i);
exit(0);
} else {
countfree();
printf("child done %d\n", i);
exit(0);
}
}
}
for(int i = 0; i < NCHILD; i++){
wait(0);
}
printf("test3 OK\n");
}

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,24 +0,0 @@
#include "kernel/types.h"
#include "kernel/stat.h"
#include "kernel/fcntl.h"
#include "user/user.h"
int
statistics(void *buf, int sz)
{
int fd, i, n;
fd = open("statistics", O_RDONLY);
if(fd < 0) {
fprintf(2, "stats: open failed\n");
exit(1);
}
for (i = 0; i < sz; ) {
if ((n = read(fd, buf+i, sz-i)) < 0) {
break;
}
i += n;
}
close(fd);
return i;
}

View File

@ -1,24 +0,0 @@
#include "kernel/types.h"
#include "kernel/stat.h"
#include "kernel/fcntl.h"
#include "user/user.h"
#define SZ 4096
char buf[SZ];
int
main(void)
{
int i, n;
while (1) {
n = statistics(buf, SZ);
for (i = 0; i < n; i++) {
write(1, buf+i, 1);
}
if (n != SZ)
break;
}
exit(0);
}

View File

@ -22,14 +22,6 @@ int getpid(void);
char* sbrk(int); char* sbrk(int);
int sleep(int); int sleep(int);
int uptime(void); int uptime(void);
#ifdef LAB_NET
int connect(uint32, uint16, uint16);
#endif
#ifdef LAB_PGTBL
int pgaccess(void *base, int len, void *mask);
// usyscall region
int ugetpid(void);
#endif
// ulib.c // ulib.c
int stat(const char*, struct stat*); int stat(const char*, struct stat*);
@ -47,4 +39,3 @@ void free(void*);
int atoi(const char*); int atoi(const char*);
int memcmp(const void *, const void *, uint); int memcmp(const void *, const void *, uint);
void *memcpy(void *, const void *, uint); void *memcpy(void *, const void *, uint);
int statistics(void*, int);

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