Commit fdd29977 authored by neverlord's avatar neverlord

CPPA_DISABLE_CONTEXT_SWITCHING

parent b3471511
......@@ -31,6 +31,11 @@
#ifndef CPPA_CONFIG_HPP
#define CPPA_CONFIG_HPP
// uncomment this line or use
// ./configure CXXFLAGS="-DCPPA_DISABLE_CONTEXT_SWITCHING"
// if ucontext_t is not available on your platform
//#define CPPA_DISABLE_CONTEXT_SWITCHING
#if defined(__GNUC__)
# define CPPA_GCC
#endif
......@@ -55,8 +60,10 @@
#ifdef CPPA_MACOS
# include <libkern/OSAtomic.h>
# define CPPA_MEMORY_BARRIER() OSMemoryBarrier()
#elif defined(CPPA_LINUX)
#elif defined(CPPA_GCC)
# define CPPA_MEMORY_BARRIER() __sync_synchronize()
#else
# error Plattform and/or compiler not supportet
#endif
#endif // CPPA_CONFIG_HPP
......@@ -103,7 +103,7 @@ class converted_thread_context : public abstract_actor<local_actor>
throw_on_exit_result throw_on_exit(any_tuple const& msg);
pattern<atom_value, actor_ptr, std::uint32_t> m_exit_msg_pattern;
pattern<atom_value, std::uint32_t> m_exit_msg_pattern;
};
......
......@@ -31,6 +31,10 @@
#ifndef YIELDING_ACTOR_HPP
#define YIELDING_ACTOR_HPP
#include "cppa/config.hpp"
#ifndef CPPA_DISABLE_CONTEXT_SWITCHING
#include <stack>
#include "cppa/pattern.hpp"
......@@ -85,4 +89,6 @@ class yielding_actor : public abstract_scheduled_actor
} } // namespace cppa::detail
#endif // CPPA_DISABLE_CONTEXT_SWITCHING
#endif // YIELDING_ACTOR_HPP
......@@ -33,13 +33,22 @@
#include "cppa/config.hpp"
#if defined (CPPA_MACOS) || defined (CPPA_LINUX)
#if defined(CPPA_MACOS) || defined(CPPA_LINUX)
# define CPPA_USE_UCONTEXT_IMPL
#elif defined (CPPA_WINDOWS)
# define CPPA_USE_FIBER_IMPL
#endif
#ifdef CPPA_USE_UCONTEXT_IMPL
#ifdef CPPA_DISABLE_CONTEXT_SWITCHING
namespace cppa { namespace util {
struct fiber
{
inline static void swap(fiber&, fiber&) { }
};
} }
#elif defined(CPPA_USE_UCONTEXT_IMPL)
namespace cppa { namespace util {
......
......@@ -47,11 +47,10 @@ converted_thread_context::converted_thread_context()
void converted_thread_context::quit(std::uint32_t reason)
{
try { super::cleanup(reason); } catch(...) { }
super::cleanup(reason);
// actor_exited should not be catched, but if anyone does,
// self must point to a newly created instance
self.set(nullptr);
//set_self(nullptr);
//self.set(nullptr);
throw actor_exited(reason);
}
......@@ -88,7 +87,7 @@ void converted_thread_context::dequeue(timed_invoke_rules& rules) /*override*/
queue_node_ptr node(m_mailbox.try_pop());
do
{
while (!node)
if (!node)
{
node.reset(m_mailbox.try_pop(timeout));
if (!node)
......@@ -102,13 +101,11 @@ void converted_thread_context::dequeue(timed_invoke_rules& rules) /*override*/
while (dq(node, rules, buffer) == false);
}
converted_thread_context::throw_on_exit_result
converted_thread_context::throw_on_exit(const any_tuple& msg)
converted_thread_context::throw_on_exit(any_tuple const& msg)
{
pattern<atom_value, actor_ptr, std::uint32_t>::mapping_vector* ptr = nullptr;
auto j = m_exit_msg_pattern.begin();
if (detail::matches(pm_decorated(msg.begin(), ptr), j))
if (matches(msg.begin(), m_exit_msg_pattern.begin()))
{
auto reason = *reinterpret_cast<const std::uint32_t*>(msg.at(2));
auto reason = msg.get_as<std::uint32_t>(1);
if (reason != exit_reason::normal)
{
// throws
......
......@@ -32,6 +32,9 @@
#define _XOPEN_SOURCE
#endif
#include "cppa/config.hpp"
#ifndef CPPA_DISABLE_CONTEXT_SWITCHING
#include <atomic>
#include <cstddef>
#include <cstring>
......@@ -41,107 +44,35 @@
#include "cppa/util/fiber.hpp"
#include "cppa/detail/thread.hpp"
#if defined(CPPA_USE_UCONTEXT_IMPL) || defined(CPPA_USE_PTH_IMPL)
#ifdef CPPA_USE_UCONTEXT_IMPL
#include <signal.h>
#include <sys/mman.h>
#ifdef CPPA_USE_PTH_IMPL
#include "pth.h"
#else
#include <ucontext.h>
#endif
namespace {
constexpr size_t STACK_SIZE = SIGSTKSZ;
struct stack_node
{
stack_node* next;
void* s;
stack_node(): next(NULL) , s(mmap(0, STACK_SIZE,
PROT_EXEC | PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANON,
-1,
0))
//new char[STACK_SIZE])
{
//memset(s, 0, STACK_SIZE);
}
~stack_node()
{
munmap(s, STACK_SIZE);
//delete[] reinterpret_cast<char*>(s);
}
};
std::atomic<stack_node*> s_head(nullptr);
std::atomic<size_t> s_size(0);
constexpr size_t s_stack_size = SIGSTKSZ;
struct cleanup_helper
inline void* get_stack()
{
~cleanup_helper()
{
stack_node* h = s_head.load();
while (s_head.compare_exchange_weak(h, nullptr) == false)
{
// try again
}
s_size = 0;
while (h)
{
auto tmp = h->next;
delete h;
h = tmp;
}
}
return mmap(0,
s_stack_size,
PROT_EXEC | PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANON,
-1,
0);
}
s_cleanup_helper;
stack_node* get_stack_node()
inline void release_stack(void* mem)
{
stack_node* result = s_head.load();
for (;;)
{
if (result)
{
if (s_head.compare_exchange_weak(result, result->next))
{
--s_size;
return result;
}
}
else
{
return new stack_node;
}
}
}
void release_stack_node(stack_node* node)
{
if (++s_size < 16)
{
node->next = s_head.load();
for (;;)
{
if (s_head.compare_exchange_weak(node->next, node)) return;
}
}
else
{
--s_size;
delete node;
}
munmap(mem, s_stack_size);
}
typedef void (*void_function)();
typedef void (*void_ptr_function)(void*);
#ifndef CPPA_USE_PTH_IMPL
template<size_t PointerSize,
typename FunType = void_function,
typename IntType = int>
......@@ -195,25 +126,21 @@ struct trampoline<8, FunType, IntType>
4, func_addr[0], func_addr[1], arg_addr[0], arg_addr[1]);
}
};
#else
cppa::detail::mutex s_uctx_make_mtx;
#endif
} // namespace <anonymous>
namespace cppa { namespace util {
#ifndef CPPA_USE_PTH_IMPL
struct fiber_impl
{
bool m_initialized;
stack_node* m_node;
void* m_stack;
void (*m_func)(void*);
void* m_arg;
ucontext_t m_ctx;
fiber_impl() throw() : m_initialized(true), m_node(0), m_func(0), m_arg(0)
fiber_impl() throw() : m_initialized(true), m_stack(0), m_func(0), m_arg(0)
{
memset(&m_ctx, 0, sizeof(ucontext_t));
getcontext(&m_ctx);
......@@ -221,7 +148,7 @@ struct fiber_impl
fiber_impl(void (*func)(void*), void* arg)
: m_initialized(false)
, m_node(nullptr)
, m_stack(nullptr)
, m_func(func)
, m_arg(arg)
{
......@@ -235,11 +162,11 @@ struct fiber_impl
void initialize()
{
m_initialized = true;
m_node = get_stack_node();
memset(&m_ctx, 0, sizeof(ucontext_t));
getcontext(&m_ctx);
m_ctx.uc_stack.ss_sp = m_node->s;
m_ctx.uc_stack.ss_size = STACK_SIZE;
m_stack = get_stack();
m_ctx.uc_stack.ss_sp = m_stack;
m_ctx.uc_stack.ss_size = s_stack_size;
m_ctx.uc_link = nullptr;
trampoline<sizeof(void*)>::prepare(&m_ctx, m_func, m_arg);
}
......@@ -251,69 +178,10 @@ struct fiber_impl
~fiber_impl()
{
if (m_node) release_stack_node(m_node);
}
};
#else
struct fiber_impl
{
bool m_initialized;
stack_node* m_node;
void (*m_func)(void*);
void* m_arg;
pth_uctx_t m_ctx;
fiber_impl() throw() : m_initialized(true), m_node(0), m_func(0), m_arg(0)
{
memset(&m_ctx, 0, sizeof(pth_uctx_t));
pth_uctx_create(&m_ctx);
}
fiber_impl(void (*func)(void*), void* arg)
: m_initialized(false)
, m_node(nullptr)
, m_func(func)
, m_arg(arg)
{
}
inline void swap(fiber_impl* to)
{
pth_uctx_switch(m_ctx, to->m_ctx);
}
void initialize()
{
m_initialized = true;
m_node = get_stack_node();
memset(&m_ctx, 0, sizeof(pth_uctx_t));
pth_uctx_create(&m_ctx);
// lifetime scope of guard
{
// pth uses static data to initialize m_ctx
detail::unique_lock<detail::mutex> guard(s_uctx_make_mtx);
pth_uctx_make(m_ctx, reinterpret_cast<char*>(m_node->s), STACK_SIZE,
nullptr, m_func, m_arg, nullptr);
}
}
inline void lazy_init()
{
if (!m_initialized) initialize();
}
~fiber_impl()
{
if (m_node) release_stack_node(m_node);
pth_uctx_destroy(m_ctx);
if (m_stack) release_stack(m_stack);
}
};
#endif
fiber::fiber() throw() : m_impl(new fiber_impl)
{
......@@ -368,4 +236,10 @@ fiber::~fiber()
}
}
#endif
#endif // CPPA_USE_FIBER_IMPL
#else // ifdef CPPA_DISABLE_CONTEXT_SWITCHING
namespace { int keep_compiler_happy() { return 42; } }
#endif // CPPA_DISABLE_CONTEXT_SWITCHING
......@@ -41,7 +41,7 @@
std::cout << "[process id: " \
<< cppa::process_information::get()->process_id() \
<< "] " << arg << std::endl
*/
//*/
#define DEBUG(unused) ((void) 0)
......
......@@ -56,7 +56,6 @@ void run_actor(cppa::intrusive_ptr<cppa::local_actor> m_self,
cppa::scheduled_actor* behavior)
{
cppa::self.set(m_self.get());
//cppa::set_self(m_self.get());
if (behavior)
{
try { behavior->act(); }
......@@ -64,6 +63,7 @@ void run_actor(cppa::intrusive_ptr<cppa::local_actor> m_self,
try { behavior->on_exit(); }
catch (...) { }
delete behavior;
cppa::self.set(nullptr);
}
cppa::detail::dec_actor_count();
}
......
......@@ -73,7 +73,7 @@
std::cout << "[process id: " \
<< cppa::process_information::get()->process_id() \
<< "] " << arg << std::endl
*/
//*/
#define DEBUG(unused) ((void) 0)
......
......@@ -36,6 +36,7 @@
#include "cppa/scheduled_actor.hpp"
#include "cppa/detail/invokable.hpp"
#include "cppa/detail/actor_count.hpp"
#include "cppa/detail/mock_scheduler.hpp"
#include "cppa/detail/task_scheduler.hpp"
#include "cppa/detail/yielding_actor.hpp"
#include "cppa/detail/yield_interface.hpp"
......@@ -134,9 +135,17 @@ actor_ptr task_scheduler::spawn(abstract_event_based_actor* what)
return spawn_impl(what->attach_to_scheduler(enqueue_fun, this));
}
actor_ptr task_scheduler::spawn(scheduled_actor* behavior, scheduling_hint)
#ifndef CPPA_DISABLE_CONTEXT_SWITCHING
actor_ptr task_scheduler::spawn(scheduled_actor* bhvr, scheduling_hint hint)
{
return spawn_impl(new yielding_actor(behavior, enqueue_fun, this));
if (hint == detached) return mock_scheduler::spawn(bhvr);
return spawn_impl(new yielding_actor(bhvr, enqueue_fun, this));
}
#else
actor_ptr task_scheduler::spawn(scheduled_actor* bhvr, scheduling_hint)
{
return mock_scheduler::spawn(bhvr);
}
#endif
} } // namespace cppa::detail
......@@ -237,19 +237,24 @@ actor_ptr thread_pool_scheduler::spawn(abstract_event_based_actor* what)
return spawn_impl(what->attach_to_scheduler(enqueue_fun, this), false);
}
actor_ptr thread_pool_scheduler::spawn(scheduled_actor* behavior,
#ifndef CPPA_DISABLE_CONTEXT_SWITCHING
actor_ptr thread_pool_scheduler::spawn(scheduled_actor* bhvr,
scheduling_hint hint)
{
if (hint == detached)
{
return mock_scheduler::spawn(behavior);
return mock_scheduler::spawn(bhvr);
}
else
{
return spawn_impl(new yielding_actor(behavior,
enqueue_fun,
this));
return spawn_impl(new yielding_actor(bhvr, enqueue_fun, this));
}
}
#else
actor_ptr thread_pool_scheduler::spawn(scheduled_actor* bhvr, scheduling_hint)
{
return mock_scheduler::spawn(bhvr);
}
#endif
} } // namespace cppa::detail
......@@ -28,13 +28,15 @@
\******************************************************************************/
#include "cppa/detail/yielding_actor.hpp"
#ifndef CPPA_DISABLE_CONTEXT_SWITCHING
#include <iostream>
#include "cppa/cppa.hpp"
#include "cppa/self.hpp"
#include "cppa/detail/invokable.hpp"
#include "cppa/detail/intermediate.hpp"
#include "cppa/detail/yielding_actor.hpp"
namespace cppa { namespace detail {
......@@ -184,3 +186,9 @@ void yielding_actor::resume(util::fiber* from, resume_callback* callback)
}
} } // namespace cppa::detail
#else // ifdef CPPA_DISABLE_CONTEXT_SWITCHING
namespace { int keep_compiler_happy() { return 42; } }
#endif // CPPA_DISABLE_CONTEXT_SWITCHING
......@@ -59,7 +59,7 @@ size_t test__remote_actor(char const* app_path, bool is_client,
}
while (!success);
std::ostringstream oss;
oss << app_path << " run=remote_actor port=" << port << " &>/dev/null";
oss << app_path << " run=remote_actor port=" << port;// << " &>/dev/null";
// execute client_part() in a separate process,
// connected via localhost socket
detail::thread child([&oss]() { system(oss.str().c_str()); });
......
......@@ -334,6 +334,7 @@ size_t test__spawn()
CPPA_TEST(test__spawn);
spawn(testee1);
return 0;
spawn(event_testee2());
auto cstk = spawn(new chopstick);
......
......@@ -57,6 +57,12 @@ size_t test__yield_interface()
{
CPPA_TEST(test__yield_interface);
# ifdef CPPA_DISABLE_CONTEXT_SWITCHING
cout << "WARNING: context switching was explicitly disabled using "
"CPPA_DISABLE_CONTEXT_SWITCHING"
<< endl;
return CPPA_TEST_RESULT;
# else
pseudo_worker worker;
fiber fself;
......@@ -77,4 +83,5 @@ size_t test__yield_interface()
CPPA_CHECK_EQUAL(i, 12);
return CPPA_TEST_RESULT;
# endif
}
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