Commit d2d24c12 authored by neverlord's avatar neverlord

ported util::fiber to boost.context

parent ab20ad06
...@@ -31,14 +31,9 @@ ...@@ -31,14 +31,9 @@
#ifndef FIBER_HPP #ifndef FIBER_HPP
#define FIBER_HPP #define FIBER_HPP
#include <memory>
#include "cppa/config.hpp" #include "cppa/config.hpp"
#if defined(CPPA_MACOS) || defined(CPPA_LINUX)
# define CPPA_USE_UCONTEXT_IMPL
#elif defined (CPPA_WINDOWS)
# define CPPA_USE_FIBER_IMPL
#endif
#ifdef CPPA_DISABLE_CONTEXT_SWITCHING #ifdef CPPA_DISABLE_CONTEXT_SWITCHING
namespace cppa { namespace util { namespace cppa { namespace util {
...@@ -48,7 +43,7 @@ class fiber { ...@@ -48,7 +43,7 @@ class fiber {
}; };
} } // namespace cppa::util } } // namespace cppa::util
#elif defined(CPPA_USE_UCONTEXT_IMPL) #else // CPPA_DISABLE_CONTEXT_SWITCHING
namespace cppa { namespace util { namespace cppa { namespace util {
...@@ -56,9 +51,7 @@ struct fiber_impl; ...@@ -56,9 +51,7 @@ struct fiber_impl;
class fiber { class fiber {
fiber_impl* m_impl; public:
public:
fiber() throw(); fiber() throw();
...@@ -68,42 +61,14 @@ public: ...@@ -68,42 +61,14 @@ public:
static void swap(fiber& from, fiber& to); static void swap(fiber& from, fiber& to);
}; private:
} } // namespace cppa::util
#elif defined(CPPA_USE_FIBER_IMPL)
#include <Winsock2.h>
#include <Windows.h>
namespace cppa { namespace util {
class fiber {
LPVOID handle;
// true if this fiber was created with ConvertThreadToFiber
bool is_converted_thread;
void init();
public:
fiber(); fiber_impl* m_impl;
fiber(LPFIBER_START_ROUTINE func, LPVOID arg1);
~fiber();
inline static void swap(fiber&, fiber& to) {
SwitchToFiber(to.handle);
}
}; };
} } // namespace cppa::util } } // namespace cppa::util
#endif // CPPA_USE_UCONTEXT_IMPL
#endif // CPPA_DISABLE_CONTEXT_SWITCHING
#endif // FIBER_HPP #endif // FIBER_HPP
...@@ -28,188 +28,74 @@ ...@@ -28,188 +28,74 @@
\******************************************************************************/ \******************************************************************************/
#ifndef _XOPEN_SOURCE #ifdef CPPA_DISABLE_CONTEXT_SWITCHING
#define _XOPEN_SOURCE
#endif
#include "cppa/config.hpp" namespace { int keep_compiler_happy() { return 42; } }
#ifndef CPPA_DISABLE_CONTEXT_SWITCHING
#else // ifdef CPPA_DISABLE_CONTEXT_SWITCHING
#include <thread>
#include <atomic>
#include <cstddef>
#include <cstring>
#include <cstdint> #include <cstdint>
#include <type_traits> #include <boost/context/all.hpp>
#include "cppa/util/fiber.hpp" #include "cppa/util/fiber.hpp"
#ifdef CPPA_USE_UCONTEXT_IMPL
#include <signal.h>
#include <sys/mman.h>
#include <ucontext.h>
namespace {
constexpr size_t s_stack_size = SIGSTKSZ;
typedef void (*void_function)();
typedef void (*void_ptr_function)(void*);
template<size_t PointerSize,
typename FunType = void_function,
typename IntType = int>
struct trampoline;
template<typename FunType, typename IntType>
struct trampoline<4, FunType, IntType> {
static_assert(sizeof(int) == 4, "sizeof(int) != 4");
static void bounce(int func_ptr, int ptr) {
auto func = reinterpret_cast<void_ptr_function>(func_ptr);
func(reinterpret_cast<void*>(ptr));
}
static void prepare(ucontext_t* ctx, void_ptr_function func, void* arg) {
makecontext(ctx, (FunType) &trampoline<4>::bounce,
2, (IntType) func, (IntType) arg);
}
};
template<typename FunType, typename IntType>
struct trampoline<8, FunType, IntType> {
static_assert(sizeof(int) == 4, "sizeof(int) != 4");
static void bounce(int func_first_4_byte, int func_second_4_byte,
int arg_first_4_byte, int arg_second_4_byte) {
std::uint64_t arg_ptr; {
int* _addr = reinterpret_cast<int*>(&arg_ptr);
_addr[0] = arg_first_4_byte;
_addr[1] = arg_second_4_byte;
}
std::uint64_t func_ptr; {
int* _addr = reinterpret_cast<int*>(&func_ptr);
_addr[0] = func_first_4_byte;
_addr[1] = func_second_4_byte;
}
auto func = reinterpret_cast<void_ptr_function>(func_ptr);
func((void*) arg_ptr);
}
static void prepare(ucontext_t* ctx, void_ptr_function func, void* arg) {
std::uint64_t arg_ptr = reinterpret_cast<std::uint64_t>(arg);
std::uint64_t func_ptr = reinterpret_cast<std::uint64_t>(func);
int* func_addr = reinterpret_cast<int*>(&func_ptr);
int* arg_addr = reinterpret_cast<int*>(&arg_ptr);
makecontext(ctx, (FunType) &trampoline<8>::bounce,
4, func_addr[0], func_addr[1], arg_addr[0], arg_addr[1]);
}
};
} // namespace <anonymous>
namespace cppa { namespace util { namespace cppa { namespace util {
void fiber_trampoline(intptr_t iptr);
struct fiber_impl { struct fiber_impl {
bool m_initialized;
void (*m_func)(void*);
void* m_arg; void* m_arg;
void* m_stack; bool m_converted;
void (*m_fun)(void*);
# ifdef __APPLE__ boost::ctx::fcontext_t m_ctx;
// ucontext implementation on macosx kinda sucks boost::ctx::stack_allocator m_alloc;
static constexpr size_t ucontext_size = sizeof(ucontext_t) + 60;
char m_ctx_storage[sizeof(ucontext_t) + 60]; fiber_impl() : m_arg(nullptr), m_converted(true), m_fun(nullptr) { }
inline ucontext_t* ctx() { return reinterpret_cast<ucontext_t*>(m_ctx_storage); }
# else fiber_impl(void (*fun)(void*), void* arg) : m_arg(arg), m_converted(false), m_fun(fun) {
static constexpr size_t ucontext_size = sizeof(ucontext_t); auto st = m_alloc.allocate(boost::ctx::minimum_stacksize());
ucontext_t m_ctx; m_ctx.fc_stack.base = st;
inline ucontext_t* ctx() { return &m_ctx; } m_ctx.fc_stack.limit = static_cast<char*>(st) - boost::ctx::minimum_stacksize();
# endif boost::ctx::make_fcontext(&m_ctx, fiber_trampoline);
fiber_impl() throw() : m_initialized(true), m_func(0), m_arg(0), m_stack(0) {
memset(ctx(), 0, ucontext_size);
getcontext(ctx());
}
fiber_impl(void (*func)(void*), void* arg)
: m_initialized(false)
, m_func(func)
, m_arg(arg)
, m_stack(nullptr) {
} }
inline void swap(fiber_impl* to) { inline void run() {
swapcontext(ctx(), to->ctx()); m_fun(m_arg);
} }
void initialize() { void swap(fiber_impl* to) {
m_initialized = true; boost::ctx::jump_fcontext(&m_ctx, &(to->m_ctx), (intptr_t) to);
memset(ctx(), 0, ucontext_size);
getcontext(ctx());
m_stack = malloc(s_stack_size);
ctx()->uc_stack.ss_sp = m_stack;
ctx()->uc_stack.ss_size = s_stack_size;
ctx()->uc_link = nullptr;
trampoline<sizeof(void*)>::prepare(ctx(), m_func, m_arg);
}
inline void lazy_init() {
if (!m_initialized) initialize();
} }
~fiber_impl() { ~fiber_impl() {
if (m_stack) free(m_stack); if (m_converted == false) {
m_alloc.deallocate(m_ctx.fc_stack.base, boost::ctx::minimum_stacksize());
}
} }
}; };
fiber::fiber() throw() : m_impl(new fiber_impl) { void fiber_trampoline(intptr_t iptr) {
auto ptr = (fiber_impl*) iptr;
ptr->run();
} }
fiber::fiber(void (*func)(void*), void* arg) : m_impl(new fiber_impl(func, arg)) { fiber::fiber() throw() : m_impl(new fiber_impl) {
} }
fiber::~fiber() { fiber::fiber(void (*func)(void*), void* arg)
delete m_impl; : m_impl(new fiber_impl(func, arg)) {
} }
void fiber::swap(fiber& from, fiber& to) { void fiber::swap(fiber& from, fiber& to) {
to.m_impl->lazy_init();
from.m_impl->swap(to.m_impl); from.m_impl->swap(to.m_impl);
} }
} } // namespace cppa::util
#elif defined(CPPA_USE_FIBER_IMPL)
#include <stdexcept>
fiber::fiber() : handle(nullptr), is_converted_thread(true) {
handle = ConvertThreadToFiber(nullptr);
if (handle == nullptr) {
throw std::logic_error("handle == nullptr");
}
}
fiber::fiber(LPFIBER_START_ROUTINE func, LPVOID arg1)
: handle(nullptr)
, is_converted_thread(false) {
handle = CreateFiber(0, func, arg1);
if (handle == nullptr) {
throw std::logic_error("handle == nullptr");
}
}
fiber::~fiber() { fiber::~fiber() {
if (handle != nullptr && !is_converted_thread) { delete m_impl;
DeleteFiber(handle);
}
} }
#endif // CPPA_USE_FIBER_IMPL } } // namespace cppa::util
#else // ifdef CPPA_DISABLE_CONTEXT_SWITCHING
namespace { int keep_compiler_happy() { return 42; } }
#endif // CPPA_DISABLE_CONTEXT_SWITCHING #endif // CPPA_DISABLE_CONTEXT_SWITCHING
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment