aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/thread.cc54
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);
}