Permalink
Browse files

Merge branch 'lab7'

* lab7:
  7.1
  The last two labs have evolved over time. Add the old ones for historic reference.
  Clear DF after setting it in memmove
  Fix grade script to enable the NIC and to stop after each test is done instead of timing out.  Remove a few old tests that only test provided code.
  Bug fix from ezyang
  lab7
  • Loading branch information...
2 parents a9bc2aa + b449cb8 commit 06d9a2fd78d85cdbb18dab53475ecc38d6195920 @wh5a committed Jun 12, 2010
Showing with 1,405 additions and 176 deletions.
  1. +2 −2 conf/lab.mk
  2. +17 −0 fs/Makefrag
  3. +12 −0 fs/lorem
  4. +1 −0 fs/out
  5. +5 −0 fs/script
  6. +1 −1 fs/serv.c
  7. +69 −0 fs/testshell.key
  8. +1 −0 fs/testshell.out
  9. +8 −0 fs/testshell.sh
  10. +3 −2 grade-functions.sh
  11. +60 −0 grade-lab7.sh
  12. +12 −0 inc/lib.h
  13. +1 −0 inc/trap.h
  14. +11 −8 kern/Makefrag
  15. +6 −2 kern/init.c
  16. +3 −0 kern/trap.c
  17. +3 −0 lib/Makefrag
  18. +112 −1 lib/console.c
  19. +4 −2 lib/fd.c
  20. +3 −1 lib/fork.c
  21. +195 −0 lib/pipe.c
  22. +36 −0 lib/spawn.c
  23. +2 −0 lib/string.c
  24. +13 −0 lib/wait.c
  25. BIN luiz/lab5.pdf
  26. BIN luiz/lab6.pdf
  27. +0 −146 user/faultregs.c
  28. +0 −10 user/faultwrite.c
  29. +19 −1 user/init.c
  30. +318 −0 user/sh.c
  31. +67 −0 user/testfdsharing.c
  32. +26 −0 user/testkbd.c
  33. +24 −0 user/testmalloc.c
  34. +64 −0 user/testpipe.c
  35. +66 −0 user/testpiperace.c
  36. +69 −0 user/testpiperace2.c
  37. +42 −0 user/testptelibrary.c
  38. +45 −0 user/testpteshare.c
  39. +85 −0 user/testshell.c
