diff --git a/apps/sh.c b/apps/sh.c index bafb5477..9f32b054 100644 --- a/apps/sh.c +++ b/apps/sh.c @@ -3,6 +3,7 @@ #include #include #include +#include #include static char** split_command_into_argv(const char* cmd) @@ -94,7 +95,6 @@ int main() return 1; } - // Don't have sched_yield() or waitpid() yet... - sleep(1); + if (waitpid(child, NULL, 0) < 0) perror("waitpid"); } } diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 3647406c..fca7d1f7 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -32,6 +32,7 @@ set(SOURCES src/sys/id.cpp src/sys/mkdir.cpp src/sys/mknod.cpp + src/sys/waitpid.cpp src/fs/VFS.cpp src/fs/tmpfs/FileSystem.cpp src/fs/devices/DeviceRegistry.cpp diff --git a/kernel/src/sys/exit.cpp b/kernel/src/sys/exit.cpp index 5d02f321..56802709 100644 --- a/kernel/src/sys/exit.cpp +++ b/kernel/src/sys/exit.cpp @@ -11,4 +11,5 @@ Result sys_exit(Registers*, SyscallArgs args) current->state = ThreadState::Exited; kernel_yield(); + unreachable(); } diff --git a/kernel/src/sys/waitpid.cpp b/kernel/src/sys/waitpid.cpp new file mode 100644 index 00000000..c15648bd --- /dev/null +++ b/kernel/src/sys/waitpid.cpp @@ -0,0 +1,28 @@ +#include "memory/MemoryManager.h" +#include "sys/Syscall.h" +#include "thread/Scheduler.h" +#include + +Result sys_waitpid(Registers*, SyscallArgs args) +{ + pid_t pid = (pid_t)args[0]; + int* status_ptr = (int*)args[1]; + int options = (int)args[2]; + + Thread* thread = TRY(Result::from_option(Scheduler::find_by_pid(pid), ESRCH)); + + while (thread->state != ThreadState::Exited) + { + if (options & WNOHANG) return err(EAGAIN); + kernel_sleep(10); + } + + int status = (int)thread->status; + + thread->state = ThreadState::Dying; + + if (status_ptr) + if (!MemoryManager::copy_to_user_typed(status_ptr, &status)) return err(EFAULT); + + return (u64)pid; +} diff --git a/kernel/src/thread/Scheduler.cpp b/kernel/src/thread/Scheduler.cpp index 4cf21f52..477850d6 100644 --- a/kernel/src/thread/Scheduler.cpp +++ b/kernel/src/thread/Scheduler.cpp @@ -253,6 +253,17 @@ namespace Scheduler return result; } + + Option find_by_pid(pid_t pid) + { + Option result; + + g_threads.for_each([&](Thread* thread) { + if (thread->id == (u64)pid && thread->state != ThreadState::Dying) result = thread; + }); + + return result; + } } void kernel_sleep(u64 ms) diff --git a/kernel/src/thread/Scheduler.h b/kernel/src/thread/Scheduler.h index 31b1853c..4b331f04 100644 --- a/kernel/src/thread/Scheduler.h +++ b/kernel/src/thread/Scheduler.h @@ -26,6 +26,8 @@ namespace Scheduler void invoke(Registers* regs); LinkedList check_for_dying_threads(); + + Option find_by_pid(pid_t pid); } extern "C" void kernel_yield(); diff --git a/libc/CMakeLists.txt b/libc/CMakeLists.txt index 8e85fc1a..9df5f6ad 100644 --- a/libc/CMakeLists.txt +++ b/libc/CMakeLists.txt @@ -15,6 +15,7 @@ set(SOURCES src/init.cpp src/sys/stat.cpp src/sys/mman.cpp + src/sys/wait.cpp ) if(${LUNA_ARCH} STREQUAL "x86_64") diff --git a/libc/include/bits/waitpid.h b/libc/include/bits/waitpid.h new file mode 100644 index 00000000..8b7922b4 --- /dev/null +++ b/libc/include/bits/waitpid.h @@ -0,0 +1,8 @@ +/* bits/waitpid.h: Constants for waitpid(). */ + +#ifndef _BITS_WAITPID_H +#define _BITS_WAITPID_H + +#define WNOHANG 1 + +#endif diff --git a/libc/include/sys/wait.h b/libc/include/sys/wait.h new file mode 100644 index 00000000..362924f4 --- /dev/null +++ b/libc/include/sys/wait.h @@ -0,0 +1,21 @@ +/* sys/wait.h: Functions for waiting. */ + +#ifndef _SYS_WAIT_H +#define _SYS_WAIT_H + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + /* Wait for a child process to exit. */ + pid_t waitpid(pid_t pid, int* status, int options); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libc/src/sys/wait.cpp b/libc/src/sys/wait.cpp new file mode 100644 index 00000000..519a5b88 --- /dev/null +++ b/libc/src/sys/wait.cpp @@ -0,0 +1,13 @@ +#include +#include +#include +#include + +extern "C" +{ + pid_t waitpid(pid_t pid, int* status, int options) + { + long rc = syscall(SYS_waitpid, pid, status, options); + __errno_return(rc, pid_t); + } +} diff --git a/libluna/include/luna/Syscall.h b/libluna/include/luna/Syscall.h index a32f23ee..4950a6e7 100644 --- a/libluna/include/luna/Syscall.h +++ b/libluna/include/luna/Syscall.h @@ -2,7 +2,7 @@ #define enumerate_syscalls(_e) \ _e(exit) _e(clock_gettime) _e(mmap) _e(munmap) _e(usleep) _e(open) _e(close) _e(read) _e(getpid) _e(write) \ - _e(lseek) _e(mkdir) _e(exec) _e(mknod) _e(fork) + _e(lseek) _e(mkdir) _e(exec) _e(mknod) _e(fork) _e(waitpid) enum Syscalls {