summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrtm <rtm>2006-06-27 14:35:53 +0000
committerrtm <rtm>2006-06-27 14:35:53 +0000
commitc41f1de5d41a527a3fa2d1e94215766130eac456 (patch)
tree86f6a467be8b42aec42a05299789f39ace9cc5e2
parentb61c2547b8b489cab16984c0940a1cb6593a2a3d (diff)
downloadxv6-labs-c41f1de5d41a527a3fa2d1e94215766130eac456.tar.gz
xv6-labs-c41f1de5d41a527a3fa2d1e94215766130eac456.tar.bz2
xv6-labs-c41f1de5d41a527a3fa2d1e94215766130eac456.zip
file descriptors
pipes
-rw-r--r--Makefile18
-rw-r--r--Notes8
-rw-r--r--defs.h16
-rw-r--r--fd.c80
-rw-r--r--fd.h9
-rw-r--r--main.c8
-rw-r--r--param.h2
-rw-r--r--pipe.c100
-rw-r--r--proc.c9
-rw-r--r--proc.h1
-rw-r--r--syscall.c93
-rw-r--r--syscall.h3
-rw-r--r--trap.c4
-rw-r--r--ulib.c44
-rw-r--r--user1.c38
-rw-r--r--usertests.c30
16 files changed, 424 insertions, 39 deletions
diff --git a/Makefile b/Makefile
index 9cac647..0b716b4 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
OBJS = main.o console.o string.o kalloc.o proc.o trapasm.o trap.o vectors.o \
- syscall.o ide.o picirq.o mp.o spinlock.o
+ syscall.o ide.o picirq.o mp.o spinlock.o fd.o pipe.o
CC = i386-jos-elf-gcc
LD = i386-jos-elf-ld
@@ -20,22 +20,30 @@ bootblock : bootasm.S bootmain.c
$(OBJCOPY) -S -O binary bootblock.o bootblock
./sign.pl bootblock
-kernel : $(OBJS) bootother.S user1
+kernel : $(OBJS) bootother.S user1 usertests
$(CC) -nostdinc -I. -c bootother.S
$(LD) -N -e start -Ttext 0x7000 -o bootother.out bootother.o
$(OBJCOPY) -S -O binary bootother.out bootother
$(OBJDUMP) -S bootother.o > bootother.asm
- $(LD) -Ttext 0x100000 -e main -o kernel $(OBJS) -b binary bootother user1
+ $(LD) -Ttext 0x100000 -e main -o kernel $(OBJS) -b binary bootother user1 usertests
$(OBJDUMP) -S kernel > kernel.asm
vectors.S : vectors.pl
perl vectors.pl > vectors.S
-user1 : user1.c
+user1 : user1.c ulib.o
$(CC) -nostdinc -I. -c user1.c
- $(LD) -N -e main -Ttext 0 -o user1 user1.o
+ $(LD) -N -e main -Ttext 0 -o user1 user1.o ulib.o
$(OBJDUMP) -S user1 > user1.asm
+usertests : usertests.c ulib.o
+ $(CC) -nostdinc -I. -c usertests.c
+ $(LD) -N -e main -Ttext 0 -o usertests usertests.o ulib.o
+ $(OBJDUMP) -S usertests > usertests.asm
+
+ulib.o : ulib.c
+ $(CC) -nostdinc -I. -c ulib.c
+
-include *.d
clean :
diff --git a/Notes b/Notes
index 88b725c..350d929 100644
--- a/Notes
+++ b/Notes
@@ -83,3 +83,11 @@ it's IRQ 0, but it comes at a weird and changing vector (e.g. 119) if
you don't initialize the PIC. why doesn't jos see this? if i
initialize the PIC with IRQ_OFFSET 32, the interrupt arrives at vector
32.
+
+test out-of-fd cases for creating pipe.
+test pipe circular buffer
+test pipe writer or reader closes while other active or waiting
+test exit vs fd reference counts
+test write of more than PIPESIZE
+test reader goes first vs writer goes first
+test streaming of a lot of data
diff --git a/defs.h b/defs.h
index f10859e..d7cc09b 100644
--- a/defs.h
+++ b/defs.h
@@ -37,6 +37,7 @@ void pic_init(void);
void mp_init(void);
int cpu(void);
int mp_isbcpu(void);
+void lapic_init(int c);
// spinlock.c
extern uint32_t kernel_lock;
@@ -46,3 +47,18 @@ void release_grant_spinlock(uint32_t* lock, int cpu);
// main.c
void load_icode(struct proc *p, uint8_t *binary, unsigned size);
+
+// pipe.c
+struct pipe;
+struct fd;
+int pipe_alloc(struct fd **fd1, struct fd **fd2);
+void pipe_close(struct pipe *p, int writeable);
+int pipe_write(struct pipe *p, char *addr, int n);
+int pipe_read(struct pipe *p, char *addr, int n);
+
+// fd.c
+int fd_ualloc();
+struct fd * fd_alloc();
+void fd_close(struct fd *);
+int fd_read(struct fd *fd, char *addr, int n);
+int fd_write(struct fd *fd, char *addr, int n);
diff --git a/fd.c b/fd.c
new file mode 100644
index 0000000..0546cef
--- /dev/null
+++ b/fd.c
@@ -0,0 +1,80 @@
+#include "types.h"
+#include "param.h"
+#include "x86.h"
+#include "mmu.h"
+#include "proc.h"
+#include "defs.h"
+#include "fd.h"
+
+struct fd fds[NFD];
+
+/*
+ * allocate a file descriptor number for curproc.
+ */
+int
+fd_ualloc()
+{
+ int fd;
+ struct proc *p = curproc[cpu()];
+ for(fd = 0; fd < NOFILE; fd++)
+ if(p->fds[fd] == 0)
+ return fd;
+ return -1;
+}
+
+struct fd *
+fd_alloc()
+{
+ int i;
+
+ for(i = 0; i < NFD; i++){
+ if(fds[i].type == FD_CLOSED){
+ fds[i].type = FD_NONE;
+ fds[i].count = 1;
+ return fds + i;
+ }
+ }
+ return 0;
+}
+
+void
+fd_close(struct fd *fd)
+{
+ if(fd->type == FD_CLOSED || fd->count <= 0)
+ panic("fd_close");
+ fd->count -= 1;
+ if(fd->count == 0){
+ if(fd->type == FD_PIPE)
+ pipe_close(fd->pipe, fd->writeable);
+ fd->type = FD_CLOSED;
+ }
+}
+
+/*
+ * addr is a kernel address, pointing into some process's p->mem.
+ */
+int
+fd_write(struct fd *fd, char *addr, int n)
+{
+ if(fd->writeable == 0)
+ return -1;
+ if(fd->type == FD_PIPE){
+ return pipe_write(fd->pipe, addr, n);
+ } else {
+ panic("fd_write");
+ return -1;
+ }
+}
+
+int
+fd_read(struct fd *fd, char *addr, int n)
+{
+ if(fd->readable == 0)
+ return -1;
+ if(fd->type == FD_PIPE){
+ return pipe_read(fd->pipe, addr, n);
+ } else {
+ panic("fd_read");
+ return -1;
+ }
+}
diff --git a/fd.h b/fd.h
new file mode 100644
index 0000000..c8d0c34
--- /dev/null
+++ b/fd.h
@@ -0,0 +1,9 @@
+struct fd {
+ enum { FD_CLOSED, FD_NONE, FD_PIPE } type;
+ int count; // reference count
+ char readable;
+ char writeable;
+ struct pipe *pipe;
+};
+
+extern struct fd fds[NFD];
diff --git a/main.c b/main.c
index 1226a8f..92b8f24 100644
--- a/main.c
+++ b/main.c
@@ -11,8 +11,8 @@
extern char edata[], end[];
extern int acpu;
-extern char _binary_user1_start[];
-extern char _binary_user1_size[];
+extern char _binary_user1_start[], _binary_user1_size[];
+extern char _binary_usertests_start[], _binary_usertests_size[];
char buf[512];
@@ -25,7 +25,7 @@ main()
cprintf("an application processor\n");
release_spinlock(&kernel_lock);
acquire_spinlock(&kernel_lock);
- idtinit();
+ idtinit(); // CPU's idt
lapic_init(cpu());
curproc[cpu()] = &proc[0]; // XXX
swtch();
@@ -70,7 +70,7 @@ main()
#if 1
p = newproc();
- load_icode(p, _binary_user1_start, (unsigned) _binary_user1_size);
+ load_icode(p, _binary_usertests_start, (unsigned) _binary_usertests_size);
#endif
#if 0
diff --git a/param.h b/param.h
index 0a931d9..dac7e10 100644
--- a/param.h
+++ b/param.h
@@ -2,3 +2,5 @@
#define PAGE 4096
#define KSTACKSIZE PAGE
#define NCPU 8
+#define NOFILE 16 // file descriptors per process
+#define NFD 100 // file descriptors per system
diff --git a/pipe.c b/pipe.c
new file mode 100644
index 0000000..9a81e0b
--- /dev/null
+++ b/pipe.c
@@ -0,0 +1,100 @@
+#include "types.h"
+#include "param.h"
+#include "x86.h"
+#include "mmu.h"
+#include "proc.h"
+#include "defs.h"
+#include "fd.h"
+
+#define PIPESIZE 512
+
+struct pipe {
+ int readopen; // read fd is still open
+ int writeopen; // write fd is still open
+ int writep; // next index to write
+ int readp; // next index to read
+ char data[PIPESIZE];
+};
+
+int
+pipe_alloc(struct fd **fd1, struct fd **fd2)
+{
+ *fd1 = *fd2 = 0;
+ struct pipe *p = 0;
+
+ if((*fd1 = fd_alloc()) == 0)
+ goto oops;
+ if((*fd2 = fd_alloc()) == 0)
+ goto oops;
+ if((p = (struct pipe *) kalloc(PAGE)) == 0)
+ goto oops;
+ (*fd1)->type = FD_PIPE;
+ (*fd1)->readable = 1;
+ (*fd1)->writeable = 0;
+ (*fd1)->pipe = p;
+ (*fd2)->type = FD_PIPE;
+ (*fd2)->readable = 0;
+ (*fd2)->writeable = 1;
+ (*fd2)->pipe = p;
+ return 0;
+ oops:
+ if(p)
+ kfree((char *) p, PAGE);
+ if(*fd1){
+ (*fd1)->type = FD_NONE;
+ fd_close(*fd1);
+ }
+ if(*fd2){
+ (*fd2)->type = FD_NONE;
+ fd_close(*fd2);
+ }
+ return -1;
+}
+
+void
+pipe_close(struct pipe *p, int writeable)
+{
+ if(writeable)
+ p->writeopen = 0;
+ else
+ p->readopen = 0;
+ if(p->readopen == 0 && p->writeopen == 0)
+ kfree((char *) p, PAGE);
+}
+
+int
+pipe_write(struct pipe *p, char *addr, int n)
+{
+ int i;
+
+ for(i = 0; i < n; i++){
+ while(((p->writep + 1) % PIPESIZE) == p->readp){
+ if(p->readopen == 0)
+ return -1;
+ sleep(&p->writep);
+ }
+ p->data[p->writep] = addr[i];
+ p->writep = (p->writep + 1) % PIPESIZE;
+ }
+ return i;
+}
+
+int
+pipe_read(struct pipe *p, char *addr, int n)
+{
+ int i;
+
+ while(p->readp == p->writep){
+ if(p->writeopen == 0)
+ return 0;
+ sleep(&p->readp);
+ }
+
+ for(i = 0; i < n; i++){
+ if(p->readp == p->writep)
+ break;
+ addr[i] = p->data[p->readp];
+ p->readp = (p->readp + 1) % PIPESIZE;
+ }
+ return i;
+}
diff --git a/proc.c b/proc.c
index e8a911d..97e84e3 100644
--- a/proc.c
+++ b/proc.c
@@ -2,6 +2,7 @@
#include "mmu.h"
#include "x86.h"
#include "param.h"
+#include "fd.h"
#include "proc.h"
#include "defs.h"
@@ -49,6 +50,7 @@ newproc()
struct proc *np;
struct proc *op = curproc[cpu()];
unsigned *sp;
+ int fd;
for(np = &proc[1]; np < &proc[NPROC]; np++)
if(np->state == UNUSED)
@@ -80,6 +82,13 @@ newproc()
np->esp = (unsigned) sp;
np->ebp = (unsigned) sp;
+ // copy file descriptors
+ for(fd = 0; fd < NOFILE; fd++){
+ np->fds[fd] = op->fds[fd];
+ if(np->fds[fd])
+ np->fds[fd]->count += 1;
+ }
+
np->state = RUNNABLE;
cprintf("newproc %x\n", np);
diff --git a/proc.h b/proc.h
index 36e608e..14164db 100644
--- a/proc.h
+++ b/proc.h
@@ -24,6 +24,7 @@ struct proc{
int pid;
int ppid;
void *chan; // sleep
+ struct fd *fds[NOFILE];
struct Taskstate ts; // only to give cpu address of kernel stack
struct Segdesc gdt[NSEGS];
diff --git a/syscall.c b/syscall.c
index 1d2eb54..c27c226 100644
--- a/syscall.c
+++ b/syscall.c
@@ -43,6 +43,88 @@ fetcharg(int argno, int *ip)
}
int
+putint(struct proc *p, unsigned addr, int ip)
+{
+ if(addr > p->sz - 4)
+ return 0;
+ memcpy(p->mem + addr, &ip, 4);
+ return 1;
+}
+
+int
+sys_pipe()
+{
+ struct fd *rfd = 0, *wfd = 0;
+ int f1 = -1, f2 = -1;
+ struct proc *p = curproc[cpu()];
+ unsigned fdp;
+
+ if(pipe_alloc(&rfd, &wfd) < 0)
+ goto oops;
+ if((f1 = fd_ualloc()) < 0)
+ goto oops;
+ p->fds[f1] = rfd;
+ if((f2 = fd_ualloc()) < 0)
+ goto oops;
+ p->fds[f2] = wfd;
+ if(fetcharg(0, &fdp) < 0)
+ goto oops;
+ if(putint(p, fdp, f1) < 0)
+ goto oops;
+ if(putint(p, fdp+4, f2) < 0)
+ goto oops;
+ return 0;
+
+ oops:
+ cprintf("sys_pipe failed\n");
+ if(rfd)
+ fd_close(rfd);
+ if(wfd)
+ fd_close(wfd);
+ if(f1 >= 0)
+ p->fds[f1] = 0;
+ if(f2 >= 0)
+ p->fds[f2] = 0;
+ return -1;
+}
+
+int
+sys_write()
+{
+ int fd, n;
+ unsigned addr;
+ struct proc *p = curproc[cpu()];
+
+ if(fetcharg(0, &fd) < 0 || fetcharg(1, &addr) < 0 || fetcharg(2, &n) < 0)
+ return -1;
+ if(fd < 0 || fd >= NOFILE)
+ return -1;
+ if(p->fds[fd] == 0)
+ return -1;
+ if(addr + n > p->sz)
+ return -1;
+ return fd_write(p->fds[fd], p->mem + addr, n);
+}
+
+int
+sys_read()
+{
+ int fd, n;
+ unsigned addr;
+ struct proc *p = curproc[cpu()];
+
+ if(fetcharg(0, &fd) < 0 || fetcharg(1, &addr) < 0 || fetcharg(2, &n) < 0)
+ return -1;
+ if(fd < 0 || fd >= NOFILE)
+ return -1;
+ if(p->fds[fd] == 0)
+ return -1;
+ if(addr + n > p->sz)
+ return -1;
+ return fd_read(p->fds[fd], p->mem + addr, n);
+}
+
+int
sys_fork()
{
struct proc *np;
@@ -122,7 +204,7 @@ syscall()
int num = cp->tf->tf_regs.reg_eax;
int ret = -1;
- cprintf("%x sys %d\n", cp, num);
+ //cprintf("%x sys %d\n", cp, num);
switch(num){
case SYS_fork:
ret = sys_fork();
@@ -136,6 +218,15 @@ syscall()
case SYS_cons_putc:
ret = sys_cons_putc();
break;
+ case SYS_pipe:
+ ret = sys_pipe();
+ break;
+ case SYS_write:
+ ret = sys_write();
+ break;
+ case SYS_read:
+ ret = sys_read();
+ break;
default:
cprintf("unknown sys call %d\n", num);
// XXX fault
diff --git a/syscall.h b/syscall.h
index f054414..65d5ced 100644
--- a/syscall.h
+++ b/syscall.h
@@ -2,3 +2,6 @@
#define SYS_exit 2
#define SYS_wait 3
#define SYS_cons_putc 4
+#define SYS_pipe 5
+#define SYS_write 6
+#define SYS_read 7
diff --git a/trap.c b/trap.c
index 0cd4958..cfa8a57 100644
--- a/trap.c
+++ b/trap.c
@@ -37,14 +37,14 @@ trap(struct Trapframe *tf)
acquire_spinlock(&kernel_lock); // released in trapret in trapasm.S
- cprintf("trap %d eip %x:%x\n", tf->tf_trapno, tf->tf_cs, tf->tf_eip);
-
if(v == T_SYSCALL){
curproc[cpu()]->tf = tf;
syscall();
return;
}
+ cprintf("trap %d eip %x:%x\n", tf->tf_trapno, tf->tf_cs, tf->tf_eip);
+
if(v == 32){
// probably clock
return;
diff --git a/ulib.c b/ulib.c
new file mode 100644
index 0000000..694501e
--- /dev/null
+++ b/ulib.c
@@ -0,0 +1,44 @@
+int
+fork()
+{
+ asm("mov $1, %eax");
+ asm("int $48");
+}
+
+void
+cons_putc(int c)
+{
+ asm("mov $4, %eax");
+ asm("int $48");
+}
+
+int
+puts(char *s)
+{
+ int i;
+
+ for(i = 0; s[i]; i++)
+ cons_putc(s[i]);
+ return i;
+}
+
+int
+pipe(int fds[])
+{
+ asm("mov $5, %eax");
+ asm("int $48");
+}
+
+int
+read(int fd, char *buf, int n)
+{
+ asm("mov $7, %eax");
+ asm("int $48");
+}
+
+int
+write(int fd, char *buf, int n)
+{
+ asm("mov $6, %eax");
+ asm("int $48");
+}
diff --git a/user1.c b/user1.c
index 9e0c731..d414699 100644
--- a/user1.c
+++ b/user1.c
@@ -1,35 +1,19 @@
-int
-fork()
-{
- asm("mov $1, %eax");
- asm("int $48");
-}
-
-void
-cons_putc(int c)
-{
- asm("mov $4, %eax");
- asm("int $48");
-}
-
-int
-puts(char *s)
-{
- int i;
-
- for(i = 0; s[i]; i++)
- cons_putc(s[i]);
- return i;
-}
+char buf[32];
main()
{
- int pid;
+ int pid, fds[2], n;
+
+ pipe(fds);
pid = fork();
- if(pid == 0){
- cons_putc('C');
+ if(pid > 0){
+ write(fds[1], "xyz", 4);
+ puts("w");
} else {
- cons_putc('P');
+ n = read(fds[0], buf, sizeof(buf));
+ puts("r: ");
+ puts(buf);
+ puts("\n");
}
while(1)
;
diff --git a/usertests.c b/usertests.c
new file mode 100644
index 0000000..62eefda
--- /dev/null
+++ b/usertests.c
@@ -0,0 +1,30 @@
+// simple fork and pipe read/write
+
+char buf[32];
+
+void
+pipe1()
+{
+ int fds[2], pid;
+
+ pipe(fds);
+ pid = pipe();
+ if(pid == 0){
+ write(fds[1], "xyz", 4);
+ } else {
+ read(fds[0], buf, sizeof(buf));
+ if(buf[0] != 'x' || buf[1] != 'y'){
+ puts("pipe1 oops\n");
+ return;
+ }
+ }
+ puts("pipe1 ok\n");
+}
+
+main()
+{
+ pipe1();
+
+ while(1)
+ ;
+}