]> git.corax.cc Git - corax/commitdiff
Implement various IPC and scheduling improvements:
authorMatthias Kruk <m@m10k.eu>
Sat, 26 Oct 2019 07:24:58 +0000 (16:24 +0900)
committerMatthias Kruk <m@m10k.eu>
Sat, 26 Oct 2019 07:24:58 +0000 (16:24 +0900)
 - Implement signalling/waiting facilities for processes and tasks
 - Implement primitive message passing between processes
 - Implement helper functions for accesing properties of a process
 - Also keep the pid within the task structure, for faster access
 - Add a wait-queue to the scheduler, to keep track of waiting processes

14 files changed:
include/corax/ipc.h [new file with mode: 0644]
include/corax/syscall.h
include/corax/types.h
kernel/arch/defs.h
kernel/arch/entry.S
kernel/arch/init.S
kernel/arch/interrupt.c
kernel/core/Makefile
kernel/core/cxipc.c [new file with mode: 0644]
kernel/core/process.c
kernel/core/sched.c
kernel/include/arch.h
kernel/include/process.h
libc/syscall.S

diff --git a/include/corax/ipc.h b/include/corax/ipc.h
new file mode 100644 (file)
index 0000000..2e916f4
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef __CORAX_IPC_H
+#define __CORAX_IPC_H
+
+struct cxmsg {
+       u32_t cm_src;
+       u32_t cm_dst;
+       u32_t cm_len;
+
+       u32_t cm_type;
+
+       union {
+               u8_t  CM_data[CONFIG_IPC_MSGSIZE];
+       } CM_dat;
+};
+
+#define cm_data CM_dat.CM_data
+
+#endif /* __CORAX_IPC_H */
index ac51884d8ef27b6eef0973572a942d8b47c9badf..24f2c1f39f83c6bc947d85f99e101680f4c1ce59 100644 (file)
 #define SYS_POLL       11
 #define SYS_BIND       12
 
+#define IPC_SEND       0
+#define IPC_RECV       1
+#define IPC_SENDRECV   2
+
 #define SYSCALL_CORAX  0xCC
 #define SYSCALL_CXNET  0xCD
+#define SYSCALL_CXIPC  0xCE
 #define SYSCALL_POSIX  0x80
 
 #endif /* __CORAX_SYSCALL_H */
index bbc835d634e65fbecd501ecdc248435ec5fcdff4..68222646efd40111514a371910bdec730211f3f1 100644 (file)
@@ -35,4 +35,6 @@ typedef signed long long int    i64_t;
 
 typedef u32_t pid_t;
 
+#define PID_ANY ((pid_t)-1)
+
 #endif /* __TYPES_H */
index 44c42d6543f900462f39fb51878aa8c698981990..42bfaa8e4a7f19fc3b0449c1f81f2accd31e45dc 100644 (file)
 
 #define SYS_VECTOR_CORAX    0xCC
 #define SYS_VECTOR_CXNET    0xCD
+#define SYS_VECTOR_CXIPC    0xCE
 
 #if FEATURE(POSIX)
 #define SYS_VECTOR_POSIX    0x80
index d1335decd51f1e0788f9f86c0280100c777ae461..2f0369fdbdc630773a24a06d84e1db684468d044 100644 (file)
@@ -77,6 +77,7 @@
 #endif /* FEATURE(POSIX) */
 .global _sys_entryCC
 .global _sys_entryCN
+.global _sys_entryCX
 
 .global _int_entry_common
 .global _int_restore
@@ -327,7 +328,12 @@ _sys_entryCC:
 _sys_entryCN:
        pushl   $0
        pushl   $SYS_VECTOR_CXNET
-       /* fall through */
+       jmp             _int_entry_common
+
+_sys_entryCX:
+       pushl   $0
+       pushl   $SYS_VECTOR_CXIPC
+       jmp             _int_entry_common
 
 _int_entry_common:
     pusha
index c7c89a3afc55df94d3203f2d1228ad83ea3db398..79f53853c581cd2bb98802b320128a87878a8c1f 100644 (file)
@@ -85,6 +85,7 @@
 
 .extern _sys_entryCC
 .extern _sys_entryCN
+.extern _sys_entryCX
 #if FEATURE(POSIX)
 .extern _sys_entryPX
 #endif /* FEATURE(POSIX) */
@@ -377,6 +378,11 @@ _update_cs:
        addl    $8, (%esp)
        call    _segment_descriptor_set
 
