diff options
author | johannst <johannes.stoelp@gmail.com> | 2020-09-26 23:20:33 +0200 |
---|---|---|
committer | johannst <johannes.stoelp@gmail.com> | 2020-09-26 23:20:33 +0200 |
commit | 5cbdde2c97229a552852af57232c4e5bbe814a38 (patch) | |
tree | f781ba2f1b3da5217e69fdebf8500f1fa72b292e | |
parent | 9ff82723e360761e94917c6d15d070dd3534ea2a (diff) | |
download | matcha-threads-5cbdde2c97229a552852af57232c4e5bbe814a38.tar.gz matcha-threads-5cbdde2c97229a552852af57232c4e5bbe814a38.zip |
enhance comments in thread.cc
-rw-r--r-- | lib/thread.cc | 54 |
1 files changed, 33 insertions, 21 deletions
diff --git a/lib/thread.cc b/lib/thread.cc index ad07d96..d665f49 100644 --- a/lib/thread.cc +++ b/lib/thread.cc @@ -11,40 +11,52 @@ #include <unistd.h> // sysconf namespace { - static long get_pagesize() { return sysconf(_SC_PAGESIZE); } + static long get_pagesize() { return ::sysconf(_SC_PAGESIZE); } } // namespace namespace nMatcha { - Thread::Thread() { + Thread::Thread() : mStackPtr(nullptr), mExecutor(nullptr) { 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 */); + // Allocate 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); + // Simple stack overflow detection by removing permissions from last + // stack page (lowest addr). + // In theory stack pointer could be decremented by more than one page + // and the page below last stack page could be used. However we don't + // take care of that now and risk the memory corruption. + int ret = ::mprotect(stack, PAGE_SIZE, PROT_NONE); assert(ret == 0); - // stack grows downwards + // 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); - *(--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 + // 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); } |