View
4 conf/lab.mk
@@ -1,2 +1,2 @@
-LAB=6
-PACKAGEDATE=Fri Nov 13 02:30:19 EST 2009
+LAB=7
+PACKAGEDATE=Tue Nov 24 17:32:15 EST 2009
View
17 fs/Makefrag
@@ -21,6 +21,23 @@ FSIMGTXTFILES := fs/newmotd \
FSIMGTXTFILES := $(FSIMGTXTFILES) \
fs/index.html
+USERAPPS := $(USERAPPS) \
+ $(OBJDIR)/user/primespipe \
+ $(OBJDIR)/user/sh \
+ $(OBJDIR)/user/testfdsharing \
+ $(OBJDIR)/user/testkbd \
+ $(OBJDIR)/user/testpipe \
+ $(OBJDIR)/user/testpteshare \
+ $(OBJDIR)/user/testshell \
+ $(OBJDIR)/user/testmalloc
+
+FSIMGTXTFILES := $(FSIMGTXTFILES) \
+ fs/lorem \
+ fs/script \
+ fs/out \
+ fs/testshell.key \
+ fs/testshell.out \
+ fs/testshell.sh
FSIMGFILES := $(FSIMGTXTFILES) $(USERAPPS)
View
12 fs/lorem
@@ -0,0 +1,12 @@
+Lorem ipsum dolor sit amet, consectetur
+adipisicing elit, sed do eiusmod tempor
+incididunt ut labore et dolore magna
+aliqua. Ut enim ad minim veniam, quis
+nostrud exercitation ullamco laboris
+nisi ut aliquip ex ea commodo consequat.
+Duis aute irure dolor in reprehenderit
+in voluptate velit esse cillum dolore eu
+fugiat nulla pariatur. Excepteur sint
+occaecat cupidatat non proident, sunt in
+culpa qui officia deserunt mollit anim
+id est laborum.
View
1 fs/out
@@ -0,0 +1 @@
+
View
5 fs/script
@@ -0,0 +1,5 @@
+echo This is from the script.
+cat lorem | num | cat
+echo These are my file descriptors.
+lsfd -1
+echo This is the end of the script.
View
2 fs/serv.c
@@ -124,7 +124,7 @@ serve_open(envid_t envid, struct Fsreq_open *rq)
if (debug)
cprintf("sending success, page %08x\n", (uintptr_t) o->o_fd);
- ipc_send(envid, 0, o->o_fd, PTE_P|PTE_U|PTE_W|PTE_SHARE);
+ ipc_send(envid, 0, o->o_fd, PTE_P|PTE_U|PTE_W);
return;
out:
ipc_send(envid, r, 0, 0);
View
69 fs/testshell.key
@@ -0,0 +1,69 @@
+# echo hello world | cat
+hello world
+# cat lorem >out
+# cat out
+Lorem ipsum dolor sit amet, consectetur
+adipisicing elit, sed do eiusmod tempor
+incididunt ut labore et dolore magna
+aliqua. Ut enim ad minim veniam, quis
+nostrud exercitation ullamco laboris
+nisi ut aliquip ex ea commodo consequat.
+Duis aute irure dolor in reprehenderit
+in voluptate velit esse cillum dolore eu
+fugiat nulla pariatur. Excepteur sint
+occaecat cupidatat non proident, sunt in
+culpa qui officia deserunt mollit anim
+id est laborum.
+# cat lorem |num
+ 1 Lorem ipsum dolor sit amet, consectetur
+ 2 adipisicing elit, sed do eiusmod tempor
+ 3 incididunt ut labore et dolore magna
+ 4 aliqua. Ut enim ad minim veniam, quis
+ 5 nostrud exercitation ullamco laboris
+ 6 nisi ut aliquip ex ea commodo consequat.
+ 7 Duis aute irure dolor in reprehenderit
+ 8 in voluptate velit esse cillum dolore eu
+ 9 fugiat nulla pariatur. Excepteur sint
+ 10 occaecat cupidatat non proident, sunt in
+ 11 culpa qui officia deserunt mollit anim
+ 12 id est laborum.
+# cat lorem |num |num |num |num |num
+ 1 1 1 1 1 Lorem ipsum dolor sit amet, consectetur
+ 2 2 2 2 2 adipisicing elit, sed do eiusmod tempor
+ 3 3 3 3 3 incididunt ut labore et dolore magna
+ 4 4 4 4 4 aliqua. Ut enim ad minim veniam, quis
+ 5 5 5 5 5 nostrud exercitation ullamco laboris
+ 6 6 6 6 6 nisi ut aliquip ex ea commodo consequat.
+ 7 7 7 7 7 Duis aute irure dolor in reprehenderit
+ 8 8 8 8 8 in voluptate velit esse cillum dolore eu
+ 9 9 9 9 9 fugiat nulla pariatur. Excepteur sint
+ 10 10 10 10 10 occaecat cupidatat non proident, sunt in
+ 11 11 11 11 11 culpa qui officia deserunt mollit anim
+ 12 12 12 12 12 id est laborum.
+# lsfd -1
+fd 0: name testshell.sh isdir 0 size 126 dev file
+fd 1: name testshell.out isdir 0 size 1951 dev file
+# cat script
+echo This is from the script.
+cat lorem | num | cat
+echo These are my file descriptors.
+lsfd -1
+echo This is the end of the script.
+# sh <script
+This is from the script.
+ 1 Lorem ipsum dolor sit amet, consectetur
+ 2 adipisicing elit, sed do eiusmod tempor
+ 3 incididunt ut labore et dolore magna
+ 4 aliqua. Ut enim ad minim veniam, quis
+ 5 nostrud exercitation ullamco laboris
+ 6 nisi ut aliquip ex ea commodo consequat.
+ 7 Duis aute irure dolor in reprehenderit
+ 8 in voluptate velit esse cillum dolore eu
+ 9 fugiat nulla pariatur. Excepteur sint
+ 10 occaecat cupidatat non proident, sunt in
+ 11 culpa qui officia deserunt mollit anim
+ 12 id est laborum.
+These are my file descriptors.
+fd 0: name script isdir 0 size 132 dev file
+fd 1: name testshell.out isdir 0 size 2780 dev file
+This is the end of the script.
View
1 fs/testshell.out
@@ -0,0 +1 @@
+
View
8 fs/testshell.sh
@@ -0,0 +1,8 @@
+echo hello world | cat
+cat lorem >out
+cat out
+cat lorem |num
+cat lorem |num |num |num |num |num
+lsfd -1
+cat script
+sh <script
View
5 grade-functions.sh
@@ -16,6 +16,7 @@ pts=5
timeout=30
preservefs=n
qemu=`$make -s --no-print-directory which-qemu`
+brkfn=readline
echo_n () {
# suns can't echo -n, and Mac OS X can't echo "x\c"
@@ -26,7 +27,7 @@ echo_n () {
run () {
# Find the address of the kernel readline function,
# which the kernel monitor uses to read commands interactively.
- brkaddr=`grep 'readline$' obj/kern/kernel.sym | sed -e's/ .*$//g'`
+ brkaddr=`grep " $brkfn\$" obj/kern/kernel.sym | sed -e's/ .*$//g'`
#echo "brkaddr $brkaddr"
# Generate a unique GDB port
@@ -48,7 +49,7 @@ run () {
) > jos.in
sleep 1
- gdb -batch -nx -x jos.in > /dev/null
+ gdb -batch -nx -x jos.in > /dev/null 2>&1
t1=`date +%s.%N 2>/dev/null`
time=`echo "scale=1; ($t1-$t0)/1" | sed 's/.N/.0/g' | bc 2>/dev/null`
time="(${time}s)"
View
60 grade-lab7.sh
@@ -0,0 +1,60 @@
+#!/bin/sh
+
+qemuopts="-hda obj/kern/kernel.img -hdb obj/fs/fs.img -net user -net nic,model=i82559er"
+. ./grade-functions.sh
+brkfn=cons_getc
+
+
+$make
+run
+
+score=0
+
+# 10 points - run-testpteshare
+pts=10
+runtest1 -tag 'PTE_SHARE [testpteshare]' testpteshare \
+ 'fork handles PTE_SHARE right' \
+ 'spawn handles PTE_SHARE right' \
+
+# 10 points - run-testfdsharing
+pts=10
+runtest1 -tag 'fd sharing [testfdsharing]' testfdsharing \
+ 'read in parent succeeded' \
+ 'read in child succeeded' \
+ 'write to file data page succeeded'
+
+# 20 points - run-icode
+pts=20
+runtest1 -tag 'updated file system switch [icode]' icode \
+ 'icode: read /motd' \
+ 'This is /motd, the message of the day.' \
+ 'icode: spawn /init' \
+ 'init: running' \
+ 'init: data seems okay' \
+ 'icode: exiting' \
+ 'init: bss seems okay' \
+ "init: args: 'init' 'initarg1' 'initarg2'" \
+ 'init: running sh' \
+
+# 20 points - run-testshell
+pts=20
+timeout=60
+runtest1 -tag 'shell [testshell]' testshell \
+ 'shell ran correctly' \
+
+# 10 points - run-primespipe
+pts=10
+timeout=120
+echo 'The primespipe test has up to 2 minutes to complete. Be patient.'
+runtest1 -tag 'primespipe' primespipe \
+ ! 1 2 3 ! 4 5 ! 6 7 ! 8 ! 9 \
+ ! 10 11 ! 12 13 ! 14 ! 15 ! 16 17 ! 18 19 \
+ ! 20 ! 21 ! 22 23 ! 24 ! 25 ! 26 ! 27 ! 28 29 \
+ ! 30 31 ! 32 ! 33 ! 34 ! 35 ! 36 37 ! 38 ! 39 \
+ 541 1009 1097
+
+echo "Score: $score/70"
+
+if [ $score -lt 70 ]; then
+ exit 1
+fi
View
12 inc/lib.h
@@ -136,6 +136,18 @@ int pageref(void *addr);
envid_t spawn(const char *program, const char **argv);
envid_t spawnl(const char *program, const char *arg0, ...);
+// console.c
+void cputchar(int c);
+int getchar(void);
+int iscons(int fd);
+int opencons(void);
+
+// pipe.c
+int pipe(int pipefds[2]);
+int pipeisclosed(int pipefd);
+
+// wait.c
+void wait(envid_t env);
/* File open modes */
#define O_RDONLY 0x0000 /* open for reading only */
View
1 inc/trap.h
@@ -32,6 +32,7 @@
// Hardware IRQ numbers. We receive these as (IRQ_OFFSET+IRQ_WHATEVER)
#define IRQ_TIMER 0
#define IRQ_KBD 1
+#define IRQ_SERIAL 4
#define IRQ_SPURIOUS 7
#define IRQ_IDE 14
#define IRQ_ERROR 19
View
19 kern/Makefrag
@@ -39,16 +39,19 @@ KERN_SRCFILES += kern/e100.c \
# Only build files if they exist.
KERN_SRCFILES := $(wildcard $(KERN_SRCFILES))
-KERN_BINFILES := user/idle \
+# Binary program images to embed within the kernel.
+KERN_BINFILES := user/icode \
+ user/idle \
user/pingpong \
user/primes \
- user/faultregs \
- user/writemotd \
- user/icode \
- user/testtime \
- user/httpd \
- user/echosrv \
- user/echotest \
+ user/testpteshare \
+ user/testfdsharing \
+ user/testpipe \
+ user/testpiperace \
+ user/testpiperace2 \
+ user/primespipe \
+ user/testkbd \
+ user/testshell \
fs/fs \
net/ns
View
8 kern/init.c
@@ -63,10 +63,14 @@ i386_init(void)
ENV_CREATE2(TEST, TESTSIZE);
#else
// Touch all you want.
- // ENV_CREATE(user_echosrv);
- // ENV_CREATE(user_httpd);
+ ENV_CREATE(user_icode);
+ // ENV_CREATE(user_pipereadeof);
+ // ENV_CREATE(user_pipewriteeof);
#endif
+ // Should not be necessary - drain keyboard because interrupt has given up.
+ kbd_intr();
+
// Schedule and run the first user environment!
sched_yield();
View
3 kern/trap.c
@@ -165,6 +165,9 @@ trap_dispatch(struct Trapframe *tf)
print_trapframe(tf);
return;
+ //// Lab 7: Handle keyboard interrupts.
+
+
default:
if (tf->tf_trapno == IRQ_OFFSET + e100_irq) {
e100_intr();
View
3 lib/Makefrag
@@ -28,6 +28,9 @@ LIB_SRCFILES := $(LIB_SRCFILES) \
lib/sockets.c \
lib/nsipc.c \
lib/malloc.c
+LIB_SRCFILES := $(LIB_SRCFILES) \
+ lib/pipe.c \
+ lib/wait.c
LIB_OBJFILES := $(patsubst lib/%.c, $(OBJDIR)/lib/%.o, $(LIB_SRCFILES))
LIB_OBJFILES := $(patsubst lib/%.S, $(OBJDIR)/lib/%.o, $(LIB_OBJFILES))
View
113 lib/console.c
@@ -15,7 +15,118 @@ cputchar(int ch)
int
getchar(void)
{
- return sys_cgetc();
+ unsigned char c;
+ int r;
+
+ // JOS does, however, support standard _input_ redirection,
+ // allowing the user to redirect script files to the shell and such.
+ // getchar() reads a character from file descriptor 0.
+ r = read(0, &c, 1);
+ if (r < 0)
+ return r;
+ if (r < 1)
+ return -E_EOF;
+ return c;
+}
+
+
+// "Real" console file descriptor implementation.
+// The putchar/getchar functions above will still come here by default,
+// but now can be redirected to files, pipes, etc., via the fd layer.
+
+static ssize_t cons_read(struct Fd*, void*, size_t, off_t);
+static ssize_t cons_write(struct Fd*, const void*, size_t, off_t);
+static int cons_close(struct Fd*);
+static int cons_stat(struct Fd*, struct Stat*);
+
+struct Dev devcons =
+{
+ .dev_id = 'c',
+ .dev_name = "cons",
+ .dev_read = cons_read,
+ .dev_write = cons_write,
+ .dev_close = cons_close,
+ .dev_stat = cons_stat
+};
+
+int
+iscons(int fdnum)
+{
+ int r;
+ struct Fd *fd;
+
+ if ((r = fd_lookup(fdnum, &fd)) < 0)
+ return r;
+ return fd->fd_dev_id == devcons.dev_id;
}
+int
+opencons(void)
+{
+ int r;
+ struct Fd* fd;
+
+ if ((r = fd_alloc(&fd)) < 0)
+ return r;
+ if ((r = sys_page_alloc(0, fd, PTE_P|PTE_U|PTE_W|PTE_SHARE)) < 0)
+ return r;
+ fd->fd_dev_id = devcons.dev_id;
+ fd->fd_omode = O_RDWR;
+ return fd2num(fd);
+}
+
+ssize_t
+cons_read(struct Fd *fd, void *vbuf, size_t n, off_t offset)
+{
+ int c;
+
+ USED(offset);
+
+ if (n == 0)
+ return 0;
+
+ while ((c = sys_cgetc()) == 0)
+ sys_yield();
+ if (c < 0)
+ return c;
+ if (c == 0x04) // ctl-d is eof
+ return 0;
+ *(char*)vbuf = c;
+ return 1;
+}
+
+ssize_t
+cons_write(struct Fd *fd, const void *vbuf, size_t n, off_t offset)
+{
+ int tot, m;
+ char buf[128];
+
+ USED(offset);
+
+ // mistake: have to nul-terminate arg to sys_cputs,
+ // so we have to copy vbuf into buf in chunks and nul-terminate.
+ for (tot = 0; tot < n; tot += m) {
+ m = n - tot;
+ if (m > sizeof(buf) - 1)
+ m = sizeof(buf) - 1;
+ memmove(buf, (char*)vbuf + tot, m);
+ sys_cputs(buf, m);
+ }
+ return tot;
+}
+
+int
+cons_close(struct Fd *fd)
+{
+ USED(fd);
+
+ return 0;
+}
+
+int
+cons_stat(struct Fd *fd, struct Stat *stat)
+{
+ strcpy(stat->st_name, "<cons>");
+ return 0;
+}
View
6 lib/fd.c
@@ -121,6 +121,8 @@ fd_close(struct Fd *fd, bool must_exist)
static struct Dev *devtab[] =
{
&devfile,
+ &devpipe,
+ &devcons,
0
};
@@ -179,8 +181,6 @@ dup(int oldfdnum, int newfdnum)
ova = fd2data(oldfd);
nva = fd2data(newfd);
- if ((r = sys_page_map(0, oldfd, 0, newfd, vpt[VPN(oldfd)] & PTE_USER)) < 0)
- goto err;
if (vpd[PDX(ova)]) {
for (i = 0; i < PTSIZE; i += PGSIZE) {
pte = vpt[VPN(ova + i)];
@@ -191,6 +191,8 @@ dup(int oldfdnum, int newfdnum)
}
}
}
+ if ((r = sys_page_map(0, oldfd, 0, newfd, vpt[VPN(oldfd)] & PTE_USER)) < 0)
+ goto err;
return newfdnum;
View
4 lib/fork.c
@@ -55,9 +55,11 @@ duppage(envid_t envid, unsigned pn)
int r;
int pte = vpt[pn];
void *addr = (void *)(pn << PGSHIFT);
+ // Note that you should use PTE_USER, not PTE_FLAGS, to mask out the relevant bits from the page table entry. PTE_FLAGS picks up the accessed and dirty bits as well.
int perm = pte & PTE_USER;
- if ((perm&PTE_W) || (perm&PTE_COW)) {
+ // If the page table entry has the PTE_SHARE bit set, just copy the mapping directly.
+ if (!(perm&PTE_SHARE) && (perm&PTE_W || perm&PTE_COW)) {
perm &= ~PTE_W;
perm |= PTE_COW;
r = sys_page_map(0, addr, envid, addr, perm);
View
195 lib/pipe.c
@@ -0,0 +1,195 @@
+#include <inc/lib.h>
+
+#define debug 0
+
+static int pipeclose(struct Fd *fd);
+static ssize_t piperead(struct Fd *fd, void *buf, size_t n, off_t offset);
+static int pipestat(struct Fd *fd, struct Stat *stat);
+static ssize_t pipewrite(struct Fd *fd, const void *buf, size_t n, off_t offset);
+
+struct Dev devpipe =
+{
+ .dev_id= 'p',
+ .dev_name= "pipe",
+ .dev_read= piperead,
+ .dev_write= pipewrite,
+ .dev_close= pipeclose,
+ .dev_stat= pipestat,
+};
+
+#define PIPEBUFSIZ 32 // small to provoke races
+
+struct Pipe {
+ off_t p_rpos; // read position
+ off_t p_wpos; // write position
+ uint8_t p_buf[PIPEBUFSIZ]; // data buffer
+};
+
+int
+pipe(int pfd[2])
+{
+ int r;
+ struct Fd *fd0, *fd1;
+ void *va;
+
+ // allocate the file descriptor table entries
+ if ((r = fd_alloc(&fd0)) < 0
+ || (r = sys_page_alloc(0, fd0, PTE_P|PTE_W|PTE_U|PTE_SHARE)) < 0)
+ goto err;
+
+ if ((r = fd_alloc(&fd1)) < 0
+ || (r = sys_page_alloc(0, fd1, PTE_P|PTE_W|PTE_U|PTE_SHARE)) < 0)
+ goto err1;
+
+ // allocate the pipe structure as first data page in both
+ va = fd2data(fd0);
+ if ((r = sys_page_alloc(0, va, PTE_P|PTE_W|PTE_U|PTE_SHARE)) < 0)
+ goto err2;
+ if ((r = sys_page_map(0, va, 0, fd2data(fd1), PTE_P|PTE_W|PTE_U|PTE_SHARE)) < 0)
+ goto err3;
+
+ // set up fd structures
+ fd0->fd_dev_id = devpipe.dev_id;
+ fd0->fd_omode = O_RDONLY;
+
+ fd1->fd_dev_id = devpipe.dev_id;
+ fd1->fd_omode = O_WRONLY;
+
+ if (debug)
+ cprintf("[%08x] pipecreate %08x\n", env->env_id, vpt[VPN(va)]);
+
+ pfd[0] = fd2num(fd0);
+ pfd[1] = fd2num(fd1);
+ return 0;
+
+ err3:
+ sys_page_unmap(0, va);
+ err2:
+ sys_page_unmap(0, fd1);
+ err1:
+ sys_page_unmap(0, fd0);
+ err:
+ return r;
+}
+
+static int
+_pipeisclosed(struct Fd *fd, struct Pipe *p)
+{
+ int n, nn, ret;
+
+ while (1) {
+ n = env->env_runs;
+ ret = pageref(fd) == pageref(p);
+ nn = env->env_runs;
+ if (n == nn)
+ return ret;
+ if (n != nn && ret == 1)
+ cprintf("pipe race avoided\n", n, env->env_runs, ret);
+ }
+}
+
+int
+pipeisclosed(int fdnum)
+{
+ struct Fd *fd;
+ struct Pipe *p;
+ int r;
+
+ if ((r = fd_lookup(fdnum, &fd)) < 0)
+ return r;
+ p = (struct Pipe*) fd2data(fd);
+ return _pipeisclosed(fd, p);
+}
+
+static ssize_t
+piperead(struct Fd *fd, void *vbuf, size_t n, off_t offset)
+{
+ uint8_t *buf;
+ size_t i;
+ struct Pipe *p;
+
+ (void) offset; // shut up compiler
+
+ p = (struct Pipe*)fd2data(fd);
+ if (debug)
+ cprintf("[%08x] piperead %08x %d rpos %d wpos %d\n",
+ env->env_id, vpt[VPN(p)], n, p->p_rpos, p->p_wpos);
+
+ buf = vbuf;
+ for (i = 0; i < n; i++) {
+ while (p->p_rpos == p->p_wpos) {
+ // pipe is empty
+ // if we got any data, return it
+ if (i > 0)
+ return i;
+ // if all the writers are gone, note eof
+ if (_pipeisclosed(fd, p))
+ return 0;
+ // yield and see what happens
+ if (debug)
+ cprintf("piperead yield\n");
+ sys_yield();
+ }
+ // there's a byte. take it.
+ // wait to increment rpos until the byte is taken!
+ buf[i] = p->p_buf[p->p_rpos % PIPEBUFSIZ];
+ p->p_rpos++;
+ }
+ return i;
+}
+
+static ssize_t
+pipewrite(struct Fd *fd, const void *vbuf, size_t n, off_t offset)
+{
+ const uint8_t *buf;
+ size_t i;
+ struct Pipe *p;
+
+ (void) offset; // shut up compiler
+
+ p = (struct Pipe*) fd2data(fd);
+ if (debug)
+ cprintf("[%08x] pipewrite %08x %d rpos %d wpos %d\n",
+ env->env_id, vpt[VPN(p)], n, p->p_rpos, p->p_wpos);
+
+ buf = vbuf;
+ for (i = 0; i < n; i++) {
+ while (p->p_wpos >= p->p_rpos + sizeof(p->p_buf)) {
+ // pipe is full
+ // if all the readers are gone
+ // (it's only writers like us now),
+ // note eof
+ if (_pipeisclosed(fd, p))
+ return 0;
+ // yield and see what happens
+ if (debug)
+ cprintf("pipewrite yield\n");
+ sys_yield();
+ }
+ // there's room for a byte. store it.
+ // wait to increment wpos until the byte is stored!
+ p->p_buf[p->p_wpos % PIPEBUFSIZ] = buf[i];
+ p->p_wpos++;
+ }
+
+ return i;
+}
+
+static int
+pipestat(struct Fd *fd, struct Stat *stat)
+{
+ struct Pipe *p = (struct Pipe*) fd2data(fd);
+ strcpy(stat->st_name, "<pipe>");
+ stat->st_size = p->p_wpos - p->p_rpos;
+ stat->st_isdir = 0;
+ stat->st_dev = &devpipe;
+ return 0;
+}
+
+static int
+pipeclose(struct Fd *fd)
+{
+ (void) sys_page_unmap(0, fd);
+ return sys_page_unmap(0, fd2data(fd));
+}
+
View
36 lib/spawn.c
@@ -9,6 +9,7 @@
static int init_stack(envid_t child, const char **argv, uintptr_t *init_esp);
static int map_segment(envid_t child, uintptr_t va, size_t memsz,
int fd, size_t filesz, off_t fileoffset, int perm);
+static int copy_shared_pages(envid_t child);
// Spawn a child process from a program image loaded from the file system.
// prog: the pathname of the program to run.
@@ -124,6 +125,10 @@ spawn(const char *prog, const char **argv)
close(fd);
fd = -1;
+ // Copy shared library state.
+ if ((r = copy_shared_pages(child)) < 0)
+ panic("copy_shared_pages: %e", r);
+
if ((r = sys_env_set_trapframe(child, &child_tf)) < 0)
panic("sys_env_set_trapframe: %e", r);
@@ -276,4 +281,35 @@ map_segment(envid_t child, uintptr_t va, size_t memsz,
return 0;
}
+// Loop through all page table entries in the current process (just like fork did), copying any page mappings that have the PTE_SHARE bit set into the child process.
+static int
+copy_shared_pages(envid_t child)
+{
+ int r;
+ int pdeno, pteno;
+ uint32_t pn = 0;
+
+ for (pdeno = 0; pdeno < VPD(UTOP); pdeno++) {
+ if (vpd[pdeno] == 0) {
+ // skip empty PDEs
+ pn += NPTENTRIES;
+ continue;
+ }
+
+ for (pteno = 0; pteno < NPTENTRIES; pteno++,pn++) {
+ if (vpt[pn] == 0)
+ // skip empty PTEs
+ continue;
+
+ int perm = vpt[pn] & PTE_USER;
+ if (perm & PTE_SHARE) {
+ void *addr = (void *)(pn << PGSHIFT);
+ r = sys_page_map(0, addr, child, addr, perm);
+ if (r)
+ return r;
+ }
+ }
+ }
+ return 0;
+}
View
2 lib/string.c
@@ -147,6 +147,8 @@ memmove(void *dst, const void *src, size_t n)
else
asm volatile("std; rep movsb\n"
:: "D" (d-1), "S" (s-1), "c" (n) : "cc", "memory");
+ // Some versions of GCC rely on DF being clear
+ asm volatile("cld" ::: "cc");
} else {
if ((int)s%4 == 0 && (int)d%4 == 0 && n%4 == 0)
asm volatile("cld; rep movsl\n"
View
13 lib/wait.c
@@ -0,0 +1,13 @@
+#include <inc/lib.h>
+
+// Waits until 'envid' exits.
+void
+wait(envid_t envid)
+{
+ volatile struct Env *e;
+
+ assert(envid != 0);
+ e = &envs[ENVX(envid)];
+ while (e->env_id == envid && e->env_status != ENV_FREE)
+ sys_yield();
+}
View
BIN luiz/lab5.pdf
Binary file not shown.
View
BIN luiz/lab6.pdf
Binary file not shown.
View
146 user/faultregs.c
@@ -1,146 +0,0 @@
-// test register restore on user-level page fault return
-
-#include <inc/lib.h>
-
-struct regs
-{
- struct PushRegs regs;
- uintptr_t eip;
- uint32_t eflags;
- uintptr_t esp;
-};
-
-#define SAVE_REGS(base) \
- "\tmovl %%edi, "base"+0x00\n" \
- "\tmovl %%esi, "base"+0x04\n" \
- "\tmovl %%ebp, "base"+0x08\n" \
- "\tmovl %%ebx, "base"+0x10\n" \
- "\tmovl %%edx, "base"+0x14\n" \
- "\tmovl %%ecx, "base"+0x18\n" \
- "\tmovl %%eax, "base"+0x1c\n" \
- "\tmovl %%esp, "base"+0x28\n"
-
-#define LOAD_REGS(base) \
- "\tmovl "base"+0x00, %%edi\n" \
- "\tmovl "base"+0x04, %%esi\n" \
- "\tmovl "base"+0x08, %%ebp\n" \
- "\tmovl "base"+0x10, %%ebx\n" \
- "\tmovl "base"+0x14, %%edx\n" \
- "\tmovl "base"+0x18, %%ecx\n" \
- "\tmovl "base"+0x1c, %%eax\n" \
- "\tmovl "base"+0x28, %%esp\n"
-
-static struct regs before, during, after;
-
-static void
-check_regs(struct regs* a, const char *an, struct regs* b, const char *bn,
- const char *testname)
-{
- int mismatch = 0;
-
- cprintf("%-6s %-8s %-8s\n", "", an, bn);
-
-#define CHECK(name, field) \
- do { \
- cprintf("%-6s %08x %08x ", #name, a->field, b->field); \
- if (a->field == b->field) \
- cprintf("OK\n"); \
- else { \
- cprintf("MISMATCH\n"); \
- mismatch = 1; \
- } \
- } while (0)
-
- CHECK(edi, regs.reg_edi);
- CHECK(esi, regs.reg_esi);
- CHECK(ebp, regs.reg_ebp);
- CHECK(ebx, regs.reg_ebx);
- CHECK(edx, regs.reg_edx);
- CHECK(ecx, regs.reg_ecx);
- CHECK(eax, regs.reg_eax);
- CHECK(eip, eip);
- CHECK(eflags, eflags);
- CHECK(esp, esp);
-
-#undef CHECK
-
- cprintf("Registers %s ", testname);
- if (!mismatch)
- cprintf("OK\n");
- else
- cprintf("MISMATCH\n");
-}
-
-static void
-pgfault(struct UTrapframe *utf)
-{
- int r;
-
- if (utf->utf_fault_va != (uint32_t)UTEMP)
- panic("pgfault expected at UTEMP, got 0x%08x (eip %08x)",
- utf->utf_fault_va, utf->utf_eip);
-
- // Check registers in UTrapframe
- during.regs = utf->utf_regs;
- during.eip = utf->utf_eip;
- during.eflags = utf->utf_eflags;
- during.esp = utf->utf_esp;
- check_regs(&before, "before", &during, "during", "in UTrapframe");
-
- // Map UTEMP so the write succeeds
- if ((r = sys_page_alloc(0, UTEMP, PTE_U|PTE_P|PTE_W)) < 0)
- panic("sys_page_alloc: %e", r);
-}
-
-void
-umain(void)
-{
- set_pgfault_handler(pgfault);
-
- __asm __volatile(
- // Light up eflags to catch more errors
- "\tpushl %%eax\n"
- "\tpushfl\n"
- "\tpopl %%eax\n"
- "\torl $0x8d5, %%eax\n"
- "\tpushl %%eax\n"
- "\tpopfl\n"
-
- // Save before registers
- // eflags
- "\tmov %%eax, %0+0x24\n"
- // eip
- "\tleal 0f, %%eax\n"
- "\tmovl %%eax, %0+0x20\n"
- "\tpopl %%eax\n"
- // others
- SAVE_REGS("%0")
-
- // Fault at UTEMP
- "\t0: movl $42, 0x400000\n"
-
- // Save after registers (except eip and eflags)
- SAVE_REGS("%1")
- // Restore registers (except eip and eflags). This
- // way, the test will run even if EIP is the *only*
- // thing restored correctly.
- LOAD_REGS("%0")
- // Save after eflags (now that stack is back); note
- // that we were very careful not to modify eflags in
- // since we saved it
- "\tpushl %%eax\n"
- "\tpushfl\n"
- "\tpopl %%eax\n"
- "\tmov %%eax, %1+0x24\n"
- "\tpopl %%eax\n"
- : : "m" (before), "m" (after) : "memory", "cc");
-
- // Check UTEMP to roughly determine that EIP was restored
- // correctly (of course, we probably wouldn't get this far if
- // it weren't)
- if (*(int*)UTEMP != 42)
- cprintf("EIP after page-fault MISMATCH\n");
- after.eip = before.eip;
-
- check_regs(&before, "before", &after, "after", "after page-fault");
-}
View
10 user/faultwrite.c
@@ -1,10 +0,0 @@
-// buggy program - faults with a write to location zero
-
-#include <inc/lib.h>
-
-void
-umain(void)
-{
- *(unsigned*)0 = 0;
-}
-
View
20 user/init.c
@@ -42,5 +42,23 @@ umain(int argc, char **argv)
cprintf(" '%s'", argv[i]);
cprintf("\n");
- cprintf("init: exiting\n");
+ cprintf("init: running sh\n");
+
+ // being run directly from kernel, so no file descriptors open yet
+ close(0);
+ if ((r = opencons()) < 0)
+ panic("opencons: %e", r);
+ if (r != 0)
+ panic("first opencons used fd %d", r);
+ if ((r = dup(0, 1)) < 0)
+ panic("dup: %e", r);
+ while (1) {
+ cprintf("init: starting sh\n");
+ r = spawnl("/sh", "sh", (char*)0);
+ if (r < 0) {
+ cprintf("init: spawn sh: %e\n", r);
+ continue;
+ }
+ wait(r);
+ }
}
View
318 user/sh.c
@@ -0,0 +1,318 @@
+#include <inc/lib.h>
+
+#define BUFSIZ 1024 /* Find the buffer overrun bug! */
+int debug = 0;
+
+
+// gettoken(s, 0) prepares gettoken for subsequent calls and returns 0.
+// gettoken(0, token) parses a shell token from the previously set string,
+// null-terminates that token, stores the token pointer in '*token',
+// and returns a token ID (0, '<', '>', '|', or 'w').
+// Subsequent calls to 'gettoken(0, token)' will return subsequent
+// tokens from the string.
+int gettoken(char *s, char **token);
+
+
+// Parse a shell command from string 's' and execute it.
+// Do not return until the shell command is finished.
+// runcmd() is called in a forked child,
+// so it's OK to manipulate file descriptor state.
+#define MAXARGS 16
+void
+runcmd(char* s)
+{
+ char *argv[MAXARGS], *t, argv0buf[BUFSIZ];
+ int argc, c, i, r, p[2], fd, pipe_child;
+
+ pipe_child = 0;
+ gettoken(s, 0);
+
+again:
+ argc = 0;
+ while (1) {
+ switch ((c = gettoken(0, &t))) {
+
+ case 'w': // Add an argument
+ if (argc == MAXARGS) {
+ cprintf("too many arguments\n");
+ exit();
+ }
+ argv[argc++] = t;
+ break;
+
+ case '<': // Input redirection
+ // Grab the filename from the argument list
+ if (gettoken(0, &t) != 'w') {
+ cprintf("syntax error: < not followed by word\n");
+ exit();
+ }
+ if ((fd = open(t, O_RDONLY)) < 0) {
+ cprintf("open %s for read: %e", t, fd);
+ exit();
+ }
+ if (fd != 0) {
+ dup(fd, 0);
+ close(fd);
+ }
+ break;
+
+ case '>': // Output redirection
+ // Grab the filename from the argument list
+ if (gettoken(0, &t) != 'w') {
+ cprintf("syntax error: > not followed by word\n");
+ exit();
+ }
+ if ((fd = open(t, O_WRONLY)) < 0) {
+ cprintf("open %s for write: %e", t, fd);
+ exit();
+ }
+ if (fd != 1) {
+ dup(fd, 1);
+ close(fd);
+ }
+ ftruncate(fd, 0);
+ break;
+
+ case '|': // Pipe
+ if ((r = pipe(p)) < 0) {
+ cprintf("pipe: %e", r);
+ exit();
+ }
+ if (debug)
+ cprintf("PIPE: %d %d\n", p[0], p[1]);
+ if ((r = fork()) < 0) {
+ cprintf("fork: %e", r);
+ exit();
+ }
+ if (r == 0) {
+ if (p[0] != 0) {
+ dup(p[0], 0);
+ close(p[0]);
+ }
+ close(p[1]);
+ goto again;
+ } else {
+ pipe_child = r;
+ if (p[1] != 1) {
+ dup(p[1], 1);
+ close(p[1]);
+ }
+ close(p[0]);
+ goto runit;
+ }
+ panic("| not implemented");
+ break;
+
+ case 0: // String is complete
+ // Run the current command!
+ goto runit;
+
+ default:
+ panic("bad return %d from gettoken", c);
+ break;
+
+ }
+ }
+
+runit:
+ // Return immediately if command line was empty.
+ if(argc == 0) {
+ if (debug)
+ cprintf("EMPTY COMMAND\n");
+ return;
+ }
+
+ // Clean up command line.
+ // Read all commands from the filesystem: add an initial '/' to
+ // the command name.
+ // This essentially acts like 'PATH=/'.
+ if (argv[0][0] != '/') {
+ argv0buf[0] = '/';
+ strcpy(argv0buf + 1, argv[0]);
+ argv[0] = argv0buf;
+ }
+ argv[argc] = 0;
+
+ // Print the command.
+ if (debug) {
+ cprintf("[%08x] SPAWN:", env->env_id);
+ for (i = 0; argv[i]; i++)
+ cprintf(" %s", argv[i]);
+ cprintf("\n");
+ }
+
+ // Spawn the command!
+ if ((r = spawn(argv[0], (const char**) argv)) < 0)
+ cprintf("spawn %s: %e\n", argv[0], r);
+
+ // In the parent, close all file descriptors and wait for the
+ // spawned command to exit.
+ close_all();
+ if (r >= 0) {
+ if (debug)
+ cprintf("[%08x] WAIT %s %08x\n", env->env_id, argv[0], r);
+ wait(r);
+ if (debug)
+ cprintf("[%08x] wait finished\n", env->env_id);
+ }
+
+ // If we were the left-hand part of a pipe,
+ // wait for the right-hand part to finish.
+ if (pipe_child) {
+ if (debug)
+ cprintf("[%08x] WAIT pipe_child %08x\n", env->env_id, pipe_child);
+ wait(pipe_child);
+ if (debug)
+ cprintf("[%08x] wait finished\n", env->env_id);
+ }
+
+ // Done!
+ exit();
+}
+
+
+// Get the next token from string s.
+// Set *p1 to the beginning of the token and *p2 just past the token.
+// Returns
+// 0 for end-of-string;
+// < for <;
+// > for >;
+// | for |;
+// w for a word.
+//
+// Eventually (once we parse the space where the \0 will go),
+// words get nul-terminated.
+#define WHITESPACE " \t\r\n"
+#define SYMBOLS "<|>&;()"
+
+int
+_gettoken(char *s, char **p1, char **p2)
+{
+ int t;
+
+ if (s == 0) {
+ if (debug > 1)
+ cprintf("GETTOKEN NULL\n");
+ return 0;
+ }
+
+ if (debug > 1)
+ cprintf("GETTOKEN: %s\n", s);
+
+ *p1 = 0;
+ *p2 = 0;
+
+ while (strchr(WHITESPACE, *s))
+ *s++ = 0;
+ if (*s == 0) {
+ if (debug > 1)
+ cprintf("EOL\n");
+ return 0;
+ }
+ if (strchr(SYMBOLS, *s)) {
+ t = *s;
+ *p1 = s;
+ *s++ = 0;
+ *p2 = s;
+ if (debug > 1)
+ cprintf("TOK %c\n", t);
+ return t;
+ }
+ *p1 = s;
+ while (*s && !strchr(WHITESPACE SYMBOLS, *s))
+ s++;
+ *p2 = s;
+ if (debug > 1) {
+ t = **p2;
+ **p2 = 0;
+ cprintf("WORD: %s\n", *p1);
+ **p2 = t;
+ }
+ return 'w';
+}
+
+int
+gettoken(char *s, char **p1)
+{
+ static int c, nc;
+ static char* np1, *np2;
+
+ if (s) {
+ nc = _gettoken(s, &np1, &np2);
+ return 0;
+ }
+ c = nc;
+ *p1 = np1;
+ nc = _gettoken(np2, &np1, &np2);
+ return c;
+}
+
+
+void
+usage(void)
+{
+ cprintf("usage: sh [-dix] [command-file]\n");
+ exit();
+}
+
+void
+umain(int argc, char **argv)
+{
+ int r, interactive, echocmds;
+
+ interactive = '?';
+ echocmds = 0;
+ ARGBEGIN{
+ case 'd':
+ debug++;
+ break;
+ case 'i':
+ interactive = 1;
+ break;
+ case 'x':
+ echocmds = 1;
+ break;
+ default:
+ usage();
+ }ARGEND
+
+ if (argc > 1)
+ usage();
+ if (argc == 1) {
+ close(0);
+ if ((r = open(argv[0], O_RDONLY)) < 0)
+ panic("open %s: %e", argv[0], r);
+ assert(r == 0);
+ }
+ if (interactive == '?')
+ interactive = iscons(0);
+
+ while (1) {
+ char *buf;
+
+ buf = readline(interactive ? "$ " : NULL);
+ if (buf == NULL) {
+ if (debug)
+ cprintf("EXITING\n");
+ exit(); // end of file
+ }
+ if (debug)
+ cprintf("LINE: %s\n", buf);
+ if (buf[0] == '#')
+ continue;
+ if (echocmds)
+ fprintf(1, "# %s\n", buf);
+ if (debug)
+ cprintf("BEFORE FORK\n");
+ if ((r = fork()) < 0)
+ panic("fork: %e", r);
+ if (debug)
+ cprintf("FORK: %d\n", r);
+ if (r == 0) {
+ runcmd(buf);
+ exit();
+ } else
+ wait(r);
+ }
+}
+
View
67 user/testfdsharing.c
@@ -0,0 +1,67 @@
+#include <inc/x86.h>
+#include <inc/lib.h>
+
+char buf[512], buf2[512];
+
+void
+umain(void)
+{
+ int fd, r, n, n2;
+
+ if ((fd = open("motd", O_RDONLY)) < 0)
+ panic("open motd: %e", fd);
+ seek(fd, 0);
+ if ((n = readn(fd, buf, sizeof buf)) <= 0)
+ panic("readn: %e", n);
+
+ if ((r = fork()) < 0)
+ panic("fork: %e", r);
+ if (r == 0) {
+ seek(fd, 0);
+ cprintf("going to read in child (might page fault if your sharing is buggy)\n");
+ if ((n2 = readn(fd, buf2, sizeof buf2)) != n)
+ panic("read in parent got %d, read in child got %d", n, n2);
+ if (memcmp(buf, buf2, n) != 0)
+ panic("read in parent got different bytes from read in child");
+ cprintf("read in child succeeded\n");
+ seek(fd, 0);
+ close(fd);
+ exit();
+ }
+ wait(r);
+ if ((n2 = readn(fd, buf2, sizeof buf2)) != n)
+ panic("read in parent got %d, then got %d", n, n2);
+ cprintf("read in parent succeeded\n");
+ close(fd);
+
+ if ((fd = open("newmotd", O_RDWR)) < 0)
+ panic("open newmotd: %e", fd);
+ seek(fd, 0);
+ if ((n = write(fd, "hello", 5)) != 5)
+ panic("write: %e", n);
+
+ if ((r = fork()) < 0)
+ panic("fork: %e", r);
+ if (r == 0) {
+ seek(fd, 0);
+ cprintf("going to write in child\n");
+ if ((n = write(fd, "world", 5)) != 5)
+ panic("write in child: %e", n);
+ cprintf("write in child finished\n");
+ close(fd);
+ exit();
+ }
+ wait(r);
+ seek(fd, 0);
+ if ((n = readn(fd, buf, 5)) != 5)
+ panic("readn: %e", n);
+ buf[5] = 0;
+ if (strcmp(buf, "hello") == 0)
+ cprintf("write to file data page failed; got old data\n");
+ else if (strcmp(buf, "world") == 0)
+ cprintf("write to file data page succeeded\n");
+ else
+ cprintf("write to file data page failed; got %s\n", buf);
+
+ breakpoint();
+}
View
26 user/testkbd.c
@@ -0,0 +1,26 @@
+
+#include <inc/lib.h>
+
+void
+umain(void)
+{
+ int r;
+
+ close(0);
+ if ((r = opencons()) < 0)
+ panic("opencons: %e", r);
+ if (r != 0)
+ panic("first opencons used fd %d", r);
+ if ((r = dup(0, 1)) < 0)
+ panic("dup: %e", r);
+
+ for(;;){
+ char *buf;
+
+ buf = readline("Type a line: ");
+ if (buf != NULL)
+ fprintf(1, "%s\n", buf);
+ else
+ fprintf(1, "(end of file received)\n");
+ }
+}
View
24 user/testmalloc.c
@@ -0,0 +1,24 @@
+#include <inc/lib.h>
+
+void
+umain(int argc, char **argv)
+{
+ char *buf;
+ int n;
+ void *v;
+
+ while (1) {
+ buf = readline("> ");
+ if (buf == 0)
+ exit();
+ if (memcmp(buf, "free ", 5) == 0) {
+ v = (void*) strtol(buf + 5, 0, 0);
+ free(v);
+ } else if (memcmp(buf, "malloc ", 7) == 0) {
+ n = strtol(buf + 7, 0, 0);
+ v = malloc(n);
+ printf("\t0x%x\n", (uintptr_t) v);
+ } else
+ printf("?unknown command\n");
+ }
+}
View
64 user/testpipe.c
@@ -0,0 +1,64 @@
+#include <inc/lib.h>
+
+char *msg = "Now is the time for all good men to come to the aid of their party.";
+
+void
+umain(void)
+{
+ char buf[100];
+ int i, pid, p[2];
+
+ argv0 = "pipereadeof";
+
+ if ((i = pipe(p)) < 0)
+ panic("pipe: %e", i);
+
+ if ((pid = fork()) < 0)
+ panic("fork: %e", i);
+
+ if (pid == 0) {
+ cprintf("[%08x] pipereadeof close %d\n", env->env_id, p[1]);
+ close(p[1]);
+ cprintf("[%08x] pipereadeof readn %d\n", env->env_id, p[0]);
+ i = readn(p[0], buf, sizeof buf-1);
+ if (i < 0)
+ panic("read: %e", i);
+ buf[i] = 0;
+ if (strcmp(buf, msg) == 0)
+ cprintf("\npipe read closed properly\n");
+ else
+ cprintf("\ngot %d bytes: %s\n", i, buf);
+ exit();
+ } else {
+ cprintf("[%08x] pipereadeof close %d\n", env->env_id, p[0]);
+ close(p[0]);
+ cprintf("[%08x] pipereadeof write %d\n", env->env_id, p[1]);
+ if ((i = write(p[1], msg, strlen(msg))) != strlen(msg))
+ panic("write: %e", i);
+ close(p[1]);
+ }
+ wait(pid);
+
+ argv0 = "pipewriteeof";
+ if ((i = pipe(p)) < 0)
+ panic("pipe: %e", i);
+
+ if ((pid = fork()) < 0)
+ panic("fork: %e", i);
+
+ if (pid == 0) {
+ close(p[0]);
+ while (1) {
+ cprintf(".");
+ if (write(p[1], "x", 1) != 1)
+ break;
+ }
+ cprintf("\npipe write closed properly\n");
+ exit();
+ }
+ close(p[0]);
+ close(p[1]);
+ wait(pid);
+
+ cprintf("pipe tests passed\n");
+}
View
66 user/testpiperace.c
@@ -0,0 +1,66 @@
+#include <inc/lib.h>
+
+void
+umain(void)
+{
+ int p[2], r, pid, i, max;
+ void *va;
+ struct Fd *fd;
+ volatile struct Env *kid;
+
+ cprintf("testing for dup race...\n");
+ if ((r = pipe(p)) < 0)
+ panic("pipe: %e", r);
+ max = 200;
+ if ((r = fork()) < 0)
+ panic("fork: %e", r);
+ if (r == 0) {
+ close(p[1]);
+ //
+ // Now the ref count for p[0] will toggle between 2 and 3
+ // as the parent dups and closes it (there's a close implicit in dup).
+ //
+ // The ref count for p[1] is 1.
+ // Thus the ref count for the underlying pipe structure
+ // will toggle between 3 and 4.
+ //
+ // If a clock interrupt catches close between unmapping
+ // the pipe structure and unmapping the fd, we'll have
+ // a ref count for p[0] of 3, a ref count for p[1] of 1,
+ // and a ref count for the pipe structure of 3, which is
+ // a no-no.
+ //
+ // If a clock interrupt catches dup between mapping the
+ // fd and mapping the pipe structure, we'll have the same
+ // ref counts, still a no-no.
+ //
+ for (i=0; i<max; i++) {
+ if(pipeisclosed(p[0])){
+ cprintf("RACE: pipe appears closed\n");
+ exit();
+ }
+ sys_yield();
+ }
+ // do something to be not runnable besides exiting
+ ipc_recv(0,0,0);
+ }
+ pid = r;
+ cprintf("pid is %d\n", pid);
+ va = 0;
+ kid = &envs[ENVX(pid)];
+ cprintf("kid is %d\n", kid-envs);
+ dup(p[0], 10);
+ while (kid->env_status == ENV_RUNNABLE)
+ dup(p[0], 10);
+
+ cprintf("child done with loop\n");
+ if (pipeisclosed(p[0]))
+ panic("somehow the other end of p[0] got closed!");
+ if ((r = fd_lookup(p[0], &fd)) < 0)
+ panic("cannot look up p[0]: %e", r);
+ va = fd2data(fd);
+ if (pageref(va) != 3+1)
+ cprintf("\nchild detected race\n");
+ else
+ cprintf("\nrace didn't happen\n", max);
+}
View
69 user/testpiperace2.c
@@ -0,0 +1,69 @@
+
+#include <inc/lib.h>
+
+void
+umain(void)
+{
+ int p[2], r, i;
+ struct Fd *fd;
+ volatile struct Env *kid;
+
+ cprintf("testing for pipeisclosed race...\n");
+ if ((r = pipe(p)) < 0)
+ panic("pipe: %e", r);
+ if ((r = fork()) < 0)
+ panic("fork: %e", r);
+ if (r == 0) {
+ // child just dups and closes repeatedly,
+ // yielding so the parent can see
+ // the fd state between the two.
+ close(p[1]);
+ for (i = 0; i < 200; i++) {
+ if (i % 10 == 0)
+ cprintf("%d.", i);
+ // dup, then close. yield so that other guy will
+ // see us while we're between them.
+ dup(p[0], 10);
+ sys_yield();
+ close(10);
+ sys_yield();
+ }
+ exit();
+ }
+
+ // We hold both p[0] and p[1] open, so pipeisclosed should
+ // never return false.
+ //
+ // Now the ref count for p[0] will toggle between 2 and 3
+ // as the child dups and closes it.
+ // The ref count for p[1] is 1.
+ // Thus the ref count for the underlying pipe structure
+ // will toggle between 3 and 4.
+ //
+ // If pipeisclosed checks pageref(p[0]) and gets 3, and
+ // then the child closes, and then pipeisclosed checks
+ // pageref(pipe structure) and gets 3, then it will return true
+ // when it shouldn't.
+ //
+ // If pipeisclosed checks pageref(pipe structure) and gets 3,
+ // and then the child dups, and then pipeisclosed checks
+ // pageref(p[0]) and gets 3, then it will return true when
+ // it shouldn't.
+ //
+ // So either way, pipeisclosed is going give a wrong answer.
+ //
+ kid = &envs[ENVX(r)];
+ while (kid->env_status == ENV_RUNNABLE)
+ if (pipeisclosed(p[0]) != 0) {
+ cprintf("\nRACE: pipe appears closed\n");
+ sys_env_destroy(r);
+ exit();
+ }
+ cprintf("child done with loop\n");
+ if (pipeisclosed(p[0]))
+ panic("somehow the other end of p[0] got closed!");
+ if ((r = fd_lookup(p[0], &fd)) < 0)
+ panic("cannot look up p[0]: %e", r);
+ (void) fd2data(fd);
+ cprintf("race didn't happen\n");
+}
View
42 user/testptelibrary.c
@@ -0,0 +1,42 @@
+#include <inc/lib.h>
+
+#define VA ((char *) 0xA0000000)
+char *msg = "hello, world\n";
+char *msg2 = "goodbye, world\n";
+
+void childofspawn(void);
+
+void
+umain(int argc, char **argv)
+{
+ int r;
+
+ if (argc != 0)
+ childofspawn();
+
+ if ((r = sys_page_alloc(0, VA, PTE_P|PTE_W|PTE_U|PTE_SHARE)) < 0)
+ panic("sys_page_alloc: %e", r);
+
+ // check fork
+ if ((r = fork()) < 0)
+ panic("fork: %e", r);
+ if (r == 0) {
+ strcpy(VA, msg);
+ exit();
+ }
+ wait(r);
+ cprintf("fork handles PTE_SHARE %s\n", strcmp(VA, msg) == 0 ? "right" : "wrong");
+
+ // check spawn
+ if ((r = spawnl("/testptelibrary", "testptelibrary", "arg", 0)) < 0)
+ panic("spawn: %e", r);
+ wait(r);
+ cprintf("spawn handles PTE_SHARE %s\n", strcmp(VA, msg2) == 0 ? "right" : "wrong");
+}
+
+void
+childofspawn(void)
+{
+ strcpy(VA, msg2);
+ exit();
+}
View
45 user/testpteshare.c
@@ -0,0 +1,45 @@
+#include <inc/x86.h>
+#include <inc/lib.h>
+
+#define VA ((char *) 0xA0000000)
+char *msg = "hello, world\n";
+char *msg2 = "goodbye, world\n";
+
+void childofspawn(void);
+
+void
+umain(int argc, char **argv)
+{
+ int r;
+
+ if (argc != 0)
+ childofspawn();
+
+ if ((r = sys_page_alloc(0, VA, PTE_P|PTE_W|PTE_U|PTE_SHARE)) < 0)
+ panic("sys_page_alloc: %e", r);
+
+ // check fork
+ if ((r = fork()) < 0)
+ panic("fork: %e", r);
+ if (r == 0) {
+ strcpy(VA, msg);
+ exit();
+ }
+ wait(r);
+ cprintf("fork handles PTE_SHARE %s\n", strcmp(VA, msg) == 0 ? "right" : "wrong");
+
+ // check spawn
+ if ((r = spawnl("/testpteshare", "testpteshare", "arg", 0)) < 0)
+ panic("spawn: %e", r);
+ wait(r);
+ cprintf("spawn handles PTE_SHARE %s\n", strcmp(VA, msg2) == 0 ? "right" : "wrong");
+
+ breakpoint();
+}
+
+void
+childofspawn(void)
+{
+ strcpy(VA, msg2);
+ exit();
+}
View
85 user/testshell.c
@@ -0,0 +1,85 @@
+#include <inc/x86.h>
+#include <inc/lib.h>
+
+void wrong(int, int, int);
+
+void
+umain(void)
+{
+ char c1, c2;
+ int r, rfd, wfd, kfd, n1, n2, off, nloff;
+
+ close(0);
+ close(1);
+ opencons();
+ opencons();
+
+ if ((rfd = open("testshell.sh", O_RDONLY)) < 0)
+ panic("open testshell.sh: %e", rfd);
+ if ((wfd = open("testshell.out", O_WRONLY)) < 0)
+ panic("open testshell.out: %e", wfd);
+
+ cprintf("running sh -x < testshell.sh > testshell.out\n");
+ if ((r = fork()) < 0)
+ panic("fork: %e", r);
+ if (r == 0) {
+ dup(rfd, 0);
+ dup(wfd, 1);
+ close(rfd);
+ close(wfd);
+ if ((r = spawnl("/sh", "sh", "-x", 0)) < 0)
+ panic("spawn: %e", r);
+ close(0);
+ close(1);
+ wait(r);
+ exit();
+ }
+ close(rfd);
+ close(wfd);
+ wait(r);
+
+ if ((rfd = open("testshell.out", O_RDONLY)) < 0)
+ panic("open testshell.out for reading: %e", rfd);
+ if ((kfd = open("testshell.key", O_RDONLY)) < 0)
+ panic("open testshell.key for reading: %e", kfd);
+
+ nloff = 0;
+ for (off=0;; off++) {
+ n1 = read(rfd, &c1, 1);
+ n2 = read(kfd, &c2, 1);
+ if (n1 < 0)
+ panic("reading testshell.out: %e", n1);
+ if (n2 < 0)
+ panic("reading testshell.key: %e", n2);
+ if (n1 == 0 && n2 == 0)
+ break;
+ if (n1 != 1 || n2 != 1 || c1 != c2)
+ wrong(rfd, kfd, nloff);
+ if (c1 == '\n')
+ nloff = off+1;
+ }
+ cprintf("shell ran correctly\n");
+
+ breakpoint();
+}
+
+void
+wrong(int rfd, int kfd, int off)
+{
+ char buf[100];
+ int n;
+
+ seek(rfd, off);
+ seek(kfd, off);
+
+ cprintf("shell produced incorrect output.\n");
+ cprintf("expected:\n===\n");
+ while ((n = read(kfd, buf, sizeof buf-1)) > 0)
+ sys_cputs(buf, n);
+ cprintf("===\ngot:\n===\n");
+ while ((n = read(rfd, buf, sizeof buf-1)) > 0)
+ sys_cputs(buf, n);
+ cprintf("===\n");
+ exit();
+}
+

0 comments on commit 06d9a2f

Please sign in to comment.