diff --git a/init/init.c b/init/init.c index 5e19d17..5c64b58 100644 --- a/init/init.c +++ b/init/init.c @@ -8,8 +8,27 @@ int main(int argc, char **argv) (void) argv; - FILE *fp = fopen("/dev/debug", "w"); - fprintf(fp, "Hello, filesystem!\n"); + int fd[2]; + pipe(fd); + + pid_t childpid = fork(); + + if(childpid) + { + printf("I am parent!\n"); + close(fd[1]); + write(fd[0], "Hi, pipe!\n", 10); + close(fd[0]); + } + else + { + printf("I am child!\n"); + close(fd[0]); + char buffer[255]; + read(fd[1], buffer, 255); + printf("Received string: %s\n", buffer); + close(fd[1]); + } for(;;); diff --git a/kernel/fs/pipe.c b/kernel/fs/pipe.c new file mode 100644 index 0000000..90032a7 --- /dev/null +++ b/kernel/fs/pipe.c @@ -0,0 +1,150 @@ +#include +#include +#include +#include +#include +#include + +#define PIPE_SIZE 0x1000 + +struct pipe_data +{ + uint8_t *buffer; + lock_t lock; + uint64_t size; + uint64_t readers; + uint64_t writers; + uint64_t read_pos; + uint64_t write_pos; + file_t *reader; + file_t *writer; +}; + +int pipe_open(file_t *file, uint64_t flags) +{ + (void) flags; + struct pipe_data *d = file->data; + spin_lock(&d->lock); + if(file == d->reader) + d->readers ++; + else + d->writers ++; + spin_unlock(&d->lock); + return 0; +} + +int pipe_close(file_t *file) +{ + debug("Closing pipe\n"); + struct pipe_data *d = file->data; + spin_lock(&d->lock); + if(file == d->reader) + d->readers --; + else + d->writers --; + if((!d->readers) && !(d->writers)) + { + debug("Freeing pipe\n"); + kfree(d); + kfree(file); + } else { + spin_unlock(&d->lock); + } + return 0; +} + +size_t pipe_read(file_t *file, void *buffer, size_t nbyte, size_t offset) +{ + (void) offset; + struct pipe_data *d = file->data; + uint8_t *buf = buffer; + + spin_lock(&d->lock); + while(d->read_pos >= d->write_pos) + { + spin_unlock(&d->lock); + schedule(); + spin_lock(&d->lock); + } + + uint64_t bytes = d->write_pos - d->read_pos; + if(bytes > nbyte) bytes = nbyte; + + uint64_t buf_pos = d->read_pos % d->size; + uint64_t n = d->size - buf_pos; + if(n > bytes) n = bytes; + + memcpy(buf, &d->buffer[buf_pos], n); + if(bytes-n) + memcpy(&buf[n], d->buffer, bytes-n); + + d->read_pos += bytes; + + spin_unlock(&d->lock); + return bytes; +} + +size_t pipe_write(file_t *file, void *buffer, size_t nbyte, size_t offset) +{ + (void) offset; + struct pipe_data *d = file->data; + uint8_t *buf = buffer; + uint64_t written = 0; + + spin_lock(&d->lock); + while(nbyte) + { + while(d->write_pos >= d->read_pos + d->size) + { + spin_unlock(&d->lock); + schedule(); + spin_lock(&d->lock); + } + + uint64_t bytes = d->size - (d->write_pos - d->read_pos); + if(bytes > nbyte) bytes = nbyte; + + uint64_t buf_pos = d->write_pos % d->size; + uint64_t n = d->size - buf_pos; + if(n > bytes) n = bytes; + + memcpy(&d->buffer[buf_pos], &buf[written], n); + if(bytes-n) + memcpy(d->buffer, &buf[written + n], bytes-n); + + nbyte -= bytes; + d->write_pos += bytes; + written += bytes; + } + + spin_unlock(&d->lock); + return written; +} + +fs_driver_t pipe_writer = { + .open = pipe_open, + .close = pipe_close, + .write = pipe_write, +}; +fs_driver_t pipe_reader = { + .open = pipe_open, + .close = pipe_close, + .read = pipe_read, +}; + +int pipe(file_t **r, file_t **w) +{ + *r = kcalloc(1, sizeof(file_t)); + *w = kcalloc(1, sizeof(file_t)); + struct pipe_data *data = (*r)->data = (*w)->data = kcalloc(1, sizeof(struct pipe_data)); + (*r)->driver = &pipe_reader; + (*w)->driver = &pipe_writer; + + data->buffer = kcalloc(1, PIPE_SIZE); + data->size = PIPE_SIZE; + spin_unlock(&data->lock); + data->reader = *r; + data->writer = *w; + + return 0; +} diff --git a/kernel/include/syscall.h b/kernel/include/syscall.h index df0c2d1..a2c8ee4 100644 --- a/kernel/include/syscall.h +++ b/kernel/include/syscall.h @@ -46,6 +46,7 @@ SYSCALL_DECL(read); SYSCALL_DECL(write); SYSCALL_DECL(isatty); SYSCALL_DECL(seek); +SYSCALL_DECL(pipe); SYSCALL_DECL(brk); diff --git a/kernel/include/vfs.h b/kernel/include/vfs.h index 8f7e068..11f0402 100644 --- a/kernel/include/vfs.h +++ b/kernel/include/vfs.h @@ -59,3 +59,4 @@ void fs_umount(const char *path); file_t *fs_namef(const char *path); file_t debug_file; +int pipe(file_t **reader, file_t **writer); diff --git a/kernel/syscall/sys_fs.c b/kernel/syscall/sys_fs.c index 41a4fd0..4110b7f 100644 --- a/kernel/syscall/sys_fs.c +++ b/kernel/syscall/sys_fs.c @@ -78,3 +78,59 @@ SYSCALL_DEF(seek) return p->fp[fd].pos; } + +SYSCALL_DEF(pipe) +{ + SYSCALL_INIT(int *, fd); + process_t *p = get_current_process(); + file_t *r, *w; + pipe(&r, &w); + + fd[0] = -1; + fd[1] = -1; + + int i; + for(i = 0; i < PROC_NUMFP; i++) + { + if(!p->fp[i].file) + { + p->fp[i].file = fs_get(w); + fs_open(w,0); + fd[0] = i; + break; + } + } + if(i == PROC_NUMFP) + goto pipe_fail; + for(i = 0; i < PROC_NUMFP; i++) + { + if(!p->fp[i].file) + { + p->fp[i].file = fs_get(r); + fs_open(r,0); + fd[1] = i; + break; + } + } + if(i == PROC_NUMFP) + goto pipe_fail; + + return 0; + +pipe_fail: + if(r) + kfree(r); + if(w) + kfree(w); + if(fd[0] != -1) + { + fs_put(p->fp[fd[0]].file); + p->fp[fd[0]].file = 0; + } + if(fd[1] != -1) + { + fs_put(p->fp[fd[1]].file); + p->fp[fd[1]].file = 0; + } + return -1; +} diff --git a/kernel/syscall/syscall.c b/kernel/syscall/syscall.c index 6058023..8324355 100644 --- a/kernel/syscall/syscall.c +++ b/kernel/syscall/syscall.c @@ -62,6 +62,7 @@ void syscall_init() SYSCALL_REGISTER(write, SYS_WRITE); SYSCALL_REGISTER(isatty, SYS_ISATTY); SYSCALL_REGISTER(seek, SYS_SEEK); + SYSCALL_REGISTER(pipe, SYS_PIPE); SYSCALL_REGISTER(brk, SYS_BRK); diff --git a/libc/file_io.c b/libc/file_io.c index ff3aa57..005e4fe 100644 --- a/libc/file_io.c +++ b/libc/file_io.c @@ -69,3 +69,9 @@ SYSCALL_DEF(ioctl) kernel_debug("==> IOCTL - unsupported request:%lx\n", request); return -1; } + +SYSCALL_DEF(pipe) +{ + SYSCALL_INIT(int *, fd); + return kernel_syscall(SYS_PIPE, fd); +} diff --git a/libc/syscall_num.h b/libc/syscall_num.h index c07bfe6..f542aa1 100644 --- a/libc/syscall_num.h +++ b/libc/syscall_num.h @@ -14,3 +14,5 @@ #define SYS_FORK 0x008 #define SYS_EXIT 0x009 #define SYS_WAIT 0x00A + +#define SYS_PIPE 0x00B