aboutsummaryrefslogtreecommitdiff
path: root/kernel/features
diff options
context:
space:
mode:
authorMarvin Borner2021-04-15 22:47:54 +0200
committerMarvin Borner2021-04-15 22:47:54 +0200
commit4d4e784770b576199b18f22100689125a18bfd9a (patch)
tree5009a65f79af966fa6253307e64271479b1b0bed /kernel/features
parent462eaa9531b9e62916b02ab52759cd070de755d3 (diff)
Basic block/unblock
Diffstat (limited to 'kernel/features')
-rw-r--r--kernel/features/io.c40
-rw-r--r--kernel/features/proc.c2
-rw-r--r--kernel/features/syscall.c10
3 files changed, 51 insertions, 1 deletions
diff --git a/kernel/features/io.c b/kernel/features/io.c
index b8275f9..6042818 100644
--- a/kernel/features/io.c
+++ b/kernel/features/io.c
@@ -3,15 +3,18 @@
#include <assert.h>
#include <def.h>
#include <fb.h>
+#include <interrupts.h>
#include <io.h>
#include <list.h>
#include <mm.h>
+#include <proc.h>
#include <ps2.h>
#include <rand.h>
#include <str.h>
#include <timer.h>
PROTECTED static struct io_dev *io_mappings[IO_MAX] = { 0 };
+PROTECTED static struct list *io_listeners[IO_MAX] = { 0 };
static u8 io_type_valid(enum io_type io)
{
@@ -75,11 +78,48 @@ res io_read(enum io_type io, void *buf, u32 offset, u32 count)
if (!(dev = io_get(io)) || !dev->read)
return -ENOENT;
+ if (dev->ready && !dev->ready())
+ return -EAGAIN;
+
return dev->read(buf, offset, count);
}
+void io_block(enum io_type io, struct proc *proc, struct regs *r)
+{
+ assert(r->eax == SYS_IOREAD);
+ assert(io_type_valid(io));
+ list_add(io_listeners[io], proc);
+ proc_state(proc_current(), PROC_BLOCKED);
+ proc_yield(r);
+}
+
+void io_unblock(enum io_type io)
+{
+ struct page_dir *dir_bak;
+ memory_backup_dir(&dir_bak);
+
+ assert(io_type_valid(io));
+ struct node *iterator = io_listeners[io]->head;
+ while (iterator) {
+ struct proc *proc = iterator->data;
+ struct regs *r = &proc->regs;
+
+ memory_switch_dir(proc->page_dir);
+ r->eax = io_read(r->ebx, (void *)r->ecx, r->edx, r->esi);
+ memory_switch_dir(dir_bak);
+
+ proc_state(proc, PROC_RUNNING);
+ struct node *next = iterator->next;
+ list_remove(io_listeners[io], iterator);
+ iterator = next;
+ }
+}
+
CLEAR void io_install(struct boot_info *boot)
{
+ for (u32 i = 0; i < IO_MAX; i++)
+ io_listeners[i] = list_new();
+
ps2_detect();
u8 ps2_keyboard = ps2_keyboard_detect();
diff --git a/kernel/features/proc.c b/kernel/features/proc.c
index a71919e..6ddeb32 100644
--- a/kernel/features/proc.c
+++ b/kernel/features/proc.c
@@ -124,6 +124,8 @@ void proc_reset_quantum(struct proc *proc)
void proc_state(struct proc *proc, enum proc_state state)
{
+ assert(proc != idle_proc->data);
+
if (state == PROC_RUNNING && !list_first_data(proc_list_running, proc)) {
assert(list_remove(proc_list_blocked, list_first_data(proc_list_blocked, proc)));
assert(list_add(proc_list_running, proc));
diff --git a/kernel/features/syscall.c b/kernel/features/syscall.c
index abd7130..2c30a3b 100644
--- a/kernel/features/syscall.c
+++ b/kernel/features/syscall.c
@@ -60,7 +60,12 @@ static void syscall_handler(struct regs *r)
break;
}
case SYS_IOREAD: {
- r->eax = io_read(r->ebx, (void *)r->ecx, r->edx, r->esi);
+ res ret = io_read(r->ebx, (void *)r->ecx, r->edx, r->esi);
+ if (ret == -EAGAIN) {
+ io_block(r->ebx, proc_current(), r);
+ } else {
+ r->eax = ret;
+ }
break;
}
case SYS_IOWRITE: {
@@ -87,10 +92,12 @@ static void syscall_handler(struct regs *r)
break;
}
case SYS_EXIT: {
+ r->eax = EOK;
proc_exit(proc_current(), r, (s32)r->ebx);
break;
}
case SYS_YIELD: {
+ r->eax = EOK;
proc_yield(r);
break;
}
@@ -126,6 +133,7 @@ static void syscall_handler(struct regs *r)
// TODO: Reimplement network functions using VFS
default: {
+ r->eax = -EINVAL;
printf("Unknown syscall %d!\n", num);
break;
}