From 50c4dcbd5f55965cd4144c19af7c0945cad05dd5 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Sun, 5 Oct 2014 18:05:38 +0300 Subject: [PATCH] posix: posix_thread: allocate stack manually Otherwise, the stack is allocated on the creating thread and destroyed on the created thread, which we don't support. --- core/posix.cc | 34 +++++++++++++++++++++++++++++++--- core/posix.hh | 25 +++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 3 deletions(-) diff --git a/core/posix.cc b/core/posix.cc index a5f1d574e7..ce93c48a86 100644 --- a/core/posix.cc +++ b/core/posix.cc @@ -3,6 +3,7 @@ */ #include "posix.hh" +#include "align.hh" #include void mmap_deleter::operator()(void* ptr) const { @@ -21,8 +22,34 @@ void* posix_thread::start_routine(void* arg) { return nullptr; } -posix_thread::posix_thread(std::function func) : _func(std::make_unique>(std::move(func))) { - auto r = pthread_create(&_pthread, nullptr, +posix_thread::posix_thread(std::function func) + : posix_thread(attr{}, std::move(func)) { +} + +posix_thread::posix_thread(attr a, std::function func) + : _func(std::make_unique>(std::move(func))) { + pthread_attr_t pa; + auto r = pthread_attr_init(&pa); + if (r) { + throw std::system_error(r, std::system_category()); + } + auto stack_size = a._stack_size.size; + if (!stack_size) { + stack_size = 2 << 20; + } + // allocate guard area as well + _stack = mmap_anonymous(nullptr, stack_size + (4 << 20), + PROT_NONE, MAP_PRIVATE | MAP_NORESERVE); + auto stack_start = align_up(_stack.get() + 1, 2 << 20); + mmap_area real_stack = mmap_anonymous(stack_start, stack_size, + PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED | MAP_STACK); + real_stack.release(); // protected by @_stack + ::madvise(stack_start, stack_size, MADV_HUGEPAGE); + r = pthread_attr_setstack(&pa, stack_start, stack_size); + if (r) { + throw std::system_error(r, std::system_category()); + } + r = pthread_create(&_pthread, &pa, &posix_thread::start_routine, _func.get()); if (r) { throw std::system_error(r, std::system_category()); @@ -30,7 +57,8 @@ posix_thread::posix_thread(std::function func) : _func(std::make_unique } posix_thread::posix_thread(posix_thread&& x) - : _func(std::move(x._func)), _pthread(x._pthread), _valid(x._valid) { + : _func(std::move(x._func)), _pthread(x._pthread), _valid(x._valid) + , _stack(std::move(x._stack)) { x._valid = false; } diff --git a/core/posix.hh b/core/posix.hh index 60e7fbb85a..6e413b8301 100644 --- a/core/posix.hh +++ b/core/posix.hh @@ -195,17 +195,42 @@ using mmap_area = std::unique_ptr; mmap_area mmap_anonymous(void* addr, size_t length, int prot, int flags); class posix_thread { +public: + class attr; +private: // must allocate, since this class is moveable std::unique_ptr> _func; pthread_t _pthread; bool _valid = true; + mmap_area _stack; private: static void* start_routine(void* arg); public: posix_thread(std::function func); + posix_thread(attr a, std::function func); posix_thread(posix_thread&& x); ~posix_thread(); void join(); +public: + class attr { + public: + struct stack_size { size_t size = 0; }; + attr() = default; + template + attr(A... a) { + set(std::forward(a)...); + } + void set() {} + template + void set(A a, Rest... rest) { + set(std::forward(a)); + set(std::forward(rest)...); + } + void set(stack_size ss) { _stack_size = ss; } + private: + stack_size _stack_size; + friend class posix_thread; + }; };