summaryrefslogtreecommitdiffstats
path: root/proc
diff options
context:
space:
mode:
Diffstat (limited to 'proc')
-rw-r--r--proc/process.c67
-rw-r--r--proc/process.h11
-rw-r--r--proc/scheduler.c117
-rw-r--r--proc/scheduler.h5
4 files changed, 190 insertions, 10 deletions
diff --git a/proc/process.c b/proc/process.c
index 137e35c..62c0269 100644
--- a/proc/process.c
+++ b/proc/process.c
@@ -1,6 +1,8 @@
#include "process.h"
+#include "api/error.h"
#include "api/process.h"
#include "hal/smp.h"
+#include "proc/scheduler.h"
#include "sys/objdir.h"
#include <string.h>
@@ -26,6 +28,71 @@ pcb_new(jove_owned_obj_t *pcb_obj, size_t size, jove_owned_obj_t *rootdir_obj)
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);
+ 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;
+ }
+
+ pcb_header->send.obj = subject;
+ pcb_header->send.pid = target;
+
+ scheduler_block_for_mail(pcb_header, timeout, target);
+
+ if(pcb_header->send.obj) 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;
+ }
+
+ if(timeout == 0) {
+ return -EEMPTY;
+ }
+
+ 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;
+}
+
pcb_t *pcb_frompid(pid_t pid)
{
return (pcb_t*)rbtree_search((struct rbtree_node*)pcb_tree, pid);
diff --git a/proc/process.h b/proc/process.h
index 950f63e..21dbf8d 100644
--- a/proc/process.h
+++ b/proc/process.h
@@ -7,14 +7,14 @@
struct pcb_mailbox
{
- jove_obj_t *obj;
+ jove_owned_obj_t *obj;
pid_t pid;
};
struct pcb_header
{
struct rbtree_node tree_node;
- struct pcb_header *sched_next;
+ struct pcb_header *sched_prev, *sched_next;
size_t size;
pid_t pid;
@@ -22,6 +22,7 @@ struct pcb_header
enum pcb_state state;
intmax_t state_code;
+ size_t block_until;
struct pcb_mailbox send, recv;
@@ -42,6 +43,9 @@ 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);
+
enum pcb_state pcb_getstate(pcb_t *pcb);
intmax_t pcb_getstatecode(pcb_t *pcb);
@@ -50,6 +54,9 @@ void **pcb_getksp_ref(pcb_t *pcb);
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);
+
extern struct rbtree_node *pcb_tree;
#endif
diff --git a/proc/scheduler.c b/proc/scheduler.c
index 875bcc4..29f45b5 100644
--- a/proc/scheduler.c
+++ b/proc/scheduler.c
@@ -5,24 +5,27 @@
#include "proc/init.h"
#include "proc/process.h"
+//TODO: Better scheduling algorithm than round robin.
+static struct pcb_header *s_running_list;
+
static struct pcb_header *s_ready_queue;
+static struct pcb_header *s_mail_queue;
+
+static uintmax_t s_this_tick;
-static inline int
-s_scheduler_yield_pcb(processor_t *proc, pcb_t *current_pcb, pcb_t *target_pcb)
+static inline void
+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);
+ obj_release(target_rootdir);
processor_setpcb(proc, target_pcb_obj);
- obj_release(target_rootdir);
_scheduler_switch_pcb_arch(target_pcb);
scheduler_switch(pcb_getksp_ref(current_pcb), pcb_getksp(target_pcb));
-
- return 0;
}
-
int scheduler_yield(pid_t target_pid)
{
processor_t *proc = processor_current();
@@ -35,19 +38,117 @@ int scheduler_yield(pid_t target_pid)
if(target_pcb == 0) {
return -EBADPROC;
}
+
+ scheduler_savestate();
+ s_scheduler_swap_pcb(proc, current_pcb, target_pcb);
+ scheduler_restorestate();
+ return 0;
+}
- return s_scheduler_yield_pcb(proc, current_pcb, target_pcb);
+void
+s_enqueue_pcb(struct pcb_header *pcb, struct pcb_header *list)
+{
+ if(pcb->sched_prev) pcb->sched_prev->sched_next = pcb->sched_next;
+ if(pcb->sched_prev) pcb->sched_next->sched_prev = pcb->sched_prev;
+
+ list->sched_prev = pcb;
+ pcb->sched_next = list;
+ pcb->sched_prev = NULL;
+}
+
+void
+scheduler_block_for_mail(struct pcb_header *pcb, uintmax_t timeout, pid_t yield_target)
+{
+ pcb->state = PCB_STATE_BLOCKED_MAIL;
+
+ s_enqueue_pcb(pcb, s_mail_queue);
+ s_mail_queue = pcb;
+
+ pcb->block_until = s_this_tick + timeout;
+ scheduler_yield(yield_target);
+}
+
+void
+s_schedule_ready_queue(void)
+{
+ for(struct pcb_header *pcb = s_ready_queue; pcb; pcb = s_ready_queue) {
+ s_ready_queue = pcb->sched_next;
+
+ //Add this process to the ready list after the last ready process.
+ pcb->state = PCB_STATE_READY;
+ s_enqueue_pcb(pcb, s_running_list);
+ s_running_list = pcb;
+ }
+}
+
+void
+s_schedule_mail_queue(void)
+{
+ struct pcb_header *pcb = s_mail_queue;
+ 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;
+ }
+ }
+ if(pcb->recv.obj) {
+ s_enqueue_pcb(pcb, s_running_list);
+ s_running_list = pcb;
+ goto loop_end;
+ }
+
+ if(s_this_tick >= pcb->block_until) {
+ s_enqueue_pcb(pcb, s_running_list);
+ s_running_list = pcb;
+ }
+loop_end:
+ pcb = next_pcb;
+ }
+}
+
+void
+scheduler_tick()
+{
+ size_t last_tick = s_this_tick++;
+
+ s_schedule_ready_queue();
+ s_schedule_mail_queue();
+
+ processor_t *proc = processor_current();
+ struct pcb_header *current_pcb = obj_deref(processor_getpcb(proc));
+ struct pcb_header *next_pcb = s_running_list;
+ struct pcb_header *tail = next_pcb;
+
+ while(tail->sched_next) {
+ tail = tail->sched_next;
+ if(tail == next_pcb) break;
+ }
+
+ tail->sched_next = next_pcb;
+ next_pcb->sched_prev = tail;
+ s_running_list = next_pcb->sched_next;
+
+ s_scheduler_swap_pcb(proc, (pcb_t*)current_pcb, (pcb_t*)next_pcb);
}
void scheduler_init(jove_owned_obj_t *pcb_obj, void *process_main)
{
struct pcb_header *pcb_header = obj_deref(pcb_obj);
pcb_header->state = PCB_STATE_RUNNING;
- pcb_header->sched_next = pcb_header;
processor_t *proc = processor_current();
processor_setpcb(proc, pcb_obj);
+ s_running_list = pcb_header;
+
__asm__("movq %0, %%rsp; \
xorq %%rbp, %%rbp; \
jmp %1"::
diff --git a/proc/scheduler.h b/proc/scheduler.h
index 0371e86..2fc0c44 100644
--- a/proc/scheduler.h
+++ b/proc/scheduler.h
@@ -5,10 +5,15 @@
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_pcb_arch(pcb_t *target);
int scheduler_yield(pid_t target);
+void scheduler_tick(void);
+void scheduler_block_for_mail(struct pcb_header *pcb, size_t timeout, pid_t yield_target);
#endif