From 671f2a2de3a9f08222945e66a83b39017a12a8c4 Mon Sep 17 00:00:00 2001 From: apio Date: Tue, 18 Oct 2022 21:30:52 +0200 Subject: [PATCH] Kernel, libc: Implement waitpid() FIXME: exec() is now doing weird page table stuff. But at least it works, no panics :) --- apps/Makefile | 1 - apps/src/init.c | 21 ++++++++++++--------- kernel/include/errno.h | 1 + kernel/include/sys/Syscall.h | 4 +++- kernel/include/thread/Task.h | 1 + kernel/src/memory/AddressSpace.cpp | 3 +++ kernel/src/memory/PMM.cpp | 1 + kernel/src/panic/Panic.cpp | 4 ++-- kernel/src/sys/Syscall.cpp | 1 + kernel/src/sys/sched.cpp | 22 ++++++++++++++++++++++ kernel/src/thread/Scheduler.cpp | 4 +++- libs/libc/include/errno.h | 3 ++- libs/libc/include/luna/syscall.h | 1 + libs/libc/include/sys/wait.h | 27 +++++++++++++++++++++++++++ libs/libc/src/string.cpp | 1 + libs/libc/src/sys/wait.cpp | 16 ++++++++++++++++ libs/libc/src/unistd.cpp | 1 + 17 files changed, 97 insertions(+), 15 deletions(-) create mode 100644 libs/libc/include/sys/wait.h create mode 100644 libs/libc/src/sys/wait.cpp diff --git a/apps/Makefile b/apps/Makefile index ad028845..89299fd9 100644 --- a/apps/Makefile +++ b/apps/Makefile @@ -11,7 +11,6 @@ CFLAGS := -Wall -Wextra -Werror -Os -fno-asynchronous-unwind-tables $(APPS_BIN)/%: $(APPS_SRC)/%.c @mkdir -p $(@D) $(CC) $(CFLAGS) -o $@ $^ - $(STRIP) $@ build: $(REAL_APPS) diff --git a/apps/src/init.c b/apps/src/init.c index a1c86ff7..211ae3ec 100644 --- a/apps/src/init.c +++ b/apps/src/init.c @@ -4,6 +4,7 @@ #include #include #include +#include #include int print_version() @@ -162,7 +163,7 @@ int main() } if (child == 0) { - msleep(500); + sleep(2); printf("I am the child (PID %ld), my parent is PID %ld!!\n", getpid(), getppid()); execv("/bin/sym", NULL); perror("execv"); @@ -170,14 +171,16 @@ int main() } else { printf("Success!! Got PID %ld\n", child); } - jmp_buf env; - int val = setjmp(env); - if (val == 0) { printf("Returning from setjmp!\n"); } - else + int status; + pid_t result; + while ((result = waitpid(child, &status, 0)) == 0) // Child has not yet exited { - printf("Returning from longjmp! val=%d\n", val); - return 0; + msleep(100); } - - longjmp(env, 3); + if (result < 0) + { + perror("waitpid"); + return 1; + } + if (WIFEXITED(status)) { printf("Child process %ld exited with code %d\n", result, WEXITSTATUS(status)); } } diff --git a/kernel/include/errno.h b/kernel/include/errno.h index e38e0d11..0d9c4b73 100644 --- a/kernel/include/errno.h +++ b/kernel/include/errno.h @@ -2,6 +2,7 @@ #define EPERM 1 #define ENOENT 2 +#define ESRCH 3 #define ENOEXEC 8 #define EBADF 9 #define ENOMEM 12 diff --git a/kernel/include/sys/Syscall.h b/kernel/include/sys/Syscall.h index 934bb342..8d8e3202 100644 --- a/kernel/include/sys/Syscall.h +++ b/kernel/include/sys/Syscall.h @@ -20,6 +20,7 @@ #define SYS_clock 15 #define SYS_mkdir 16 #define SYS_fork 17 +#define SYS_waitpid 18 namespace Syscall { @@ -45,4 +46,5 @@ void sys_fcntl(Context* context, int fd, int command, uintptr_t arg); void sys_mprotect(Context* context, void* address, size_t size, int prot); void sys_clock(Context* context); void sys_mkdir(Context* context, const char* filename); -void sys_fork(Context* context); \ No newline at end of file +void sys_fork(Context* context); +void sys_waitpid(Context* context, long pid, int* wstatus, int options); \ No newline at end of file diff --git a/kernel/include/thread/Task.h b/kernel/include/thread/Task.h index cd2dc780..7405b9e8 100644 --- a/kernel/include/thread/Task.h +++ b/kernel/include/thread/Task.h @@ -14,6 +14,7 @@ struct Task Idle, Running, Sleeping, + Dying, Exited }; diff --git a/kernel/src/memory/AddressSpace.cpp b/kernel/src/memory/AddressSpace.cpp index 28aee513..5cf92f8c 100644 --- a/kernel/src/memory/AddressSpace.cpp +++ b/kernel/src/memory/AddressSpace.cpp @@ -126,6 +126,9 @@ void AddressSpace::clear() pages_freed++; PMM::free_page(pdp); } + memset(m_pml4, 0, PAGE_SIZE); + + VMM::install_kernel_page_directory_into_address_space(*this); kdbgln("Reclaimed %ld pages from address space!", pages_freed); } diff --git a/kernel/src/memory/PMM.cpp b/kernel/src/memory/PMM.cpp index 17a2ac32..f4f11a75 100644 --- a/kernel/src/memory/PMM.cpp +++ b/kernel/src/memory/PMM.cpp @@ -130,6 +130,7 @@ void* PMM::request_pages(uint64_t count) void PMM::free_page(void* address) { uint64_t index = (uint64_t)address / PAGE_SIZE; + if (index > (bitmap_size * 8)) return; if (!bitmap_read(index)) return; bitmap_set(index, false); used_mem -= PAGE_SIZE; diff --git a/kernel/src/panic/Panic.cpp b/kernel/src/panic/Panic.cpp index 32d86893..eac29e7c 100644 --- a/kernel/src/panic/Panic.cpp +++ b/kernel/src/panic/Panic.cpp @@ -48,8 +48,8 @@ void dump_registers(Context* context) void fatal_dump_registers(Context* context) { printf("-- Possibly Relevant Registers:\n"); - printf("rbp: %lx, rsp: %lx, rip: %lx, cs: %lx, ss: %lx, rflags: %lx, cr2: %lx\n", context->rbp, context->rsp, - context->rip, context->cs, context->ss, context->rflags, context->cr2); + printf("rbp: %lx, rsp: %lx, rip: %lx, cs: %lx, ss: %lx, rflags: %lx, cr2: %lx, error code: %lx\n", context->rbp, + context->rsp, context->rip, context->cs, context->ss, context->rflags, context->cr2, context->error_code); } [[noreturn]] void __panic_fatal_stub(Context* context) diff --git a/kernel/src/sys/Syscall.cpp b/kernel/src/sys/Syscall.cpp index 44a38774..c6d9565f 100644 --- a/kernel/src/sys/Syscall.cpp +++ b/kernel/src/sys/Syscall.cpp @@ -29,6 +29,7 @@ void Syscall::entry(Context* context) case SYS_clock: sys_clock(context); break; case SYS_mkdir: sys_mkdir(context, (const char*)context->rdi); break; case SYS_fork: sys_fork(context); break; + case SYS_waitpid: sys_waitpid(context, (long)context->rdi, (int*)context->rsi, (int)context->rdx); break; default: context->rax = -ENOSYS; break; } VMM::exit_syscall_context(); diff --git a/kernel/src/sys/sched.cpp b/kernel/src/sys/sched.cpp index d658263a..487239d7 100644 --- a/kernel/src/sys/sched.cpp +++ b/kernel/src/sys/sched.cpp @@ -1,3 +1,5 @@ +#include "errno.h" +#include "memory/VMM.h" #include "thread/Scheduler.h" void sys_exit(Context* context, int status) @@ -18,4 +20,24 @@ void sys_sleep(Context* context, uint64_t ms) task->task_sleep = ms; task->state = task->Sleeping; Scheduler::task_yield(context); +} + +void sys_waitpid(Context* context, long pid, int* wstatus, + int) // FIXME: Use the value in options and block if WNOHANG has not been specified. +{ + Task* child = Scheduler::find_by_pid(pid); // FIXME: Wait for any child process if PID is -1. + if (!child) + { + context->rax = -ESRCH; + return; + } + if (child->state != child->Dying) // FIXME: This should block if WNOHANG has not been specified. + { + context->rax = 0; + return; + } + uint64_t phys = VMM::get_physical((uint64_t)wstatus); + if (phys != (uint64_t)-1) { *(int*)phys = (int)(child->exit_status & 0xff); } + child->state = child->Exited; + context->rax = (long)child->id; } \ No newline at end of file diff --git a/kernel/src/thread/Scheduler.cpp b/kernel/src/thread/Scheduler.cpp index 8b86f274..0c40af00 100644 --- a/kernel/src/thread/Scheduler.cpp +++ b/kernel/src/thread/Scheduler.cpp @@ -260,7 +260,9 @@ void Scheduler::task_exit(Context* context, int64_t status) ASSERT(Interrupts::is_in_handler()); kdbgln("exit: task %ld finished running, used %ld ms of cpu time", sched_current_task->id, sched_current_task->cpu_time); - sched_current_task->state = sched_current_task->Exited; + if (sched_current_task->id == 1) sched_current_task->state = sched_current_task->Exited; + else + sched_current_task->state = sched_current_task->Dying; sched_current_task->exit_status = status; task_yield(context); } diff --git a/libs/libc/include/errno.h b/libs/libc/include/errno.h index b1496ee6..37487b9d 100644 --- a/libs/libc/include/errno.h +++ b/libs/libc/include/errno.h @@ -6,6 +6,7 @@ extern int errno; #define EPERM 1 // Operation not permitted #define ENOENT 2 // No such file or directory +#define ESRCH 3 // No such process #define ENOEXEC 8 // Exec format error #define EBADF 9 // Bad file descriptor #define ENOMEM 12 // Cannot allocate memory @@ -18,6 +19,6 @@ extern int errno; #define ENOSPC 28 // No space left on device #define EPIPE 32 // Broken pipe. Not implemented. #define ENOSYS 38 // Function not implemented -#define ENOTSUP 95 // Operation not supported. +#define ENOTSUP 95 // Operation not supported #endif \ No newline at end of file diff --git a/libs/libc/include/luna/syscall.h b/libs/libc/include/luna/syscall.h index 7b1b387a..d2310be0 100644 --- a/libs/libc/include/luna/syscall.h +++ b/libs/libc/include/luna/syscall.h @@ -19,6 +19,7 @@ #define SYS_clock 15 #define SYS_mkdir 16 #define SYS_fork 17 +#define SYS_waitpid 18 #ifndef __want_syscalls #ifdef __cplusplus diff --git a/libs/libc/include/sys/wait.h b/libs/libc/include/sys/wait.h new file mode 100644 index 00000000..458d00bd --- /dev/null +++ b/libs/libc/include/sys/wait.h @@ -0,0 +1,27 @@ +#ifndef _SYS_WAIT_H +#define _SYS_WAIT_H + +#include + +/* Has the child process exited by calling exit() or _exit()? */ +#define WIFEXITED(status) ((status) || 1) + +/* What was the child's exit status? */ +#define WEXITSTATUS(status) (char)((status)&0xff) + +#ifdef __cplusplus +extern "C" +{ +#endif + + /* Waits for the child process to finish running. */ + pid_t waitpid(pid_t pid, int* wstatus, int options); + + /* Waits for any child process to finish running. */ + pid_t wait(int* wstatus); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/libs/libc/src/string.cpp b/libs/libc/src/string.cpp index df1a8f4d..c2406681 100644 --- a/libs/libc/src/string.cpp +++ b/libs/libc/src/string.cpp @@ -193,6 +193,7 @@ extern "C" { case EPERM: return "Operation not permitted"; case EINVAL: return "Invalid argument"; + case ESRCH: return "No such process"; case ENOMEM: return "Cannot allocate memory"; case ENOSYS: return "Function not implemented"; case ENOENT: return "No such file or directory"; diff --git a/libs/libc/src/sys/wait.cpp b/libs/libc/src/sys/wait.cpp new file mode 100644 index 00000000..0458d2b2 --- /dev/null +++ b/libs/libc/src/sys/wait.cpp @@ -0,0 +1,16 @@ +#include +#include +#include + +extern "C" +{ + pid_t waitpid(pid_t pid, int* wstatus, int options) + { + return syscall(SYS_waitpid, pid, wstatus, options); + } + + pid_t wait(int* wstatus) + { + return waitpid(-1, wstatus, 0); + } +} \ No newline at end of file diff --git a/libs/libc/src/unistd.cpp b/libs/libc/src/unistd.cpp index 0a088413..63d0f1aa 100644 --- a/libs/libc/src/unistd.cpp +++ b/libs/libc/src/unistd.cpp @@ -64,6 +64,7 @@ extern "C" case SYS_write: case SYS_read: case SYS_mprotect: + case SYS_waitpid: case SYS_mmap: { arg arg0 = va_arg(ap, arg); arg arg1 = va_arg(ap, arg);