From: Matthias Kruk Date: Sat, 26 Oct 2019 07:24:58 +0000 (+0900) Subject: Implement various IPC and scheduling improvements: X-Git-Url: https://git.corax.cc/?a=commitdiff_plain;h=646e6baef7a62a15eabc32d2acee3cd5dcf39ddf;p=corax Implement various IPC and scheduling improvements: - 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 --- diff --git a/include/corax/ipc.h b/include/corax/ipc.h new file mode 100644 index 0000000..2e916f4 --- /dev/null +++ b/include/corax/ipc.h @@ -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 */ diff --git a/include/corax/syscall.h b/include/corax/syscall.h index ac51884..24f2c1f 100644 --- a/include/corax/syscall.h +++ b/include/corax/syscall.h @@ -15,8 +15,13 @@ #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 */ diff --git a/include/corax/types.h b/include/corax/types.h index bbc835d..6822264 100644 --- a/include/corax/types.h +++ b/include/corax/types.h @@ -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 */ diff --git a/kernel/arch/defs.h b/kernel/arch/defs.h index 44c42d6..42bfaa8 100644 --- a/kernel/arch/defs.h +++ b/kernel/arch/defs.h @@ -139,6 +139,7 @@ #define SYS_VECTOR_CORAX 0xCC #define SYS_VECTOR_CXNET 0xCD +#define SYS_VECTOR_CXIPC 0xCE #if FEATURE(POSIX) #define SYS_VECTOR_POSIX 0x80 diff --git a/kernel/arch/entry.S b/kernel/arch/entry.S index d1335de..2f0369f 100644 --- a/kernel/arch/entry.S +++ b/kernel/arch/entry.S @@ -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 diff --git a/kernel/arch/init.S b/kernel/arch/init.S index c7c89a3..79f5385 100644 --- a/kernel/arch/init.S +++ b/kernel/arch/init.S @@ -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 diff --git a/kernel/arch/interrupt.c b/kernel/arch/interrupt.c index dcd2bb0..d751b0c 100644 --- a/kernel/arch/interrupt.c +++ b/kernel/arch/interrupt.c @@ -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; diff --git a/kernel/core/Makefile b/kernel/core/Makefile index ef8b7c5..2839bfc 100644 --- a/kernel/core/Makefile +++ b/kernel/core/Makefile @@ -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 index 0000000..a93ba26 --- /dev/null +++ b/kernel/core/cxipc.c @@ -0,0 +1,116 @@ +#include +#include +#include +#include +#include +#include +#include + +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); +} diff --git a/kernel/core/process.c b/kernel/core/process.c index 17d0582..daec1a3 100644 --- a/kernel/core/process.c +++ b/kernel/core/process.c @@ -2,21 +2,78 @@ #include #include #include +#include #include #include #include -#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); +} diff --git a/kernel/core/sched.c b/kernel/core/sched.c index e0a6182..10a76e3 100644 --- a/kernel/core/sched.c +++ b/kernel/core/sched.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -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); +} diff --git a/kernel/include/arch.h b/kernel/include/arch.h index b66894b..eb42a61 100644 --- a/kernel/include/arch.h +++ b/kernel/include/arch.h @@ -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); diff --git a/kernel/include/process.h b/kernel/include/process.h index f8c80bf..6ec4286 100644 --- a/kernel/include/process.h +++ b/kernel/include/process.h @@ -20,6 +20,7 @@ #define __PROCESS_H #include +#include 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 */ diff --git a/libc/syscall.S b/libc/syscall.S index f1321ab..7d53714 100644 --- a/libc/syscall.S +++ b/libc/syscall.S @@ -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