Commit d2d24c12 authored by neverlord's avatar neverlord

ported util::fiber to boost.context

parent ab20ad06
......@@ -31,14 +31,9 @@
#ifndef FIBER_HPP
#define FIBER_HPP
#include <memory>
#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
namespace cppa { namespace util {
......@@ -48,7 +43,7 @@ class fiber {
};
} } // namespace cppa::util
#elif defined(CPPA_USE_UCONTEXT_IMPL)
#else // CPPA_DISABLE_CONTEXT_SWITCHING
namespace cppa { namespace util {
......@@ -56,9 +51,7 @@ struct fiber_impl;
class fiber {
fiber_impl* m_impl;
public:
public:
fiber() throw();
......@@ -68,42 +61,14 @@ public:
static void swap(fiber& from, fiber& to);
};
} } // 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:
private:
fiber();
fiber(LPFIBER_START_ROUTINE func, LPVOID arg1);
~fiber();
inline static void swap(fiber&, fiber& to) {
SwitchToFiber(to.handle);
}
fiber_impl* m_impl;
};
} } // namespace cppa::util
#endif // CPPA_USE_UCONTEXT_IMPL
#endif // CPPA_DISABLE_CONTEXT_SWITCHING
#endif // FIBER_HPP
......@@ -28,188 +28,74 @@
\******************************************************************************/
#ifndef _XOPEN_SOURCE
#define _XOPEN_SOURCE
#endif
#ifdef CPPA_DISABLE_CONTEXT_SWITCHING
#include "cppa/config.hpp"
#ifndef CPPA_DISABLE_CONTEXT_SWITCHING
namespace { int keep_compiler_happy() { return 42; } }
#else // ifdef CPPA_DISABLE_CONTEXT_SWITCHING
#include <thread>
#include <atomic>
#include <cstddef>
#include <cstring>
#include <cstdint>
#include <type_traits>
#include <boost/context/all.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 {
void fiber_trampoline(intptr_t iptr);
struct fiber_impl {
bool m_initialized;
void (*m_func)(void*);
void* m_arg;
void* m_stack;
# ifdef __APPLE__
// ucontext implementation on macosx kinda sucks
static constexpr size_t ucontext_size = sizeof(ucontext_t) + 60;
char m_ctx_storage[sizeof(ucontext_t) + 60];
inline ucontext_t* ctx() { return reinterpret_cast<ucontext_t*>(m_ctx_storage); }
# else
static constexpr size_t ucontext_size = sizeof(ucontext_t);
ucontext_t m_ctx;
inline ucontext_t* ctx() { return &m_ctx; }
# endif
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) {
bool m_converted;
void (*m_fun)(void*);
boost::ctx::fcontext_t m_ctx;
boost::ctx::stack_allocator m_alloc;
fiber_impl() : m_arg(nullptr), m_converted(true), m_fun(nullptr) { }
fiber_impl(void (*fun)(void*), void* arg) : m_arg(arg), m_converted(false), m_fun(fun) {
auto st = m_alloc.allocate(boost::ctx::minimum_stacksize());
m_ctx.fc_stack.base = st;
m_ctx.fc_stack.limit = static_cast<char*>(st) - boost::ctx::minimum_stacksize();
boost::ctx::make_fcontext(&m_ctx, fiber_trampoline);
}
inline void swap(fiber_impl* to) {
swapcontext(ctx(), to->ctx());
inline void run() {
m_fun(m_arg);
}
void initialize() {
m_initialized = true;
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();
void swap(fiber_impl* to) {
boost::ctx::jump_fcontext(&m_ctx, &(to->m_ctx), (intptr_t) to);
}
~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() {
delete m_impl;
fiber::fiber(void (*func)(void*), void* arg)
: m_impl(new fiber_impl(func, arg)) {
}
void fiber::swap(fiber& from, fiber& to) {
to.m_impl->lazy_init();
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() {
if (handle != nullptr && !is_converted_thread) {
DeleteFiber(handle);
}
delete m_impl;
}
#endif // CPPA_USE_FIBER_IMPL
#else // ifdef CPPA_DISABLE_CONTEXT_SWITCHING
namespace { int keep_compiler_happy() { return 42; } }
} } // namespace cppa::util
#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