diff --git a/src/arch/x86_64/syscall.asm b/src/arch/x86_64/syscall.asm index f89398ba..f8f05a57 100644 --- a/src/arch/x86_64/syscall.asm +++ b/src/arch/x86_64/syscall.asm @@ -15,7 +15,8 @@ extern syscall_stat extern syscall_fstat extern syscall_fork extern syscall_execve -func_count equ 14 +extern syscall_waitpid +func_count equ 15 func_table: @@ -33,6 +34,7 @@ func_table: dq syscall_fstat dq syscall_fork dq syscall_execve + dq syscall_waitpid section .text global asm_syscall_entry diff --git a/src/include/kernel/sched.h b/src/include/kernel/sched.h index 55c6f267..4f617807 100644 --- a/src/include/kernel/sched.h +++ b/src/include/kernel/sched.h @@ -18,6 +18,9 @@ #define THREAD_STATE_BLOCKED 2 #define THREAD_STATE_BLOCKED_INTR 3 +#define PROC_STATE_NORMAL 0 +#define PROC_STATE_ZOMBIE 1 + typedef unsigned long state_t; struct _proc_t; @@ -41,6 +44,8 @@ typedef struct _thread_t{ typedef struct _proc_t{ int lock; + int state; + int status; struct _proc_t* parent; struct _proc_t* sibling; struct _proc_t* child; @@ -52,6 +57,7 @@ typedef struct _proc_t{ size_t threadcount; dirnode_t* root; dirnode_t* cwd; + event_t childevent; } proc_t; diff --git a/src/sys/syscalls/waitpid.c b/src/sys/syscalls/waitpid.c new file mode 100644 index 00000000..0c0d14c2 --- /dev/null +++ b/src/sys/syscalls/waitpid.c @@ -0,0 +1,86 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define UNSUPPORTED "astral: waitpid: Unsupported waitpid options!\n" +#define UNSUPPORTED_PG "astral: waitpid: Process group waits are not supported yet.\n" + +syscallret syscall_waitpid(pid_t pid, int *status, int options){ + syscallret retv; + retv.ret = -1; + + if(status > USER_SPACE_END - sizeof(int)){ + retv.errno = EFAULT; + return retv; + } + + if(options != 0){ + console_write(UNSUPPORTED, strlen(UNSUPPORTED)); + retv.errno = ENOSYS; + return retv; + } + + + if(pid < -1 || pid == 0){ + console_write(UNSUPPORTED_PG, strlen(UNSUPPORTED_PG)); + retv.errno = ENOSYS; + return retv; + } + + + proc_t* proc = arch_getcls()->thread->proc; + + event_wait(&proc->childevent, true); + + // now find the child + + spinlock_acquire(&proc->lock); + proc_t* child = proc->child; + proc_t* sibling = NULL; + + while(child){ + if(pid > 0 && child->pid != pid) + continue; + + if(child->state == PROC_STATE_ZOMBIE){ + break; + } + + if(child->sibling) + sibling = child; + child = child->sibling; + + } + + if(!child){ + spinlock_release(&proc->lock); + retv.errno = ECHILD; + return retv; + } + + if(sibling){ + spinlock_acquire(&sibling->lock); + sibling->sibling = child->sibling; + spinlock_release(&sibling->lock); + } + + spinlock_release(&proc->lock); + + *status = child->status; // XXX safer way of doing this + + free(child); + + retv.ret = child->pid; + retv.errno = 0; + + return retv; + + +}