diff --git a/include/kernel/syscall.h b/include/kernel/syscall.h index 24838d42..08ce9b23 100644 --- a/include/kernel/syscall.h +++ b/include/kernel/syscall.h @@ -46,7 +46,6 @@ typedef enum { SYSCALL_OBJECT_STATS, SYSCALL_OBJECT_SET_TAG, SYSCALL_OBJECT_GET_TAG, - SYSCALL_OBJECT_SET_BLOCKING, SYSCALL_OBJECT_MAX, SYSCALL_SYSTEM_STATS, SYSCALL_SYSTEM_TIME, diff --git a/include/library/syscalls.h b/include/library/syscalls.h index 37feca56..328427c4 100644 --- a/include/library/syscalls.h +++ b/include/library/syscalls.h @@ -54,7 +54,6 @@ int syscall_object_close(int fd); int syscall_object_stats(int fd, struct object_stats *stats ); int syscall_object_set_tag(int fd, char *tag); int syscall_object_get_tag(int fd, char *buffer, int buffer_size); -int syscall_object_set_blocking(int fd, int b); int syscall_object_max(); /* Syscalls that query or affect the whole system state. */ diff --git a/kernel/Makefile b/kernel/Makefile index b6c7e565..b227285a 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -1,6 +1,6 @@ include ../Makefile.config -KERNEL_OBJECTS=kernelcore.o main.o console.o page.o keyboard.o mouse.o clock.o interrupt.o kmalloc.o pic.o ata.o cdromfs.o string.o bitmap.o graphics.o font.o syscall_handler.o process.o mutex.o list.o pagetable.o rtc.o kshell.o fs.o hash_set.o diskfs.o serial.o elf.o device.o kobject.o pipe.o bcache.o printf.o is_valid.o +KERNEL_OBJECTS=kernelcore.o main.o console.o page.o keyboard.o mouse.o clock.o interrupt.o kmalloc.o pic.o ata.o cdromfs.o string.o bitmap.o graphics.o font.o syscall_handler.o process.o mutex.o monitor.o list.o pagetable.o rtc.o kshell.o fs.o hash_set.o diskfs.o serial.o elf.o device.o kobject.o pipe.o bcache.o printf.o is_valid.o basekernel.img: bootblock kernel cat bootblock kernel /dev/zero | head -c 1474560 > basekernel.img diff --git a/kernel/clock.c b/kernel/clock.c index 871a150e..a337c650 100644 --- a/kernel/clock.c +++ b/kernel/clock.c @@ -9,6 +9,7 @@ See the file LICENSE for details. #include "clock.h" #include "ioports.h" #include "process.h" +#include "monitor.h" #define CLICKS_PER_SECOND 10 @@ -21,12 +22,12 @@ See the file LICENSE for details. static uint32_t clicks = 0; static uint32_t seconds = 0; -static struct list queue = { 0, 0 }; +static struct monitor monitor = MONITOR_INIT_INTERRUPT_SAFE; static void clock_interrupt(int i, int code) { clicks++; - process_wakeup_all(&queue); + monitor_notify_all(&monitor); if(clicks >= CLICKS_PER_SECOND) { clicks = 0; seconds++; @@ -35,11 +36,21 @@ static void clock_interrupt(int i, int code) } } -clock_t clock_read() +static clock_t clock_read_unlocked() { clock_t result; + result.seconds = seconds; result.millis = 1000 * clicks / CLICKS_PER_SECOND; + + return result; +} + +clock_t clock_read() +{ + monitor_lock(&monitor); + clock_t result = clock_read_unlocked(); + monitor_unlock(&monitor); return result; } @@ -60,12 +71,16 @@ void clock_wait(uint32_t millis) clock_t start, elapsed; uint32_t total; - start = clock_read(); + monitor_lock(&monitor); + + start = clock_read_unlocked(); do { - process_wait(&queue); - elapsed = clock_diff(start, clock_read()); + monitor_wait(&monitor); + elapsed = clock_diff(start, clock_read_unlocked()); total = elapsed.millis + elapsed.seconds * 1000; } while(total < millis); + + monitor_unlock(&monitor); } void clock_init() diff --git a/kernel/keyboard.c b/kernel/keyboard.c index 72a97471..67ab48d8 100644 --- a/kernel/keyboard.c +++ b/kernel/keyboard.c @@ -8,7 +8,7 @@ See the file LICENSE for details. #include "ioports.h" #include "interrupt.h" #include "kernel/ascii.h" -#include "process.h" +#include "monitor.h" #include "device.h" #include "kernelcore.h" @@ -46,7 +46,7 @@ static uint8_t buffer[BUFFER_SIZE]; static int keyboard_buffer_read = 0; static int keyboard_buffer_write = 0; -static struct list queue = { 0, 0 }; +static struct monitor monitor = MONITOR_INIT_INTERRUPT_SAFE; static int shift_mode = 0; static int alt_mode = 0; @@ -143,17 +143,22 @@ static void keyboard_interrupt(int i, int intr_code) return; buffer[keyboard_buffer_write] = c; keyboard_buffer_write = (keyboard_buffer_write + 1) % BUFFER_SIZE; - process_wakeup(&queue); + monitor_notify(&monitor); } char keyboard_read( int non_blocking ) { + monitor_lock(&monitor); while(keyboard_buffer_read == keyboard_buffer_write) { - if(non_blocking) return -1; - process_wait(&queue); + if(non_blocking) { + monitor_unlock(&monitor); + return -1; + } + monitor_wait(&monitor); } char c = buffer[keyboard_buffer_read]; keyboard_buffer_read = (keyboard_buffer_read + 1) % BUFFER_SIZE; + monitor_unlock(&monitor); return c; } diff --git a/kernel/kobject.c b/kernel/kobject.c index 5c09ec20..2381e665 100644 --- a/kernel/kobject.c +++ b/kernel/kobject.c @@ -305,24 +305,10 @@ int kobject_close(struct kobject *kobject) kfree(kobject->tag); kfree(kobject); return 0; - } else if(kobject->refcount>1 ) { - if(kobject->type==KOBJECT_PIPE) { - pipe_flush(kobject->data.pipe); - } } return 0; } -int kobject_set_blocking(struct kobject *kobject, int b) -{ - switch (kobject->type) { - case KOBJECT_PIPE: - return pipe_set_blocking(kobject->data.pipe, b); - default: - return 0; - } -} - int kobject_size(struct kobject *kobject, int *dims, int n) { switch (kobject->type) { diff --git a/kernel/kobject.h b/kernel/kobject.h index 0785f70d..d28c28d9 100644 --- a/kernel/kobject.h +++ b/kernel/kobject.h @@ -54,7 +54,6 @@ struct kobject * kobject_copy( struct kobject *ksrc, struct kobject **kdst ); int kobject_remove( struct kobject *kobject, const char *name ); int kobject_close(struct kobject *kobject); -int kobject_set_blocking(struct kobject *kobject, int b); int kobject_get_type(struct kobject *kobject); int kobject_set_tag(struct kobject *kobject, char *new_tag); int kobject_get_tag(struct kobject *kobject, char *buffer, int buffer_size); diff --git a/kernel/monitor.c b/kernel/monitor.c new file mode 100644 index 00000000..079c60fd --- /dev/null +++ b/kernel/monitor.c @@ -0,0 +1,49 @@ +/* +Copyright (C) 2015-2019 The University of Notre Dame +This software is distributed under the GNU General Public License. +See the file LICENSE for details. +*/ + +#include "monitor.h" +#include "process.h" +#include "interrupt.h" + +void monitor_lock(struct monitor *m) +{ + if(m->type==MONITOR_TYPE_INTERRUPT_SAFE) { + interrupt_block(); + } else { + mutex_lock(&m->mutex); + } +} + +void monitor_unlock(struct monitor *m) +{ + if(m->type==MONITOR_TYPE_INTERRUPT_SAFE) { + interrupt_unblock(); + } else { + mutex_unlock(&m->mutex); + } +} + +void monitor_wait(struct monitor *m) +{ + if(m->type==MONITOR_TYPE_INTERRUPT_SAFE) { + process_wait(&m->queue); + } else { + mutex_unlock_and_wait(&m->mutex,&m->queue); + } + monitor_lock(m); +} + +void monitor_notify(struct monitor *m) +{ + process_wakeup(&m->queue); +} + +void monitor_notify_all(struct monitor *m) +{ + while(m->queue.head) { + process_wakeup(&m->queue); + } +} diff --git a/kernel/monitor.h b/kernel/monitor.h new file mode 100644 index 00000000..c95dadca --- /dev/null +++ b/kernel/monitor.h @@ -0,0 +1,31 @@ +/* +Copyright (C) 2015-2019 The University of Notre Dame +This software is distributed under the GNU General Public License. +See the file LICENSE for details. +*/ + +#ifndef MONITOR_H +#define MONITOR_H + +#include "mutex.h" +#include "list.h" + +struct monitor { + int type; + struct mutex mutex; + struct list queue; +}; + +#define MONITOR_TYPE_INTERRUPT_SAFE 1 +#define MONITOR_TYPE_PROCESS_SAFE 2 + +#define MONITOR_INIT_INTERRUPT_SAFE {MONITOR_TYPE_INTERRUPT_SAFE,MUTEX_INIT,LIST_INIT} +#define MONITOR_INIT_PROCESS_SAFE {MONITOR_TYPE_PROCESS_SAFE,MUTEX_INIT,LIST_INIT} + +void monitor_lock( struct monitor *m ); +void monitor_wait( struct monitor *m ); +void monitor_notify( struct monitor *m ); +void monitor_notify_all( struct monitor *m ); +void monitor_unlock( struct monitor *m ); + +#endif diff --git a/kernel/mutex.c b/kernel/mutex.c index 87cc73df..3acf39e6 100644 --- a/kernel/mutex.c +++ b/kernel/mutex.c @@ -12,7 +12,7 @@ void mutex_lock(struct mutex *m) { interrupt_block(); while(m->locked) { - process_wait(&m->waitqueue); + process_wait(&m->queue); interrupt_block(); } m->locked = 1; @@ -23,6 +23,15 @@ void mutex_unlock(struct mutex *m) { interrupt_block(); m->locked = 0; - process_wakeup(&m->waitqueue); + process_wakeup(&m->queue); interrupt_unblock(); } + +void mutex_unlock_and_wait( struct mutex *m, struct list *queue ) +{ + interrupt_block(); + m->locked = 0; + process_wakeup(&m->queue); + process_wait(queue); + /* process wait unblocks interrupts on process switch */ +} diff --git a/kernel/mutex.h b/kernel/mutex.h index 7c6a1f74..b6b001e2 100644 --- a/kernel/mutex.h +++ b/kernel/mutex.h @@ -11,12 +11,13 @@ See the file LICENSE for details. struct mutex { int locked; - struct list waitqueue; + struct list queue; }; #define MUTEX_INIT {0,LIST_INIT} -void mutex_lock(struct mutex *m); -void mutex_unlock(struct mutex *m); +void mutex_lock( struct mutex *m ); +void mutex_unlock( struct mutex *m ); +void mutex_unlock_and_wait( struct mutex *m, struct list *queue ); #endif diff --git a/kernel/pipe.c b/kernel/pipe.c index 656f1512..866edf27 100644 --- a/kernel/pipe.c +++ b/kernel/pipe.c @@ -9,29 +9,27 @@ See the file LICENSE for details. #include "kmalloc.h" #include "process.h" #include "list.h" +#include "monitor.h" -#define PIPE_SIZE (1024) +#define PIPE_SIZE PAGE_SIZE struct pipe { char *buffer; int read_pos; int write_pos; - int blocking; int flushed; int refcount; - struct list queue; + struct monitor monitor; }; struct pipe *pipe_create() { - struct pipe *p = kmalloc(sizeof(*p)); + struct pipe *p = page_alloc(0); p->buffer = kmalloc(PIPE_SIZE * sizeof(char)); p->read_pos = 0; p->write_pos = 0; - p->blocking = 1; p->flushed = 0; - p->queue.head = 0; - p->queue.tail = 0; + p->monitor = (struct monitor) MONITOR_INIT_PROCESS_SAFE; p->refcount = 1; return p; } @@ -44,9 +42,7 @@ struct pipe *pipe_addref( struct pipe *p ) void pipe_flush(struct pipe *p) { - if(p) { - p->flushed = 1; - } + p->flushed = 1; } void pipe_delete(struct pipe *p) @@ -55,82 +51,60 @@ void pipe_delete(struct pipe *p) p->refcount--; if(p->refcount==0) { - if(p->buffer) { - kfree(p->buffer); - } + if(p->buffer) page_free(p->buffer); kfree(p); } } -int pipe_set_blocking(struct pipe *p, int b) +static int pipe_is_full( struct pipe *p ) { - if(p) { - p->blocking = b; - return 1; - } - return 0; + return (p->write_pos + 1) % PIPE_SIZE == p->read_pos; +} + +static int pipe_is_empty( struct pipe *p ) +{ + return p->write_pos==p->read_pos; } int pipe_write(struct pipe *p, char *buffer, int size) { - if(!p || !buffer) { - return -1; - } int written = 0; - if(p->blocking) { - for(written = 0; written < size; written++) { - while((p->write_pos + 1) % PIPE_SIZE == p->read_pos) { - if(p->flushed) { - p->flushed = 0; - return written; - } - process_wait(&p->queue); - } - p->buffer[p->write_pos] = buffer[written]; - p->write_pos = (p->write_pos + 1) % PIPE_SIZE; - } - process_wakeup_all(&p->queue); - } else { - while(written < size && p->write_pos != (p->read_pos - 1) % PIPE_SIZE) { - p->buffer[p->write_pos] = buffer[written]; - p->write_pos = (p->write_pos + 1) % PIPE_SIZE; - written++; + + monitor_lock(&p->monitor); + + for(written = 0; written < size; written++) { + while(pipe_is_full(p)) { + if(p->flushed ) break; + monitor_notify_all(&p->monitor); + monitor_wait(&p->monitor); } + p->buffer[p->write_pos] = buffer[written]; + p->write_pos = (p->write_pos + 1) % PIPE_SIZE; } - p->flushed = 0; + + monitor_notify_all(&p->monitor); + monitor_unlock(&p->monitor); return written; } -int pipe_read_internal(struct pipe *p, char *buffer, int size, int block) +static int pipe_read_internal(struct pipe *p, char *buffer, int size, int block) { - if(!p || !buffer) { - return -1; - } int read = 0; - if(p->blocking) { - for(read = 0; read < size; read++) { - while(p->write_pos == p->read_pos) { - if(p->flushed) { - p->flushed = 0; - return read; - } - if (block == 0) { - return -1; - } - process_wait(&p->queue); - } - buffer[read] = p->buffer[p->read_pos]; - p->read_pos = (p->read_pos + 1) % PIPE_SIZE; - } - process_wakeup_all(&p->queue); - } else { - while(read < size && p->read_pos != p->write_pos) { - buffer[read] = p->buffer[p->read_pos]; - p->read_pos = (p->read_pos + 1) % PIPE_SIZE; - read++; + + monitor_lock(&p->monitor); + + for(read = 0; read < size; read++) { + while(pipe_is_empty(p)) { + if(p->flushed || !block) break; + monitor_notify_all(&p->monitor); + monitor_wait(&p->monitor); } + buffer[read] = p->buffer[p->read_pos]; + p->read_pos = (p->read_pos + 1) % PIPE_SIZE; } - p->flushed = 0; + + monitor_notify_all(&p->monitor); + monitor_unlock(&p->monitor); return read; } diff --git a/kernel/pipe.h b/kernel/pipe.h index d533aa76..7f969218 100644 --- a/kernel/pipe.h +++ b/kernel/pipe.h @@ -7,7 +7,6 @@ struct pipe *pipe_create(); struct pipe *pipe_addref( struct pipe *p ); void pipe_delete(struct pipe *p); void pipe_flush(struct pipe *p); -int pipe_set_blocking(struct pipe *p, int b); int pipe_write(struct pipe *p, char *buffer, int size); int pipe_read(struct pipe *p, char *buffer, int size); diff --git a/kernel/syscall_handler.c b/kernel/syscall_handler.c index 5cb3d7fc..8dc979ed 100644 --- a/kernel/syscall_handler.c +++ b/kernel/syscall_handler.c @@ -522,12 +522,6 @@ int sys_object_get_tag(int fd, char *buffer, int buffer_size) return kobject_get_tag(current->ktable[fd], buffer, buffer_size); } -int sys_object_set_blocking(int fd, int b) -{ - if(!is_valid_object(fd)) return KERROR_INVALID_OBJECT; - return kobject_set_blocking(current->ktable[fd], b); -} - int sys_object_size(int fd, int *dims, int n) { if(!is_valid_object(fd)) return KERROR_INVALID_OBJECT; @@ -673,8 +667,6 @@ int32_t syscall_handler(syscall_t n, uint32_t a, uint32_t b, uint32_t c, uint32_ return sys_object_set_tag(a, (char *) b); case SYSCALL_OBJECT_GET_TAG: return sys_object_get_tag(a, (char *) b, c); - case SYSCALL_OBJECT_SET_BLOCKING: - return sys_object_set_blocking(a, b); case SYSCALL_OBJECT_SIZE: return sys_object_size(a, (int *) b, c); case SYSCALL_OBJECT_MAX: diff --git a/library/syscalls.c b/library/syscalls.c index 62dc3712..9340cdc6 100644 --- a/library/syscalls.c +++ b/library/syscalls.c @@ -168,11 +168,6 @@ int syscall_object_get_tag(int fd, char *buffer, int buffer_size) return syscall(SYSCALL_OBJECT_GET_TAG, fd, (uint32_t)buffer, buffer_size, 0, 0); } -int syscall_object_set_blocking(int fd, int b) -{ - return syscall(SYSCALL_OBJECT_SET_BLOCKING, fd, b, 0, 0, 0); -} - int syscall_object_size(int fd, int *dims, int n) { return syscall(SYSCALL_OBJECT_SIZE, fd, (uint32_t) dims, n, 0, 0); diff --git a/user/pipetest.c b/user/pipetest.c index bb2d926f..93e337d5 100644 --- a/user/pipetest.c +++ b/user/pipetest.c @@ -6,7 +6,6 @@ int main(int argc, char *argv[]) { printf("%d: Running pipe test!\n", syscall_process_self()); int w = syscall_open_pipe(); - syscall_object_set_blocking(w, 0); int x = syscall_process_fork(); if(x) { printf("%d: Writing...\n", syscall_process_self());