From fc83627b14536d0b13b2dd751d09cecbea9db378 Mon Sep 17 00:00:00 2001 From: johannst Date: Tue, 29 Sep 2020 02:06:41 +0200 Subject: move thread init into arch/ --- lib/Makefile | 3 ++- lib/arch/x86_64/api.h | 6 ++++++ lib/arch/x86_64/asm.h | 4 ---- lib/arch/x86_64/init_stack.cc | 33 +++++++++++++++++++++++++++++++++ lib/executor.cc | 4 ++-- lib/thread.cc | 31 +++---------------------------- 6 files changed, 46 insertions(+), 35 deletions(-) create mode 100644 lib/arch/x86_64/api.h delete mode 100644 lib/arch/x86_64/asm.h create mode 100644 lib/arch/x86_64/init_stack.cc (limited to 'lib') diff --git a/lib/Makefile b/lib/Makefile index 5fbbf0b..1416c9d 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -11,7 +11,8 @@ ARCH := x86_64 libmatcha.a: compile_guard.o thread.o executor.o \ thread.h executor.h \ arch/$(ARCH)/thread_create.o arch/$(ARCH)/yield.o \ - arch/$(ARCH)/asm.h + arch/$(ARCH)/init_stack.o \ + arch/$(ARCH)/api.h $(AR) rcs $@ $(filter %.o,$^) %.o: %.cc diff --git a/lib/arch/x86_64/api.h b/lib/arch/x86_64/api.h new file mode 100644 index 0000000..b2babc9 --- /dev/null +++ b/lib/arch/x86_64/api.h @@ -0,0 +1,6 @@ +/* Copyright (c) 2020 Johannes Stoelp */ + +#pragma once + +extern "C" void yield(const void* new_stack, void* const* old_stack); +void* init_stack(void* stack_ptr, void (*entry)(void*), void* ctx); diff --git a/lib/arch/x86_64/asm.h b/lib/arch/x86_64/asm.h deleted file mode 100644 index 962ff1b..0000000 --- a/lib/arch/x86_64/asm.h +++ /dev/null @@ -1,4 +0,0 @@ -/* Copyright (c) 2020 Johannes Stoelp */ - -extern "C" void thread_create(); -extern "C" void yield(const void* new_stack, void* const* old_stack); diff --git a/lib/arch/x86_64/init_stack.cc b/lib/arch/x86_64/init_stack.cc new file mode 100644 index 0000000..748fb56 --- /dev/null +++ b/lib/arch/x86_64/init_stack.cc @@ -0,0 +1,33 @@ +#include +#include // uintN_t + +extern "C" void thread_create(); + +void* init_stack(void* stack_ptr, void (*entry)(void*), void* ctx) { + static_assert(sizeof(uint64_t) == sizeof(std::uintptr_t), "Pointer must be 64bit!"); + + // Setup initial stack frame which will be popped when yielding + // first time into the thread. + // Basic idea is to yield into Thread::entry() function which will + // then call the user function. + + uint64_t* stack = static_cast(stack_ptr); + // Arguments for `thread_create`. + *(--stack) = reinterpret_cast(ctx); + *(--stack) = reinterpret_cast(entry); + + // Yield epilogue. + *(--stack) = reinterpret_cast(thread_create); // Return address + *(--stack) = static_cast(0); // rbp + + // Callee saved registers. + *(--stack) = static_cast(0); // rbx + *(--stack) = reinterpret_cast(static_cast(stack_ptr) - 4); // rbp + *(--stack) = static_cast(0); // r12 + *(--stack) = static_cast(0); // r13 + *(--stack) = static_cast(0); // r14 + *(--stack) = static_cast(0); // r15 + + assert((reinterpret_cast(stack) & 0xf) == 0); // 16byte aligned + return static_cast(stack); +} diff --git a/lib/executor.cc b/lib/executor.cc index 8977ee3..175d7a5 100644 --- a/lib/executor.cc +++ b/lib/executor.cc @@ -2,7 +2,7 @@ #include "executor.h" -#include "arch/x86_64/asm.h" +#include "arch/x86_64/api.h" namespace nMatcha { void Executor::spawn(std::unique_ptr t) { @@ -11,13 +11,13 @@ namespace nMatcha { } void Executor::run() { + // Round robin until all threads finished. while (!mThreads.empty()) { for (const std::unique_ptr& t : mThreads) { if (!t->isFinished()) { yield_to(t.get()); } } - mThreads.remove_if([](const std::unique_ptr& t) { return t->isFinished(); }); } } diff --git a/lib/thread.cc b/lib/thread.cc index ec7fd64..e25fa5a 100644 --- a/lib/thread.cc +++ b/lib/thread.cc @@ -2,11 +2,10 @@ #include "thread.h" -#include "arch/x86_64/asm.h" +#include "arch/x86_64/api.h" #include "executor.h" #include -#include // uintN_t #include #include #include // mmap @@ -35,33 +34,9 @@ namespace nMatcha { // Adjust stack pointer, as stack grows downwards. mStackPtr = static_cast(stack) + STACK_SIZE; - { - static_assert(sizeof(uint64_t) == sizeof(std::uintptr_t), "Pointer must be 64bit!"); - // Setup initial stack frame which will be popped when yielding - // first time into the thread. - // Basic idea is to yield into Thread::entry() function which will - // then call the user function. - - uint64_t* stack = static_cast(mStackPtr); - // Arguments for `thread_create`. - *(--stack) = reinterpret_cast(this); - *(--stack) = reinterpret_cast(Thread::entry); - - // Yield epilogue. - *(--stack) = reinterpret_cast(thread_create); // Return address - *(--stack) = static_cast(0); // rbp - - // Callee saved registers. - *(--stack) = static_cast(0); // rbx - *(--stack) = reinterpret_cast(static_cast(mStackPtr) - 4); // rbp - *(--stack) = static_cast(0); // r12 - *(--stack) = static_cast(0); // r13 - *(--stack) = static_cast(0); // r14 - *(--stack) = static_cast(0); // r15 - - mStackPtr = static_cast(stack); - } + // Arch specific stack initialization. + mStackPtr = init_stack(mStackPtr, Thread::entry, static_cast(this)); } void Thread::entry(void* obj) { -- cgit v1.2.3