# HG changeset patch # User John Tsiombikas # Date 1318653956 -10800 # Node ID 3941e82b07f24150282ce9ba6243f468cfa233df # Parent c7bd6ec7b946aa232bd13566bc2844306892996d - implemented syscalls: exit, waitpid, getppid - moved sys_whatever functions out of syscall.c into more reasonable files - putting all the definitions that must be synced with userland to include/kdef.h diff -r c7bd6ec7b946 -r 3941e82b07f2 Makefile --- a/Makefile Thu Oct 13 05:22:35 2011 +0300 +++ b/Makefile Sat Oct 15 07:45:56 2011 +0300 @@ -1,4 +1,5 @@ ifneq ($(shell uname -m), i386) + # -m32 instructs the compiler to produce 32bit code ccemu = -m32 ifeq ($(shell uname -s), FreeBSD) @@ -18,11 +19,10 @@ CC = gcc -inc = -Isrc -Isrc/klibc -Isrc/boot +inc = -Isrc -Isrc/klibc -Isrc/boot -Iinclude # -nostdinc instructs the compiler to ignore standard include directories -# -m32 instructs the compiler to produce 32bit code (in case we have a 64bit compiler) -CFLAGS = $(ccemu) -Wall -g -nostdinc -fno-builtin $(inc) +CFLAGS = $(ccemu) -Wall -g -nostdinc -fno-builtin $(inc) -DKERNEL ASFLAGS = $(ccemu) -g -nostdinc -fno-builtin $(inc) bin = kernel.elf diff -r c7bd6ec7b946 -r 3941e82b07f2 include/kdef.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/include/kdef.h Sat Oct 15 07:45:56 2011 +0300 @@ -0,0 +1,55 @@ +/* definitions that must be in-sync between kernel and user space */ +#ifndef KERNEL_DEFS_H_ +#define KERNEL_DEFS_H_ + +/* --- defines for sys/wait.h */ +#if defined(KERNEL) || defined(KDEF_WAIT_H) +#define WNOHANG 1 + +#define WEXITSTATUS(s) ((s) & _WSTATUS_MASK) +#define WCOREDUMP(s) ((s) & _WCORE_BIT) + +#define WIFEXITED(s) (_WREASON(s) == _WREASON_EXITED) +#define WIFSIGNALED(s) (_WREASON(s) == _WREASON_SIGNALED) + +/* implementation details */ +#define _WSTATUS_MASK 0xff + +#define _WREASON_SHIFT 8 +#define _WREASON_MASK 0xf00 +#define _WREASON(s) (((s) & _WREASON_MASK) >> _WREASON_SHIFT) + +#define _WREASON_EXITED 1 +#define _WREASON_SIGNALED 2 + +#define _WCORE_BIT 0x1000 +#endif /* sys/wait.h */ + + + +/* --- defines for errno.h */ +#if defined(KERNEL) || defined(KDEF_ERRNO_H) +#define EAGAIN 1 +#define EINVAL 2 +#define ECHILD 3 +#endif /* errno.h */ + + +/* --- defines for syscall.h */ +#if defined(KERNEL) || defined(KDEF_SYSCALL_H) + +#define SYSCALL_INT 0x80 + +#define SYS_HELLO 0 +#define SYS_SLEEP 1 +#define SYS_FORK 2 +#define SYS_EXIT 3 +#define SYS_WAITPID 4 +#define SYS_GETPID 5 +#define SYS_GETPPID 6 + +#define NUM_SYSCALLS 7 + +#endif /* syscall.h */ + +#endif /* KERNEL_DEFS_H_ */ diff -r c7bd6ec7b946 -r 3941e82b07f2 src/klibc/errno.h --- a/src/klibc/errno.h Thu Oct 13 05:22:35 2011 +0300 +++ b/src/klibc/errno.h Sat Oct 15 07:45:56 2011 +0300 @@ -1,6 +1,9 @@ #ifndef ERRNO_H_ #define ERRNO_H_ -#define EAGAIN 1 +/* all kernel-definitions that should be shared with user space + * are in include/kdef.h + */ +#include "kdef.h" #endif /* ERRNO_H_ */ diff -r c7bd6ec7b946 -r 3941e82b07f2 src/proc.c --- a/src/proc.c Thu Oct 13 05:22:35 2011 +0300 +++ b/src/proc.c Sat Oct 15 07:45:56 2011 +0300 @@ -12,6 +12,7 @@ #include "syscall.h" #include "sched.h" #include "tss.h" +#include "kdef.h" #define FLAGS_INTR_BIT (1 << 9) @@ -138,7 +139,7 @@ intr_ret(ifrm); } -int fork(void) +int sys_fork(void) { int i, pid; struct process *p, *parent; @@ -189,8 +190,13 @@ /* initialize the rest of the process structure */ p->id = pid; p->parent = parent->id; + p->child_list = 0; p->next = p->prev = 0; + /* add to the child list */ + p->sib_next = parent->child_list; + parent->child_list = p; + /* will be copied on write */ p->user_stack_pg = parent->user_stack_pg; @@ -203,6 +209,105 @@ return pid; } +int sys_exit(int status) +{ + struct process *p, *child; + + p = get_current_proc(); + + /* TODO deliver SIGCHLD to the parent */ + + /* find any child processes and make init adopt them */ + child = p->child_list; + while(child) { + child->parent = 1; + child = child->sib_next; + } + + cleanup_vm(p); + + /* remove it from the runqueue */ + remove_proc(p->id); + + /* make it a zombie until its parent reaps it */ + p->state = STATE_ZOMBIE; + p->exit_status = (status & _WSTATUS_MASK) | (_WREASON_EXITED << _WREASON_SHIFT); + + /* wakeup any processes waiting for it + * we're waking up the parent's address, because waitpid waits + * on it's own process struct, not knowing which child will die + * first. + */ + wakeup(get_process(p->parent)); + return 0; +} + +int sys_waitpid(int pid, int *status, int opt) +{ + struct process *p, *child; + + p = get_current_proc(); + +restart: + if(pid <= 0) { + /* search for zombie children */ + child = p->child_list; + while(child) { + if(child->state == STATE_ZOMBIE) { + break; + } + child = child->sib_next; + } + } else { + if(!(child = get_process(pid)) || child->parent != p->id) { + return -ECHILD; + } + if(child->state != STATE_ZOMBIE) { + child = 0; + } + } + + /* found ? */ + if(child) { + int res; + struct process *prev, dummy; + + if(status) { + *status = child->exit_status; + } + res = child->id; + + /* remove it from our children list */ + dummy.sib_next = p->child_list; + prev = &dummy; + while(prev->next) { + if(prev->next == child) { + prev->next = child->next; + break; + } + } + p->child_list = dummy.next; + + /* invalidate the id */ + child->id = 0; + return res; + } + + /* not found, wait or sod off */ + if(!(opt & WNOHANG)) { + /* wait on our own process struct because + * we have no way of knowing which child will + * die first. + * exit will wakeup the parent structure... + */ + wait(p); + /* done waiting, restart waitpid */ + goto restart; + } + + return 0; /* he's not dead jim */ +} + void context_switch(int pid) { static struct process *prev, *new; @@ -262,5 +367,25 @@ struct process *get_process(int pid) { - return &proc[pid]; + struct process *p = proc + pid; + if(p->id != pid) { + printf("get_process called with invalid pid: %d\n", pid); + return 0; + } + return p; } + +int sys_getpid(void) +{ + return cur_pid; +} + +int sys_getppid(void) +{ + struct process *p = get_current_proc(); + + if(!p) { + return 0; + } + return p->parent; +} diff -r c7bd6ec7b946 -r 3941e82b07f2 src/proc.h --- a/src/proc.h Thu Oct 13 05:22:35 2011 +0300 +++ b/src/proc.h Sat Oct 15 07:45:56 2011 +0300 @@ -27,6 +27,8 @@ int id, parent; enum proc_state state; + int exit_status; + /* when blocked it's waiting for a wakeup on this address */ void *wait_addr; @@ -44,12 +46,17 @@ struct context ctx; + struct process *child_list; + struct process *next, *prev; /* for the scheduler queues */ + struct process *sib_next; /* for the sibling list */ }; void init_proc(void); -int fork(void); +int sys_fork(void); +int sys_exit(int status); +int sys_waitpid(int pid, int *status, int opt); void context_switch(int pid); @@ -58,6 +65,9 @@ struct process *get_current_proc(void); struct process *get_process(int pid); +int sys_getpid(void); +int sys_getppid(void); + /* defined in proc-asm.S */ uint32_t get_instr_ptr(void); uint32_t get_caller_instr_ptr(void); diff -r c7bd6ec7b946 -r 3941e82b07f2 src/sched.c --- a/src/sched.c Thu Oct 13 05:22:35 2011 +0300 +++ b/src/sched.c Sat Oct 15 07:45:56 2011 +0300 @@ -75,6 +75,20 @@ set_intr_state(istate); } +void remove_proc(int pid) +{ + int istate; + struct process *proc; + + istate = get_intr_state(); + disable_intr(); + + proc = get_process(pid); + remove(&runq, proc); + + set_intr_state(istate); +} + /* block the process until we get a wakeup call for address ev */ void wait(void *wait_addr) { diff -r c7bd6ec7b946 -r 3941e82b07f2 src/sched.h --- a/src/sched.h Thu Oct 13 05:22:35 2011 +0300 +++ b/src/sched.h Sat Oct 15 07:45:56 2011 +0300 @@ -6,6 +6,7 @@ void schedule(void); void add_proc(int pid); +void remove_proc(int pid); void wait(void *wait_addr); void wakeup(void *wait_addr); diff -r c7bd6ec7b946 -r 3941e82b07f2 src/syscall.c --- a/src/syscall.c Thu Oct 13 05:22:35 2011 +0300 +++ b/src/syscall.c Sat Oct 15 07:45:56 2011 +0300 @@ -10,16 +10,16 @@ static void syscall(int inum); static int sys_hello(void); -static int sys_sleep(int sec); -static int sys_fork(void); -static int sys_getpid(void); void init_syscall(void) { sys_func[SYS_HELLO] = sys_hello; - sys_func[SYS_SLEEP] = sys_sleep; - sys_func[SYS_FORK] = sys_fork; - sys_func[SYS_GETPID] = sys_getpid; + sys_func[SYS_SLEEP] = sys_sleep; /* timer.c */ + sys_func[SYS_FORK] = sys_fork; /* proc.c */ + sys_func[SYS_EXIT] = sys_exit; /* proc.c */ + sys_func[SYS_WAITPID] = sys_waitpid; /* proc.c */ + sys_func[SYS_GETPID] = sys_getpid; /* proc.c */ + sys_func[SYS_GETPPID] = sys_getppid; /* proc.c */ interrupt(SYSCALL_INT, syscall); } @@ -41,6 +41,12 @@ * so that it'll be restored into eax before returning to userland. */ frm->regs.eax = sys_func[idx](frm->regs.ebx, frm->regs.ecx, frm->regs.edx, frm->regs.esi, frm->regs.edi); + + /* we don't necessarily want to return to the same process + * might have blocked or exited or whatever, so call schedule + * to decide what's going to run next. + */ + schedule(); } static int sys_hello(void) @@ -48,23 +54,3 @@ printf("process %d says hello!\n", get_current_pid()); return 0; } - -static int sys_sleep(int sec) -{ - printf("process %d will sleep for %d seconds\n", get_current_pid(), sec); - sleep(sec * 1000); /* timer.c */ - return 0; -} - -static int sys_fork(void) -{ - printf("process %d is forking\n", get_current_pid()); - return fork(); /* proc.c */ -} - -static int sys_getpid(void) -{ - int pid = get_current_pid(); - printf("process %d getpid\n", pid); - return pid; -} diff -r c7bd6ec7b946 -r 3941e82b07f2 src/syscall.h --- a/src/syscall.h Thu Oct 13 05:22:35 2011 +0300 +++ b/src/syscall.h Sat Oct 15 07:45:56 2011 +0300 @@ -1,15 +1,8 @@ #ifndef SYSCALL_H_ #define SYSCALL_H_ -#define SYSCALL_INT 0x80 - -/* when we get rid of test_proc.S we'll turn this into an enum */ -#define SYS_HELLO 0 -#define SYS_SLEEP 1 -#define SYS_FORK 2 -#define SYS_GETPID 3 - -#define NUM_SYSCALLS 4 +#define KDEF_SYSCALL_H +#include "kdef.h" #ifndef ASM void init_syscall(void); diff -r c7bd6ec7b946 -r 3941e82b07f2 src/timer.c --- a/src/timer.c Thu Oct 13 05:22:35 2011 +0300 +++ b/src/timer.c Sat Oct 15 07:45:56 2011 +0300 @@ -75,13 +75,20 @@ interrupt(IRQ_TO_INTR(0), timer_handler); } +int sys_sleep(int sec) +{ + printf("process %d will sleep for %d seconds\n", get_current_pid(), sec); + sleep(sec * 1000); /* timer.c */ + + /* TODO if interrupted, return the remaining seconds */ + return 0; +} + void sleep(unsigned long msec) { int ticks, tsum, istate; struct timer_event *ev, *node; - printf("sleep(%lu)\n", msec); - if((ticks = MSEC_TO_TICKS(msec)) <= 0) { return; } diff -r c7bd6ec7b946 -r 3941e82b07f2 src/timer.h --- a/src/timer.h Thu Oct 13 05:22:35 2011 +0300 +++ b/src/timer.h Sat Oct 15 07:45:56 2011 +0300 @@ -5,6 +5,7 @@ void init_timer(void); +int sys_sleep(int sec); void sleep(unsigned long msec); #endif /* _TIMER_H_ */ diff -r c7bd6ec7b946 -r 3941e82b07f2 src/vm.c --- a/src/vm.c Thu Oct 13 05:22:35 2011 +0300 +++ b/src/vm.c Sat Oct 15 07:45:56 2011 +0300 @@ -803,6 +803,28 @@ pdest->ctx.pgtbl_paddr = paddr; } +/* cleanup_vm called by exit to clean up any memory used by the process */ +void cleanup_vm(struct process *p) +{ + struct rbnode *vmnode; + + /* go through the vm map and reduce refcounts all around + * when a ref goes to 0, free the physical page + */ + rb_begin(&p->vmmap); + while((vmnode = rb_next(&p->vmmap))) { + struct vm_page *page = vmnode->data; + if(--page->nref <= 0) { + /* free the physical page if nref goes to 0 */ + free_phys_page(PAGE_TO_ADDR(page->ppage)); + } + } + + /* destroying the tree will free the nodes */ + rb_destroy(&p->vmmap); +} + + int get_page_bit(int pgnum, uint32_t bit, int wholepath) { int tidx = PAGE_TO_PGTBL(pgnum); diff -r c7bd6ec7b946 -r 3941e82b07f2 src/vm.h --- a/src/vm.h Thu Oct 13 05:22:35 2011 +0300 +++ b/src/vm.h Sat Oct 15 07:45:56 2011 +0300 @@ -78,7 +78,11 @@ int pgalloc_vrange(int start, int num); void pgfree(int start, int num); +/* don't be fooled by the fact these two accept process arguments + * they in fact work only for the "current" process (psrc and p) + */ void clone_vm(struct process *pdest, struct process *psrc, int cow); +void cleanup_vm(struct process *p); int get_page_bit(int pgnum, uint32_t bit, int wholepath); void set_page_bit(int pgnum, uint32_t bit, int wholepath);