diff options
author | johannst <johannes.stoelp@gmail.com> | 2020-09-29 02:06:41 +0200 |
---|---|---|
committer | johannst <johannes.stoelp@gmail.com> | 2020-09-29 02:06:41 +0200 |
commit | fc83627b14536d0b13b2dd751d09cecbea9db378 (patch) | |
tree | 68d42350261fb7769615ceaa8af4187eb2dc571e | |
parent | 38d7af6768871a5d285e776bbcfe18b6e7440cfb (diff) | |
download | matcha-threads-fc83627b14536d0b13b2dd751d09cecbea9db378.tar.gz matcha-threads-fc83627b14536d0b13b2dd751d09cecbea9db378.zip |
move thread init into arch/
-rw-r--r-- | lib/Makefile | 3 | ||||
-rw-r--r-- | lib/arch/x86_64/api.h (renamed from lib/arch/x86_64/asm.h) | 4 | ||||
-rw-r--r-- | lib/arch/x86_64/init_stack.cc | 33 | ||||
-rw-r--r-- | lib/executor.cc | 4 | ||||
-rw-r--r-- | lib/thread.cc | 31 |
5 files changed, 43 insertions, 32 deletions
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/asm.h b/lib/arch/x86_64/api.h index 962ff1b..b2babc9 100644 --- a/lib/arch/x86_64/asm.h +++ b/lib/arch/x86_64/api.h @@ -1,4 +1,6 @@ /* Copyright (c) 2020 Johannes Stoelp */ -extern "C" void thread_create(); +#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/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 <cassert> +#include <cstdint> // 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<uint64_t*>(stack_ptr); + // Arguments for `thread_create`. + *(--stack) = reinterpret_cast<uint64_t>(ctx); + *(--stack) = reinterpret_cast<uint64_t>(entry); + + // Yield epilogue. + *(--stack) = reinterpret_cast<uint64_t>(thread_create); // Return address + *(--stack) = static_cast<uint64_t>(0); // rbp + + // Callee saved registers. + *(--stack) = static_cast<uint64_t>(0); // rbx + *(--stack) = reinterpret_cast<uint64_t>(static_cast<uint64_t*>(stack_ptr) - 4); // rbp + *(--stack) = static_cast<uint64_t>(0); // r12 + *(--stack) = static_cast<uint64_t>(0); // r13 + *(--stack) = static_cast<uint64_t>(0); // r14 + *(--stack) = static_cast<uint64_t>(0); // r15 + + assert((reinterpret_cast<std::uintptr_t>(stack) & 0xf) == 0); // 16byte aligned + return static_cast<void*>(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<Thread> t) { @@ -11,13 +11,13 @@ namespace nMatcha { } void Executor::run() { + // Round robin until all threads finished. while (!mThreads.empty()) { for (const std::unique_ptr<Thread>& t : mThreads) { if (!t->isFinished()) { yield_to(t.get()); } } - mThreads.remove_if([](const std::unique_ptr<Thread>& 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 <cassert> -#include <cstdint> // uintN_t #include <exception> #include <iostream> #include <sys/mman.h> // mmap @@ -35,33 +34,9 @@ namespace nMatcha { // Adjust stack pointer, as stack grows downwards. mStackPtr = static_cast<uint8_t*>(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<uint64_t*>(mStackPtr); - // Arguments for `thread_create`. - *(--stack) = reinterpret_cast<uint64_t>(this); - *(--stack) = reinterpret_cast<uint64_t>(Thread::entry); - - // Yield epilogue. - *(--stack) = reinterpret_cast<uint64_t>(thread_create); // Return address - *(--stack) = static_cast<uint64_t>(0); // rbp - - // Callee saved registers. - *(--stack) = static_cast<uint64_t>(0); // rbx - *(--stack) = reinterpret_cast<uint64_t>(static_cast<uint64_t*>(mStackPtr) - 4); // rbp - *(--stack) = static_cast<uint64_t>(0); // r12 - *(--stack) = static_cast<uint64_t>(0); // r13 - *(--stack) = static_cast<uint64_t>(0); // r14 - *(--stack) = static_cast<uint64_t>(0); // r15 - - mStackPtr = static_cast<void*>(stack); - } + // Arch specific stack initialization. + mStackPtr = init_stack(mStackPtr, Thread::entry, static_cast<void*>(this)); } void Thread::entry(void* obj) { |