file descriptors

pipes
This commit is contained in:
rtm 2006-06-27 14:35:53 +00:00
parent b61c2547b8
commit c41f1de5d4
16 changed files with 424 additions and 39 deletions

View file

@ -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 :

8
Notes
View file

@ -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

16
defs.h
View file

@ -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);

80
fd.c Normal file
View file

@ -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;
}
}

9
fd.h Normal file
View file

@ -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];

8
main.c
View file

@ -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

View file

@ -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

100
pipe.c Normal file
View file

@ -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;
}

9
proc.c
View file

@ -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);

1
proc.h
View file

@ -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];

View file

@ -42,6 +42,88 @@ fetcharg(int argno, int *ip)
return fetchint(curproc[cpu()], esp + 8 + 4*argno, 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()
{
@ -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

View file

@ -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

4
trap.c
View file

@ -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;

44
ulib.c Normal file
View file

@ -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");
}

38
user1.c
View file

@ -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)
;

30
usertests.c Normal file
View file

@ -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)
;
}