Commit 394d641e authored by Dominik Charousset's avatar Dominik Charousset

refactored singleton handling

singletons use a `static create_singleton`, `initialize`,
`dispose`, and `destroy` interface to minimize code in `singleton_manager`
parent 9c00c1ae
...@@ -294,3 +294,4 @@ src/actor_addressing.cpp ...@@ -294,3 +294,4 @@ src/actor_addressing.cpp
cppa/weak_ptr_anchor.hpp cppa/weak_ptr_anchor.hpp
src/weak_ptr_anchor.cpp src/weak_ptr_anchor.cpp
cppa/actor_companion_mixin.hpp cppa/actor_companion_mixin.hpp
cppa/detail/singleton_mixin.hpp
...@@ -42,9 +42,15 @@ ...@@ -42,9 +42,15 @@
#include "cppa/attachable.hpp" #include "cppa/attachable.hpp"
#include "cppa/util/shared_spinlock.hpp" #include "cppa/util/shared_spinlock.hpp"
#include "cppa/detail/singleton_mixin.hpp"
namespace cppa { namespace detail { namespace cppa { namespace detail {
class actor_registry { class singleton_manager;
class actor_registry : public singleton_mixin<actor_registry> {
friend class singleton_mixin<actor_registry>;
public: public:
...@@ -55,8 +61,6 @@ class actor_registry { ...@@ -55,8 +61,6 @@ class actor_registry {
*/ */
typedef std::pair<actor_ptr, std::uint32_t> value_type; typedef std::pair<actor_ptr, std::uint32_t> value_type;
actor_registry();
/** /**
* @brief Returns the {nullptr, invalid_exit_reason}. * @brief Returns the {nullptr, invalid_exit_reason}.
*/ */
...@@ -98,6 +102,8 @@ class actor_registry { ...@@ -98,6 +102,8 @@ class actor_registry {
mutable util::shared_spinlock m_instances_mtx; mutable util::shared_spinlock m_instances_mtx;
entries m_entries; entries m_entries;
actor_registry();
}; };
} } // namespace cppa::detail } } // namespace cppa::detail
......
...@@ -34,13 +34,15 @@ ...@@ -34,13 +34,15 @@
#include <map> #include <map>
#include <string> #include <string>
#include "cppa/detail/singleton_mixin.hpp"
namespace cppa { namespace detail { namespace cppa { namespace detail {
class decorated_names_map { class decorated_names_map : public singleton_mixin<decorated_names_map> {
public: friend class singleton_mixin<decorated_names_map>;
decorated_names_map(); public:
// returns either a decorated version of @p demangled_name or // returns either a decorated version of @p demangled_name or
// @p demangled_name itself // @p demangled_name itself
...@@ -48,6 +50,8 @@ class decorated_names_map { ...@@ -48,6 +50,8 @@ class decorated_names_map {
private: private:
decorated_names_map();
std::map<std::string, std::string> m_map; std::map<std::string, std::string> m_map;
}; };
......
...@@ -32,16 +32,21 @@ ...@@ -32,16 +32,21 @@
#define CPPA_EMPTY_TUPLE_HPP #define CPPA_EMPTY_TUPLE_HPP
#include "cppa/detail/abstract_tuple.hpp" #include "cppa/detail/abstract_tuple.hpp"
#include "cppa/detail/singleton_mixin.hpp"
namespace cppa { namespace detail { namespace cppa { namespace detail {
class empty_tuple : public abstract_tuple { class empty_tuple : public singleton_mixin<empty_tuple,abstract_tuple> {
friend class singleton_manager;
friend class singleton_mixin<empty_tuple,abstract_tuple>;
typedef singleton_mixin<empty_tuple,abstract_tuple> super;
public: public:
using abstract_tuple::const_iterator; using abstract_tuple::const_iterator;
empty_tuple();
size_t size() const; size_t size() const;
void* mutable_at(size_t); void* mutable_at(size_t);
abstract_tuple* copy() const; abstract_tuple* copy() const;
...@@ -50,6 +55,13 @@ class empty_tuple : public abstract_tuple { ...@@ -50,6 +55,13 @@ class empty_tuple : public abstract_tuple {
const uniform_type_info* type_at(size_t) const; const uniform_type_info* type_at(size_t) const;
const std::type_info* type_token() const; const std::type_info* type_token() const;
private:
empty_tuple();
inline void initialize() /*override*/ { ref(); }
inline void destroy() /*override*/ { deref(); }
}; };
} } // namespace cppa::detail } } // namespace cppa::detail
......
...@@ -38,13 +38,15 @@ ...@@ -38,13 +38,15 @@
#include "cppa/group.hpp" #include "cppa/group.hpp"
#include "cppa/util/shared_spinlock.hpp" #include "cppa/util/shared_spinlock.hpp"
#include "cppa/detail/singleton_mixin.hpp"
namespace cppa { namespace detail { namespace cppa { namespace detail {
class group_manager { class group_manager : public singleton_mixin<group_manager> {
public: friend class singleton_mixin<group_manager>;
group_manager(); public:
intrusive_ptr<group> get(const std::string& module_name, intrusive_ptr<group> get(const std::string& module_name,
const std::string& group_identifier); const std::string& group_identifier);
...@@ -62,6 +64,8 @@ class group_manager { ...@@ -62,6 +64,8 @@ class group_manager {
modules_map m_mmap; modules_map m_mmap;
std::mutex m_mmap_mtx; std::mutex m_mmap_mtx;
group_manager();
}; };
} } // namespace cppa::detail } } // namespace cppa::detail
......
...@@ -54,9 +54,9 @@ namespace cppa { namespace detail { ...@@ -54,9 +54,9 @@ namespace cppa { namespace detail {
class logging { class logging {
public: friend class singleton_manager;
virtual ~logging(); public:
virtual void log(const char* level, virtual void log(const char* level,
const char* class_name, const char* class_name,
...@@ -65,14 +65,8 @@ class logging { ...@@ -65,14 +65,8 @@ class logging {
int line_num, int line_num,
const std::string& msg ) = 0; const std::string& msg ) = 0;
virtual void start() = 0;
virtual void stop() = 0;
static logging* instance(); static logging* instance();
static logging* create_singleton();
class trace_helper { class trace_helper {
public: public:
...@@ -102,6 +96,18 @@ class logging { ...@@ -102,6 +96,18 @@ class logging {
}; };
protected:
virtual ~logging();
static logging* create_singleton();
virtual void initialize() = 0;
virtual void destroy() = 0;
inline void dispose() { delete this; }
}; };
} } // namespace cppa::detail } } // namespace cppa::detail
......
...@@ -70,7 +70,6 @@ class singleton_manager { ...@@ -70,7 +70,6 @@ class singleton_manager {
static actor_registry* get_actor_registry(); static actor_registry* get_actor_registry();
// created on-the-fly on a successfull call to set_scheduler()
static network::middleman* get_middleman(); static network::middleman* get_middleman();
static uniform_type_info_map* get_uniform_type_info_map(); static uniform_type_info_map* get_uniform_type_info_map();
...@@ -83,16 +82,42 @@ class singleton_manager { ...@@ -83,16 +82,42 @@ class singleton_manager {
private: private:
/**
* @brief Type @p T has to provide: <tt>static T* create_singleton()</tt>,
* <tt>void initialize()</tt>, <tt>void destroy()</tt>,
* and <tt>dispose()</tt>.
* The constructor of T shall be lightweigt, since more than one object
* might get constructed initially.
* <tt>dispose()</tt> is called on objects with failed CAS operation.
* <tt>initialize()</tt> is called on objects with succeeded CAS operation.
* <tt>destroy()</tt> is called during shutdown on initialized objects.
*
* Both <tt>dispose</tt> and <tt>destroy</tt> must delete the object
* eventually.
*/
template<typename T> template<typename T>
static void stop_and_kill(std::atomic<T*>& ptr) { static T* lazy_get(std::atomic<T*>& ptr) {
T* result = ptr.load();
while (result == nullptr) {
auto tmp = T::create_singleton();
if (ptr.compare_exchange_weak(result, tmp)) {
tmp->initialize();
result = tmp;
}
else tmp->dispose();
}
return result;
}
template<typename T>
static void destroy(std::atomic<T*>& ptr) {
for (;;) { for (;;) {
auto p = ptr.load(); auto p = ptr.load();
if (p == nullptr) { if (p == nullptr) {
return; return;
} }
else if (ptr.compare_exchange_weak(p, nullptr)) { else if (ptr.compare_exchange_weak(p, nullptr)) {
p->stop(); p->destroy();
delete p;
ptr = nullptr; ptr = nullptr;
return; return;
} }
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011, 2012 *
* Dominik Charousset <dominik.charousset@haw-hamburg.de> *
* *
* This file is part of libcppa. *
* libcppa is free software: you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation, either version 3 of the License *
* or (at your option) any later version. *
* *
* libcppa is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#ifndef CPPA_SINGLETON_MIXIN_HPP
#define CPPA_SINGLETON_MIXIN_HPP
#include <utility>
namespace cppa { namespace detail {
class singleton_manager;
// a mixin for simple singleton classes
template<class Derived, class Base = void>
class singleton_mixin : public Base {
friend class singleton_manager;
inline static Derived* create_singleton() { return new Derived; }
inline void dispose() { delete this; }
inline void destroy() { delete this; }
inline void initialize() { }
protected:
template<typename... Args>
singleton_mixin(Args&&... args) : Base(std::forward<Args>(args)...) { }
virtual ~singleton_mixin() { }
};
template<class Derived>
class singleton_mixin<Derived, void> {
friend class singleton_manager;
inline static Derived* create_singleton() { return new Derived; }
inline void dispose() { delete this; }
inline void destroy() { delete this; }
inline void initialize() { }
protected:
virtual ~singleton_mixin() { }
};
} } // namespace cppa::detail
#endif // CPPA_SINGLETON_MIXIN_HPP
...@@ -49,9 +49,13 @@ class thread_pool_scheduler : public scheduler { ...@@ -49,9 +49,13 @@ class thread_pool_scheduler : public scheduler {
struct worker; struct worker;
void start() /*override*/; thread_pool_scheduler();
void stop() /*override*/; thread_pool_scheduler(size_t num_worker_threads);
void initialize() /*override*/;
void destroy() /*override*/;
void enqueue(scheduled_actor* what) /*override*/; void enqueue(scheduled_actor* what) /*override*/;
...@@ -74,12 +78,13 @@ class thread_pool_scheduler : public scheduler { ...@@ -74,12 +78,13 @@ class thread_pool_scheduler : public scheduler {
//typedef util::single_reader_queue<abstract_scheduled_actor> job_queue; //typedef util::single_reader_queue<abstract_scheduled_actor> job_queue;
typedef util::producer_consumer_list<scheduled_actor> job_queue; typedef util::producer_consumer_list<scheduled_actor> job_queue;
size_t m_num_threads;
job_queue m_queue; job_queue m_queue;
scheduled_actor_dummy m_dummy; scheduled_actor_dummy m_dummy;
std::thread m_supervisor; std::thread m_supervisor;
static void worker_loop(worker*); static void worker_loop(worker*);
static void supervisor_loop(job_queue*, scheduled_actor*); static void supervisor_loop(job_queue*, scheduled_actor*, size_t);
actor_ptr spawn_impl(scheduled_actor_ptr what); actor_ptr spawn_impl(scheduled_actor_ptr what);
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include <string> #include <string>
#include <utility> // std::pair #include <utility> // std::pair
#include "cppa/detail/singleton_mixin.hpp"
#include "cppa/detail/default_uniform_type_info_impl.hpp" #include "cppa/detail/default_uniform_type_info_impl.hpp"
namespace cppa { class uniform_type_info; } namespace cppa { class uniform_type_info; }
...@@ -44,9 +45,10 @@ namespace cppa { namespace detail { ...@@ -44,9 +45,10 @@ namespace cppa { namespace detail {
class uniform_type_info_map_helper; class uniform_type_info_map_helper;
// note: this class is implemented in uniform_type_info.cpp // note: this class is implemented in uniform_type_info.cpp
class uniform_type_info_map { class uniform_type_info_map : public singleton_mixin<uniform_type_info_map> {
friend class uniform_type_info_map_helper; friend class uniform_type_info_map_helper;
friend class singleton_mixin<uniform_type_info_map>;
public: public:
...@@ -54,10 +56,6 @@ class uniform_type_info_map { ...@@ -54,10 +56,6 @@ class uniform_type_info_map {
typedef std::map<std::string, uniform_type_info*> uti_map_type; typedef std::map<std::string, uniform_type_info*> uti_map_type;
typedef std::map<int, std::pair<set_type, set_type> > int_map_type; typedef std::map<int, std::pair<set_type, set_type> > int_map_type;
uniform_type_info_map();
~uniform_type_info_map();
inline const int_map_type& int_names() const { inline const int_map_type& int_names() const {
return m_ints; return m_ints;
} }
...@@ -82,6 +80,10 @@ class uniform_type_info_map { ...@@ -82,6 +80,10 @@ class uniform_type_info_map {
// maps sizeof(-integer_type-) to { signed-names-set, unsigned-names-set } // maps sizeof(-integer_type-) to { signed-names-set, unsigned-names-set }
int_map_type m_ints; int_map_type m_ints;
uniform_type_info_map();
~uniform_type_info_map();
}; };
} } // namespace cppa::detail } } // namespace cppa::detail
......
...@@ -73,12 +73,13 @@ class middleman { ...@@ -73,12 +73,13 @@ class middleman {
protected: protected:
virtual void stop() = 0; virtual void destroy() = 0;
virtual void start() = 0; virtual void initialize() = 0;
private: private:
static middleman* create_singleton(); static middleman* create_singleton();
inline void dispose() { delete this; }
}; };
......
...@@ -59,14 +59,15 @@ namespace detail { ...@@ -59,14 +59,15 @@ namespace detail {
// forwards self_type as actor_ptr, otherwise equal to std::forward // forwards self_type as actor_ptr, otherwise equal to std::forward
template<typename T> template<typename T>
struct spawn_fwd_ { struct spawn_fwd_ {
static inline T&& _(T&& arg) { return std::move(arg); } static inline T&& _(T&& arg) { return std::move(arg); }
static inline T& _(T& arg) { return arg; } static inline T& _(T& arg) { return arg; }
static inline const T& _(const T& arg) { return arg; } static inline const T& _(const T& arg) { return arg; }
}; };
template<> template<>
struct spawn_fwd_<self_type> { struct spawn_fwd_<self_type> {
static inline actor_ptr _(const self_type& s) { return s.get(); } static inline actor_ptr _(const self_type& s) { return s.get(); }
}; };
class singleton_manager;
} // namespace detail } // namespace detail
/** /**
...@@ -78,23 +79,32 @@ class scheduler { ...@@ -78,23 +79,32 @@ class scheduler {
channel* delayed_send_helper(); channel* delayed_send_helper();
friend class detail::singleton_manager;
protected: protected:
scheduler(); scheduler();
public:
virtual ~scheduler(); virtual ~scheduler();
/** /**
* @warning Always call scheduler::start on overriding. * @warning Always call scheduler::initialize on overriding.
*/ */
virtual void start(); virtual void initialize();
/** /**
* @warning Always call scheduler::stop on overriding. * @warning Always call scheduler::destroy on overriding.
*/ */
virtual void stop(); virtual void destroy();
private:
static scheduler* create_singleton();
inline void dispose() { delete this; }
public:
virtual void enqueue(scheduled_actor*) = 0; virtual void enqueue(scheduled_actor*) = 0;
...@@ -225,8 +235,13 @@ class scheduler { ...@@ -225,8 +235,13 @@ class scheduler {
void set_scheduler(scheduler* sched); void set_scheduler(scheduler* sched);
/** /**
* @brief Gets the actual used scheduler implementation. * @brief Sets a thread pool scheduler with @p num_threads worker threads.
* @returns The active scheduler (usually default constructed). * @throws std::runtime_error if there's already a scheduler defined.
*/
void set_default_scheduler(size_t num_threads);
/**
* @brief Returns the currently running scheduler.
*/ */
scheduler* get_scheduler(); scheduler* get_scheduler();
......
...@@ -33,8 +33,7 @@ ...@@ -33,8 +33,7 @@
namespace cppa { namespace detail { namespace cppa { namespace detail {
empty_tuple::empty_tuple() : abstract_tuple(tuple_impl_info::statically_typed) { empty_tuple::empty_tuple() : super(tuple_impl_info::statically_typed) { }
}
size_t empty_tuple::size() const { size_t empty_tuple::size() const {
return 0; return 0;
......
...@@ -67,16 +67,17 @@ class logging_impl : public logging { ...@@ -67,16 +67,17 @@ class logging_impl : public logging {
public: public:
void start() { void initialize() {
m_thread = thread([this] { (*this)(); }); m_thread = thread([this] { (*this)(); });
log("TRACE ", "logging", "run", __FILE__, 31337, "ENTRY"); log("TRACE ", "logging", "run", __FILE__, 31337, "ENTRY");
} }
void stop() { void destroy() {
log("TRACE ", "logging", "run", __FILE__, 31337, "EXIT"); log("TRACE ", "logging", "run", __FILE__, 31337, "EXIT");
// an empty string means: shut down // an empty string means: shut down
m_queue.push_back(new log_event{0, ""}); m_queue.push_back(new log_event{0, ""});
m_thread.join(); m_thread.join();
delete this;
} }
void operator()() { void operator()() {
......
...@@ -439,7 +439,7 @@ class middleman_impl : public abstract_middleman { ...@@ -439,7 +439,7 @@ class middleman_impl : public abstract_middleman {
protected: protected:
void start() { void initialize() {
int pipefds[2]; int pipefds[2];
if (pipe(pipefds) != 0) { CPPA_CRITICAL("cannot create pipe"); } if (pipe(pipefds) != 0) { CPPA_CRITICAL("cannot create pipe"); }
m_pipe_read = pipefds[0]; m_pipe_read = pipefds[0];
...@@ -449,7 +449,7 @@ class middleman_impl : public abstract_middleman { ...@@ -449,7 +449,7 @@ class middleman_impl : public abstract_middleman {
m_thread = thread([this] { middleman_loop(this); }); m_thread = thread([this] { middleman_loop(this); });
} }
void stop() { void destroy() {
run_later([this] { run_later([this] {
CPPA_LOG_TRACE("lambda from middleman_impl::stop"); CPPA_LOG_TRACE("lambda from middleman_impl::stop");
this->m_done = true; this->m_done = true;
...@@ -458,6 +458,7 @@ class middleman_impl : public abstract_middleman { ...@@ -458,6 +458,7 @@ class middleman_impl : public abstract_middleman {
m_thread.join(); m_thread.join();
close(m_pipe_read); close(m_pipe_read);
close(m_pipe_write); close(m_pipe_write);
delete this;
} }
private: private:
......
...@@ -220,12 +220,13 @@ void scheduler_helper::time_emitter(scheduler_helper::ptr_type m_self) { ...@@ -220,12 +220,13 @@ void scheduler_helper::time_emitter(scheduler_helper::ptr_type m_self) {
scheduler::scheduler() : m_helper(new scheduler_helper) { scheduler::scheduler() : m_helper(new scheduler_helper) {
} }
void scheduler::start() { void scheduler::initialize() {
m_helper->start(); m_helper->start();
} }
void scheduler::stop() { void scheduler::destroy() {
m_helper->stop(); m_helper->stop();
delete this;
} }
scheduler::~scheduler() { scheduler::~scheduler() {
...@@ -254,19 +255,16 @@ void set_scheduler(scheduler* sched) { ...@@ -254,19 +255,16 @@ void set_scheduler(scheduler* sched) {
} }
} }
void set_default_scheduler(size_t num_threads) {
set_scheduler(new detail::thread_pool_scheduler(num_threads));
}
scheduler* get_scheduler() { scheduler* get_scheduler() {
scheduler* result = detail::singleton_manager::get_scheduler(); return detail::singleton_manager::get_scheduler();
if (result == nullptr) { }
result = new detail::thread_pool_scheduler;
try { scheduler* scheduler::create_singleton() {
set_scheduler(result); return new detail::thread_pool_scheduler;
}
catch (std::runtime_error&) {
delete result;
return detail::singleton_manager::get_scheduler();
}
}
return result;
} }
} // namespace cppa } // namespace cppa
...@@ -49,16 +49,11 @@ ...@@ -49,16 +49,11 @@
#include "cppa/detail/thread_pool_scheduler.hpp" #include "cppa/detail/thread_pool_scheduler.hpp"
#include "cppa/detail/uniform_type_info_map.hpp" #include "cppa/detail/uniform_type_info_map.hpp"
using std::cout; namespace cppa { void shutdown() { detail::singleton_manager::shutdown(); } }
using std::endl;
namespace { namespace cppa { namespace detail {
using namespace cppa;
using namespace cppa::detail;
//volatile uniform_type_info_map* s_uniform_type_info_map = 0;
namespace {
std::atomic<uniform_type_info_map*> s_uniform_type_info_map; std::atomic<uniform_type_info_map*> s_uniform_type_info_map;
std::atomic<decorated_names_map*> s_decorated_names_map; std::atomic<decorated_names_map*> s_decorated_names_map;
...@@ -69,55 +64,27 @@ std::atomic<empty_tuple*> s_empty_tuple; ...@@ -69,55 +64,27 @@ std::atomic<empty_tuple*> s_empty_tuple;
std::atomic<scheduler*> s_scheduler; std::atomic<scheduler*> s_scheduler;
std::atomic<logging*> s_logger; std::atomic<logging*> s_logger;
template<typename T>
T* lazy_get(std::atomic<T*>& ptr) {
T* result = ptr.load(std::memory_order_seq_cst);
if (result == nullptr) {
auto tmp = new T;
if (ptr.compare_exchange_strong(result, tmp, std::memory_order_seq_cst)) {
return tmp;
}
else {
delete tmp;
return lazy_get(ptr);
}
}
return result;
}
} // namespace <anonymous> } // namespace <anonymous>
namespace cppa { void shutdown() { singleton_manager::shutdown(); } }
namespace cppa { namespace detail {
void singleton_manager::shutdown() { void singleton_manager::shutdown() {
CPPA_LOGF_TRACE("");
CPPA_LOGF_DEBUG("prepare to shutdown"); CPPA_LOGF_DEBUG("prepare to shutdown");
if (self.unchecked() != nullptr) { if (self.unchecked() != nullptr) {
try { self.unchecked()->quit(exit_reason::normal); } try { self.unchecked()->quit(exit_reason::normal); }
catch (actor_exited&) { } catch (actor_exited&) { }
} }
auto rptr = s_actor_registry.load(); auto rptr = s_actor_registry.load();
if (rptr) { if (rptr) rptr->await_running_count_equal(0);
rptr->await_running_count_equal(0); destroy(s_scheduler);
} destroy(s_middleman);
stop_and_kill(s_scheduler);
stop_and_kill(s_middleman);
std::atomic_thread_fence(std::memory_order_seq_cst); std::atomic_thread_fence(std::memory_order_seq_cst);
// it's safe now to delete all other singletons now // it's safe now to delete all other singletons now
delete s_actor_registry.load(); destroy(s_actor_registry);
s_actor_registry = nullptr; destroy(s_group_manager);
delete s_group_manager.load(); destroy(s_empty_tuple);
s_group_manager = nullptr; destroy(s_uniform_type_info_map);
auto et = s_empty_tuple.load(); destroy(s_decorated_names_map);
if (et) et->deref(); destroy(s_logger);
s_empty_tuple = nullptr;
delete s_uniform_type_info_map.load();
s_uniform_type_info_map = nullptr;
delete s_decorated_names_map.load();
s_decorated_names_map = nullptr;
// last but not least: kill logger
stop_and_kill(s_logger);
} }
actor_registry* singleton_manager::get_actor_registry() { actor_registry* singleton_manager::get_actor_registry() {
...@@ -133,7 +100,7 @@ group_manager* singleton_manager::get_group_manager() { ...@@ -133,7 +100,7 @@ group_manager* singleton_manager::get_group_manager() {
} }
scheduler* singleton_manager::get_scheduler() { scheduler* singleton_manager::get_scheduler() {
return s_scheduler.load(); return lazy_get(s_scheduler);
} }
decorated_names_map* singleton_manager::get_decorated_names_map() { decorated_names_map* singleton_manager::get_decorated_names_map() {
...@@ -141,62 +108,27 @@ decorated_names_map* singleton_manager::get_decorated_names_map() { ...@@ -141,62 +108,27 @@ decorated_names_map* singleton_manager::get_decorated_names_map() {
} }
logging* singleton_manager::get_logger() { logging* singleton_manager::get_logger() {
auto result = s_logger.load(); return lazy_get(s_logger);
if (result == nullptr) {
auto tmp = logging::create_singleton();
if (s_logger.compare_exchange_weak(result, tmp) == false) {
delete tmp;
}
else {
result = tmp;
result->start();
}
}
return result;
} }
bool singleton_manager::set_scheduler(scheduler* ptr) { bool singleton_manager::set_scheduler(scheduler* ptr) {
scheduler* expected = nullptr; scheduler* expected = nullptr;
if (s_scheduler.compare_exchange_weak(expected, ptr)) { if (s_scheduler.compare_exchange_weak(expected, ptr)) {
ptr->start(); ptr->initialize();
network::middleman* mm = network::middleman::create_singleton();
network::middleman* mm_expected = nullptr;
if (s_middleman.compare_exchange_weak(mm_expected, mm)) {
mm->start();
}
else delete mm;
return true; return true;
} }
else { else {
delete ptr; ptr->dispose();
return false; return false;
} }
} }
network::middleman* singleton_manager::get_middleman() { network::middleman* singleton_manager::get_middleman() {
auto result = s_middleman.load(); return lazy_get(s_middleman);
if (result == nullptr) {
scheduler* s = new thread_pool_scheduler;
// set_scheduler sets s_network_manager
set_scheduler(s);
return get_middleman();
}
return result;
} }
empty_tuple* singleton_manager::get_empty_tuple() { empty_tuple* singleton_manager::get_empty_tuple() {
empty_tuple* result = s_empty_tuple.load(); return lazy_get(s_empty_tuple);
if (result == nullptr) {
auto tmp = new empty_tuple;
if (s_empty_tuple.compare_exchange_weak(result, tmp) == false) {
delete tmp;
}
else {
result = tmp;
result->ref();
}
}
return result;
} }
} } // namespace cppa::detail } } // namespace cppa::detail
...@@ -160,11 +160,20 @@ void thread_pool_scheduler::worker_loop(thread_pool_scheduler::worker* w) { ...@@ -160,11 +160,20 @@ void thread_pool_scheduler::worker_loop(thread_pool_scheduler::worker* w) {
(*w)(); (*w)();
} }
thread_pool_scheduler::thread_pool_scheduler() {
m_num_threads = std::max<size_t>(std::thread::hardware_concurrency() * 2, 4);
}
thread_pool_scheduler::thread_pool_scheduler(size_t num_worker_threads) {
m_num_threads = num_worker_threads;
}
void thread_pool_scheduler::supervisor_loop(job_queue* jqueue, void thread_pool_scheduler::supervisor_loop(job_queue* jqueue,
scheduled_actor* dummy) { scheduled_actor* dummy,
size_t num_threads) {
std::vector<std::unique_ptr<thread_pool_scheduler::worker> > workers; std::vector<std::unique_ptr<thread_pool_scheduler::worker> > workers;
size_t num_workers = std::max<size_t>(std::thread::hardware_concurrency() * 2, 4); for (size_t i = 0; i < num_threads; ++i) {
for (size_t i = 0; i < num_workers; ++i) {
workers.emplace_back(new worker(jqueue, dummy)); workers.emplace_back(new worker(jqueue, dummy));
workers.back()->start(); workers.back()->start();
} }
...@@ -174,13 +183,13 @@ void thread_pool_scheduler::supervisor_loop(job_queue* jqueue, ...@@ -174,13 +183,13 @@ void thread_pool_scheduler::supervisor_loop(job_queue* jqueue,
} }
} }
void thread_pool_scheduler::start() { void thread_pool_scheduler::initialize() {
m_supervisor = std::thread(&thread_pool_scheduler::supervisor_loop, m_supervisor = std::thread(&thread_pool_scheduler::supervisor_loop,
&m_queue, &m_dummy); &m_queue, &m_dummy, m_num_threads);
super::start(); super::initialize();
} }
void thread_pool_scheduler::stop() { void thread_pool_scheduler::destroy() {
m_queue.push_back(&m_dummy); m_queue.push_back(&m_dummy);
m_supervisor.join(); m_supervisor.join();
// make sure job queue is empty, because destructor of m_queue would // make sure job queue is empty, because destructor of m_queue would
...@@ -195,7 +204,7 @@ void thread_pool_scheduler::stop() { ...@@ -195,7 +204,7 @@ void thread_pool_scheduler::stop() {
} }
ptr = m_queue.try_pop(); ptr = m_queue.try_pop();
} }
super::stop(); super::destroy();
} }
void thread_pool_scheduler::enqueue(scheduled_actor* what) { void thread_pool_scheduler::enqueue(scheduled_actor* what) {
......
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