summaryrefslogtreecommitdiffstats
path: root/proc
diff options
context:
space:
mode:
Diffstat (limited to 'proc')
-rw-r--r--proc/init.c2
-rw-r--r--proc/ipc.c116
-rw-r--r--proc/ipc.h35
-rw-r--r--proc/process.c124
-rw-r--r--proc/process.h27
-rw-r--r--proc/scheduler.c70
-rw-r--r--proc/scheduler.h2
7 files changed, 293 insertions, 83 deletions
diff --git a/proc/init.c b/proc/init.c
index 10f8a01..130b10e 100644
--- a/proc/init.c
+++ b/proc/init.c
@@ -3,7 +3,7 @@
#include "hal/memory.h"
#include "panic/panic.h"
-objpath_part_t s_last_region = JOVE_OBJDIR_ENTRIES-1;
+objpath_part_t s_last_region = OBJDIR_ENTRIES-1;
jove_owned_obj_t
init_pop_alloc(void)
diff --git a/proc/ipc.c b/proc/ipc.c
new file mode 100644
index 0000000..db1233d
--- /dev/null
+++ b/proc/ipc.c
@@ -0,0 +1,116 @@
+#include "ipc.h"
+#include "api/error.h"
+#include "proc/process.h"
+#include "sys/objdir.h"
+#include "jove.h"
+
+inline pid_t port_get_owner(struct port *port)
+{
+ return port->owner;
+}
+
+inline struct port *port_get_send_target(struct port *port)
+{
+ return port->send_target;
+}
+
+inline struct port *port_get_recv_target(struct port *port)
+{
+ return port->recv_target;
+}
+
+inline void port_set_recv_target(struct port *port, struct port *target)
+{
+ port->recv_target = target;
+}
+
+inline bool port_poll_send(struct port *port) { return port_get_send_target(port) != 0; }
+inline bool port_poll_recv(struct port *port) { return obj_peektype(port->recv) != JOVE_OBJ_NONE; }
+
+int port_take_send(struct port *port, jove_owned_obj_t *dest_obj)
+{
+ jove_owned_obj_t *send_obj = obj_take(&port->send);
+
+ if(!port_get_send_target(port)) {
+ ipc_klogf("Port %p does not have mail to send\n", port);
+ obj_release(send_obj);
+ return -EEMPTY;
+ }
+
+ ipc_klogf("Taking obj from %i into obj %p\n", port->send_target, dest_obj);
+
+ objdir_swapobj(send_obj, dest_obj);
+ port->send_target = 0;
+ obj_release(send_obj);
+ return 0;
+}
+
+struct port *port_take_recv(struct port *port, jove_owned_obj_t *dest_obj)
+{
+ errno = 0;
+ jove_owned_obj_t *recv_obj = obj_take(&port->recv);
+
+ //Validate that the port has an object in the recv object.
+ if(obj_gettype(recv_obj) == JOVE_OBJ_NONE) {
+ ipc_klogf("Port %p does not have mail\n", port);
+ obj_release(recv_obj);
+ errno = EEMPTY;
+ return NULL;
+ }
+
+ ipc_klogf("Taking obj from %i into obj %p\n", port->recv_target, dest_obj);
+
+ objdir_swapobj(recv_obj, dest_obj);
+ struct port *recv_port = port_get_recv_target(port);
+ port_set_recv_target(port, (void*)-1);
+ obj_release(recv_obj);
+
+ return recv_port;
+}
+
+int port_send(struct port *source, struct port *target, jove_owned_obj_t *sent_obj)
+{
+ jove_owned_obj_t *target_recv_obj = obj_take(&target->recv);
+
+ //Validate that the target is full or is not accepting from this port.
+ if((port_get_recv_target(target) != 0 && port_get_recv_target(target) != source)
+ || port_poll_recv(target)) {
+
+ obj_release(target_recv_obj);
+ ipc_klogf("Target %p is full. Sending to send buffer. \n", target);
+
+ jove_owned_obj_t *source_send_obj = obj_take(&source->send);
+
+ //Validate that the send buffer has space.
+ if(port_get_send_target(source)) {
+ ipc_klogf("Source %p is full\n", source);
+ obj_release(source_send_obj);
+ return -EFULL;
+ }
+ objdir_swapobj(source_send_obj, sent_obj);
+ source->send_target = target;
+
+ obj_release(source_send_obj);
+ return 1;
+ }
+
+ objdir_swapobj(target_recv_obj, sent_obj);
+ target->recv_target = source;
+
+ obj_release(target_recv_obj);
+ return 0;
+}
+
+int port_recv(struct port *source, struct port *target)
+{
+ jove_owned_obj_t *source_send_obj = obj_take(&source->send);
+ jove_owned_obj_t *target_recv_obj = obj_take(&target->recv);
+
+ objdir_swapobj(source_send_obj, target_recv_obj);
+ target->recv_target = source;
+ source->send_target = NULL;
+
+ obj_release(target_recv_obj);
+ obj_release(source_send_obj);
+ return 0;
+}
diff --git a/proc/ipc.h b/proc/ipc.h
new file mode 100644
index 0000000..4a3dce3
--- /dev/null
+++ b/proc/ipc.h
@@ -0,0 +1,35 @@
+#ifndef _JOVE_PROC_IPC_H
+#define _JOVE_PROC_IPC_H 1
+
+#include "hal/obj.h"
+#include "api/process.h"
+#include <stdatomic.h>
+#include <stdbool.h>
+
+struct port
+{
+ pid_t owner;
+
+ struct port *send_target;
+ jove_obj_t send;
+
+ struct port *recv_target;
+ jove_obj_t recv;
+};
+
+pid_t port_get_owner(struct port *port);
+
+struct port *port_get_send_target(struct port *port);
+struct port *port_get_recv_target(struct port *port);
+void port_set_recv_target(struct port *port, struct port *target);
+
+bool port_poll_send(struct port *port);
+bool port_poll_recv(struct port *port);
+
+int port_take_send(struct port *port, jove_owned_obj_t *dest_obj);
+struct port *port_take_recv(struct port *port, jove_owned_obj_t *dest_obj);
+
+int port_send(struct port *source, struct port *target, jove_owned_obj_t *sent_obj);
+int port_recv(struct port *source, struct port *target);
+
+#endif
diff --git a/proc/process.c b/proc/process.c
index f0b83c6..f659c24 100644
--- a/proc/process.c
+++ b/proc/process.c
@@ -2,9 +2,10 @@
#include "api/error.h"
#include "api/process.h"
#include "hal/smp.h"
+#include "proc/ipc.h"
#include "proc/scheduler.h"
#include "sys/objdir.h"
-#include <string.h>
+#include "lib/string.h"
struct rbtree_node *pcb_tree;
pid_t __next_pid = 1;
@@ -23,74 +24,81 @@ pcb_new(jove_owned_obj_t *pcb_obj, size_t size, jove_owned_obj_t *rootdir_obj)
pcb_header->tree_node.get_key = (void*)pcb_getpid;
pcb_tree = rbtree_insert(pcb_tree, &pcb_header->tree_node);
+ pcb_header->mailbox.owner = pcb_header->pid;
+
pcb_header->state = PCB_STATE_EMBRYO;
- pcb_header->ksp = (void*)pcb_obj + size - sizeof(uintmax_t);
+ pcb_header->ksp = (void*)(__syscall_stack + 0x1000 - sizeof(void*));
return _pcb_new_arch((pcb_t*)pcb_header);
}
int
pcb_send(pcb_t *pcb, pid_t target, jove_owned_obj_t *subject, size_t timeout)
{
- struct pcb_header *pcb_header = (struct pcb_header*)pcb;
- struct pcb_header *target_pcb = (struct pcb_header*)rbtree_search(pcb_tree, target);
+ //Validate that the target PCB has a valid port.
+ pcb_t *target_pcb = (pcb_t*)rbtree_search(pcb_tree, target);
if(target_pcb == 0) {
return -EBADPROC;
}
- if(target_pcb->recv.obj == NULL &&
- (target_pcb->recv.pid == pcb_getpid(pcb) || target_pcb->recv.pid == 0))
- {
- target_pcb->recv.obj = subject;
- target_pcb->recv.pid = pcb_getpid(pcb);
- return scheduler_yield(target);
- }
-
- if(timeout == 0) {
- return -EFULL;
- }
+ struct port *pcb_port = pcb_getport(pcb);
+ struct port *target_port = pcb_getport(target_pcb);
- pcb_header->send.obj = subject;
- pcb_header->send.pid = target;
-
- scheduler_block_for_mail(pcb_header, timeout, target);
+ //Try to send to either the send buffer or the target recv buffer.
+ int port_send_result = port_send(pcb_port, target_port, subject);
- if(pcb_header->send.obj) return -ETIMEOUT;
+ if(port_send_result < 0) {
+ //Port send buffer was full. Wait for it to clear, or timeout.
+ if(timeout == 0) return -EFULL;
+ scheduler_block_for_mail((struct pcb_header*)pcb, timeout, target);
+ if((port_send_result = port_send(pcb_port, target_port, subject)) < 0) {
+ //If the send buffer is still full, then we timed out.
+ return -ETIMEOUT;
+ }
+ }
+ if(port_send_result == 1) {
+ //We sent to the port, but it's stuck in the send buffer.
+ scheduler_block_for_mail((struct pcb_header*)pcb, timeout, target);
+ if(port_poll_send(pcb_port)) {
+ //If the send buffer is still full, then we timed out.
+ port_take_send(pcb_port, subject);
+ return -ETIMEOUT;
+ }
+ }
return 0;
}
int
pcb_recv(pcb_t *pcb, pid_t target, jove_owned_obj_t *dest_obj, size_t timeout)
{
- struct pcb_header *pcb_header = (struct pcb_header*)pcb;
- struct pcb_header *target_pcb = (struct pcb_header*)rbtree_search(pcb_tree, target);
- if(target_pcb == 0) {
- return -EBADPROC;
- }
-
- if(pcb_header->recv.obj) {
- goto recv_success;
- return 0;
+ struct port *target_port = NULL;
+ if(target == 0) {
+ //If the target is zero, we're accepting from all send targets.
+ pcb_t *target_pcb = (pcb_t*)rbtree_search(pcb_tree, target);
+ if(target_pcb == 0) {
+ return -EBADPROC;
+ }
+ target_port = pcb_getport(target_pcb);
}
- if(timeout == 0) {
- return -EEMPTY;
+ struct port *pcb_port = pcb_getport(pcb);
+
+ //Block PCB port from recieving from anything other than the target.
+ port_set_recv_target(pcb_port, target_port);
+ struct port *recv_from = port_take_recv(pcb_port, dest_obj);
+
+ if(recv_from == 0) {
+ if(timeout == 0) {
+ //If non-blocking, leave immediately.
+ return -EEMPTY;
+ }
+ scheduler_block_for_mail((struct pcb_header*)pcb, timeout, target);
+ recv_from = port_take_recv(pcb_port, dest_obj);
+ if(recv_from == 0) {
+ //If blocking, and timeout expired, then we timed out.
+ return -ETIMEOUT;
+ }
}
-
- pcb_header->recv.pid = target;
- scheduler_block_for_mail(pcb_header, timeout, target);
-
- if(!pcb_header->recv.obj) {
- pcb_header->recv.pid = -1;
- return -ETIMEOUT;
- }
-
-recv_success:
- objdir_swapobj(pcb_header->recv.obj, dest_obj);
- obj_release(pcb_header->recv.obj);
- pcb_header->recv.obj = 0;
- pcb_header->recv.pid = -1;
-
- return 0;
+ return port_get_owner(recv_from);
}
pcb_t *pcb_frompid(pid_t pid)
@@ -104,49 +112,55 @@ process_current(void)
return processor_getpcb(((processor_t*)processor_current()));
}
-pid_t
+inline pid_t
pcb_getpid(pcb_t *pcb)
{
return ((struct pcb_header*)pcb)->pid;
}
-jove_obj_t*
+inline jove_obj_t*
pcb_getrootdir(pcb_t *pcb)
{
return ((struct pcb_header*)pcb)->rootdir;
}
-jove_owned_obj_t*
+inline jove_owned_obj_t*
pcb_getpagedir(jove_owned_obj_t *rootdir_obj)
{
return objdir_getlocal(rootdir_obj, PCB_ROOTDIR_PAGEDIR_I);
}
-jove_owned_obj_t*
+inline jove_owned_obj_t*
pcb_getself(jove_owned_obj_t *rootdir_obj)
{
return objdir_getlocal(rootdir_obj, PCB_ROOTDIR_SELF_I);
}
-enum pcb_state
+inline struct port*
+pcb_getport(pcb_t *pcb)
+{
+ return &((struct pcb_header*)pcb)->mailbox;
+}
+
+inline enum pcb_state
pcb_getstate(pcb_t *pcb)
{
return ((struct pcb_header*)pcb)->state;
}
-intmax_t
+inline intmax_t
pcb_getstatecode(pcb_t *pcb)
{
return ((struct pcb_header*)pcb)->state_code;
}
-void*
+inline void*
pcb_getksp(pcb_t *pcb)
{
return ((struct pcb_header*)pcb)->ksp;
}
-void**
+inline void**
pcb_getksp_ref(pcb_t *pcb)
{
return &((struct pcb_header*)pcb)->ksp;
diff --git a/proc/process.h b/proc/process.h
index 21dbf8d..f566ba4 100644
--- a/proc/process.h
+++ b/proc/process.h
@@ -1,15 +1,18 @@
#ifndef _JOVE_HAL_PROCESS_H
#define _JOVE_HAL_PROCESS_H 1
+#include "hal/memory.h"
#include "hal/obj.h"
#include "lib/rbtree.h"
#include "api/process.h"
+#include "proc/ipc.h"
-struct pcb_mailbox
-{
- jove_owned_obj_t *obj;
- pid_t pid;
-};
+#ifdef DEBUG_IPC
+#include "lib/printf.h"
+#define ipc_klogf(fmt, ...) kprintf("%s: " fmt, __func__, __VA_ARGS__)
+#else
+#define ipc_klogf(fmt, ...)
+#endif
struct pcb_header
{
@@ -24,7 +27,7 @@ struct pcb_header
intmax_t state_code;
size_t block_until;
- struct pcb_mailbox send, recv;
+ struct port mailbox;
void *ksp;
};
@@ -43,8 +46,7 @@ jove_obj_t *pcb_getrootdir(pcb_t *pcb);
jove_owned_obj_t *pcb_getpagedir(jove_owned_obj_t *rootdir_obj);
jove_owned_obj_t *pcb_getself(jove_owned_obj_t *rootdir_obj);
-struct pcb_mailbox *pcb_getmail_send(pcb_t *pcb);
-struct pcb_mailbox *pcb_getmail_recv(pcb_t *pcb);
+struct port *pcb_getport(pcb_t *pcb);
enum pcb_state pcb_getstate(pcb_t *pcb);
intmax_t pcb_getstatecode(pcb_t *pcb);
@@ -57,6 +59,15 @@ pcb_t *pcb_frompid(pid_t pid);
int pcb_send(pcb_t *pcb, pid_t target, jove_owned_obj_t *subject, size_t timeout);
int pcb_recv(pcb_t *pcb, pid_t target, jove_owned_obj_t *dest_obj, size_t timeout);
+physaddr_t pcb_get_syscall_stack(pcb_t *pcb);
+physaddr_t pcb_get_interrupt_stack(pcb_t *pcb);
+
+physaddr_t pcb_set_syscall_stack(pcb_t *pcb, physaddr_t page);
+physaddr_t pcb_set_interrupt_stack(pcb_t *pcb, physaddr_t page);
+
+void pcb_map_syscall_stack(pcb_t *pcb);
+void pcb_map_interrupt_stack(pcb_t *pcb);
+
extern struct rbtree_node *pcb_tree;
#endif
diff --git a/proc/scheduler.c b/proc/scheduler.c
index 29f45b5..ba00abc 100644
--- a/proc/scheduler.c
+++ b/proc/scheduler.c
@@ -1,9 +1,11 @@
#include "scheduler.h"
#include "api/error.h"
#include "hal/smp.h"
+#include "lib/printf.h"
#include "sys/objdir.h"
#include "proc/init.h"
#include "proc/process.h"
+#include "proc/ipc.h"
//TODO: Better scheduling algorithm than round robin.
static struct pcb_header *s_running_list;
@@ -18,12 +20,18 @@ s_scheduler_swap_pcb(processor_t *proc, pcb_t *current_pcb, pcb_t *target_pcb)
{
jove_owned_obj_t *target_rootdir = obj_take(pcb_getrootdir(target_pcb));
jove_owned_obj_t *target_pcb_obj = pcb_getself(target_rootdir);
+ jove_obj_t target_pagedir = objdir_peeklocal(target_rootdir, PCB_ROOTDIR_PAGEDIR_I);
+
obj_release(target_rootdir);
processor_setpcb(proc, target_pcb_obj);
_scheduler_switch_pcb_arch(target_pcb);
- scheduler_switch(pcb_getksp_ref(current_pcb), pcb_getksp(target_pcb));
+
+ scheduler_switch(
+ pcb_getksp_ref(current_pcb),
+ pcb_getksp(target_pcb),
+ (void*)obj_getvalue((jove_owned_obj_t*)&target_pagedir));
}
int scheduler_yield(pid_t target_pid)
@@ -59,6 +67,8 @@ s_enqueue_pcb(struct pcb_header *pcb, struct pcb_header *list)
void
scheduler_block_for_mail(struct pcb_header *pcb, uintmax_t timeout, pid_t yield_target)
{
+ ipc_klogf("Blocking PID %i for %i ticks for %i\n",
+ pcb_getpid((pcb_t*)pcb), timeout, yield_target);
pcb->state = PCB_STATE_BLOCKED_MAIL;
s_enqueue_pcb(pcb, s_mail_queue);
@@ -88,24 +98,31 @@ s_schedule_mail_queue(void)
while(pcb) {
struct pcb_header *next_pcb = pcb->sched_next;
- if(pcb->send.obj) {
- struct pcb_header *send_target = (struct pcb_header*)pcb_frompid(pcb->send.pid);
- if(send_target->recv.pid == 0 || send_target->recv.pid == pcb->pid) {
- objdir_swapobj(send_target->recv.obj, pcb->send.obj);
- send_target->recv.pid = pcb->pid;
-
- s_enqueue_pcb(pcb, s_running_list);
- s_running_list = pcb;
- goto loop_end;
- }
+ struct port *pcb_port = pcb_getport((pcb_t*)pcb);
+ if(port_poll_send(pcb_port)) {
+ //Send buffer is full. Try to transfer to target recv buffer.
+ //First check if the target recv buffer has space.
+ struct port *recv_port = port_get_send_target(pcb_port);
+ if(port_poll_recv(recv_port)) continue;
+
+ //Now check if the recv buffer is accepting from this port.
+ struct port *recv_target = port_get_recv_target(recv_port);
+ if(recv_target != 0 && pcb_port != recv_target) continue;
+
+ //This never hits, but if things change in impl we may have to abort here.
+ if(port_recv(recv_port, pcb_port) < 0) continue;
+ s_enqueue_pcb(pcb, s_running_list);
+ s_running_list = pcb;
}
- if(pcb->recv.obj) {
+ if(port_poll_recv(pcb_port)) {
+ //Recv buffer is full, so unblock.
s_enqueue_pcb(pcb, s_running_list);
s_running_list = pcb;
- goto loop_end;
}
if(s_this_tick >= pcb->block_until) {
+ ipc_klogf("Unblocking %i due to timeout\n", pcb_getpid((pcb_t*)pcb));
+
s_enqueue_pcb(pcb, s_running_list);
s_running_list = pcb;
}
@@ -147,10 +164,27 @@ void scheduler_init(jove_owned_obj_t *pcb_obj, void *process_main)
processor_t *proc = processor_current();
processor_setpcb(proc, pcb_obj);
- s_running_list = pcb_header;
+ jove_owned_obj_t syscall_stack = init_pop_alloc();
+ jove_owned_obj_t interrupt_stack = init_pop_alloc();
- __asm__("movq %0, %%rsp; \
- xorq %%rbp, %%rbp; \
- jmp %1"::
- "m"(pcb_header->ksp), "r"(process_main));
+ pcb_set_syscall_stack((pcb_t*)pcb_header, obj_getvalue(&syscall_stack));
+ pcb_set_interrupt_stack((pcb_t*)pcb_header, obj_getvalue(&interrupt_stack));
+
+ kprintf("Syscall stack %p %p\n", *__syscall_stack_mapping, pcb_get_syscall_stack((pcb_t*)pcb_header));
+ kprintf("Interrupt stack %p %p\n", *__interrupt_stack_mapping, pcb_get_interrupt_stack((pcb_t*)pcb_header));
+
+ _scheduler_switch_pcb_arch((pcb_t*)pcb_header);
+
+ jove_owned_obj_t *pagedir_obj = pcb_getpagedir(_rootdir_obj);
+ void *pagedir = (void*)obj_getvalue(pagedir_obj);
+ obj_release(pagedir_obj);
+
+ pcb_map_syscall_stack((pcb_t*)pcb_header);
+ pcb_map_interrupt_stack((pcb_t*)pcb_header);
+
+ s_running_list = pcb_header;
+ __asm__ volatile("\
+ movq %0, %%rsp; \
+ xorq %%rbp, %%rbp; \
+ jmpq %1":: "r"(pcb_header->ksp), "r"(process_main));
}
diff --git a/proc/scheduler.h b/proc/scheduler.h
index 2fc0c44..964f2c0 100644
--- a/proc/scheduler.h
+++ b/proc/scheduler.h
@@ -8,7 +8,7 @@ void scheduler_init(jove_owned_obj_t *pcb_obj, void *process_main);
void scheduler_savestate(void);
void scheduler_restorestate(void);
-void scheduler_switch(void *this_sp, void *other_sp);
+void scheduler_switch(void *this_sp, void *other_sp, void *other_cr3);
void _scheduler_switch_pcb_arch(pcb_t *target);
int scheduler_yield(pid_t target);