diff options
-rw-r--r-- | Makefile | 20 | ||||
-rw-r--r-- | lib/matcha.cc | 68 | ||||
-rw-r--r-- | lib/matcha.h | 67 |
3 files changed, 87 insertions, 68 deletions
@@ -1,15 +1,29 @@ -CXX := g++ +AS := gcc +CXX := g++ CXXFLAGS := -g -O0 -Wall -Wextra -I. +AR := ar +RANLIB := ranlib -example/test: example/test.cc lib/thread_create.s lib/matcha.h - $(CXX) -o $@ $^ $(CXXFLAGS) +lib/libmatcha.a: lib/matcha.o lib/thread_create.o lib/matcha.h + $(AR) rcs $@ $(filter %.o,$^) + $(RANLIB) $@ + +%.o: %.cc + $(CXX) -c -o $@ $^ $(CXXFLAGS) + +%.o: %.s + $(AS) -c -o $@ $^ fmt: fd --type f '.+.h$$|.+.cc$$' --exec clang-format -i {} +example/test: example/test.o lib/libmatcha.a + $(CXX) -o $@ $^ + gdb: example/test which cgdb && cgdb -x util.gdb -ex 'start' example/test \ || gdb -x util.gdb -ex 'start' example/test clean: rm -f example/test + rm -f **/*.o **/lib*.a diff --git a/lib/matcha.cc b/lib/matcha.cc new file mode 100644 index 0000000..3f7cd7b --- /dev/null +++ b/lib/matcha.cc @@ -0,0 +1,68 @@ +#include "matcha.h" + +#include <cassert> +#include <cstdint> +#include <cstdio> +#include <sys/mman.h> +#include <unistd.h> // sysconf + +// asm fns +extern "C" void thread_create(); +extern "C" void yield(void* new_stack, void** old_stack); + +long get_pagesize() { + return sysconf(_SC_PAGESIZE); +} + +Thread::Thread(void (*fn)()) : mUserFn(fn) { + const long PAGE_SIZE = get_pagesize(); + const long STACK_SIZE = 8 * PAGE_SIZE; + + // create new stack + void* stack = mmap(nullptr, STACK_SIZE, PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1 /* fd */, 0 /* offset */); + assert(stack != MAP_FAILED); + + // protect last stack page (lowest addr) + int ret = mprotect(stack, PAGE_SIZE, PROT_NONE); + assert(ret == 0); + + // stack grows downwards + mStackPtr = static_cast<uint8_t*>(stack) + STACK_SIZE; + { + uint64_t* stack = static_cast<uint64_t*>(mStackPtr); + *(--stack) = (uint64_t)this; + *(--stack) = (uint64_t)Thread::entry; + + // initial values for yield epilog + *(--stack) = (uint64_t)thread_create; + *(--stack) = (uint64_t)0; + + // initial values for callee saved regs + *(--stack) = (uint64_t)0; // rbx + *(--stack) = (uint64_t)(static_cast<uint64_t*>(mStackPtr) - 4); // rbp + *(--stack) = (uint64_t)0; // r12 + *(--stack) = (uint64_t)0; // r13 + *(--stack) = (uint64_t)0; // r14 + *(--stack) = (uint64_t)0; // r15 + + mStackPtr = static_cast<void*>(stack); + } +} + +void Thread::entry(void* obj) { + Thread* t = static_cast<Thread*>(obj); + + puts("thread entry"); + t->mUserFn(); + puts("thread done"); +} + +void* gOriginalStack; + +void yield_to(const Thread& t) { + yield(t.mStackPtr, &gOriginalStack); +} + +void yield_from(Thread& t) { + yield(gOriginalStack, &t.mStackPtr); +} diff --git a/lib/matcha.h b/lib/matcha.h index 9387bf9..905107f 100644 --- a/lib/matcha.h +++ b/lib/matcha.h @@ -1,16 +1,3 @@ -#include <cassert> -#include <cstdint> -#include <cstdio> -#include <sys/mman.h> -#include <unistd.h> // sysconf - -extern "C" void thread_create(); -extern "C" void yield(void* new_stack, void** old_stack); - -long get_pagesize() { - return sysconf(_SC_PAGESIZE); -} - struct Thread { Thread(const Thread&) = delete; Thread& operator=(const Thread&) = delete; @@ -23,55 +10,5 @@ struct Thread { void (*mUserFn)(); }; -Thread::Thread(void (*fn)()) : mUserFn(fn) { - const long PAGE_SIZE = get_pagesize(); - const long STACK_SIZE = 8 * PAGE_SIZE; - - // create new stack - void* stack = mmap(nullptr, STACK_SIZE, PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1 /* fd */, 0 /* offset */); - assert(stack != MAP_FAILED); - - // protect last stack page (lowest addr) - int ret = mprotect(stack, PAGE_SIZE, PROT_NONE); - assert(ret == 0); - - // stack grows downwards - mStackPtr = static_cast<uint8_t*>(stack) + STACK_SIZE; - { - uint64_t* stack = static_cast<uint64_t*>(mStackPtr); - *(--stack) = (uint64_t)this; - *(--stack) = (uint64_t)Thread::entry; - - // initial values for yield epilog - *(--stack) = (uint64_t)thread_create; - *(--stack) = (uint64_t)0; - - // initial values for callee saved regs - *(--stack) = (uint64_t)0; // rbx - *(--stack) = (uint64_t)(static_cast<uint64_t*>(mStackPtr) - 4); // rbp - *(--stack) = (uint64_t)0; // r12 - *(--stack) = (uint64_t)0; // r13 - *(--stack) = (uint64_t)0; // r14 - *(--stack) = (uint64_t)0; // r15 - - mStackPtr = static_cast<void*>(stack); - } -} - -void Thread::entry(void* obj) { - Thread* t = static_cast<Thread*>(obj); - - puts("thread entry"); - t->mUserFn(); - puts("thread done"); -} - -void* gOriginalStack; - -void yield_to(const Thread& t) { - yield(t.mStackPtr, &gOriginalStack); -} - -void yield_from(Thread& t) { - yield(gOriginalStack, &t.mStackPtr); -} +void yield_to(const Thread& t); +void yield_from(Thread& t); |