event.h

Go to the documentation of this file.
00001 /*
00002  *  Copyright (C) 2004-2005 Alo Sarv <madcat_@users.sourceforge.net>
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017  */
00018 
00019 /** @file event.h Interface for Event subsystem */
00020 
00021 #ifndef __EVENT_H__
00022 #define __EVENT_H__
00023 
00024 /**
00025  * @page ehsv2 Event Handling Subsystem, version 2
00026  *
00027  * \section intro Introduction
00028  * Event Handling Subsystem version 2 (EHS) provides a generic API for passing
00029  * arbitary objects from a <i>source</i> to one or more <i>handlers</i> without
00030  * coupling neither the source and handlers, nor coupling either of those with
00031  * the EHS.
00032  *
00033  * \section ratio Rationale
00034  * The original Event Handling Subsystem (version 1) had a number of issues that
00035  * made the subsystem inconvenient to use, errorpone and hard to debug. Namely,
00036  * the syntax for postingevents and/or setting handlers was so inconvenient that
00037  * we had to resort to preprocessor macros to compensate for that. In addition,
00038  * the original engine was based on CBFunctor library, which dates back to 1994,
00039  * and thus breaks on some modern compilers. Thus, the system was rewritten.
00040  *
00041  * \section req Requirements
00042  * The requirements for EHSv2 are:
00043  * \list
00044  * - Decouple the event source from event tables. This is required to allow
00045  *   posting events from sources that were originally not designed for events,
00046  *   because they come from, for example, third-party libraries.
00047  * - Easy-to-learn and easy-to-use usage syntax.
00048  * - Base on a modern function objects library that is portable.
00049  *
00050  * \section usage Usage
00051  * There are two common operations needed to be done when it comes to event
00052  * tables usage - setting up event handlers, and posting events. In order to
00053  * provide maximum simplicity for those operations, there are a set of utility
00054  * methods (defined in <b>EHS</b> namespace) which simplify the syntax. The
00055  * basic usage of EHS goes as follows:
00056  *
00057  * \code
00058  * // Initialize objects. Note: the first event (posted in MySource
00059  * // constructor) is not handled.
00060  * MyHandler *h = new MyHandler;
00061  * MySource *s = new MySource;
00062  * // Set up handler, and post an event
00063  * EHS::addHandler(s, h, &MyHandler::handlerfunc);
00064  * EHS::postEvent(s, MyEvent("Hello world!"));
00065  * \endcode
00066  */
00067 
00068 // hydranode includes
00069 #include <hn/osdep.h>
00070 #include <hn/bind_placeholders.h>
00071 #include <hn/eventbase.h>
00072 #include <hn/gettickcount.h>
00073 #include <hn/log.h>
00074 #include <hn/utils.h>
00075 
00076 // event tables backend - Boost.Signal, Boost.Function and Boost.Bind libraries
00077 #include <boost/signal.hpp>
00078 #include <boost/signals/trackable.hpp>
00079 #include <boost/signals/connection.hpp>
00080 #include <boost/function.hpp>
00081 #include <boost/bind.hpp>
00082 #include <boost/shared_ptr.hpp>
00083 #include <boost/type_traits.hpp>
00084 
00085 // multi-thread safety - Boost.Thread (mutexes)
00086 #include <boost/thread.hpp>
00087 
00088 // std includes
00089 #include <map>
00090 #include <set>
00091 
00092 /**
00093  * Trackable object allows tracking the object's lifetime by Event subsystem,
00094  * and thus avoid emitting events from already-destroyed sources. To enable
00095  * source object tracking, derive the event source type publically from
00096  * Trackable,and the rest of the machinery is done automatically by Event
00097  * subsystem (via compile-time type-checking).
00098  *
00099  * Trackable is also boost::signals::trackable, so connections established by
00100  * a Trackable object are also disconnected when Trackable object is destroyed,
00101  * thus providing automatic and safe event handlers removal.
00102  *
00103  * \note This does not work with smart-pointer types yet.
00104  */
00105 class Trackable : public boost::signals::trackable {
00106 public:
00107         Trackable() : m_validator(new bool(true)) {}
00108         ~Trackable() { *m_validator = false; }
00109         boost::shared_ptr<bool> getValidator() const { return m_validator; }
00110 private:
00111         boost::shared_ptr<bool> m_validator;
00112 };
00113 
00114 /**
00115  * EventTable template class encapsulates pending events storage, event handlers
00116  * storage and event handlers calling when instructed to do so from main event
00117  * loop. For each event source and event type, there is a specific event table.
00118  *
00119  * @param Source    Type of object the events are emitting from. This should
00120  *                  generally be a pointer type, e.g. MyClass*
00121  * @param Event     Type of event the source emits.
00122  */
00123 template<typename Source, typename Event>
00124 class EventTable : public EventTableBase {
00125         class InternalEvent;
00126         class DelayedEvent;
00127         //! Internal event shared pointer
00128         typedef boost::shared_ptr<InternalEvent> EventPtr;
00129         //! Delayed event shared pointer
00130         typedef boost::shared_ptr<DelayedEvent> DelayedPtr;
00131         //! Type of handler function
00132         typedef typename boost::function<void (Source, Event)> Handler;
00133         //! Type of signal used in this event table
00134         typedef typename boost::signal<void (Source, Event)> SigType;
00135         //! Helper typedef, for iterating on sigMap
00136         typedef typename std::map<Source, SigType*>::iterator Iter;
00137         //! Helper typedef, for iterating on pending events vector
00138         typedef typename std::vector<EventPtr>::iterator PIter;
00139         //! Helper typedef, for iterator in m_toDelete vector
00140         typedef typename std::set<Source>::iterator DeleteIter;
00141 public:
00142         //! Dummy default constructor
00143         EventTable() {}
00144         //! Dummy destructor
00145         ~EventTable() {}
00146 
00147         /**
00148          * Connect an event handler to a source. The handler shall be called
00149          * whenever the source object emits events.
00150          *
00151          * \note It is recommended to use classes derived from boost::signals::
00152          *       trackable for event handlers, and connect them via the
00153          *       overloaded addHandler method, since that way automatic
00154          *       disconnection is guaranteed when either the signal source or
00155          *       the signal handler objects get destroyed.
00156          *
00157          * @param src     Source the handler is interested in
00158          * @param ha      Event handler function object
00159          * @return        The established connection between the event source
00160          *                and event handler. This can later be used to
00161          *                disconnect the handler from the source.
00162          */
00163         boost::signals::connection addHandler(Source src, Handler ha) {
00164                 if (!src) {
00165                         return addAllHandler(ha);
00166                 }
00167 
00168                 boost::recursive_mutex::scoped_lock l(m_sigMapMutex);
00169                 Iter i = m_sigMap.find(src);
00170                 if (i == m_sigMap.end()) {
00171                         i = m_sigMap.insert(
00172                                 std::make_pair(src, new SigType())
00173                         ).first;
00174                 }
00175                 return (*i).second->connect(ha, boost::signals::at_front);
00176         }
00177 
00178         /**
00179          * Overloaded version of the above method, performs function object
00180          * binding internally. This is the recommended version of this function,
00181          * since while being also simpler to use, it also guarantees function
00182          * disconnection in case the object is derived from boost::signals::
00183          * trackable.
00184          *
00185          * \note This limitation is inherent from Boost.Signals library -
00186          *       namely, trackable objects only work when bound with
00187          *       boost::bind, raw Boost.Function or Boost.Lambda functors do not
00188          *       implement the necesery interface for this to work.
00189          *
00190          * @param src   Event source to be interested in
00191          * @param obj   Event handler object
00192          * @param func  Event handler function
00193          * @return      The established connection between the event source and
00194          *              event handler, which can later be used to disconnect the
00195          *              handler from the source.
00196          */
00197         template<typename T>
00198         boost::signals::connection addHandler(
00199                 Source src, T *obj, void (T::*func)(Source, Event)
00200         ) {
00201                 if (!src) {
00202                         return addAllHandler(boost::bind(func, obj, _b1, _b2));
00203                 }
00204 
00205                 boost::recursive_mutex::scoped_lock l(m_sigMapMutex);
00206                 Iter i = m_sigMap.find(src);
00207                 if (i == m_sigMap.end()) {
00208                         i = m_sigMap.insert(
00209                                 std::make_pair(src, new SigType())
00210                         ).first;
00211                 }
00212 
00213                 return (*i).second->connect(
00214                         boost::bind(func, obj, _b1, _b2),
00215                         boost::signals::at_front
00216                 );
00217         }
00218 
00219         /**
00220          * Connect a raw function to the source signal.
00221          */
00222         template<typename T>
00223         boost::signals::connection addHandler(
00224                 Source src, void (*ha)(Source, Event)
00225         ) {
00226                 if (!src) {
00227                         return addAllHandler(ha);
00228                 }
00229 
00230                 boost::recursive_mutex::scoped_lock l(m_sigMapMutex);
00231                 Iter i = m_sigMap.find(src);
00232                 if (i == m_sigMap.end()) {
00233                         i = m_sigMap.insert(
00234                                 m_sigMap.begin(),
00235                                 std::make_pair(src, new SigType)
00236                         );
00237                 }
00238                 return (*i).second->connect(ha, boost::signals::at_front);
00239         }
00240 
00241         /**
00242          * @name Add handler for all events from all sources of this type.
00243          */
00244         //@{
00245         boost::signals::connection addAllHandler(Handler ha) {
00246                 boost::recursive_mutex::scoped_lock l(m_sigMapMutex);
00247                 return m_allSig.connect(ha);
00248         }
00249         template<typename T>
00250         boost::signals::connection addAllHandler(
00251                 T *obj, void (T::*func)(Source, Event)
00252         ) {
00253                 boost::recursive_mutex::scoped_lock l(m_sigMapMutex);
00254                 return m_allSig.connect(boost::bind(func, obj, _b1, _b2));
00255         }
00256         template<typename T>
00257         boost::signals::connection addAllHandler(void (*func)(Source, Event)) {
00258                 boost::recursive_mutex::scoped_lock l(m_sigMapMutex);
00259                 return m_allSig.connect(func);
00260         }
00261         //@}
00262 
00263         /**
00264          * Disconnect an event handler which has previously been connected with
00265          * addHandler() method.
00266          *
00267          * @param src     Event source
00268          * @param c       Connection to be disconnected
00269          */
00270         void delHandler(Source src, const boost::signals::connection &c) {
00271                 boost::recursive_mutex::scoped_lock l(m_sigMapMutex);
00272                 c.disconnect();
00273                 Iter i = m_sigMap.find(src);
00274                 if (i != m_sigMap.end() && (*i).second->empty()) {
00275                         delete (*i).second;
00276                         m_sigMap.erase(i);
00277                 }
00278         }
00279 
00280         /**
00281          * Erase all handlers refering to a specific source. This is useful to
00282          * be called from either source object's destructor, or by whoever is
00283          * destroying the source, to clean up the event table things.
00284          *
00285          * @param src    Source object
00286          */
00287         void delHandler(Source src) {
00288                 boost::recursive_mutex::scoped_lock l(m_sigMapMutex);
00289                 Iter i = m_sigMap.find(src);
00290                 if (i != m_sigMap.end()) {
00291                         delete (*i).second;
00292                         m_sigMap.erase(i);
00293                 }
00294         }
00295 
00296         /**
00297          * Special version of handler removal, which works for functions that
00298          * can be compared (e.g. raw free functions).
00299          *
00300          * @param src   Source to be disconnected from
00301          * @param ha    Event handler function
00302          */
00303         void delHandler(Source src, void (*ha)(Source, Event)) {
00304                 boost::recursive_mutex::scoped_lock l(m_sigMapMutex);
00305                 Iter i = m_sigMap.find(src);
00306                 if (i != m_sigMap.end()) {
00307                         (*i).second->disconnect(ha);
00308                         if ((*i).second->empty()) {
00309                                 delete (*i).second;
00310                                 m_sigMap.erase(i);
00311                         }
00312                 }
00313         }
00314 
00315         /**
00316          * Post an event to the event queue, which shall be passed to all
00317          * handlers during next event loop.
00318          *
00319          * @param src     Event source
00320          * @param evt     The event itself
00321          */
00322         void postEvent(Source src, Event evt) {
00323                 boost::recursive_mutex::scoped_lock l(m_pendingMutex);
00324                 m_pending.push_back(EventPtr(new InternalEvent(src, evt)));
00325                 notify();
00326         }
00327 
00328         /**
00329          * Post a delayed event, which shall be emitted when the delay is over.
00330          * Note that the actual delay until to the event emitting may vary,
00331          * depending on application load, up to 100ms.
00332          *
00333          * @param src     Event source
00334          * @param evt     The event itself
00335          * @param delay   Delay, in milliseconds, until event will be passed to
00336          *                handlers
00337          *
00338          * \note Breaks compilation on non-pointer source types
00339          * \note Could be optimized to use compile-time type-checking instead
00340          *       of runtime.
00341          */
00342         void postEvent(Source src, Event evt, uint32_t delay) {
00343                 boost::recursive_mutex::scoped_lock l(m_delayedMutex);
00344                 DelayedPtr devt(new DelayedEvent(src, evt, delay));
00345                 m_delayed.insert(devt);
00346         }
00347 
00348         /**
00349          * Request EventTables to safely delete the source object, after all
00350          * events for the source have been processed.
00351          *
00352          * @param src        Source object to be deleted
00353          */
00354         void safeDelete(Source src) {
00355                 boost::recursive_mutex::scoped_lock l(m_deleteMutex);
00356                 m_toDelete.insert(src);
00357         }
00358 
00359         /**
00360          * Emit an event from source object, and then request EventTables to
00361          * safely delete the source object, after all events for the source have
00362          * been processed.
00363          *
00364          * @param src        Source object to emit event from and to delete
00365          * @param evt        Event to be emitted
00366          */
00367         void safeDelete(Source src, Event evt) {
00368                 postEvent(src, evt);
00369                 safeDelete(src);
00370         }
00371 
00372         /**
00373          * Call all handlers for all pending events. This method is called from
00374          * main event loop.
00375          */
00376         virtual void handleEvents() {
00377                 checkForDelayed();
00378 
00379                 boost::recursive_mutex::scoped_lock l1(m_pendingMutex);
00380                 boost::recursive_mutex::scoped_lock l2(m_sigMapMutex);
00381 
00382                 while (m_pending.size()) {
00383                         EventPtr evt = m_pending.front();
00384                         if (!evt->isValid()) {
00385                                 m_pending.pop_front();
00386                                 continue;
00387                         }
00388                         Iter j = m_sigMap.find(evt->getSource());
00389                         if (j != m_sigMap.end()) {
00390                                 (*(*j).second)(
00391                                         evt->getSource(), evt->getEvent()
00392                                 );
00393                         }
00394                         m_allSig(evt->getSource(), evt->getEvent());
00395                         m_pending.pop_front();
00396                 }
00397 
00398                 checkDelete();
00399         }
00400 
00401         //! Delete-function, used by safeDelete; declared public in order to
00402         //! create friendship with Src class
00403         template<typename Src, bool>
00404         struct Deleter {
00405                 static void doDel(Src) {}
00406         };
00407         template<typename Src>
00408         struct Deleter<Src, true> {
00409                 static void doDel(Src ptr) {
00410                         delete ptr;
00411                 }
00412         };
00413 private:
00414         /**
00415          * @name Copying is not allowed
00416          */
00417         //@{
00418         EventTable(const EventTable&);
00419         EventTable& operator=(const EventTable &);
00420         //@}
00421 
00422         /**
00423          * Stores all signal objects for all objects of type Source. This map
00424          * is filled by addHandler() method, which adds the signal here if it's
00425          * not here already. Also, addHandler() connects functions to the
00426          * signals in this map. When a signal in this map no longer has any
00427          * handlers, it should be removed (done in delHandler() method).
00428          *
00429          * \note We'r using heap-allocated signal objects here, since Signal
00430          *       is not copyable.
00431          */
00432         std::map<Source, SigType*> m_sigMap;
00433 
00434         /**
00435          * Signal which will be fired whenever ANY source of this type emits
00436          * an event. This is a way to handle events from all sources of a given
00437          * type.
00438          */
00439         SigType m_allSig;
00440 
00441         /**
00442          * Pending events queue, filled by postEvent() method and cleared in
00443          * handleEvents().
00444          */
00445         std::deque<EventPtr> m_pending;
00446 
00447         /**
00448          * Delayed events, which will be posted when the timeout is over.
00449          * The key to this map is the actual tick when the event should be
00450          * emitted.
00451          */
00452         std::multiset<DelayedPtr, Utils::PtrLess<DelayedPtr> > m_delayed;
00453 
00454         /**
00455          * Deletion queue, filled by safeDelete method; objects here are
00456          * deleted once all events for the source have been processed, at
00457          * the end of event loop.
00458          */
00459         std::set<Source> m_toDelete;
00460 
00461         /**
00462          * Recursive mutexes which protect the above four containers in multi-
00463          * threaded environment. They are recursive since we are most likely
00464          * to be called from an event handler from same thread, in which case we
00465          * want to be able to access the containers.
00466          */
00467         //@{
00468         boost::recursive_mutex m_sigMapMutex;
00469         boost::recursive_mutex m_pendingMutex;
00470         boost::recursive_mutex m_delayedMutex;
00471         boost::recursive_mutex m_deleteMutex;
00472         //@}
00473 
00474         /**
00475          * Performs compile-time type-checking to find out if source is derived
00476          * from Trackable, and if it is so, the below specialization of this
00477          * class template is chosen, which takes the source validator and
00478          * attaches it to the event. When source is destroyed, the validator
00479          * is invalidated, and thus the event won't be emitted.
00480          */
00481         template<typename _Src, typename _Evt, bool>
00482         struct GetSetHandler {
00483                 static void doSet(_Src, _Evt) {}
00484         };
00485         template<typename _Src, typename _Evt>
00486         struct GetSetHandler<_Src, _Evt, true> {
00487                 static void doSet(_Src src, _Evt evt) {
00488                         evt->setValidator(((Trackable*)src)->getValidator());
00489                 }
00490         };
00491 
00492         /**
00493          * Helper method, which automatically deducts template arguments from
00494          * parameters; used to compensate against MSVC's problems with the above
00495          * constructs.
00496          */
00497         template<typename _Src, typename _Evt>
00498         static void getSetHandler(_Src src, _Evt evt) {
00499                 GetSetHandler<
00500                         _Src, _Evt, boost::is_base_and_derived<
00501                                 Trackable,
00502                                 typename boost::remove_pointer<_Src>::type
00503                         >::value
00504                 >::doSet(src, evt);
00505         }
00506 
00507         /**
00508          * Wrapper class for temporary storing pending events and similar.
00509          */
00510         class InternalEvent {
00511         public:
00512                 //! Constructor
00513                 InternalEvent(Source src, Event evt) : m_src(src), m_evt(evt) {
00514                         EventTable::getSetHandler(src, this);
00515                 }
00516 
00517                 Source getSource() const { return m_src; }
00518                 Event  getEvent()  const { return m_evt; }
00519                 //! Check the validity of this event
00520                 bool isValid() const { return m_valid ? *m_valid : true; }
00521                 //! Set the validator for this event
00522                 void setValidator(boost::shared_ptr<bool> v) { m_valid = v; }
00523         private:
00524                 Source   m_src;                    //!< Event source object
00525                 Event    m_evt;                    //!< The event itself
00526                 boost::shared_ptr<bool> m_valid;   //!< Validity
00527         };
00528 
00529         /**
00530          * DelayedEvent is an event that is to be emitted after specified time
00531          * has passed. DelayedEvents can be invalidated at any time before
00532          * their emitting via setting the shared pointer m_valid to false.
00533          * Trackable-derived objects automatically set this pointer to false
00534          * upon destruction.
00535          */
00536         class DelayedEvent : public InternalEvent {
00537         public:
00538                 /**
00539                  * Constructor
00540                  *
00541                  * @param src         Source object
00542                  * @param evt         Event object
00543                  * @param delay       Delay, in milliseconds
00544                  */
00545                 DelayedEvent(Source src, Event evt, uint32_t delay)
00546                 : InternalEvent(src, evt), m_postTime(Utils::getTick() + delay)
00547                 {}
00548 
00549                 //! Comparison operator, ordered by m_postTime member
00550                 friend bool operator<(
00551                         const DelayedEvent &x, const DelayedEvent &y
00552                 ) {
00553                         return x.m_postTime < y.m_postTime;
00554                 }
00555                 //! Implicit conversion to uint64_t returns m_postTime
00556                 operator uint64_t() const { return m_postTime; }
00557         private:
00558                 uint64_t m_postTime;               //!< Posting time
00559         };
00560 
00561         /**
00562          * Transfer all delayed events for which the delay is over to pending
00563          * list.
00564          */
00565         void checkForDelayed() {
00566                 boost::recursive_mutex::scoped_lock l1(m_delayedMutex);
00567                 boost::recursive_mutex::scoped_lock l2(m_pendingMutex);
00568                 uint64_t tick = Utils::getTick();
00569 
00570                 while (m_delayed.size() && (*(*m_delayed.begin()) <= tick)) {
00571                         m_pending.push_back(*m_delayed.begin());
00572                         m_delayed.erase(m_delayed.begin());
00573                 }
00574         }
00575 
00576         /**
00577          * Deletes all objects in m_toDelete container; to be called at the end
00578          * of event loop, after all events are processed.
00579          */
00580         void checkDelete() {
00581                 boost::recursive_mutex::scoped_lock l(m_deleteMutex);
00582                 DeleteIter it = m_toDelete.begin();
00583                 while (it != m_toDelete.end()) {
00584                         Deleter<
00585                                 Source,
00586                                 boost::is_pointer<Source>::value
00587                         >::doDel(*it++);
00588                 }
00589                 m_toDelete.clear();
00590         }
00591 };
00592 
00593 /**
00594  * Use this macro to define an event table for a specific object. This generates
00595  * a static member function getEventTable(), which can be used to get access to
00596  * the event table.
00597  *
00598  * @param Source      Event source type. This must be a fully qualified type,
00599  *                    for usage within EventTables.  Example: SocketClient*
00600  * @param Event       Event emitted from the source. Example: SocketEvent
00601  *
00602  * \note This design was chosen because alternative approaches which would not
00603  *       couple the event table with the event source causes problems with win32
00604  *       dynamic loader and linker and thus could not be used.
00605  * \note Friend declaration is needed for checkDelete() to work with private
00606  *       destructors.
00607  */
00608 #define DECLARE_EVENT_TABLE(Source, Event)                                 \
00609         static EventTable<Source, Event>& getEventTable();                 \
00610         friend struct EventTable<Source, Event >::Deleter<                 \
00611                 Source, boost::is_pointer< Source >::value                 \
00612         >
00613 
00614 #define IMPLEMENT_EVENT_TABLE(SourceClass, Source, Event)                  \
00615         EventTable<Source, Event>& SourceClass::getEventTable() {          \
00616                 static EventTable<Source, Event> s_evtT;                   \
00617                 return s_evtT;                                             \
00618         } class SourceClass
00619 
00620 #endif