From 6a41a4e8b8ba4ed52a065da5843476997a643136 Mon Sep 17 00:00:00 2001 From: Garen Tyler Date: Mon, 30 Oct 2023 16:45:02 -0600 Subject: [PATCH] rewrite pipe.c --- kernel/Makefile | 1 - kernel/defs.h | 4 +- kernel/pipe.c | 130 --------------------- kernel/rustkernel/src/console/uart.rs | 8 +- kernel/rustkernel/src/fs/file.rs | 16 +-- kernel/rustkernel/src/io/pipe.rs | 155 +++++++++++++++++++++++--- 6 files changed, 154 insertions(+), 160 deletions(-) delete mode 100644 kernel/pipe.c diff --git a/kernel/Makefile b/kernel/Makefile index 93c9307..2b6bfa1 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -8,7 +8,6 @@ KERNEL_SOURCES = \ bio.c \ fs.c \ log.c \ - pipe.c \ exec.c \ sysfile.c \ kernelvec.c \ diff --git a/kernel/defs.h b/kernel/defs.h index 61de271..f98ccc9 100644 --- a/kernel/defs.h +++ b/kernel/defs.h @@ -2,13 +2,15 @@ #include "types.h" #include "riscv.h" +#define PIPESIZE 512 + struct buf; struct context; struct file; struct inode; +struct spinlock; struct pipe; struct proc; -struct spinlock; struct sleeplock; struct stat; struct superblock; diff --git a/kernel/pipe.c b/kernel/pipe.c deleted file mode 100644 index 85cd88b..0000000 --- a/kernel/pipe.c +++ /dev/null @@ -1,130 +0,0 @@ -#include "types.h" -#include "riscv.h" -#include "defs.h" -#include "param.h" -#include "spinlock.h" -#include "proc.h" -#include "fs.h" -#include "sleeplock.h" -#include "file.h" - -#define PIPESIZE 512 - -struct pipe { - struct spinlock lock; - char data[PIPESIZE]; - uint nread; // number of bytes read - uint nwrite; // number of bytes written - int readopen; // read fd is still open - int writeopen; // write fd is still open -}; - -int -pipealloc(struct file **f0, struct file **f1) -{ - struct pipe *pi; - - pi = 0; - *f0 = *f1 = 0; - if((*f0 = filealloc()) == 0 || (*f1 = filealloc()) == 0) - goto bad; - if((pi = (struct pipe*)kalloc()) == 0) - goto bad; - pi->readopen = 1; - pi->writeopen = 1; - pi->nwrite = 0; - pi->nread = 0; - initlock(&pi->lock, "pipe"); - (*f0)->type = FD_PIPE; - (*f0)->readable = 1; - (*f0)->writable = 0; - (*f0)->pipe = pi; - (*f1)->type = FD_PIPE; - (*f1)->readable = 0; - (*f1)->writable = 1; - (*f1)->pipe = pi; - return 0; - - bad: - if(pi) - kfree((char*)pi); - if(*f0) - fileclose(*f0); - if(*f1) - fileclose(*f1); - return -1; -} - -void -pipeclose(struct pipe *pi, int writable) -{ - acquire(&pi->lock); - if(writable){ - pi->writeopen = 0; - wakeup(&pi->nread); - } else { - pi->readopen = 0; - wakeup(&pi->nwrite); - } - if(pi->readopen == 0 && pi->writeopen == 0){ - release(&pi->lock); - kfree((char*)pi); - } else - release(&pi->lock); -} - -int -pipewrite(struct pipe *pi, uint64 addr, int n) -{ - int i = 0; - struct proc *pr = myproc(); - - acquire(&pi->lock); - while(i < n){ - if(pi->readopen == 0 || killed(pr)){ - release(&pi->lock); - return -1; - } - if(pi->nwrite == pi->nread + PIPESIZE){ //DOC: pipewrite-full - wakeup(&pi->nread); - sleep_lock(&pi->nwrite, &pi->lock); - } else { - char ch; - if(copyin(pr->pagetable, &ch, addr + i, 1) == -1) - break; - pi->data[pi->nwrite++ % PIPESIZE] = ch; - i++; - } - } - wakeup(&pi->nread); - release(&pi->lock); - - return i; -} - -int -piperead(struct pipe *pi, uint64 addr, int n) -{ - int i; - struct proc *pr = myproc(); - char ch; - - acquire(&pi->lock); - while(pi->nread == pi->nwrite && pi->writeopen){ //DOC: pipe-empty - if(killed(pr)){ - release(&pi->lock); - return -1; - } - sleep_lock(&pi->nread, &pi->lock); // DOC: piperead-sleep - } - for(i = 0; i < n; i++){ //DOC: piperead-copy - if(pi->nread == pi->nwrite) - break; - ch = pi->data[pi->nread++ % PIPESIZE]; - if(copyout(pr->pagetable, addr + i, &ch, 1) == -1) - break; - } - wakeup(&pi->nwrite); //DOC: piperead-wakeup - release(&pi->lock); - return i; -} diff --git a/kernel/rustkernel/src/console/uart.rs b/kernel/rustkernel/src/console/uart.rs index 86bdac6..f4fb74c 100644 --- a/kernel/rustkernel/src/console/uart.rs +++ b/kernel/rustkernel/src/console/uart.rs @@ -1,12 +1,7 @@ //! Low-level driver routines for 16550a UART. #![allow(non_upper_case_globals)] -use crate::{ - console::consoleintr, - proc::wakeup, - sync::spinlock::Spinlock, - trap::InterruptBlocker, -}; +use crate::{console::consoleintr, proc::wakeup, sync::spinlock::Spinlock, trap::InterruptBlocker}; use core::ptr::addr_of; // The UART control registers. @@ -209,4 +204,3 @@ impl Uart { } } } - diff --git a/kernel/rustkernel/src/fs/file.rs b/kernel/rustkernel/src/fs/file.rs index 544bff6..79bfcdb 100644 --- a/kernel/rustkernel/src/fs/file.rs +++ b/kernel/rustkernel/src/fs/file.rs @@ -22,19 +22,19 @@ pub enum FileType { #[repr(C)] #[derive(Copy, Clone)] pub struct File { - kind: FileType, + pub kind: FileType, /// Reference count. - references: i32, - readable: u8, - writable: u8, + pub references: i32, + pub readable: u8, + pub writable: u8, /// FileType::Pipe - pipe: *mut Pipe, + pub pipe: *mut Pipe, /// FileType::Inode and FileType::Device - ip: *mut Inode, + pub ip: *mut Inode, /// FileType::Inode - off: u32, + pub off: u32, /// FileType::Device - major: i16, + pub major: i16, } impl File { pub const unsafe fn uninitialized() -> File { diff --git a/kernel/rustkernel/src/io/pipe.rs b/kernel/rustkernel/src/io/pipe.rs index 6a97fd7..16d34ef 100644 --- a/kernel/rustkernel/src/io/pipe.rs +++ b/kernel/rustkernel/src/io/pipe.rs @@ -1,25 +1,154 @@ -use crate::{fs::file::File, sync::spinlock::Spinlock}; -use core::ffi::c_char; +use crate::{ + fs::file::{filealloc, fileclose, File, FileType}, + mem::{ + kalloc::{kalloc, kfree}, + virtual_memory::{copyin, copyout}, + }, + proc::{killed, myproc, wakeup}, + sync::spinlock::Spinlock, +}; +use core::ptr::{addr_of, addr_of_mut}; -pub const PIPESIZE: usize = 512usize; +pub const PIPESIZE: usize = 512; #[repr(C)] pub struct Pipe { - lock: Spinlock, - data: [c_char; PIPESIZE], + pub lock: Spinlock, + pub data: [u8; PIPESIZE], /// Number of bytes read. - nread: u32, + pub bytes_read: u32, /// Number of bytes written. - nwrite: u32, + pub bytes_written: u32, /// Read fd is still open. - readopen: i32, + pub is_read_open: i32, /// Write fd is still open. - writeopen: i32, + pub is_write_open: i32, +} +impl Pipe { + pub fn new() -> Pipe { + Pipe { + lock: Spinlock::new(), + data: [0u8; PIPESIZE], + bytes_read: 0, + bytes_written: 0, + is_read_open: 1, + is_write_open: 1, + } + } } extern "C" { - pub fn pipealloc(a: *mut *mut File, b: *mut *mut File) -> i32; - pub fn pipeclose(pipe: *mut Pipe, writable: i32); - pub fn pipewrite(pipe: *mut Pipe, addr: u64, n: i32) -> i32; - pub fn piperead(pipe: *mut Pipe, addr: u64, n: i32) -> i32; + // pub fn pipealloc(a: *mut *mut File, b: *mut *mut File) -> i32; + // pub fn pipeclose(pipe: *mut Pipe, writable: i32); + // pub fn pipewrite(pipe: *mut Pipe, addr: u64, n: i32) -> i32; + // pub fn piperead(pipe: *mut Pipe, addr: u64, n: i32) -> i32; +} + +#[no_mangle] +pub unsafe extern "C" fn pipealloc(a: *mut *mut File, b: *mut *mut File) -> i32 { + *a = filealloc(); + *b = filealloc(); + let pipe = kalloc() as *mut Pipe; + + // If any of them fail, close and return -1. + if a.is_null() || b.is_null() || pipe.is_null() { + if !pipe.is_null() { + kfree(pipe as *mut u8); + } + if !a.is_null() { + fileclose(*a); + } + if !b.is_null() { + fileclose(*b); + } + -1 + } else { + *pipe = Pipe::new(); + (**a).kind = FileType::Pipe; + (**a).readable = 1; + (**a).writable = 0; + (**a).pipe = pipe; + (**b).kind = FileType::Pipe; + (**b).readable = 0; + (**b).writable = 1; + (**b).pipe = pipe; + 0 + } +} + +#[no_mangle] +pub unsafe extern "C" fn pipeclose(pipe: *mut Pipe, writable: i32) { + let _guard = (*pipe).lock.lock(); + + if writable > 0 { + (*pipe).is_write_open = 0; + wakeup(addr_of!((*pipe).bytes_read).cast_mut().cast()); + } else { + (*pipe).is_read_open = 0; + wakeup(addr_of!((*pipe).bytes_written).cast_mut().cast()); + } + + if (*pipe).is_read_open == 0 && (*pipe).is_write_open == 0 { + kfree(pipe.cast()); + } +} + +#[no_mangle] +pub unsafe extern "C" fn pipewrite(pipe: *mut Pipe, addr: u64, n: i32) -> i32 { + let mut i = 0; + let p = myproc(); + let lock = (*pipe).lock.lock(); + + while i < n { + if (*pipe).is_read_open == 0 || killed(p) > 0 { + return -1; + } + if (*pipe).bytes_written == (*pipe).bytes_read + PIPESIZE as u32 { + // DOC: pipewrite-full + wakeup(addr_of!((*pipe).bytes_read).cast_mut().cast()); + lock.sleep(addr_of!((*pipe).bytes_written).cast_mut().cast()); + } else { + let mut b = 0u8; + if copyin((*p).pagetable, addr_of_mut!(b), addr + i as u64, 1) == -1 { + break; + } + (*pipe).data[(*pipe).bytes_written as usize % PIPESIZE] = b; + (*pipe).bytes_written += 1; + i += 1; + } + } + wakeup(addr_of!((*pipe).bytes_read).cast_mut().cast()); + i +} + +#[no_mangle] +pub unsafe extern "C" fn piperead(pipe: *mut Pipe, addr: u64, n: i32) -> i32 { + let mut i = 0; + let p = myproc(); + let lock = (*pipe).lock.lock(); + + // DOC: pipe-empty + while (*pipe).bytes_read == (*pipe).bytes_written && (*pipe).is_write_open > 0 { + if killed(p) > 0 { + return -1; + } else { + // DOC: piperead-sleep + lock.sleep(addr_of!((*pipe).bytes_read).cast_mut().cast()); + } + } + + // DOC: piperead-copy + while i < n { + if (*pipe).bytes_read == (*pipe).bytes_written { + break; + } + let b = (*pipe).data[(*pipe).bytes_read as usize % PIPESIZE]; + (*pipe).bytes_read += 1; + if copyout((*p).pagetable, addr + i as u64, addr_of!(b).cast_mut(), 1) == -1 { + break; + } + i += 1; + } + wakeup(addr_of!((*pipe).bytes_written).cast_mut().cast()); + i }