diff options
Diffstat (limited to 'proc')
| -rw-r--r-- | proc/init.c | 2 | ||||
| -rw-r--r-- | proc/ipc.c | 116 | ||||
| -rw-r--r-- | proc/ipc.h | 35 | ||||
| -rw-r--r-- | proc/process.c | 124 | ||||
| -rw-r--r-- | proc/process.h | 27 | ||||
| -rw-r--r-- | proc/scheduler.c | 70 | ||||
| -rw-r--r-- | proc/scheduler.h | 2 |
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); |