+       /* add an entry for Corax IPC syscalls */
+       movl    $_sys_entryCX, 12(%esp)
+       addl    $8, (%esp)
+       call    _segment_descriptor_set
+
     movw    $((IDT_ENTRIES * 8) + 1), (%esp)
     movl    $_cpu, %eax
     addl    $IDT_OFFSET, %eax
index dcd2bb0e9ee4c0d78d137acdeaa6a194269eb8eb..d751b0c421b33e5bd66af240030ff13d2eff0e3e 100644 (file)
@@ -25,6 +25,7 @@
 
 void sched_tick(void);
 extern int sys_cxnet(long, long, long, long, long, long, long);
+extern int sys_cxipc(long, long, long);
 
 static const char *_exc_name[] = {
     "#DE", "#DB", "NMI", "#BP", "#OF", "#BR", "#UD", "#NM", "#DF", "#MF",
@@ -149,6 +150,10 @@ void _sys_handle(stack_frame_t ctx)
                dbg_printf("_corax_call(0x%x, 0x%x, 0x%x);\n", ctx.eax, ctx.ebx, ctx.ecx);
                break;
 
+       case SYS_VECTOR_CXIPC:
+               ret_val = sys_cxipc(ctx.eax, ctx.ebx, ctx.ecx);
+               break;
+
        case SYS_VECTOR_CXNET:
                ret_val = sys_cxnet(ctx.eax, ctx.ebx, ctx.ecx, ctx.edx, ctx.esi, ctx.edi, ctx.ebp);
                break;
index ef8b7c5e9fe19f6a455349c1a14514506ef17a4c..2839bfcfc12fd1de06dfd9c823ba26f3020f6368 100644 (file)
@@ -1,4 +1,4 @@
-OBJECTS = main.o process.o sched.o cxnet.o socket.o mbuf.o
+OBJECTS = main.o process.o sched.o cxnet.o socket.o cxipc.o
 OUTPUT = core.o
 INCLUDES = -I../include -I../../include -I../..
 CFLAGS += $(INCLUDES)
diff --git a/kernel/core/cxipc.c b/kernel/core/cxipc.c
new file mode 100644 (file)
index 0000000..a93ba26
--- /dev/null
@@ -0,0 +1,116 @@
+#include <config.h>
+#include <corax/types.h>
+#include <corax/errno.h>
+#include <corax/syscall.h>
+#include <corax/ipc.h>
+#include <corax/heap.h>
+#include <process.h>
+
+int sys_cxsend(pid_t to, struct cxmsg *msg)
+{
+       process_t *sproc;
+       process_t *dproc;
+       int ret_val;
+
+       ret_val = -EFAULT;
+       sproc = process_get_current();
+       dproc = process_lookup(to);
+
+       if(sproc && dproc) {
+               struct cxmsg *kmsg;
+
+               kmsg = kmalloc(sizeof(*kmsg));
+
+               if(!kmsg) {
+                       ret_val = -ENOMEM;
+               } else {
+                       /*
+                        * We can't copy the message directly into the address space of the destination
+                        * process since we don't know the address of the user-space buffer yet. That's
+                        * why we store the message in a kernel-space buffer, from where it will be
+                        * dispatched once the receiving process calls cxrecv().
+                        */
+                       process_memcpy_ptok(sproc, kmsg, msg, sizeof(*kmsg));
+
+                       kmsg->cm_src = process_get_id(sproc);
+                       kmsg->cm_dst = to;
+
+                       /* make sure cm_len doesn't exceed the size of the message */
+                       if(kmsg->cm_len > CONFIG_IPC_MSGSIZE) {
+                               kmsg->cm_len = CONFIG_IPC_MSGSIZE;
+                       }
+
+                       /* place the message somewhere the destination process can find it */
+                       ret_val = process_inbox_put(dproc, kmsg);
+
+                       if(ret_val < 0) {
+                               kfree(kmsg);
+                       } else {
+                               /* wait for destination process to pick up the message */
+
+                               process_wait(to);
+                       }
+               }
+       }
+
+       return(ret_val);
+}
+
+int sys_cxrecv(pid_t from, struct cxmsg *msg)
+{
+       process_t *cproc;
+       int ret_val;
+
+       ret_val = -EFAULT;
+       cproc = process_get_current();
+
+       if(cproc) {
+               struct cxmsg *kmsg;
+
+               /* process_inbox_get() always returns a valid message (or waits forever) */
+               kmsg = process_inbox_get(from);
+
+               process_memcpy_ktop(cproc, msg, kmsg, sizeof(*msg));
+
+               /* signal source that their message was picked up */
+               process_signal(kmsg->cm_src);
+
+               /* we don't need the kernel-space buffer anymore */
+               kfree(kmsg);
+
+               ret_val = 0;
+       }
+
+       return(ret_val);
+}
+
+int sys_cxsendrecv(pid_t tofrom, struct cxmsg *msg)
+{
+       return(-ENOSYS);
+}
+
+int sys_cxipc(long arg0, long arg1, long arg2)
+{
+       int ret_val;
+
+       ret_val = -EOPNOTSUPP;
+
+       switch(arg0) {
+       case IPC_SEND:
+               ret_val = sys_cxsend((pid_t)arg1, (struct cxmsg*)arg2);
+               break;
+
+       case IPC_RECV:
+               ret_val = sys_cxrecv((pid_t)arg1, (struct cxmsg*)arg2);
+               break;
+
+       case IPC_SENDRECV:
+               ret_val = sys_cxsendrecv((pid_t)arg1, (struct cxmsg*)arg2);
+               break;
+
+       default:
+               break;
+       }
+
+       return(ret_val);
+}
index 17d05822463b5d40d01d8aa4fd9752c19b62d9cd..daec1a3086f0fb9beb09e7789c8a105db090e4b6 100644 (file)
@@ -2,21 +2,78 @@
 #include <corax/types.h>
 #include <corax/errno.h>
 #include <corax/heap.h>
+#include <corax/ipc.h>
 #include <arch.h>
 #include <debug.h>
 #include <process.h>
-#include "sched.h"
 #include "fd.h"
 
 struct process {
        struct pagedir *p_pgdir;
        struct task    *p_tasks;
        u32_t          p_privl;
+       pid_t          p_id;
+
+       struct {
+               struct cxmsg *msg;
+               pid_t        sender;
+       } p_inbox[32];
 
        struct fd      p_fds[16];
 };
 
-extern int sched_enqueue(task_t*);
+struct proc_list {
+       struct proc_list *next;
+       process_t *proc;
+};
+
+static pid_t _next_pid = 100;
+static struct proc_list *_procs;
+
+extern int  sched_enqueue(task_t*);
+extern void sched_wait(pid_t);
+extern int  sched_signal(pid_t);
+
+static inline int NQ(process_t *p)
+{
+       struct proc_list *pl;
+       int ret_val;
+
+       ret_val = -ENOMEM;
+       pl = kmalloc(sizeof(*pl));
+
+       if(pl) {
+               pl->next = _procs;
+               pl->proc = p;
+               _procs = pl;
+               ret_val = 0;
+       }
+
+       return(ret_val);
+}
+
+static inline int DQ(process_t *p)
+{
+       struct proc_list **pl;
+       int ret_val;
+
+       ret_val = -ENOENT;
+
+       for(pl = &_procs; *pl; pl = &((*pl)->next)) {
+               if((*pl)->proc == p) {
+                       struct proc_list *freeme;
+
+                       freeme = *pl;
+                       *pl = (*pl)->next;
+
+                       kfree(freeme);
+                       ret_val = 0;
+                       break;
+               }
+       }
+
+       return(ret_val);
+}
 
 int process_create(process_t **dst, u32_t ppl, void *entry)
 {
@@ -49,6 +106,7 @@ int process_create(process_t **dst, u32_t ppl, void *entry)
                }
 
                proc->p_privl = ppl;
+               proc->p_id = _next_pid++;
 
                task_prepare(proc->p_tasks, (u32_t)pdbr, (u32_t)entry,
                                         (u32_t)kstack + CONFIG_KERNEL_STACK_SIZE,
@@ -58,6 +116,13 @@ int process_create(process_t **dst, u32_t ppl, void *entry)
                proc->p_tasks->t_tslice = 50;
                proc->p_tasks->t_rslice = 50;
                proc->p_tasks->t_proc = proc;
+               proc->p_tasks->t_pid = proc->p_id;
+
+               ret_val = NQ(proc);
+
+               if(ret_val < 0) {
+                       goto cleanup;
+               }
 
                if(sched_enqueue(proc->p_tasks) != 0) {
                        PANIC("sched_enqueue() failed for a new task\n");
@@ -168,6 +233,21 @@ process_t* process_get_current(void)
        return(ret_val);
 }
 
+process_t* process_lookup(pid_t pid)
+{
+       struct proc_list *lst;
+       process_t *ret_val;
+
+       for(ret_val = NULL, lst = _procs; lst; lst = lst->next) {
+               if(lst->proc->p_id == pid) {
+                       ret_val = lst->proc;
+                       break;
+               }
+       }
+
+       return(ret_val);
+}
+
 int process_memcpy_ptok(process_t *proc, void *dst, void *src, u32_t bytes)
 {
        int ret_val;
@@ -194,3 +274,98 @@ int process_memcpy_ptop(process_t *dproc, void *dst, process_t *sproc, void *src
 
        return(ret_val);
 }
+
+int process_inbox_put(process_t *proc, struct cxmsg *msg)
+{
+       process_t *cproc;
+       int ret_val;
+       int i;
+
+       cproc = process_get_current();
+
+       for(ret_val = -ENOMEM, i = 0; i < 32; i++) {
+               if(!(proc->p_inbox[i].sender)) {
+                       proc->p_inbox[i].sender = cproc->p_id;
+                       proc->p_inbox[i].msg = msg;
+
+                       ret_val = 0;
+                       break;
+               }
+       }
+
+       return(ret_val);
+}
+
+struct cxmsg* process_inbox_get(pid_t from)
+{
+       process_t *proc;
+       void *ret_val;
+
+       proc = process_get_current();
+
+       do {
+               int i;
+
+               for(ret_val = NULL, i = 0; i < 32; i++) {
+                       /* skip empty entries */
+                       if(!proc->p_inbox[i].sender) {
+                               continue;
+                       }
+
+                       if(proc->p_inbox[i].sender == from || from == PID_ANY) {
+                               ret_val = proc->p_inbox[i].msg;
+                               proc->p_inbox[i].msg = NULL;
+                               proc->p_inbox[i].sender = 0;
+
+                               break;
+                       }
+               }
+
+               if(!ret_val) {
+                       process_wait(from);
+               }
+       } while(!ret_val);
+
+       return(ret_val);
+}
+
+int process_wait(pid_t pid)
+{
+       process_t *cproc;
+       int ret_val;
+
+       ret_val = -EFAULT;
+       cproc = process_get_current();
+
+       if(cproc) {
+               sched_wait(pid);
+       }
+
+       return(ret_val);
+}
+
+int process_signal(pid_t pid)
+{
+       process_t *dproc;
+       int ret_val;
+
+       ret_val = -ENOENT;
+       dproc = process_lookup(pid);
+
+       if(dproc) {
+               sched_signal(pid);
+               ret_val = 0;
+       }
+
+       return(ret_val);
+}
+
+void* process_get_tasks(process_t *proc)
+{
+       return(proc->p_tasks);
+}
+
+pid_t process_get_id(process_t *proc)
+{
+       return(proc->p_id);
+}
index e0a6182bcfeb089970d724f7cacf224fb753f792..10a76e30db62e59c8443da3b069122501b003688 100644 (file)
@@ -2,6 +2,7 @@
 #include <corax/types.h>
 #include <corax/heap.h>
 #include <corax/errno.h>
+#include <process.h>
 #include <debug.h>
 #include <arch.h>
 
@@ -12,6 +13,7 @@ struct task_queue {
 
 /* FIXME: This should be per-processor */
 static struct task_queue *_readyq = NULL;
+static struct task_queue *_waitq = NULL;
 
 static void _nq(struct task_queue **q, task_t *t)
 {
@@ -52,6 +54,25 @@ static task_t* _dq(struct task_queue **q)
        return(ret_val);
 }
 
+static void _unq(struct task_queue **q, task_t *t)
+{
+       while(*q) {
+               if((*q)->data == t) {
+                       struct task_queue *freeme;
+
+                       freeme = *q;
+                       *q = freeme->next;
+
+                       kfree(freeme);
+                       break;
+               }
+
+               q = &((*q)->next);
+       }
+
+       return;
+}
+
 void sched_tick(void)
 {
        task_t *cur_task;
@@ -91,6 +112,30 @@ void sched_tick(void)
        return;
 }
 
+void sched_wait(pid_t pid)
+{
+       task_t *cur_task;
+
+       cur_task = task_get_current();
+
+       cur_task->t_waitpid = pid;
+       cur_task->t_state = TASK_STATE_WAITING;
+
+       /* put the current task on the wait queue */
+       _nq(&_waitq, cur_task);
+
+       /* get a task from the ready queue and execute it */
+       cur_task = _dq(&_readyq);
+
+       if(cur_task) {
+               task_switch(cur_task);
+       } else {
+               dbg_printf("This should not have happened\n");
+       }
+
+       return;
+}
+
 int sched_enqueue(task_t *t)
 {
        int ret_val;
@@ -109,3 +154,42 @@ int sched_enqueue(task_t *t)
 
        return(ret_val);
 }
+
+int sched_signal(pid_t pid)
+{
+       task_t *cur_task;
+       process_t *proc;
+       int ret_val;
+
+       ret_val = -ENOENT;
+
+       cur_task = task_get_current();
+       proc = process_lookup(pid);
+
+       if(proc) {
+               task_t *t;
+
+               /* FIXME: Implement processes with multiple tasks */
+               for(t = process_get_tasks(proc); t; t = NULL) {
+                       if(t->t_state != TASK_STATE_WAITING) {
+                               continue;
+                       }
+
+                       if(t->t_waitpid == cur_task->t_pid || t->t_waitpid == PID_ANY) {
+                               /* remove task from waitq */
+                               _unq(&_waitq, t);
+
+                               t->t_waitpid = 0;
+                               t->t_state = TASK_STATE_READY;
+
+                               /* put task on readyq */
+                               _nq(&_readyq, t);
+                               ret_val = 0;
+
+                               break;
+                       }
+               }
+       }
+
+       return(ret_val);
+}
index b66894b36c6d932169fb7112d83ed95e6f76e765..eb42a6158d22062cf3cb7dabffe19bc18dcbd97a 100644 (file)
@@ -40,6 +40,8 @@ struct task {
        u32_t t_tslice;
        u32_t t_rslice;
        void *t_proc;
+       pid_t t_waitpid;
+       pid_t t_pid;
 } __attribute__((packed));
 
 int     cpu_get_id(void);
index f8c80bfc06821f233818c34c915e37df0aff54ce..6ec428608e13de37cd3d19489c706b6b210a128f 100644 (file)
@@ -20,6 +20,7 @@
 #define __PROCESS_H
 
 #include <corax/types.h>
+#include <corax/ipc.h>
 
 typedef struct process process_t;
 
@@ -31,9 +32,19 @@ int process_ffree(process_t*, int);
 int process_flookup(process_t*, int);
 
 process_t* process_get_current(void);
+process_t* process_lookup(pid_t);
 
 int process_memcpy_ptok(process_t*, void*, void*, u32_t);
 int process_memcpy_ktop(process_t*, void*, void*, u32_t);
 int process_memcpy_ptop(process_t*, void*, process_t*, void*, u32_t);
 
+int           process_inbox_put(process_t*, struct cxmsg*);
+struct cxmsg* process_inbox_get(pid_t);
+
+int           process_wait(pid_t);
+int           process_signal(pid_t);
+
+void*         process_get_tasks(process_t*);
+pid_t         process_get_id(process_t*);
+
 #endif /* __PROCESS_H */
index f1321abba390bda5f0fdc4dace58c8c5bb271ed8..7d537144ef505a04ae35ae3ec265295435855b96 100644 (file)
@@ -186,3 +186,39 @@ bind:
 
        popl    %ebx
        ret
+
+.global cxsend
+cxsend:
+       pushl   %ebx
+
+       movl    $IPC_SEND, %eax
+       movl    8(%esp), %ebx
+       movl    12(%esp), %ecx
+       int     $SYSCALL_CXIPC
+
+       popl    %ebx
+       ret
+
+.global cxrecv
+cxrecv:
+       pushl   %ebx
+
+       movl    $IPC_RECV, %eax
+       movl    8(%esp), %ebx
+       movl    12(%esp), %ecx
+       int     $SYSCALL_CXIPC
+
+       popl    %ebx
+       ret
+
+.global cxsendrecv
+cxsendrecv:
+       pushl   %ebx
+
+       movl    $IPC_SENDRECV, %eax
+       movl    8(%esp), %ebx
+       movl    12(%esp), %ecx
+       int     $SYSCALL_CXIPC
+
+       popl    %ebx
+       ret