📄 custom_event_handler.hpp
字号:
{
return m_ceh->handle_callback_timeout(current_time, const_cast<void*>(arg));
}
private:
custom_event_handler *const m_ceh;
private:
callback_hook(callback_hook const &);
callback_hook &operator =(callback_hook const &);
};
friend class callback_hook;
// Each entry consists of the notification code and the actual arg
struct event_info
{
long code; //!< The event code
void *arg; //!< The custom event argument
event_id id; //!< The id of the event registered in the reactor
event_info(long code_, void *arg_)
: code(code_)
, arg(arg_)
, id(NULL)
{}
};
typedef ::stlsoft::shared_ptr<event_info> info_ptr;
// receiver of the callback hook's handle_timeout call,
int handle_callback_timeout(ACE_Time_Value const ¤t_time
, void *arg);
// This is used to avoid compiler warnings about using 'this' in member
// initialiser lists
class_type *get_this_()
{
return this;
}
// Invariant
as_bool_t is_valid() const;
//
event_id schedule_event_(event_info *entry, ACE_Time_Value const &delay);
as_int_t cancel_event_(event_id );
// Members
private:
// There are two maps.
//
// 1. The long=>event_info* map is used for registration/deregistration. Because
// it owns the entries it uses the associative_container_veneer
//
// 2. The event_info*=>long map is used
typedef ::std::map<event_id, info_ptr> event_map_type;
typedef ::std::map<long, event_map_type> event_code_map_type;
callback_hook m_callbackHook;
event_code_map_type m_entries;
// Not to be implemented
private:
custom_event_handler(class_type const &);
class_type &operator =(class_type const &);
};
////////////////////////////////////////////////////////////////////////////
/// @} // acestl_messaging_library
////////////////////////////////////////////////////////////////////////////
// Unit-testing
#ifdef STLSOFT_UNITTEST
# include "./unittest/custom_event_handler_unittest_.h"
#endif /* STLSOFT_UNITTEST */
/* /////////////////////////////////////////////////////////////////////////
* Implementation
*/
#ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
#ifdef STLSOFT_COMPILER_IS_MSVC
# if _MSC_VER >= 1200
# pragma warning(push)
# endif /* compiler */
# pragma warning(disable : 4702)
#endif /* compiler */
inline custom_event_handler::event_id custom_event_handler::schedule_event_(event_info *entry, ACE_Time_Value const &delay)
{
long timerId = m_callbackHook.reactor()->schedule_timer(&m_callbackHook, entry, delay);
ACESTL_MESSAGE_ASSERT("Unexpected negative value", timerId >= -1 || -1 == timerId);
return (-1 == timerId) ? NULL : reinterpret_cast<event_id>(static_cast<as_size_t>(1 + timerId));
}
inline as_int_t custom_event_handler::cancel_event_(custom_event_handler::event_id id)
{
ACESTL_ASSERT(NULL != id);
return m_callbackHook.reactor()->cancel_timer(static_cast<long>(reinterpret_cast<as_size_t>(id - 1)));
}
inline as_bool_t custom_event_handler::is_valid() const
{
return true;
}
inline custom_event_handler::custom_event_handler( ACE_Reactor *reactor /* = ACE_Reactor::instance() */
, int priority /* = ACE_Event_Handler::LO_PRIORITY */)
: parent_class_type(reactor, priority)
, m_callbackHook(get_this_(), reactor, priority)
{
ACESTL_ASSERT(NULL != reactor);
ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());
}
inline custom_event_handler::~custom_event_handler() stlsoft_throw_0()
{
ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());
ACESTL_MESSAGE_ASSERT("Custom event handler destroyed with outstanding entries: derived classes should cancel all notifications", m_entries.empty());
}
inline custom_event_handler::event_id custom_event_handler::schedule_custom_event(long code, ACE_Time_Value const &delay, void *arg /* = 0 */)
{
ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());
// Create an event, and then schedule it.
event_info *entry_;
ACE_NEW_NORETURN(entry_, event_info(code, arg));
if(NULL == entry_)
{
ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());
ACE_ERROR_RETURN( ( LM_ALERT
, ACE_TEXT("(%P|%t) out of memory"))
, 0);
}
else
{
info_ptr entry(entry_);
event_id timerId = schedule_event_(entry.get(), delay);
if(NULL == timerId)
{
ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());
ACE_ERROR_RETURN( ( LM_ALERT
, ACE_TEXT("(%P|%t) timer registration failed"))
, 0);
}
else
{
entry->id = timerId;
try
{
// Benign if leaves code but fails to add event
m_entries[code][timerId] = entry;
}
catch(std::bad_alloc &) // This clause is fine, since if bad_alloc not thrown, no foul
{
cancel_event_(timerId);
ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());
ACE_OS::last_error(ENOMEM);
ACE_ERROR_RETURN( ( LM_ALERT
, ACE_TEXT("(%P|%t) out of memory"))
, 0);
}
catch(std::exception &x)
{
cancel_event_(timerId);
ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());
ACE_ERROR_RETURN( ( LM_ALERT
, ACE_TEXT("(%P|%t) event scheduling failed: %s")
, x.what())
, 0);
}
ACESTL_MESSAGE_ASSERT("event not in handler", this->has_custom_event(timerId));
ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());
return timerId;
}
}
}
inline custom_event_handler::event_id custom_event_handler::schedule_custom_event(long code, void *arg /* = 0 */)
{
ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());
return schedule_custom_event(code, ACE_Time_Value(0), arg);
}
inline int custom_event_handler::cancel_custom_events(long code, custom_event_handler::cancelled_event_code_fn pfn, void *param)
{
ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());
event_code_map_type::iterator it = m_entries.find(code);
if(m_entries.end() == it)
{
ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());
return 0;
}
else
{
// Now need to cancel the timers for all the events in the code map
event_map_type &codes = (*it).second;
event_map_type::iterator begin = codes.begin();
event_map_type::iterator end = codes.end();
as_int_t n;
for(n = 0; begin != end; ++begin)
{
info_ptr entry = (*begin).second;
if(NULL != pfn)
{
(*pfn)(param, entry->code, entry->id, entry->arg);
}
if(cancel_event_(entry->id))
{
++n;
}
}
m_entries.erase(it);
ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());
return n;
}
}
inline int custom_event_handler::cancel_custom_events(long code)
{
return cancel_custom_events(code, NULL, NULL);
}
inline int custom_event_handler::cancel_custom_event(custom_event_handler::event_id event, void **parg /* = NULL */)
{
ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());
/// TODO: Maybe improve the performance of this later, perhaps by having a second map of id=>entry
event_code_map_type::iterator be = m_entries.begin();
event_code_map_type::iterator ee = m_entries.end();
for(; be != ee; ++be)
{
event_map_type &event_map = (*be).second;
event_map_type::iterator it = event_map.find(event);
if(event_map.end() != it)
{
if(NULL != parg)
{
*parg = (*it).second->arg;
}
event_map.erase(it);
return cancel_event_(event);
}
}
return 0;
}
inline as_int_t custom_event_handler::has_custom_event(long code) const
{
ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());
event_code_map_type::const_iterator it = m_entries.find(code);
return (m_entries.end() != it) ? static_cast<as_int_t>((*it).second.size()) : 0;
}
inline as_int_t custom_event_handler::has_custom_event(event_id event) const
{
ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());
/// TODO: Maybe improve the performance of this later, perhaps by having a second map of id=>entry
event_code_map_type::const_iterator be = m_entries.begin();
event_code_map_type::const_iterator ee = m_entries.end();
for(; be != ee; ++be)
{
event_map_type const &event_map = (*be).second;
event_map_type::const_iterator it = event_map.find(event);
if(event_map.end() != it)
{
return 1;
}
}
return 0;
}
inline int custom_event_handler::handle_callback_timeout(ACE_Time_Value const ¤t_time, void *arg)
{
ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());
event_info const *entry = static_cast<event_info const*>(arg);
event_code_map_type::iterator itc = m_entries.find(entry->code);
// Is it one of ours?
if(m_entries.end() == itc)
{
ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());
ACE_ERROR_RETURN( ( LM_ALERT
, ACE_TEXT("(%P|%t) could not locate callback entry for that code"))
, 0); // NOTE: returns 0, so as not to cause the event handler to be de-registered
}
else
{
ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());
// Yes it is. So ...
event_map_type &event_map = (*itc).second;
event_map_type::iterator ite = event_map.find(entry->id);
ACESTL_ASSERT(event_map.end() != ite);
// ... keep the entry alive, and ...
info_ptr ep = (*ite).second;
// ... we erase the entry, and ...
event_map.erase(ite);
// ... check whether we need to erase the entries map, and ...
if(event_map.empty())
{
m_entries.erase(itc);
}
ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());
// ... then call the handler
return this->handle_custom_event(current_time, entry->code, entry->arg);
}
}
#ifdef STLSOFT_COMPILER_IS_MSVC
# if _MSC_VER >= 1200
# pragma warning(push)
# else /* ? compiler */
# pragma warning(default : 4702)
# endif /* _MSC_VER */
#endif /* compiler */
#endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
/* ////////////////////////////////////////////////////////////////////// */
#ifndef _ACESTL_NO_NAMESPACE
# if defined(_STLSOFT_NO_NAMESPACE) || \
defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
} // namespace acestl
# else
} // namespace acestl_project
} // namespace stlsoft
# endif /* _STLSOFT_NO_NAMESPACE */
#endif /* !_ACESTL_NO_NAMESPACE */
/* ////////////////////////////////////////////////////////////////////// */
#endif /* ACESTL_INCL_ACESTL_HPP_CUSTOM_EVENT_HANDLER */
/* ////////////////////////////////////////////////////////////////////// */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -