00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 
00036 
00037 
00038 
00039 
00040 
00048 #ifndef ACESTL_INCL_ACESTL_REACTOR_HPP_CUSTOM_EVENT_HANDLER
00049 #define ACESTL_INCL_ACESTL_REACTOR_HPP_CUSTOM_EVENT_HANDLER
00050 
00051 #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
00052 # define ACESTL_VER_ACESTL_REACTOR_HPP_CUSTOM_EVENT_HANDLER_MAJOR     2
00053 # define ACESTL_VER_ACESTL_REACTOR_HPP_CUSTOM_EVENT_HANDLER_MINOR     1
00054 # define ACESTL_VER_ACESTL_REACTOR_HPP_CUSTOM_EVENT_HANDLER_REVISION  4
00055 # define ACESTL_VER_ACESTL_REACTOR_HPP_CUSTOM_EVENT_HANDLER_EDIT      22
00056 #endif 
00057 
00058 
00059 
00060 
00061 
00062 #ifndef ACESTL_INCL_ACESTL_HPP_ACESTL
00063 # include <acestl/acestl.hpp>
00064 #endif 
00065 
00066 #ifndef STLSOFT_INCL_ACE_H_EVENT_HANDLER
00067 # define STLSOFT_INCL_ACE_H_EVENT_HANDLER
00068 # include <ace/Event_Handler.h>             
00069 #endif 
00070 #ifndef STLSOFT_INCL_ACE_H_REACTOR
00071 # define STLSOFT_INCL_ACE_H_REACTOR
00072 # include <ace/Reactor.h>                   
00073 #endif 
00074 
00075 #ifndef STLSOFT_INCL_STLSOFT_SMARTPTR_HPP_SHARED_PTR
00076 # include <stlsoft/smartptr/shared_ptr.hpp>
00077 #endif 
00078 
00079 #ifndef STLSOFT_INCL_MAP
00080 # define STLSOFT_INCL_MAP
00081 # include <map>
00082 #endif 
00083 
00084 
00085 
00086 
00087 
00088 #if defined(STLSOFT_COMPILER_IS_INTEL) || \
00089     (   defined(STLSOFT_COMPILER_IS_MSVC) && \
00090         _MSC_VER >= 1200)
00091 # define ACESTL_CUSTOM_EVENT_HANDLER_CANCEL_EVENTS_MEMBER_CLEANUP_SUPPORT
00092 #endif 
00093 
00094 
00095 
00096 
00097 
00098 #ifndef _ACESTL_NO_NAMESPACE
00099 # if defined(_STLSOFT_NO_NAMESPACE) || \
00100      defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
00101 
00102 namespace acestl
00103 {
00104 # else
00105 
00106 
00107 namespace stlsoft
00108 {
00109 
00110 namespace acestl_project
00111 {
00112 
00113 # endif 
00114 #endif 
00115 
00116 
00117 
00118 #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
00119 
00124 struct ceh_root
00125 {
00126 private:
00127     struct event_id_ {};
00128 public:
00129     typedef event_id_*  event_id;
00130 };
00131 
00137 template<ss_typename_param_k C>
00138 struct cancel_adapter
00139 #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
00140     : public ceh_root
00141 #endif 
00142 {
00143     typedef cancel_adapter<C>   class_type;
00144 
00145     cancel_adapter(C* obj, void (C::*pfn)(long code, event_id id, void* arg))
00146         : m_obj(obj)
00147         , m_pfn(pfn)
00148     {}
00149 
00150     static void proc(void* param, long code, event_id id, void* arg)
00151     {
00152         class_type* pThis = static_cast<class_type*>(param);
00153 
00154         ((pThis->m_obj)->*(pThis->m_pfn))(code, id, arg);
00155     }
00156 
00157 private:
00158     C* const m_obj;
00159     void (C::*m_pfn)(long code, event_id id, void* arg);
00160 };
00161 
00162 #endif 
00163 
00164 
00165 
00166 
00167 
00283 
00284 class custom_event_handler
00285     : public ACE_Event_Handler
00286 #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
00287     , public ceh_root
00288 #endif 
00289 {
00292 private:
00293     struct event_id_ {};
00294 public:
00295     typedef ACE_Event_Handler       parent_class_type;
00296     typedef custom_event_handler    class_type;
00297     typedef as_bool_t               bool_type;
00298 #ifdef STLSOFT_DOCUMENTATION_SKIP_SECTION
00302     typedef event_id_*              event_id;
00303 #endif 
00307     typedef void (*cancelled_event_code_fn)(void* param, long code, event_id id, void* arg);
00309 
00310 
00311 protected:
00321     ss_explicit_k custom_event_handler( ACE_Reactor*    reactor     =   ACE_Reactor::instance()
00322                                     ,   int             priority    =   ACE_Event_Handler::LO_PRIORITY);
00323 public:
00325     virtual ~custom_event_handler() stlsoft_throw_0();
00326 
00329 public:
00347     event_id schedule_custom_event(long code, ACE_Time_Value const& delay, void* arg = 0);
00348 
00365     event_id schedule_custom_event(long code, void* arg = 0);
00366 
00377     int cancel_custom_events(long code);
00378 
00414     int cancel_custom_events(long code, cancelled_event_code_fn pfn, void* param);
00415 
00416 #if defined(ACESTL_CUSTOM_EVENT_HANDLER_CANCEL_EVENTS_MEMBER_CLEANUP_SUPPORT)
00417 #if 0
00420     template<ss_typename_param_k C>
00421     struct cancel_adapter
00422     {
00423         typedef cancel_adapter<C>   class_type;
00424 
00425         cancel_adapter(C* obj, void (C::*pfn)(long code, event_id id, void* arg))
00426             : m_obj(obj)
00427             , m_pfn(pfn)
00428         {}
00429 
00430         static void proc(void* param, long code, event_id id, void* arg)
00431         {
00432             class_type* pThis = static_cast<class_type*>(param);
00433 
00434             ((pThis->m_obj)->*(pThis->m_pfn))(code, id, arg);
00435         }
00436 
00437     private:
00438         C* const m_obj;
00439         void (C::*m_pfn)(long code, event_id id, void* arg);
00440     };
00441 #endif 
00442 
00480     template<ss_typename_param_k C>
00481     int cancel_custom_events(long code, C* obj, void (C::*pfn)(long code, event_id id, void* arg))
00482     {
00483         cancel_adapter<C>   adapter(obj, pfn);
00484 
00485         return this->cancel_custom_events(code, &cancel_adapter<C>::proc, &adapter);
00486     }
00487 #endif 
00488 
00500     int cancel_custom_event(event_id event, void** parg = NULL);
00502 
00505 public:
00507 
00510 public:
00519     as_int_t has_custom_events(long code) const;
00520 
00525     as_int_t has_custom_event(long code) const;
00526 
00534     as_int_t has_custom_event(event_id event) const;
00536 
00537 
00538 #ifdef STLSOFT_DOCUMENTATION_SKIP_SECTION
00539 public:
00540 #else 
00541 private:
00542 #endif 
00543 
00551     virtual int handle_custom_event(ACE_Time_Value const&   current_time
00552                                 ,   long                    code
00553                                 ,   void*                   arg)   =   0;
00554 
00555 
00556 private:
00557     class callback_hook
00558         : public ACE_Event_Handler
00559     {
00560     public:
00561         callback_hook(custom_event_handler* ceh, ACE_Reactor* reactor, int priority)
00562             : ACE_Event_Handler(reactor, priority)
00563             , m_ceh(ceh)
00564         {
00565             ACESTL_MESSAGE_ASSERT("reactor may not be null", NULL != reactor);
00566         }
00567         ~callback_hook() stlsoft_throw_0()
00568         {
00569             reactor()->remove_handler(this, ACE_Event_Handler::ALL_EVENTS_MASK | ACE_Event_Handler::DONT_CALL);
00570         }
00571 
00572     private:
00573         virtual int handle_timeout( ACE_Time_Value const&   current_time
00574                                 ,   void const*             arg)
00575         {
00576             return m_ceh->handle_callback_timeout(current_time, const_cast<void*>(arg));
00577         }
00578 
00579     private:
00580         custom_event_handler    *const  m_ceh;
00581 
00582     private:
00583         callback_hook(callback_hook const&);
00584         callback_hook& operator =(callback_hook const&);
00585     };
00586 
00587     friend class callback_hook;
00588 
00589     
00590     struct event_info
00591     {
00592         long        code;   
00593         void        *arg;   
00594         event_id    id;     
00595 
00596         event_info(long code_, void *arg_)
00597             : code(code_)
00598             , arg(arg_)
00599             , id(NULL)
00600         {}
00601     };
00602 
00603     typedef ::stlsoft::shared_ptr<event_info>    info_ptr;
00604 
00605     
00606     int handle_callback_timeout(ACE_Time_Value const&   current_time
00607                             ,   void*                   arg);
00608 
00609     
00610     
00611     class_type *get_this_()
00612     {
00613         return this;
00614     }
00615 
00616     
00617     bool_type   is_valid() const;
00618 
00619     
00620     event_id    schedule_event_(event_info* entry, ACE_Time_Value const& delay);
00621     as_int_t    cancel_event_(event_id );
00622 
00623 
00624 private:
00625     
00626     
00627     
00628     
00629     
00630     
00631 
00632     typedef ::std::map<event_id, info_ptr>      event_map_type;
00633     typedef ::std::map<long, event_map_type>    event_code_map_type;
00634 
00635     callback_hook       m_callbackHook;
00636     event_code_map_type m_entries;
00637 
00638 
00639 private:
00640     custom_event_handler(class_type const&);
00641     class_type& operator =(class_type const&);
00642 };
00643 
00645 
00646 
00647 #ifdef STLSOFT_UNITTEST
00648 # include "./unittest/custom_event_handler_unittest_.h"
00649 #endif 
00650 
00651 
00652 
00653 
00654 
00655 #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
00656 
00657 #ifdef STLSOFT_COMPILER_IS_MSVC
00658 # if _MSC_VER >= 1200
00659 #  pragma warning(push)
00660 # endif 
00661 # pragma warning(disable : 4702)
00662 #endif 
00663 
00664 inline custom_event_handler::event_id custom_event_handler::schedule_event_(event_info* entry, ACE_Time_Value const& delay)
00665 {
00666     long timerId = m_callbackHook.reactor()->schedule_timer(&m_callbackHook, entry, delay);
00667 
00668     ACESTL_MESSAGE_ASSERT("Unexpected negative value", (timerId >= -1 || -1 == timerId));
00669 
00670     return (-1 == timerId) ? NULL : reinterpret_cast<event_id>(static_cast<as_size_t>(1 + timerId));
00671 }
00672 
00673 inline as_int_t custom_event_handler::cancel_event_(custom_event_handler::event_id id)
00674 {
00675     ACESTL_ASSERT(NULL != id);
00676 
00677     return m_callbackHook.reactor()->cancel_timer(static_cast<long>(reinterpret_cast<as_size_t>(id - 1)));
00678 }
00679 
00680 inline custom_event_handler::bool_type custom_event_handler::is_valid() const
00681 {
00682     return true;
00683 }
00684 
00685 inline custom_event_handler::custom_event_handler(  ACE_Reactor*    reactor    
00686                                                 ,   int             priority    )
00687     : parent_class_type(reactor, priority)
00688     , m_callbackHook(get_this_(), reactor, priority)
00689 {
00690     ACESTL_ASSERT(NULL != reactor);
00691     ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());
00692 }
00693 
00694 inline custom_event_handler::~custom_event_handler() stlsoft_throw_0()
00695 {
00696     ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());
00697 
00698     ACESTL_MESSAGE_ASSERT("Custom event handler destroyed with outstanding entries: derived classes should cancel all notifications", m_entries.empty());
00699 }
00700 
00701 inline custom_event_handler::event_id custom_event_handler::schedule_custom_event(long code, ACE_Time_Value const& delay, void *arg )
00702 {
00703     ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());
00704 
00705     
00706 
00707     event_info* entry_;
00708 
00709     ACE_NEW_NORETURN(entry_, event_info(code, arg));
00710 
00711     if(NULL == entry_)
00712     {
00713         ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());
00714 
00715         ACE_ERROR_RETURN(   (   LM_ALERT
00716                             ,   ACE_TEXT("(%P|%t) out of memory"))
00717                         ,   0);
00718     }
00719     else
00720     {
00721         info_ptr    entry(entry_);
00722         event_id    timerId =   schedule_event_(entry.get(), delay);
00723 
00724         if(NULL == timerId)
00725         {
00726             ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());
00727 
00728             ACE_ERROR_RETURN(   (   LM_ALERT
00729                                 ,   ACE_TEXT("(%P|%t) timer registration failed"))
00730                             ,   0);
00731         }
00732         else
00733         {
00734             entry->id = timerId;
00735 
00736             try
00737             {
00738                 
00739                 m_entries[code][timerId] = entry;
00740             }
00741             catch(std::bad_alloc &) 
00742             {
00743                 cancel_event_(timerId);
00744 
00745                 ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());
00746 
00747                 ACE_OS::last_error(ENOMEM);
00748                 ACE_ERROR_RETURN(   (   LM_ALERT
00749                                     ,   ACE_TEXT("(%P|%t) out of memory"))
00750                                 ,   0);
00751             }
00752             catch(std::exception &x)
00753             {
00754                 cancel_event_(timerId);
00755 
00756                 ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());
00757 
00758                 ACE_ERROR_RETURN(   (   LM_ALERT
00759                                     ,   ACE_TEXT("(%P|%t) event scheduling failed: %s")
00760                                     ,   x.what())
00761                                 ,   0);
00762             }
00763 
00764             ACESTL_MESSAGE_ASSERT("event not in handler", this->has_custom_event(timerId));
00765 
00766             ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());
00767 
00768             return timerId;
00769         }
00770     }
00771 }
00772 
00773 inline custom_event_handler::event_id custom_event_handler::schedule_custom_event(long code, void *arg )
00774 {
00775     ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());
00776 
00777     return schedule_custom_event(code, ACE_Time_Value(0), arg);
00778 }
00779 
00780 inline int custom_event_handler::cancel_custom_events(long code, custom_event_handler::cancelled_event_code_fn pfn, void* param)
00781 {
00782     ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());
00783 
00784     event_code_map_type::iterator it = m_entries.find(code);
00785 
00786     if(m_entries.end() == it)
00787     {
00788         ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());
00789 
00790         return 0;
00791     }
00792     else
00793     {
00794         
00795         event_map_type&             codes   =   (*it).second;
00796         event_map_type::iterator    begin   =   codes.begin();
00797         event_map_type::iterator    end     =   codes.end();
00798         as_int_t                    n;
00799 
00800         for(n = 0; begin != end; ++begin)
00801         {
00802             info_ptr entry = (*begin).second;
00803 
00804             if(NULL != pfn)
00805             {
00806                 (*pfn)(param, entry->code, entry->id, entry->arg);
00807             }
00808 
00809             if(cancel_event_(entry->id))
00810             {
00811                 ++n;
00812             }
00813         }
00814 
00815         m_entries.erase(it);
00816 
00817         ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());
00818 
00819         return n;
00820     }
00821 }
00822 
00823 inline int custom_event_handler::cancel_custom_events(long code)
00824 {
00825     return cancel_custom_events(code, NULL, NULL);
00826 }
00827 
00828 inline int custom_event_handler::cancel_custom_event(custom_event_handler::event_id event, void **parg )
00829 {
00830     ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());
00831 
00833 
00834     event_code_map_type::iterator    be  =   m_entries.begin();
00835     event_code_map_type::iterator    ee  =   m_entries.end();
00836 
00837     for(; be != ee; ++be)
00838     {
00839         event_map_type&             event_map   =   (*be).second;
00840         event_map_type::iterator    it          =   event_map.find(event);
00841 
00842         if(event_map.end() != it)
00843         {
00844             if(NULL != parg)
00845             {
00846                 *parg = (*it).second->arg;
00847             }
00848 
00849             event_map.erase(it);
00850 
00851             return cancel_event_(event);
00852         }
00853     }
00854 
00855     return 0;
00856 }
00857 
00858 inline as_int_t custom_event_handler::has_custom_events(long code) const
00859 {
00860     ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());
00861 
00862     event_code_map_type::const_iterator it = m_entries.find(code);
00863 
00864     return (m_entries.end() != it) ? static_cast<as_int_t>((*it).second.size()) : 0;
00865 }
00866 
00867 inline as_int_t custom_event_handler::has_custom_event(long code) const
00868 {
00869     return this->has_custom_events(code);
00870 }
00871 
00872 inline as_int_t custom_event_handler::has_custom_event(event_id event) const
00873 {
00874     ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());
00875 
00877 
00878     event_code_map_type::const_iterator  be      =   m_entries.begin();
00879     event_code_map_type::const_iterator  ee      =   m_entries.end();
00880 
00881     for(; be != ee; ++be)
00882     {
00883         event_map_type const&           event_map   =   (*be).second;
00884         event_map_type::const_iterator  it          =   event_map.find(event);
00885 
00886         if(event_map.end() != it)
00887         {
00888             return 1;
00889         }
00890     }
00891 
00892     return 0;
00893 }
00894 
00895 inline int custom_event_handler::handle_callback_timeout(ACE_Time_Value const& current_time, void* arg)
00896 {
00897     ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());
00898 
00899     event_info const*               entry  =   static_cast<event_info const*>(arg);
00900     event_code_map_type::iterator   itc     =   m_entries.find(entry->code);
00901 
00902     
00903     if(m_entries.end() == itc)
00904     {
00905         ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());
00906 
00907         ACE_ERROR_RETURN(   (   LM_ALERT
00908                             ,   ACE_TEXT("(%P|%t) could not locate callback entry for that code"))
00909                         ,   0); 
00910     }
00911     else
00912     {
00913         ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());
00914 
00915         
00916         event_map_type              &event_map  =   (*itc).second;
00917         event_map_type::iterator    ite         =   event_map.find(entry->id);
00918 
00919         ACESTL_ASSERT(event_map.end() != ite);
00920 
00921         
00922         info_ptr    ep = (*ite).second;
00923 
00924         
00925         event_map.erase(ite);
00926 
00927         
00928         if(event_map.empty())
00929         {
00930             m_entries.erase(itc);
00931         }
00932 
00933         ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());
00934 
00935         
00936         return this->handle_custom_event(current_time, entry->code, entry->arg);
00937     }
00938 }
00939 
00940 #ifdef STLSOFT_COMPILER_IS_MSVC
00941 # if _MSC_VER >= 1200
00942 #  pragma warning(pop)
00943 # else 
00944 #  pragma warning(default : 4702)
00945 # endif 
00946 #endif 
00947 
00948 #endif 
00949 
00950 
00951 
00952 #ifndef _ACESTL_NO_NAMESPACE
00953 # if defined(_STLSOFT_NO_NAMESPACE) || \
00954      defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
00955 } 
00956 # else
00957 } 
00958 } 
00959 # endif 
00960 #endif 
00961 
00962 
00963 
00964 #endif 
00965 
00966