Commit 079f6372 authored by Dominik Charousset's avatar Dominik Charousset

Use RW lock for AID instead of __thread variable

Store actor IDs in an unordered map protected via RW lock instead of using a
non-portable `__thread` variable. Though this is less efficient, the
performance overhead is still negligible compared to the overall cost of
enabling logging in the first place. Close #258; a more generic
`thread_specific_ptr` implementation turned out have too much implementation
overhead to be worth the effort.
parent d6dae07b
...@@ -20,10 +20,12 @@ ...@@ -20,10 +20,12 @@
#ifndef CAF_LOGGING_HPP #ifndef CAF_LOGGING_HPP
#define CAF_LOGGING_HPP #define CAF_LOGGING_HPP
#include <thread>
#include <cstring> #include <cstring>
#include <sstream> #include <sstream>
#include <iostream> #include <iostream>
#include <type_traits> #include <type_traits>
#include <unordered_map>
#include "caf/config.hpp" #include "caf/config.hpp"
#include "caf/to_string.hpp" #include "caf/to_string.hpp"
...@@ -31,6 +33,7 @@ ...@@ -31,6 +33,7 @@
#include "caf/detail/singletons.hpp" #include "caf/detail/singletons.hpp"
#include "caf/detail/scope_guard.hpp" #include "caf/detail/scope_guard.hpp"
#include "caf/detail/shared_spinlock.hpp"
/* /*
* To enable logging, you have to define CAF_DEBUG. This enables * To enable logging, you have to define CAF_DEBUG. This enables
...@@ -51,10 +54,11 @@ namespace detail { ...@@ -51,10 +54,11 @@ namespace detail {
class singletons; class singletons;
class logging { class logging {
public:
friend class detail::singletons; friend class detail::singletons;
public: // returns the actor ID for the current thread or 0 if none is assigned
actor_id get_aid();
// associates given actor id with this thread, // associates given actor id with this thread,
// returns the previously set actor id // returns the previously set actor id
...@@ -65,26 +69,20 @@ class logging { ...@@ -65,26 +69,20 @@ class logging {
int line_num, const std::string& msg) = 0; int line_num, const std::string& msg) = 0;
class trace_helper { class trace_helper {
public: public:
trace_helper(std::string class_name, const char* fun_name, trace_helper(std::string class_name, const char* fun_name,
const char* file_name, int line_num, const char* file_name, int line_num, const std::string& msg);
const std::string& msg);
~trace_helper(); ~trace_helper();
private: private:
std::string m_class; std::string m_class;
const char* m_fun_name; const char* m_fun_name;
const char* m_file_name; const char* m_file_name;
int m_line_num; int m_line_num;
}; };
protected: protected:
virtual ~logging(); virtual ~logging();
static logging* create_singleton(); static logging* create_singleton();
...@@ -93,20 +91,29 @@ class logging { ...@@ -93,20 +91,29 @@ class logging {
virtual void stop() = 0; virtual void stop() = 0;
inline void dispose() { delete this; } inline void dispose() {
delete this;
}
private:
detail::shared_spinlock m_aids_lock;
std::unordered_map<std::thread::id, actor_id> m_aids;
}; };
struct oss_wr { struct oss_wr {
inline oss_wr() {
// nop
}
inline oss_wr() { } inline oss_wr(oss_wr&& other) : m_str(std::move(other.m_str)) {
// nop
inline oss_wr(oss_wr&& other) : m_str(std::move(other.m_str)) {} }
std::string m_str; std::string m_str;
inline std::string str() { return std::move(m_str); } inline std::string str() {
return std::move(m_str);
}
}; };
inline oss_wr operator<<(oss_wr&& lhs, std::string str) { inline oss_wr operator<<(oss_wr&& lhs, std::string str) {
......
...@@ -50,8 +50,6 @@ namespace detail { ...@@ -50,8 +50,6 @@ namespace detail {
namespace { namespace {
__thread actor_id t_self_id;
constexpr struct pop_aid_log_event_t { constexpr struct pop_aid_log_event_t {
constexpr pop_aid_log_event_t() { constexpr pop_aid_log_event_t() {
// nop // nop
...@@ -156,7 +154,7 @@ class logging_impl : public logging { ...@@ -156,7 +154,7 @@ class logging_impl : public logging {
} }
std::ostringstream line; std::ostringstream line;
line << time(0) << " " << level << " " line << time(0) << " " << level << " "
<< "actor" << t_self_id << " " << std::this_thread::get_id() << " " << "actor" << get_aid() << " " << std::this_thread::get_id() << " "
<< class_name << " " << function_name << " " << file_name << ":" << class_name << " " << function_name << " " << file_name << ":"
<< line_num << " " << msg << std::endl; << line_num << " " << msg << std::endl;
m_queue.synchronized_enqueue(m_queue_mtx, m_queue_cv, m_queue.synchronized_enqueue(m_queue_mtx, m_queue_cv,
...@@ -196,10 +194,31 @@ logging* logging::create_singleton() { ...@@ -196,10 +194,31 @@ logging* logging::create_singleton() {
return new logging_impl; return new logging_impl;
} }
// returns the actor ID for the current thread
actor_id logging::get_aid() {
shared_lock<detail::shared_spinlock> guard{m_aids_lock};
auto i = m_aids.find(std::this_thread::get_id());
if (i != m_aids.end()) {
return i->second;
}
return 0;
}
actor_id logging::set_aid(actor_id aid) { actor_id logging::set_aid(actor_id aid) {
actor_id prev = t_self_id; auto tid = std::this_thread::get_id();
t_self_id = aid; upgrade_lock<detail::shared_spinlock> guard{m_aids_lock};
return prev; auto i = m_aids.find(tid);
if (i != m_aids.end()) {
// we modify it despite the shared lock because the elements themselves
// are considered thread-local
auto res = i->second;
i->second = aid;
return res;
}
// upgrade to unique lock and insert new element
upgrade_to_unique_lock<detail::shared_spinlock> uguard{guard};
m_aids.insert(std::make_pair(tid, aid));
return 0; // was empty before
} }
} // namespace detail } // namespace detail
......
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