Commit 9a29258b authored by Dominik Charousset's avatar Dominik Charousset

further modularized middleman, fixed names in logs

moved middleman_event_handler_base to its own header;
splitted middleman interface into two parts:
  - middleman: provides `start`, `stop`, and `run_later`
  - abstract_middleman: provides non thread-safe member function for protocols;
use typeid(decltype(*this)) rather than typeid(*this) as class name in logfiles
parent 561b43b0
...@@ -289,3 +289,5 @@ cppa/detail/logging.hpp ...@@ -289,3 +289,5 @@ cppa/detail/logging.hpp
src/logging.cpp src/logging.cpp
cppa/network/continuable_writer.hpp cppa/network/continuable_writer.hpp
src/continuable_writer.cpp src/continuable_writer.cpp
cppa/network/middleman_event_handler_base.hpp
src/actor_addressing.cpp
...@@ -45,10 +45,12 @@ class deserializer; ...@@ -45,10 +45,12 @@ class deserializer;
* for actors. This class encapsulates a technology-specific * for actors. This class encapsulates a technology-specific
* actor addressing. * actor addressing.
*/ */
class actor_addressing : public ref_counted { class actor_addressing {
public: public:
virtual ~actor_addressing();
/** /**
* @brief Returns the technology identifier of the implementation. * @brief Returns the technology identifier of the implementation.
* @note All-uppercase identifiers are reserved for libcppa's * @note All-uppercase identifiers are reserved for libcppa's
......
...@@ -106,30 +106,32 @@ class logging { ...@@ -106,30 +106,32 @@ class logging {
} } // namespace cppa::detail } } // namespace cppa::detail
#define CPPA_VOID_STMT static_cast<void>(0)
#ifndef CPPA_DEBUG #ifndef CPPA_DEBUG
#define CPPA_LOG_ERROR(unused) static_cast<void>(0) #define CPPA_LOG_ERROR(unused) CPPA_VOID_STMT
#define CPPA_LOG_ERROR_IF(unused1,unused2) static_cast<void>(0) #define CPPA_LOG_ERROR_IF(unused1,unused2) CPPA_VOID_STMT
#define CPPA_LOGF_ERROR(unused) static_cast<void>(0) #define CPPA_LOGF_ERROR(unused) CPPA_VOID_STMT
#define CPPA_LOGF_ERROR_IF(unused1,unused2) static_cast<void>(0) #define CPPA_LOGF_ERROR_IF(unused1,unused2) CPPA_VOID_STMT
#define CPPA_LOG_WARNING(unused) static_cast<void>(0) #define CPPA_LOG_WARNING(unused) CPPA_VOID_STMT
#define CPPA_LOG_WARNING_IF(unused1,unused2) static_cast<void>(0) #define CPPA_LOG_WARNING_IF(unused1,unused2) CPPA_VOID_STMT
#define CPPA_LOGF_WARNING(unused) static_cast<void>(0) #define CPPA_LOGF_WARNING(unused) CPPA_VOID_STMT
#define CPPA_LOGF_WARNING_IF(unused1,unused2) static_cast<void>(0) #define CPPA_LOGF_WARNING_IF(unused1,unused2) CPPA_VOID_STMT
#define CPPA_LOG_INFO(unused) static_cast<void>(0) #define CPPA_LOG_INFO(unused) CPPA_VOID_STMT
#define CPPA_LOG_INFO_IF(unused1,unused2) static_cast<void>(0) #define CPPA_LOG_INFO_IF(unused1,unused2) CPPA_VOID_STMT
#define CPPA_LOGF_INFO(unused) static_cast<void>(0) #define CPPA_LOGF_INFO(unused) CPPA_VOID_STMT
#define CPPA_LOGF_INFO_IF(unused1,unused2) static_cast<void>(0) #define CPPA_LOGF_INFO_IF(unused1,unused2) CPPA_VOID_STMT
#define CPPA_LOG_DEBUG(unused) static_cast<void>(0) #define CPPA_LOG_DEBUG(unused) CPPA_VOID_STMT
#define CPPA_LOG_DEBUG_IF(unused1,unused2) static_cast<void>(0) #define CPPA_LOG_DEBUG_IF(unused1,unused2) CPPA_VOID_STMT
#define CPPA_LOGF_DEBUG(unused) static_cast<void>(0) #define CPPA_LOGF_DEBUG(unused) CPPA_VOID_STMT
#define CPPA_LOGF_DEBUG_IF(unused1,unused2) static_cast<void>(0) #define CPPA_LOGF_DEBUG_IF(unused1,unused2) CPPA_VOID_STMT
#define CPPA_LOG_TRACE(unused) static_cast<void>(0) #define CPPA_LOG_TRACE(unused) CPPA_VOID_STMT
#define CPPA_LOGF_TRACE(unused) static_cast<void>(0) #define CPPA_LOGF_TRACE(unused) CPPA_VOID_STMT
#else #else
...@@ -138,40 +140,44 @@ class logging { ...@@ -138,40 +140,44 @@ class logging {
::cppa::detail::logging::instance()->log( \ ::cppa::detail::logging::instance()->log( \
level, "NONE", \ level, "NONE", \
__FUNCTION__, __FILE__, __LINE__, scoped_oss.str()); \ __FUNCTION__, __FILE__, __LINE__, scoped_oss.str()); \
} static_cast<void>(0) } CPPA_VOID_STMT
#define CPPA_DO_LOG_MEMBER_FUN(level, message) { \ #define CPPA_DO_LOG_MEMBER_FUN(level, message) { \
std::ostringstream scoped_oss; scoped_oss << message; \ std::ostringstream scoped_oss; scoped_oss << message; \
::cppa::detail::logging::instance()->log( \ ::cppa::detail::logging::instance()->log( \
level, ::cppa::detail::demangle(typeid(*this)).c_str(), \ level, ::cppa::detail::demangle(typeid(*this)).c_str(), \
__FUNCTION__, __FILE__, __LINE__, scoped_oss.str()); \ __FUNCTION__, __FILE__, __LINE__, scoped_oss.str()); \
} static_cast<void>(0) } CPPA_VOID_STMT
#define CPPA_LOG_ERROR(message) CPPA_DO_LOG_MEMBER_FUN("ERROR ", message) #define CPPA_LOG_ERROR(message) CPPA_DO_LOG_MEMBER_FUN("ERROR ", message)
#define CPPA_LOGF_ERROR(message) CPPA_DO_LOG_FUN("ERROR ", message) #define CPPA_LOGF_ERROR(message) CPPA_DO_LOG_FUN("ERROR ", message)
#ifndef CPPA_LOG_LEVEL
#define CPPA_LOG_LEVEL 0
#endif
#if CPPA_LOG_LEVEL > 0 #if CPPA_LOG_LEVEL > 0
# define CPPA_LOG_WARNING(message) CPPA_DO_LOG_MEMBER_FUN("WARNING", message) # define CPPA_LOG_WARNING(message) CPPA_DO_LOG_MEMBER_FUN("WARNING", message)
# define CPPA_LOGF_WARNING(message) CPPA_DO_LOG_FUN("WARNING", message) # define CPPA_LOGF_WARNING(message) CPPA_DO_LOG_FUN("WARNING", message)
#else #else
# define CPPA_LOG_WARNING(unused) static_cast<void>(0) # define CPPA_LOG_WARNING(unused) CPPA_VOID_STMT
# define CPPA_LOGF_WARNING(unused) static_cast<void>(0) # define CPPA_LOGF_WARNING(unused) CPPA_VOID_STMT
#endif #endif
#if CPPA_LOG_LEVEL > 1 #if CPPA_LOG_LEVEL > 1
# define CPPA_LOG_INFO(message) CPPA_DO_LOG_MEMBER_FUN("INFO ", message) # define CPPA_LOG_INFO(message) CPPA_DO_LOG_MEMBER_FUN("INFO ", message)
# define CPPA_LOGF_INFO(message) CPPA_DO_LOG_FUN("INFO ", message) # define CPPA_LOGF_INFO(message) CPPA_DO_LOG_FUN("INFO ", message)
#else #else
# define CPPA_LOG_INFO(unused) static_cast<void>(0) # define CPPA_LOG_INFO(unused) CPPA_VOID_STMT
# define CPPA_LOGF_INFO(unused) static_cast<void>(0) # define CPPA_LOGF_INFO(unused) CPPA_VOID_STMT
#endif #endif
#if CPPA_LOG_LEVEL > 2 #if CPPA_LOG_LEVEL > 2
# define CPPA_LOG_DEBUG(message) CPPA_DO_LOG_MEMBER_FUN("DEBUG ", message) # define CPPA_LOG_DEBUG(message) CPPA_DO_LOG_MEMBER_FUN("DEBUG ", message)
# define CPPA_LOGF_DEBUG(message) CPPA_DO_LOG_FUN("DEBUG ", message) # define CPPA_LOGF_DEBUG(message) CPPA_DO_LOG_FUN("DEBUG ", message)
#else #else
# define CPPA_LOG_DEBUG(unused) static_cast<void>(0) # define CPPA_LOG_DEBUG(unused) CPPA_VOID_STMT
# define CPPA_LOGF_DEBUG(unused) static_cast<void>(0) # define CPPA_LOGF_DEBUG(unused) CPPA_VOID_STMT
#endif #endif
#if CPPA_LOG_LEVEL > 3 #if CPPA_LOG_LEVEL > 3
...@@ -186,7 +192,8 @@ class logging { ...@@ -186,7 +192,8 @@ class logging {
CPPA_CONCATL(cppa_trace_helper_) << message ; \ CPPA_CONCATL(cppa_trace_helper_) << message ; \
::cppa::detail::logging::trace_helper CPPA_CONCATL(cppa_fun_trace_helper_) \ ::cppa::detail::logging::trace_helper CPPA_CONCATL(cppa_fun_trace_helper_) \
CPPA_LPAREN ::cppa::detail::demangle \ CPPA_LPAREN ::cppa::detail::demangle \
CPPA_LPAREN typeid CPPA_LPAREN *this CPPA_RPAREN CPPA_RPAREN , \ CPPA_LPAREN typeid CPPA_LPAREN decltype CPPA_LPAREN *this \
CPPA_RPAREN CPPA_RPAREN CPPA_RPAREN , \
__func__ , __FILE__ , __LINE__ , \ __func__ , __FILE__ , __LINE__ , \
CPPA_CONCATL(cppa_trace_helper_) .str() CPPA_RPAREN CPPA_CONCATL(cppa_trace_helper_) .str() CPPA_RPAREN
# define CPPA_LOGF_TRACE(message) \ # define CPPA_LOGF_TRACE(message) \
...@@ -203,28 +210,28 @@ class logging { ...@@ -203,28 +210,28 @@ class logging {
#endif #endif
#define CPPA_LOG_ERROR_IF(stmt,message) \ #define CPPA_LOG_ERROR_IF(stmt,message) \
if (stmt) { CPPA_LOG_ERROR(message); }; static_cast<void>(0) if (stmt) { CPPA_LOG_ERROR(message); }; CPPA_VOID_STMT
#define CPPA_LOG_WARNING_IF(stmt,message) \ #define CPPA_LOG_WARNING_IF(stmt,message) \
if (stmt) { CPPA_LOG_WARNING(message); }; static_cast<void>(0) if (stmt) { CPPA_LOG_WARNING(message); }; CPPA_VOID_STMT
#define CPPA_LOG_INFO_IF(stmt,message) \ #define CPPA_LOG_INFO_IF(stmt,message) \
if (stmt) { CPPA_LOG_INFO(message); }; static_cast<void>(0) if (stmt) { CPPA_LOG_INFO(message); }; CPPA_VOID_STMT
#define CPPA_LOG_DEBUG_IF(stmt,message) \ #define CPPA_LOG_DEBUG_IF(stmt,message) \
if (stmt) { CPPA_LOG_DEBUG(message); }; static_cast<void>(0) if (stmt) { CPPA_LOG_DEBUG(message); }; CPPA_VOID_STMT
#define CPPA_LOGF_ERROR_IF(stmt,message) \ #define CPPA_LOGF_ERROR_IF(stmt,message) \
if (stmt) { CPPA_LOGF_ERROR(message); }; static_cast<void>(0) if (stmt) { CPPA_LOGF_ERROR(message); }; CPPA_VOID_STMT
#define CPPA_LOGF_WARNING_IF(stmt,message) \ #define CPPA_LOGF_WARNING_IF(stmt,message) \
if (stmt) { CPPA_LOGF_WARNING(message); }; static_cast<void>(0) if (stmt) { CPPA_LOGF_WARNING(message); }; CPPA_VOID_STMT
#define CPPA_LOGF_INFO_IF(stmt,message) \ #define CPPA_LOGF_INFO_IF(stmt,message) \
if (stmt) { CPPA_LOGF_INFO(message); }; static_cast<void>(0) if (stmt) { CPPA_LOGF_INFO(message); }; CPPA_VOID_STMT
#define CPPA_LOGF_DEBUG_IF(stmt,message) \ #define CPPA_LOGF_DEBUG_IF(stmt,message) \
if (stmt) { CPPA_LOGF_DEBUG(message); }; static_cast<void>(0) if (stmt) { CPPA_LOGF_DEBUG(message); }; CPPA_VOID_STMT
#endif // CPPA_DEBUG #endif // CPPA_DEBUG
......
...@@ -50,7 +50,7 @@ class default_protocol : public protocol { ...@@ -50,7 +50,7 @@ class default_protocol : public protocol {
public: public:
default_protocol(middleman* parent); default_protocol(abstract_middleman* parent);
atom_value identifier() const; atom_value identifier() const;
......
...@@ -45,26 +45,10 @@ namespace cppa { namespace detail { class singleton_manager; } } ...@@ -45,26 +45,10 @@ namespace cppa { namespace detail { class singleton_manager; } }
namespace cppa { namespace network { namespace cppa { namespace network {
class middleman_impl;
class middleman_overseer;
class middleman_event_handler;
void middleman_loop(middleman_impl*);
class middleman { class middleman {
// the most popular class in libcppa
friend class peer;
friend class protocol;
friend class peer_acceptor;
friend class singleton_manager;
friend class middleman_overseer;
friend class middleman_event_handler;
friend class detail::singleton_manager; friend class detail::singleton_manager;
friend void middleman_loop(middleman_impl*);
public: public:
virtual ~middleman(); virtual ~middleman();
...@@ -73,54 +57,43 @@ class middleman { ...@@ -73,54 +57,43 @@ class middleman {
virtual protocol_ptr protocol(atom_value id) = 0; virtual protocol_ptr protocol(atom_value id) = 0;
protected: // runs @p fun in the middleman's event loop
virtual void run_later(std::function<void()> fun) = 0;
middleman(); protected:
virtual void stop() = 0; virtual void stop() = 0;
virtual void start() = 0; virtual void start() = 0;
// to be called from protocol private:
// runs @p fun in the middleman's event loop
virtual void run_later(std::function<void()> fun) = 0;
// to be called from singleton_manager
static middleman* create_singleton(); static middleman* create_singleton();
};
// to be called from peer class middleman_event_handler;
/** class abstract_middleman : public middleman {
* @pre ptr->as_writer() != nullptr
*/
void continue_writer(const continuable_reader_ptr& ptr);
/** public:
* @pre ptr->as_writer() != nullptr
*/
void stop_writer(const continuable_reader_ptr& ptr);
// to be called form peer_acceptor or protocol inline abstract_middleman() : m_done(false) { }
void continue_reader(const continuable_reader_ptr& what); void stop_writer(const continuable_reader_ptr& ptr);
void continue_writer(const continuable_reader_ptr& ptr);
void stop_reader(const continuable_reader_ptr& what); void stop_reader(const continuable_reader_ptr& what);
void continue_reader(const continuable_reader_ptr& what);
protected:
// to be called from m_handler or middleman_overseer
inline void quit() { m_done = true; } inline void quit() { m_done = true; }
inline bool done() const { return m_done; } inline bool done() const { return m_done; }
// member variables
bool m_done; bool m_done;
std::vector<continuable_reader_ptr> m_readers; std::vector<continuable_reader_ptr> m_readers;
std::unique_ptr<middleman_event_handler> m_handler;
middleman_event_handler& handler();
}; };
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \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 MIDDLEMAN_EVENT_HANDLER_BASE_HPP
#define MIDDLEMAN_EVENT_HANDLER_BASE_HPP
#include <vector>
#include <utility>
#include "cppa/config.hpp"
#include "cppa/network/continuable_reader.hpp"
#include "cppa/network/continuable_writer.hpp"
#include "cppa/detail/logging.hpp"
namespace cppa { namespace network {
typedef int event_bitmask;
namespace event {
static constexpr event_bitmask none = 0x00;
static constexpr event_bitmask read = 0x01;
static constexpr event_bitmask write = 0x02;
static constexpr event_bitmask both = 0x03;
static constexpr event_bitmask error = 0x04;
} // namespace event
inline const char* eb2str(event_bitmask e) {
switch (e) {
default: return "INVALID";
case event::none: return "event::none";
case event::read: return "event::read";
case event::write: return "event::write";
case event::both: return "event::both";
case event::error: return "event::error";
}
}
struct fd_meta_info {
native_socket_type fd;
continuable_reader_ptr ptr;
event_bitmask mask;
fd_meta_info(native_socket_type a0,
const continuable_reader_ptr& a1,
event_bitmask a2)
: fd(a0), ptr(a1), mask(a2) { }
};
struct fd_meta_info_less {
inline bool operator()(const fd_meta_info& lhs, native_socket_type rhs) const {
return lhs.fd < rhs;
}
};
enum class fd_meta_event { add, erase, mod };
template<typename Derived>
class middleman_event_handler_base {
public:
typedef std::vector<fd_meta_info> vector_type;
virtual ~middleman_event_handler_base() { }
void alteration(const continuable_reader_ptr& ptr,
event_bitmask e,
fd_meta_event etype) {
native_socket_type fd;
switch (e) {
case event::read:
fd = ptr->read_handle();
break;
case event::write: {
auto wptr = ptr->as_writer();
if (wptr) fd = wptr->write_handle();
else {
CPPA_LOG_ERROR("ptr->as_writer() returned nullptr");
return;
}
break;
}
case event::both: {
fd = ptr->read_handle();
auto wptr = ptr->as_writer();
if (wptr) {
auto wrfd = wptr->write_handle();
if (fd != wrfd) {
CPPA_LOG_DEBUG("read_handle != write_handle, split "
"into two function calls");
// split into two function calls
e = event::read;
alteration(ptr, event::write, etype);
}
}
else {
CPPA_LOG_ERROR("ptr->as_writer() returned nullptr");
return;
}
break;
}
default:
CPPA_LOG_ERROR("invalid bitmask");
return;
}
m_alterations.emplace_back(fd_meta_info(fd, ptr, e), etype);
}
void add(const continuable_reader_ptr& ptr, event_bitmask e) {
CPPA_LOG_TRACE("ptr = " << ptr.get() << ", e = " << eb2str(e));
alteration(ptr, e, fd_meta_event::add);
}
void erase(const continuable_reader_ptr& ptr, event_bitmask e) {
CPPA_LOG_TRACE("ptr = " << ptr.get() << ", e = " << eb2str(e));
alteration(ptr, e, fd_meta_event::erase);
}
inline event_bitmask next_bitmask(event_bitmask old, event_bitmask arg, fd_meta_event op) {
CPPA_REQUIRE(op == fd_meta_event::add || op == fd_meta_event::erase);
return (op == fd_meta_event::add) ? old | arg : old & ~arg;
}
void update() {
CPPA_LOG_TRACE("");
for (auto& elem_pair : m_alterations) {
auto& elem = elem_pair.first;
auto old = event::none;
auto last = end(m_meta);
auto iter = lower_bound(begin(m_meta), last, elem.fd, m_less);
if (iter != last) old = iter->mask;
auto mask = next_bitmask(old, elem.mask, elem_pair.second);
auto ptr = elem.ptr.get();
CPPA_LOG_DEBUG("new bitmask for "
<< elem.ptr.get() << ": " << eb2str(mask));
if (iter == last || iter->fd != elem.fd) {
CPPA_LOG_INFO_IF(mask == event::none,
"cannot erase " << ptr
<< " (not found in m_meta)");
if (mask != event::none) {
m_meta.insert(iter, elem);
d()->handle_event(fd_meta_event::add, elem.fd,
event::none, mask, ptr);
}
}
else if (iter->fd == elem.fd) {
CPPA_REQUIRE(iter->ptr == elem.ptr);
if (mask == event::none) {
m_meta.erase(iter);
d()->handle_event(fd_meta_event::erase, elem.fd, old, mask, ptr);
}
else {
iter->mask = mask;
d()->handle_event(fd_meta_event::mod, elem.fd, old, mask, ptr);
}
}
}
m_alterations.clear();
}
protected:
fd_meta_info_less m_less;
vector_type m_meta; // this vector is *always* sorted
std::vector<std::pair<fd_meta_info,fd_meta_event> > m_alterations;
private:
vector_type::iterator find_meta(native_socket_type fd) {
auto last = end(m_meta);
auto iter = lower_bound(begin(m_meta), last, fd, m_less);
return (iter != last && iter->fd == fd) ? iter : last;
}
Derived* d() { return static_cast<Derived*>(this); }
};
template<class BaseIter, class BasIterAccess>
class event_iterator_impl {
public:
event_iterator_impl(const BaseIter& iter) : m_i(iter) { }
inline event_iterator_impl& operator++() {
m_access.advance(m_i);
return *this;
}
inline event_iterator_impl* operator->() { return this; }
inline const event_iterator_impl* operator->() const { return this; }
inline event_bitmask type() const {
return m_access.type(m_i);
}
inline continue_reading_result continue_reading() {
return ptr()->continue_reading();
}
inline continue_writing_result continue_writing() {
return ptr()->as_writer()->continue_writing();
}
inline bool equal_to(const event_iterator_impl& other) const {
return m_access.equal(m_i, other.m_i);
}
inline void handled() { m_access.handled(m_i); }
inline continuable_reader* ptr() { return m_access.ptr(m_i); }
private:
BaseIter m_i;
BasIterAccess m_access;
};
template<class Iter, class Access>
inline bool operator==(const event_iterator_impl<Iter,Access>& lhs,
const event_iterator_impl<Iter,Access>& rhs) {
return lhs.equal_to(rhs);
}
template<class Iter, class Access>
inline bool operator!=(const event_iterator_impl<Iter,Access>& lhs,
const event_iterator_impl<Iter,Access>& rhs) {
return !lhs.equal_to(rhs);
}
} } // namespace cppa::detail
#endif // MIDDLEMAN_EVENT_HANDLER_BASE_HPP
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
namespace cppa { namespace network { namespace cppa { namespace network {
class middleman; class abstract_middleman;
class continuable_reader; class continuable_reader;
class continuable_writer; class continuable_writer;
...@@ -56,7 +56,7 @@ class protocol : public ref_counted { ...@@ -56,7 +56,7 @@ class protocol : public ref_counted {
typedef std::initializer_list<primitive_variant> variant_args; typedef std::initializer_list<primitive_variant> variant_args;
protocol(middleman* parent); protocol(abstract_middleman* parent);
virtual atom_value identifier() const = 0; virtual atom_value identifier() const = 0;
...@@ -89,13 +89,13 @@ class protocol : public ref_counted { ...@@ -89,13 +89,13 @@ class protocol : public ref_counted {
// note: not thread-safe; call only in run_later functor! // note: not thread-safe; call only in run_later functor!
void stop_writer(continuable_reader* what); void stop_writer(continuable_reader* what);
inline middleman* parent() { return m_parent; } inline abstract_middleman* parent() { return m_parent; }
inline const middleman* parent() const { return m_parent; } inline const abstract_middleman* parent() const { return m_parent; }
private: private:
middleman* m_parent; abstract_middleman* m_parent;
}; };
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \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/>. *
\******************************************************************************/
#include"cppa/actor_addressing.hpp"
namespace cppa {
actor_addressing::~actor_addressing() { }
} // namespace cppa
...@@ -55,16 +55,13 @@ default_actor_proxy::~default_actor_proxy() { ...@@ -55,16 +55,13 @@ default_actor_proxy::~default_actor_proxy() {
CPPA_LOGF_TRACE("lambda from ~default_actor_proxy" CPPA_LOGF_TRACE("lambda from ~default_actor_proxy"
<< "; node = " << to_string(*node) << ", aid " << aid << "; node = " << to_string(*node) << ", aid " << aid
<< ", proto = " << to_string(proto->identifier())); << ", proto = " << to_string(proto->identifier()));
if (detail::singleton_manager::get_middleman()) { proto->addressing()->erase(*node, aid);
proto->addressing()->erase(*node, aid); auto p = proto->get_peer(*node);
auto p = proto->get_peer(*node); if (p && p->erase_on_last_proxy_exited()) {
if (p && p->erase_on_last_proxy_exited()) { if (proto->addressing()->count_proxies(*node) == 0) {
if (proto->addressing()->count_proxies(*node) == 0) { proto->erase_peer(p);
proto->erase_peer(p);
}
} }
} }
// else: middleman already shut down!
}); });
} }
......
...@@ -52,7 +52,7 @@ using namespace cppa::detail; ...@@ -52,7 +52,7 @@ using namespace cppa::detail;
namespace cppa { namespace network { namespace cppa { namespace network {
default_protocol::default_protocol(middleman* parent) default_protocol::default_protocol(abstract_middleman* parent)
: super(parent), m_addressing(this) { } : super(parent), m_addressing(this) { }
atom_value default_protocol::identifier() const { atom_value default_protocol::identifier() const {
......
...@@ -56,6 +56,7 @@ ...@@ -56,6 +56,7 @@
#include "cppa/network/output_stream.hpp" #include "cppa/network/output_stream.hpp"
#include "cppa/network/default_protocol.hpp" #include "cppa/network/default_protocol.hpp"
#include "cppa/network/addressed_message.hpp" #include "cppa/network/addressed_message.hpp"
#include "cppa/network/middleman_event_handler_base.hpp"
#include "cppa/detail/logging.hpp" #include "cppa/detail/logging.hpp"
#include "cppa/detail/fd_util.hpp" #include "cppa/detail/fd_util.hpp"
...@@ -79,394 +80,6 @@ using namespace std; ...@@ -79,394 +80,6 @@ using namespace std;
namespace cppa { namespace network { namespace cppa { namespace network {
namespace {
const size_t ui32_size = sizeof(uint32_t);
template<class Container, class Element>
void erase_from(Container& haystack, const Element& needle) {
typedef typename Container::value_type value_type;
auto last = end(haystack);
auto i = find_if(begin(haystack), last, [&](const value_type& value) {
return value == needle;
});
if (i != last) haystack.erase(i);
}
template<class Container, class UnaryPredicate>
void erase_from_if(Container& container, const UnaryPredicate& predicate) {
auto last = end(container);
auto i = find_if(begin(container), last, predicate);
if (i != last) container.erase(i);
}
class middleman_event {
friend class intrusive::single_reader_queue<middleman_event>;
public:
template<typename Arg>
middleman_event(Arg&& arg) : next(0), fun(forward<Arg>(arg)) { }
inline void operator()() { fun(); }
private:
middleman_event* next;
function<void()> fun;
};
typedef intrusive::single_reader_queue<middleman_event> middleman_queue;
} // namespace <anonymous>
class middleman_impl : public middleman {
friend void middleman_loop(middleman_impl*);
public:
middleman_impl() {
m_protocols.insert(make_pair(atom("DEFAULT"),
new network::default_protocol(this)));
}
void add_protocol(const protocol_ptr& impl) {
if (!impl) {
CPPA_LOG_ERROR("impl == nullptr");
throw std::invalid_argument("impl == nullptr");
}
CPPA_LOG_TRACE("identifier = " << to_string(impl->identifier()));
std::lock_guard<util::shared_spinlock> guard(m_protocols_lock);
m_protocols.insert(make_pair(impl->identifier(), impl));
}
protocol_ptr protocol(atom_value id) {
util::shared_lock_guard<util::shared_spinlock> guard(m_protocols_lock);
auto i = m_protocols.find(id);
return (i != m_protocols.end()) ? i->second : nullptr;
}
void run_later(function<void()> fun) {
CPPA_LOG_TRACE("");
m_queue._push_back(new middleman_event(move(fun)));
atomic_thread_fence(memory_order_seq_cst);
uint8_t dummy = 0;
if (write(m_pipe_write, &dummy, sizeof(dummy)) != sizeof(dummy)) {
CPPA_CRITICAL("cannot write to pipe");
}
}
protected:
void start() {
int pipefds[2];
if (pipe(pipefds) != 0) { CPPA_CRITICAL("cannot create pipe"); }
m_pipe_read = pipefds[0];
m_pipe_write = pipefds[1];
detail::fd_util::nonblocking(m_pipe_read, true);
// start threads
m_thread = thread([this] { middleman_loop(this); });
}
void stop() {
run_later([this] { this->m_done = true; });
//enqueue_message(middleman_message::create());
m_thread.join();
close(m_pipe_read);
close(m_pipe_write);
}
private:
thread m_thread;
native_socket_type m_pipe_read;
native_socket_type m_pipe_write;
middleman_queue m_queue;
util::shared_spinlock m_protocols_lock;
map<atom_value,protocol_ptr> m_protocols;
};
middleman* middleman::create_singleton() {
return new middleman_impl;
}
class middleman_overseer : public continuable_reader {
typedef continuable_reader super;
public:
middleman_overseer(int pipe_fd, middleman_queue& q)
: super(pipe_fd), m_queue(q) { }
continue_reading_result continue_reading() {
static constexpr size_t num_dummies = 64;
uint8_t dummies[num_dummies];
auto read_result = ::read(read_handle(), dummies, num_dummies);
if (read_result < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
// try again later
return read_continue_later;
}
else {
CPPA_LOG_ERROR("cannot read from pipe");
CPPA_CRITICAL("cannot read from pipe");
}
}
atomic_thread_fence(memory_order_seq_cst);
for (int i = 0; i < read_result; ++i) {
unique_ptr<middleman_event> msg(m_queue.try_pop());
if (!msg) {
CPPA_LOG_ERROR("nullptr dequeued");
CPPA_CRITICAL("nullptr dequeued");
}
(*msg)();
}
return read_continue_later;
}
private:
middleman_queue& m_queue;
};
typedef int event_bitmask;
namespace event {
static constexpr event_bitmask none = 0x00;
static constexpr event_bitmask read = 0x01;
static constexpr event_bitmask write = 0x02;
static constexpr event_bitmask both = 0x03;
static constexpr event_bitmask error = 0x04;
} // namespace event
inline const char* eb2str(event_bitmask e) {
switch (e) {
default: return "INVALID";
case event::none: return "event::none";
case event::read: return "event::read";
case event::write: return "event::write";
case event::both: return "event::both";
case event::error: return "event::error";
}
}
struct fd_meta_info {
native_socket_type fd;
continuable_reader_ptr ptr;
event_bitmask mask;
fd_meta_info(native_socket_type a0,
const continuable_reader_ptr& a1,
event_bitmask a2)
: fd(a0), ptr(a1), mask(a2) { }
};
enum class fd_meta_event { add, erase, mod };
struct fd_less {
inline bool operator()(const fd_meta_info& lhs, native_socket_type rhs) const {
return lhs.fd < rhs;
}
};
class middleman_event_handler_base {
public:
typedef vector<fd_meta_info> vector_type;
virtual ~middleman_event_handler_base() { }
void alteration(const continuable_reader_ptr& ptr, event_bitmask e, fd_meta_event etype) {
native_socket_type fd;
switch (e) {
case event::read:
fd = ptr->read_handle();
break;
case event::write: {
auto wptr = ptr->as_writer();
if (wptr) fd = wptr->write_handle();
else {
CPPA_LOG_ERROR("ptr->as_writer() returned nullptr");
return;
}
break;
}
case event::both: {
fd = ptr->read_handle();
auto wptr = ptr->as_writer();
if (wptr) {
auto wrfd = wptr->write_handle();
if (fd != wrfd) {
CPPA_LOG_DEBUG("read_handle != write_handle, split "
"into two function calls");
// split into two function calls
e = event::read;
alteration(ptr, event::write, etype);
}
}
else {
CPPA_LOG_ERROR("ptr->as_writer() returned nullptr");
return;
}
break;
}
default:
CPPA_LOG_ERROR("invalid bitmask");
return;
}
/*
auto last = end(m_meta);
auto iter = find_meta(fd);
CPPA_LOG_ERROR_IF(iter == last && e == event::none,
"nothing to delete (no match)");
event_bitmask old = (iter != last) ? iter->mask : event::none;
auto next = cm(old, e);
if (next != old) {
m_alterations.emplace_back(fd, ptr, next);
}
*/
m_alterations.emplace_back(fd_meta_info(fd, ptr, e), etype);
}
void add(const continuable_reader_ptr& ptr, event_bitmask e) {
CPPA_LOG_TRACE("ptr = " << ptr.get() << ", e = " << eb2str(e));
alteration(ptr, e, fd_meta_event::add);
}
void erase(const continuable_reader_ptr& ptr, event_bitmask e) {
CPPA_LOG_TRACE("ptr = " << ptr.get() << ", e = " << eb2str(e));
alteration(ptr, e, fd_meta_event::erase);
}
inline event_bitmask next_bitmask(event_bitmask old, event_bitmask arg, fd_meta_event op) {
CPPA_REQUIRE(op == fd_meta_event::add || op == fd_meta_event::erase);
return (op == fd_meta_event::add) ? old | arg : old & ~arg;
}
void update() {
CPPA_LOG_TRACE("");
for (auto& elem_pair : m_alterations) {
auto& elem = elem_pair.first;
auto old = event::none;
auto last = end(m_meta);
auto iter = lower_bound(begin(m_meta), last, elem.fd, m_less);
if (iter != last) old = iter->mask;
auto mask = next_bitmask(old, elem.mask, elem_pair.second);
auto ptr = elem.ptr.get();
CPPA_LOG_DEBUG("new bitmask for "
<< elem.ptr.get() << ": " << eb2str(mask));
if (iter == last || iter->fd != elem.fd) {
CPPA_LOG_INFO_IF(mask == event::none,
"cannot erase " << ptr
<< " (not found in m_meta)");
if (mask != event::none) {
m_meta.insert(iter, elem);
handle_event(fd_meta_event::add, elem.fd,
event::none, mask, ptr);
}
}
else if (iter->fd == elem.fd) {
CPPA_REQUIRE(iter->ptr == elem.ptr);
if (mask == event::none) {
m_meta.erase(iter);
handle_event(fd_meta_event::erase, elem.fd, old, mask, ptr);
}
else {
iter->mask = mask;
handle_event(fd_meta_event::mod, elem.fd, old, mask, ptr);
}
}
}
m_alterations.clear();
}
protected:
virtual void handle_event(fd_meta_event me,
native_socket_type fd,
event_bitmask old_bitmask,
event_bitmask new_bitmask,
continuable_reader* ptr) = 0;
fd_less m_less;
vector_type m_meta; // this vector is *always* sorted
vector<pair<fd_meta_info,fd_meta_event> > m_alterations;
private:
vector_type::iterator find_meta(native_socket_type fd) {
auto last = end(m_meta);
auto iter = lower_bound(begin(m_meta), last, fd, m_less);
return (iter != last && iter->fd == fd) ? iter : last;
}
};
template<class BaseIter, class BasIterAccess>
class event_iterator_impl {
public:
event_iterator_impl(const BaseIter& iter) : m_i(iter) { }
inline event_iterator_impl& operator++() {
m_access.advance(m_i);
return *this;
}
inline event_iterator_impl* operator->() { return this; }
inline const event_iterator_impl* operator->() const { return this; }
inline event_bitmask type() const {
return m_access.type(m_i);
}
inline continue_reading_result continue_reading() {
return ptr()->continue_reading();
}
inline continue_writing_result continue_writing() {
return ptr()->as_writer()->continue_writing();
}
inline bool equal_to(const event_iterator_impl& other) const {
return m_access.equal(m_i, other.m_i);
}
inline void handled() { m_access.handled(m_i); }
inline continuable_reader* ptr() { return m_access.ptr(m_i); }
private:
BaseIter m_i;
BasIterAccess m_access;
};
template<class Iter, class Access>
inline bool operator==(const event_iterator_impl<Iter,Access>& lhs,
const event_iterator_impl<Iter,Access>& rhs) {
return lhs.equal_to(rhs);
}
template<class Iter, class Access>
inline bool operator!=(const event_iterator_impl<Iter,Access>& lhs,
const event_iterator_impl<Iter,Access>& rhs) {
return !lhs.equal_to(rhs);
}
#ifdef CPPA_POLL_IMPL #ifdef CPPA_POLL_IMPL
typedef pair<vector<pollfd>::iterator,vector<fd_meta_info>::iterator> typedef pair<vector<pollfd>::iterator,vector<fd_meta_info>::iterator>
...@@ -507,7 +120,7 @@ struct pfd_access { ...@@ -507,7 +120,7 @@ struct pfd_access {
typedef event_iterator_impl<pfd_iterator,pfd_access> event_iterator; typedef event_iterator_impl<pfd_iterator,pfd_access> event_iterator;
struct pollfd_less { struct pollfd_meta_info_less {
inline bool operator()(const pollfd& lhs, native_socket_type rhs) const { inline bool operator()(const pollfd& lhs, native_socket_type rhs) const {
return lhs.fd < rhs; return lhs.fd < rhs;
} }
...@@ -522,7 +135,7 @@ short to_poll_bitmask(event_bitmask mask) { ...@@ -522,7 +135,7 @@ short to_poll_bitmask(event_bitmask mask) {
} }
} }
class middleman_event_handler : public middleman_event_handler_base { class middleman_event_handler : public middleman_event_handler_base<middleman_event_handler> {
public: public:
...@@ -562,8 +175,6 @@ class middleman_event_handler : public middleman_event_handler_base { ...@@ -562,8 +175,6 @@ class middleman_event_handler : public middleman_event_handler_base {
} }
} }
protected:
void handle_event(fd_meta_event me, void handle_event(fd_meta_event me,
native_socket_type fd, native_socket_type fd,
event_bitmask old_bitmask, event_bitmask old_bitmask,
...@@ -614,7 +225,7 @@ class middleman_event_handler : public middleman_event_handler_base { ...@@ -614,7 +225,7 @@ class middleman_event_handler : public middleman_event_handler_base {
} }
vector<pollfd> m_pollset; // always in sync with m_meta vector<pollfd> m_pollset; // always in sync with m_meta
pollfd_less m_pless; pollfd_meta_info_less m_pless;
}; };
...@@ -651,7 +262,7 @@ struct epoll_iterator_access { ...@@ -651,7 +262,7 @@ struct epoll_iterator_access {
typedef event_iterator_impl<vector<epoll_event>::iterator,epoll_iterator_access> typedef event_iterator_impl<vector<epoll_event>::iterator,epoll_iterator_access>
event_iterator; event_iterator;
class middleman_event_handler : public middleman_event_handler_base { class middleman_event_handler : public middleman_event_handler_base<middleman_event_handler> {
public: public:
...@@ -700,9 +311,6 @@ class middleman_event_handler : public middleman_event_handler_base { ...@@ -700,9 +311,6 @@ class middleman_event_handler : public middleman_event_handler_base {
} }
} }
protected:
void handle_event(fd_meta_event me, void handle_event(fd_meta_event me,
native_socket_type fd, native_socket_type fd,
event_bitmask old_bitmask, event_bitmask old_bitmask,
...@@ -762,6 +370,8 @@ class middleman_event_handler : public middleman_event_handler_base { ...@@ -762,6 +370,8 @@ class middleman_event_handler : public middleman_event_handler_base {
} }
} }
private:
int m_epollfd; int m_epollfd;
vector<epoll_event> m_events; vector<epoll_event> m_events;
...@@ -769,36 +379,179 @@ class middleman_event_handler : public middleman_event_handler_base { ...@@ -769,36 +379,179 @@ class middleman_event_handler : public middleman_event_handler_base {
#endif #endif
middleman::middleman() : m_done(false), m_handler(new middleman_event_handler){} class middleman_event {
friend class intrusive::single_reader_queue<middleman_event>;
public:
template<typename Arg>
middleman_event(Arg&& arg) : next(0), fun(forward<Arg>(arg)) { }
inline void operator()() { fun(); }
private:
middleman_event* next;
function<void()> fun;
};
typedef intrusive::single_reader_queue<middleman_event> middleman_queue;
class middleman_impl : public abstract_middleman {
friend class abstract_middleman;
friend void middleman_loop(middleman_impl*);
public:
middleman_impl() {
m_protocols.insert(make_pair(atom("DEFAULT"),
new network::default_protocol(this)));
}
void add_protocol(const protocol_ptr& impl) {
if (!impl) {
CPPA_LOG_ERROR("impl == nullptr");
throw std::invalid_argument("impl == nullptr");
}
CPPA_LOG_TRACE("identifier = " << to_string(impl->identifier()));
std::lock_guard<util::shared_spinlock> guard(m_protocols_lock);
m_protocols.insert(make_pair(impl->identifier(), impl));
}
protocol_ptr protocol(atom_value id) {
util::shared_lock_guard<util::shared_spinlock> guard(m_protocols_lock);
auto i = m_protocols.find(id);
return (i != m_protocols.end()) ? i->second : nullptr;
}
void run_later(function<void()> fun) {
CPPA_LOG_TRACE("");
m_queue._push_back(new middleman_event(move(fun)));
atomic_thread_fence(memory_order_seq_cst);
uint8_t dummy = 0;
if (write(m_pipe_write, &dummy, sizeof(dummy)) != sizeof(dummy)) {
CPPA_CRITICAL("cannot write to pipe");
}
}
protected:
void start() {
int pipefds[2];
if (pipe(pipefds) != 0) { CPPA_CRITICAL("cannot create pipe"); }
m_pipe_read = pipefds[0];
m_pipe_write = pipefds[1];
detail::fd_util::nonblocking(m_pipe_read, true);
// start threads
m_thread = thread([this] { middleman_loop(this); });
}
void stop() {
run_later([this] { this->m_done = true; });
//enqueue_message(middleman_message::create());
m_thread.join();
close(m_pipe_read);
close(m_pipe_write);
}
private:
thread m_thread;
native_socket_type m_pipe_read;
native_socket_type m_pipe_write;
middleman_queue m_queue;
middleman_event_handler m_handler;
util::shared_spinlock m_protocols_lock;
map<atom_value,protocol_ptr> m_protocols;
};
middleman* middleman::create_singleton() {
return new middleman_impl;
}
class middleman_overseer : public continuable_reader {
typedef continuable_reader super;
public:
middleman_overseer(int pipe_fd, middleman_queue& q)
: super(pipe_fd), m_queue(q) { }
continue_reading_result continue_reading() {
static constexpr size_t num_dummies = 64;
uint8_t dummies[num_dummies];
auto read_result = ::read(read_handle(), dummies, num_dummies);
if (read_result < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
// try again later
return read_continue_later;
}
else {
CPPA_LOG_ERROR("cannot read from pipe");
CPPA_CRITICAL("cannot read from pipe");
}
}
atomic_thread_fence(memory_order_seq_cst);
for (int i = 0; i < read_result; ++i) {
unique_ptr<middleman_event> msg(m_queue.try_pop());
if (!msg) {
CPPA_LOG_ERROR("nullptr dequeued");
CPPA_CRITICAL("nullptr dequeued");
}
(*msg)();
}
return read_continue_later;
}
private:
middleman_queue& m_queue;
};
middleman::~middleman() { } middleman::~middleman() { }
void middleman::continue_writer(const continuable_reader_ptr& ptr) { middleman_event_handler& abstract_middleman::handler() {
return static_cast<middleman_impl*>(this)->m_handler;
}
void abstract_middleman::continue_writer(const continuable_reader_ptr& ptr) {
CPPA_LOG_TRACE("ptr = " << ptr.get()); CPPA_LOG_TRACE("ptr = " << ptr.get());
CPPA_REQUIRE(ptr->as_writer() != nullptr); CPPA_REQUIRE(ptr->as_writer() != nullptr);
m_handler->add(ptr, event::write); handler().add(ptr, event::write);
} }
void middleman::stop_writer(const continuable_reader_ptr& ptr) { void abstract_middleman::stop_writer(const continuable_reader_ptr& ptr) {
CPPA_LOG_TRACE("ptr = " << ptr.get()); CPPA_LOG_TRACE("ptr = " << ptr.get());
CPPA_REQUIRE(ptr->as_writer() != nullptr); CPPA_REQUIRE(ptr->as_writer() != nullptr);
m_handler->erase(ptr, event::write); handler().erase(ptr, event::write);
} }
void middleman::continue_reader(const continuable_reader_ptr& ptr) { void abstract_middleman::continue_reader(const continuable_reader_ptr& ptr) {
CPPA_LOG_TRACE("ptr = " << ptr.get()); CPPA_LOG_TRACE("ptr = " << ptr.get());
m_readers.push_back(ptr); m_readers.push_back(ptr);
m_handler->add(ptr, event::read); handler().add(ptr, event::read);
} }
void middleman::stop_reader(const continuable_reader_ptr& ptr) { void abstract_middleman::stop_reader(const continuable_reader_ptr& ptr) {
CPPA_LOG_TRACE("ptr = " << ptr.get()); CPPA_LOG_TRACE("ptr = " << ptr.get());
m_handler->erase(ptr, event::read); handler().erase(ptr, event::read);
erase_from(m_readers, ptr);
auto last = end(m_readers);
auto i = find_if(begin(m_readers), last, [ptr](const continuable_reader_ptr& value) {
return value == ptr;
});
if (i != last) m_readers.erase(i);
} }
void middleman_loop(middleman_impl* impl) { void middleman_loop(middleman_impl* impl) {
middleman_event_handler* handler = impl->m_handler.get(); middleman_event_handler* handler = &impl->m_handler;
CPPA_LOGF_TRACE("run middleman loop, node: " CPPA_LOGF_TRACE("run middleman loop, node: "
<< to_string(*process_information::get())); << to_string(*process_information::get()));
handler->init(); handler->init();
......
...@@ -35,7 +35,7 @@ ...@@ -35,7 +35,7 @@
namespace cppa { namespace network { namespace cppa { namespace network {
protocol::protocol(middleman* parent) : m_parent(parent) { } protocol::protocol(abstract_middleman* parent) : m_parent(parent) { }
void protocol::run_later(std::function<void()> fun) { void protocol::run_later(std::function<void()> fun) {
m_parent->run_later([=] { fun(); }); m_parent->run_later([=] { fun(); });
......
...@@ -371,7 +371,6 @@ class string_deserializer : public deserializer { ...@@ -371,7 +371,6 @@ class string_deserializer : public deserializer {
throw_malformed("atom string size > 10"); throw_malformed("atom string size > 10");
} }
string substr(m_pos, substr_end); string substr(m_pos, substr_end);
std::cout << "atom string: " << substr << std::endl;
m_pos += substr.size() + 1; m_pos += substr.size() + 1;
return detail::atom_val(substr.c_str(), 0xF); return detail::atom_val(substr.c_str(), 0xF);
} }
......
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