This commit is contained in:
parent
fa576a3e11
commit
8ae588ed40
|
@ -40,6 +40,9 @@ cliever: build/drde-cliever
|
|||
.c.o:
|
||||
$(Cc) -c $(CLFLAGS) -o $<
|
||||
|
||||
build/mdLogger.o: server/mdLogger.cpp include/mdLogger.h
|
||||
$(CC) $(CFLAGS) server/mdLogger.cpp -c -o build/mdLogger.o $(SINCL)
|
||||
|
||||
build/cliever.o: server/cliever-md.cpp include/*.h
|
||||
$(CC) $(CFLAGS) server/cliever-md.cpp -c -o build/cliever.o $(SINCL)
|
||||
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
#ifndef EVENTS_FWD_H
|
||||
#define EVENTS_FWD_H
|
||||
|
||||
/**
|
||||
\file
|
||||
Class forward declaration file. Use this file for forward
|
||||
declarations of TimeStampedEvent, EventSender<Event> and
|
||||
Listener<Event>, to minimize the coupling to this library.
|
||||
|
||||
\since Sept 2002
|
||||
\author Oliver Schoenborn
|
||||
|
||||
\copyright
|
||||
Copyright (C) 2002, 2003 Oliver Schoenborn
|
||||
|
||||
This software is provided 'as-is', without
|
||||
any express or implied warranty. In no event
|
||||
will the authors be held liable for any
|
||||
damages arising from the use of this
|
||||
software.
|
||||
|
||||
You can redistribute it and/or modify it
|
||||
under the terms found in the LICENSE file that
|
||||
is included in the library distribution.
|
||||
\endcopyright
|
||||
*/
|
||||
|
||||
template <typename> class TimeStampedEvent;
|
||||
template <typename> class EventSender;
|
||||
template <typename> class Listener;
|
||||
|
||||
#endif // EVENTS_FWD_H
|
|
@ -0,0 +1,30 @@
|
|||
/**
|
||||
\class EventSender
|
||||
|
||||
Sender of events of type EvType. All public methods are static since there is
|
||||
only one instance of the sender. EventSender maintains a registry
|
||||
of listeners who want to receive the events it sends.
|
||||
|
||||
Usage:
|
||||
- No instantiation needed (actually, none is possible)
|
||||
- Call add() and remove() to add/remove a listener to/from the
|
||||
registry. Only listeners in the registry receive events. If those
|
||||
two methods are called while a send() is already in progress
|
||||
(typically from within your Listener<EvType>::processEvent()),
|
||||
the registrations/removals are queued and are enacted only
|
||||
once all listeners have received the event. This ensures the
|
||||
integrity of the registry during a send().
|
||||
- Call send() on an event to send it to all registered listeners.
|
||||
- Call isSending() to see whether or not EventSender<EvType> is currently
|
||||
doing a send() call (typically used from within your
|
||||
Listener<EvType>::processEvent() to see whether sending another
|
||||
event of type EvType is safe).
|
||||
- Call getNumListeners() to see how many listeners are currently
|
||||
registered. This number does not include listeners queued for
|
||||
registration or removal from registry.
|
||||
- Call getMinNumIgnored() to see how many listeners have ignored the
|
||||
last event sent. If called during a send(), gives the current
|
||||
number. Regardless, this number is a minimum since listeners are
|
||||
not required to tell EventSender<EvType> that they are ignoring the received
|
||||
event.
|
||||
*/
|
|
@ -0,0 +1,219 @@
|
|||
#ifndef EVENT_SENDER_H
|
||||
#define EVENT_SENDER_H
|
||||
|
||||
/**
|
||||
\file
|
||||
Class template definition file.
|
||||
|
||||
\copyright
|
||||
Copyright (C) 2002, 2003 Oliver Schoenborn
|
||||
|
||||
This software is provided 'as-is', without
|
||||
any express or implied warranty. In no event
|
||||
will the authors be held liable for any
|
||||
damages arising from the use of this
|
||||
software.
|
||||
|
||||
You can redistribute it and/or modify it
|
||||
under the terms found in the LICENSE file that
|
||||
is included in the library distribution.
|
||||
\endcopyright
|
||||
*/
|
||||
|
||||
#include <list>
|
||||
#include <typeinfo>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#include "Listener.h" // uses inline
|
||||
#include "EventFWD.h"
|
||||
#include "PolymorphEvent.h"
|
||||
//class PolymorphEvent;
|
||||
|
||||
template <typename EvType>
|
||||
class EventSender
|
||||
{
|
||||
public: // types
|
||||
/// Simpler form of Listener<EvType>
|
||||
typedef Listener<EvType> TListener;
|
||||
|
||||
private: // types
|
||||
/// So Listener<EvType> can call register etc
|
||||
friend class Listener<EvType>;
|
||||
/// Short form of std::list<TListener*>.
|
||||
typedef std::list<TListener*> Registry;
|
||||
|
||||
public: // static methods
|
||||
class IllegalSendError;
|
||||
inline static void remove(TListener&);
|
||||
inline static void add(TListener&);
|
||||
inline static void send(const EvType&);
|
||||
inline static bool isSending();
|
||||
inline static bool hasListeners();
|
||||
inline static unsigned int getNumListeners();
|
||||
inline static unsigned int getMinNumIgnored();
|
||||
|
||||
private: // construct/destroy singleton
|
||||
EventSender(): _isBusySending(false), _eventIgnored(0) {}
|
||||
~EventSender();
|
||||
|
||||
private: // methods called by Listener
|
||||
void registerListener(TListener*);
|
||||
void removeListener(TListener*);
|
||||
void incEventIgnored() {_eventIgnored ++;}
|
||||
static EventSender<EvType>& instance(); // MUST NOT BE INLINE
|
||||
|
||||
private: // utility methods
|
||||
void sendEvent(const EvType&);
|
||||
void cleanupQueues();
|
||||
bool removeFrom(Registry&, TListener*);
|
||||
inline std::string lisnrID(TListener* = NULL) const;
|
||||
//bool hasListener(TListener*) const;
|
||||
|
||||
private: // data
|
||||
/// Registry of listeners that want to hear events of this type
|
||||
Registry _registry;
|
||||
|
||||
/// True if EvType events are being sent (ie calling listeners)
|
||||
bool _isBusySending;
|
||||
/// How many listeners ignored the last event sent (so far)
|
||||
unsigned int _eventIgnored;
|
||||
/// The queue for registering listeners when send() is in progress
|
||||
Registry _registrationQueue;
|
||||
/// The queue for removing listeners when send() is in progress
|
||||
Registry _removalQueue;
|
||||
};
|
||||
|
||||
/** Specialization of EventSender for events inheriting
|
||||
from PolymorphEvent. This provides a natural alternative
|
||||
to the call on Polymorph::send().
|
||||
*/
|
||||
template <>
|
||||
class EventSender<PolymorphEvent>
|
||||
{
|
||||
public:
|
||||
/** Send the polymorphic event to its listeners. It simply calls
|
||||
PolymorphEvent::send(), which must be overriden by subclasses
|
||||
of PolymorphEvent to call EventSender<EvType>::send(const EvType&).
|
||||
Hence see the latter for more info.
|
||||
*/
|
||||
static void send(const PolymorphEvent& event)
|
||||
{
|
||||
event.send();
|
||||
}
|
||||
};
|
||||
|
||||
/* Include IllegalSendError in this header so users don't have
|
||||
to include manually. It has to be included after class definition
|
||||
since it is an inner class to EventSender.
|
||||
*/
|
||||
#include "IllegalSendError.h"
|
||||
|
||||
/** Are there listeners currently registered? If this returns false,
|
||||
creating and send()ing and event just wastes cpu cycles since no
|
||||
one will hear event.
|
||||
\return true if there are listeners in registry
|
||||
*/
|
||||
template<typename EvType>
|
||||
inline bool
|
||||
EventSender<EvType>::hasListeners()
|
||||
{
|
||||
return ! instance()._registry.empty();
|
||||
}
|
||||
|
||||
/** Get how many listeners have ignored the event
|
||||
that is currently being sent and that they have received.
|
||||
This number is reset to 0 before every call to send(const EvType&).
|
||||
This number is a minimum, since a listener is not required to
|
||||
tell EventSender<EvType> that it is ignoring an event.
|
||||
*/
|
||||
template<typename EvType>
|
||||
inline unsigned int
|
||||
EventSender<EvType>::getMinNumIgnored()
|
||||
{
|
||||
return instance()._eventIgnored;
|
||||
}
|
||||
|
||||
/** Get how many listeners are currently registered. Note that if
|
||||
isSending() is true, then this number does not take into account
|
||||
listeners that are queued for registration/removal.
|
||||
*/
|
||||
template<typename EvType>
|
||||
inline unsigned int
|
||||
EventSender<EvType>::getNumListeners()
|
||||
{
|
||||
return instance()._registry.size();
|
||||
}
|
||||
|
||||
/** Send the \a event to its listeners.
|
||||
|
||||
- Upon return, getNumIgnored() will have the number of
|
||||
listeners who have ignored the event.
|
||||
- If one of the called listeners calls registerListener or
|
||||
removeListener, the operation will be queued and processed only
|
||||
after the event has been sent to all listeners. This insures the
|
||||
integrity of the list of listeners during the send()
|
||||
process.
|
||||
- Throws an exception if called while another send() is
|
||||
taking place, see IllegalSendError. You can use
|
||||
isSending() to test whether a send is taking place.
|
||||
- All other exceptions are caught
|
||||
|
||||
\exception IllegalSendError
|
||||
*/
|
||||
template<typename EvType>
|
||||
inline void
|
||||
EventSender<EvType>::send(const EvType& event)
|
||||
{
|
||||
instance().sendEvent(event);
|
||||
}
|
||||
|
||||
/** Is this event sender currently sending the event to
|
||||
its listeners? True if yes, false otherwise.
|
||||
*/
|
||||
template<typename EvType>
|
||||
inline bool
|
||||
EventSender<EvType>::isSending()
|
||||
{
|
||||
return instance()._isBusySending;
|
||||
}
|
||||
|
||||
/** Remove the \a listener from the registry. Does
|
||||
nothing if the listener is not in the registry.
|
||||
*/
|
||||
template<typename EvType>
|
||||
inline void
|
||||
EventSender<EvType>::remove(TListener& listener)
|
||||
{
|
||||
listener.TListener::ignoreEvents();
|
||||
}
|
||||
|
||||
/** Add the \a listener to the registry. Does nothing
|
||||
if the listener is already registered.
|
||||
*/
|
||||
template<typename EvType>
|
||||
inline void
|
||||
EventSender<EvType>::add(TListener& listener)
|
||||
{
|
||||
listener.TListener::listenForEvents();
|
||||
}
|
||||
|
||||
/// Shortcut for TypeID of a listener
|
||||
template<typename EvType>
|
||||
inline std::string
|
||||
EventSender<EvType>::lisnrID(TListener* lisnr)
|
||||
const
|
||||
{
|
||||
std::ostringstream lisnrStr;
|
||||
lisnrStr << typeid(TListener).name();
|
||||
if (lisnr) lisnrStr << ":" << lisnr;
|
||||
return lisnrStr.str();
|
||||
}
|
||||
|
||||
//#ifdef __GNUG__
|
||||
// // because gcc doesn't handle separate template definition
|
||||
// #include "EventSender.cc"
|
||||
//#endif
|
||||
|
||||
#endif // EVENT_SENDER_H
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
#ifndef ILLEGAL_SEND_ERROR_H
|
||||
#define ILLEGAL_SEND_ERROR_H
|
||||
|
||||
/**
|
||||
\file
|
||||
Class template definition file.
|
||||
|
||||
\copyright
|
||||
Copyright (C) 2002, 2003 Oliver Schoenborn
|
||||
|
||||
This software is provided 'as-is', without
|
||||
any express or implied warranty. In no event
|
||||
will the authors be held liable for any
|
||||
damages arising from the use of this
|
||||
software.
|
||||
|
||||
You can redistribute it and/or modify it
|
||||
under the terms found in the LICENSE file that
|
||||
is included in the library distribution.
|
||||
\endcopyright
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <typeinfo>
|
||||
#include <stdexcept>
|
||||
|
||||
/**
|
||||
\class EventSender<EvType>::IllegalSendError
|
||||
|
||||
An exception that gets thrown when EventSender<EvType>::send() is called
|
||||
recursively at least once. This situation is more likely in complex
|
||||
systems where events cause other events to be generated.
|
||||
|
||||
An example scenario is where you create an Type1Event and call
|
||||
EventSender<Type1Event>::send(Type1Event). This call to send() in turn
|
||||
calls the processEvent() method of a listener of Type1Event's.
|
||||
If this listener's method creates another Type1Event and calls
|
||||
EventSender<Type1Event>::send(Type1Event) on it, this will cause that
|
||||
listener's processEvent() to be called once more, and the
|
||||
process repeats. This is likely to trigger an infinite loop of
|
||||
event generation. The only case where this would not happen is if
|
||||
the listener keeps state information that changes between successive
|
||||
calls to processEvent(), such that it does not generate an event
|
||||
during one of those calls (the recursion ends), or if this listener
|
||||
deregister's itself from listening.
|
||||
|
||||
Since an infinite recursion is likely to cause a program crash, and
|
||||
since it is quite easy to make that kind of mistake, EventSender<EvType>
|
||||
forbids calling send() while a send() (for that event type) is
|
||||
in progress. It will throw a EventSender<EvType>::IllegalSendError if
|
||||
such a situation occurs.
|
||||
|
||||
\author Oliver Schoenborn
|
||||
\since Sept 2002
|
||||
*/
|
||||
|
||||
template<typename EvType>
|
||||
class EventSender<EvType>::IllegalSendError
|
||||
: public std::logic_error
|
||||
{
|
||||
public:
|
||||
/// Create the exception
|
||||
IllegalSendError() : std::logic_error( msg() ) {}
|
||||
|
||||
private:
|
||||
/// Prefix for each new line
|
||||
static std::string nl() throw() { return "\n!!! "; }
|
||||
|
||||
/// The message to give to std::logic_error constructor.
|
||||
static std::string msg()
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << nl() << "BUG alert (Recursive send forbidden): "
|
||||
<< nl() << "Method send() of " << typeid(EventSender<EvType>).name()
|
||||
<< nl() << "calls itself indirectly through listeners"
|
||||
<< nl() << "(forbidden since could lead to infinite loop).";
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
|
||||
#endif // ILLEGAL_SEND_ERROR_H
|
|
@ -0,0 +1,63 @@
|
|||
|
||||
/**
|
||||
\class Listener
|
||||
|
||||
Derive your class from a Listener<EvType>, to give it the
|
||||
ability to hear (i.e. receive, listen to) events of type
|
||||
EvType. EvType is a fundamental type (bool, int, float,
|
||||
etc), a struct or a class of your choice. You must define
|
||||
Listener<EvType>::processEvent() in your Listener<EvType>
|
||||
subclass. You call listenForEvents() on your listener
|
||||
instance (at least once) for it to be able to hear (i.e.
|
||||
receive) any EvType event, and you call ignoreEvents() on
|
||||
the instance so it will no longer receive events of type
|
||||
EvType.
|
||||
|
||||
\note
|
||||
- Do not assume that the Listeners will receive the generated event in
|
||||
the same order as they registered.
|
||||
- A class can listen to more than one type of event by inheriting
|
||||
from more than one type of listener. Calling listenForEvents()
|
||||
then is done by specifying which listenForEvents() to call, e.g.
|
||||
\code
|
||||
class YourListener:
|
||||
public Listener<TicEvent>, public Listener<TacEvent>
|
||||
{
|
||||
public:
|
||||
YourListener() {
|
||||
Listener<TicEvent>::listenForEvents();
|
||||
Listener<TacEvent>::listenForEvents();
|
||||
}
|
||||
protected:
|
||||
virtual void processEvent(const TicEvent& event) {...}
|
||||
virtual void processEvent(const TacEvent& event) {...}
|
||||
};
|
||||
\endcode
|
||||
- If a subclass of your class must also process an event, remember
|
||||
that because its processEvent is virtual, it will be the first
|
||||
one called. Therefore it should call its base class method:
|
||||
\code
|
||||
struct TicEvent {...};
|
||||
class YourListener: public Listener<TicEvent> {...};
|
||||
class DerivedListener: public YourListener
|
||||
{
|
||||
public:
|
||||
// ...
|
||||
protected:
|
||||
virtual void processEvent(const TicEvent& event)
|
||||
{
|
||||
// give parent class a chance to process event
|
||||
YourListener::processEvent(event);
|
||||
// do our stuff ...
|
||||
}
|
||||
};
|
||||
\endcode
|
||||
- ignoreThisEvent(): You can call it (from inside
|
||||
processEvent()) to tell EventSender<EvType> that you will be ignoring
|
||||
the event received. This can be a useful way to signify an error in
|
||||
the data sent by the event generator. Just keep in mind that the
|
||||
generator of the event may not actually check whether any listener
|
||||
ignored the event (it may not care).
|
||||
|
||||
|
||||
*/
|
|
@ -0,0 +1,63 @@
|
|||
|
||||
/**
|
||||
\class Listener
|
||||
|
||||
Derive your class from a Listener<EvType>, to give it the
|
||||
ability to hear (i.e. receive, listen to) events of type
|
||||
EvType. EvType is a fundamental type (bool, int, float,
|
||||
etc), a struct or a class of your choice. You must define
|
||||
Listener<EvType>::processEvent() in your Listener<EvType>
|
||||
subclass. You call listenForEvents() on your listener
|
||||
instance (at least once) for it to be able to hear (i.e.
|
||||
receive) any EvType event, and you call ignoreEvents() on
|
||||
the instance so it will no longer receive events of type
|
||||
EvType.
|
||||
|
||||
\note
|
||||
- Do not assume that the Listeners will receive the generated event in
|
||||
the same order as they registered.
|
||||
- A class can listen to more than one type of event by inheriting
|
||||
from more than one type of listener. Calling listenForEvents()
|
||||
then is done by specifying which listenForEvents() to call, e.g.
|
||||
\code
|
||||
class YourListener:
|
||||
public Listener<TicEvent>, public Listener<TacEvent>
|
||||
{
|
||||
public:
|
||||
YourListener() {
|
||||
Listener<TicEvent>::listenForEvents();
|
||||
Listener<TacEvent>::listenForEvents();
|
||||
}
|
||||
protected:
|
||||
virtual void processEvent(const TicEvent& event) {...}
|
||||
virtual void processEvent(const TacEvent& event) {...}
|
||||
};
|
||||
\endcode
|
||||
- If a subclass of your class must also process an event, remember
|
||||
that because its processEvent is virtual, it will be the first
|
||||
one called. Therefore it should call its base class method:
|
||||
\code
|
||||
struct TicEvent {...};
|
||||
class YourListener: public Listener<TicEvent> {...};
|
||||
class DerivedListener: public YourListener
|
||||
{
|
||||
public:
|
||||
// ...
|
||||
protected:
|
||||
virtual void processEvent(const TicEvent& event)
|
||||
{
|
||||
// give parent class a chance to process event
|
||||
YourListener::processEvent(event);
|
||||
// do our stuff ...
|
||||
}
|
||||
};
|
||||
\endcode
|
||||
- ignoreThisEvent(): You can call it (from inside
|
||||
processEvent()) to tell EventSender<EvType> that you will be ignoring
|
||||
the event received. This can be a useful way to signify an error in
|
||||
the data sent by the event generator. Just keep in mind that the
|
||||
generator of the event may not actually check whether any listener
|
||||
ignored the event (it may not care).
|
||||
|
||||
|
||||
*/
|
|
@ -0,0 +1,67 @@
|
|||
#ifndef POLYMORPHIC_EVENT_H
|
||||
#define POLYMORPHIC_EVENT_H
|
||||
|
||||
/** \file
|
||||
Class definition file.
|
||||
|
||||
\copyright
|
||||
Copyright (C) 2002, 2003 Oliver Schoenborn
|
||||
|
||||
This software is provided 'as-is', without
|
||||
any express or implied warranty. In no event
|
||||
will the authors be held liable for any
|
||||
damages arising from the use of this
|
||||
software.
|
||||
|
||||
You can redistribute it and/or modify it
|
||||
under the terms found in the LICENSE file that
|
||||
is included in the library distribution.
|
||||
\endcopyright
|
||||
*/
|
||||
|
||||
//#include "EventFWD.h"
|
||||
|
||||
/**
|
||||
Derive your class from a PolymorphEvent to make it usable
|
||||
polymorphically. This just requires that your event subclass then
|
||||
define the send() pure virtual method, typically simply as
|
||||
\code
|
||||
struct ConcreteEvent: public PolymorphEvent
|
||||
{
|
||||
// ... your event-specific data and methods ...
|
||||
// ... and the override:
|
||||
virtual void send() const { sendTypedEvent(*this); }
|
||||
};
|
||||
\endcode
|
||||
*/
|
||||
class PolymorphEvent
|
||||
{
|
||||
public:
|
||||
/** Causes this event to be sent out to all listeners. The
|
||||
subclass must provide an override so the event can be used
|
||||
polymorphically. This allows you to have a container
|
||||
of PolymorphEvent's of unknown concrete types, e.g. to queue
|
||||
events of different types.
|
||||
*/
|
||||
virtual void send() const = 0;
|
||||
|
||||
protected:
|
||||
/// Need virtual destructor for polymorphic queues
|
||||
virtual ~PolymorphEvent() {}
|
||||
|
||||
/**
|
||||
The class derived from PolymorphEvent must override send()
|
||||
to make it call EventSender<EvType>::send(). It can also
|
||||
simply override it by making it call this method, sendTypedEvent,
|
||||
with *this. This method is really just a helper to simplify the
|
||||
syntax required for overriding send().
|
||||
*/
|
||||
template <typename EvType>
|
||||
inline static void
|
||||
sendTypedEvent(const EvType& event) {EventSender<EvType>::send(event);}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // POLYMORPHIC_EVENT_H
|
|
@ -0,0 +1,150 @@
|
|||
#ifndef TIME_STAMPED_EVENT_H
|
||||
#define TIME_STAMPED_EVENT_H
|
||||
|
||||
/** \file
|
||||
Class definition file.
|
||||
|
||||
\copyright
|
||||
Copyright (C) 2002, 2003 Oliver Schoenborn
|
||||
|
||||
This software is provided 'as-is', without
|
||||
any express or implied warranty. In no event
|
||||
will the authors be held liable for any
|
||||
damages arising from the use of this
|
||||
software.
|
||||
|
||||
You can redistribute it and/or modify it
|
||||
under the terms found in the LICENSE file that
|
||||
is included in the library distribution.
|
||||
\endcopyright
|
||||
*/
|
||||
|
||||
/**
|
||||
Example of time stamper. It requires only one typedef (DataType), and one
|
||||
member function (getTimeStamp). The extra member function, used
|
||||
for ordering two time stamps, is only necessary if your code
|
||||
does a call to the ordering functions of TimeStampedEvent.
|
||||
\note
|
||||
- The member functions need not be static and/or inline; this is
|
||||
determined by your implementation of time-stamper;
|
||||
- The return type and arguments to leftOlder() would be "const DataType&"
|
||||
instead of "DataType", if DataType were a class rather than a
|
||||
fundamental type.
|
||||
*/
|
||||
template <typename IntType>
|
||||
struct TimeStamper
|
||||
{
|
||||
/// The type of data holding the timestamp
|
||||
typedef IntType DataType;
|
||||
static IntType getTimeStamp();
|
||||
/// Return true only if \a left is strictly older than \a right
|
||||
inline static bool leftOlder(IntType left, IntType right) {return left < right;}
|
||||
};
|
||||
|
||||
/**
|
||||
Get the time stamp. This is where we define how to
|
||||
implement time stamping. Here, we simply increment a
|
||||
counter.
|
||||
*/
|
||||
template <typename IntType>
|
||||
IntType
|
||||
TimeStamper<IntType>::getTimeStamp()
|
||||
{
|
||||
static IntType stamp = 0;
|
||||
return ++ stamp;
|
||||
}
|
||||
|
||||
/**
|
||||
Default time stamper just uses a counter of type
|
||||
unsigned long int. It has the benefit of
|
||||
- complete portability
|
||||
- speed
|
||||
- garantee of unique stamp for every event
|
||||
|
||||
Time stampers that rely on system clocks typically
|
||||
suffer in all three areas: the call is relatively costly,
|
||||
several events may end up with the same time stamp,
|
||||
the system clock may provide different resolutions on
|
||||
different systems, and may not be accessible with the
|
||||
same system calls.
|
||||
|
||||
The only disadvantage is that the time stamp will cycle every 2^N
|
||||
events, where N is the number of bits for the long int data type.
|
||||
Consequences:
|
||||
- 32-bit longs:
|
||||
- over 4 billion events before rollover;
|
||||
- one million time-stamped events/second implies a rollover
|
||||
every hour;
|
||||
- therefore a program generating 1 million \em time-stamped
|
||||
events/sec (not all event types need be time-stamped in your
|
||||
program) would have to run \em uninterrupted for more than
|
||||
one hour in order to see the rollover;
|
||||
- 64-bit longs:
|
||||
- 20 billion billion events (2x10^19) before rollover;
|
||||
- one billion time-stamped events/second implies a rollover
|
||||
every 700 years;
|
||||
- therefore a program generating 1 billion \em time-stamped
|
||||
events/sec would have to run \em uninterrupted for more than
|
||||
700 years in order to see the rollover.
|
||||
|
||||
If this limitation is not acceptable, you have two choices:
|
||||
- Create your own integer-based time-stamper, via a new class or a
|
||||
specialization of TimeStamper<IntType>, with an integer type that
|
||||
garantees enough bits (e.g., certain libraries provide a class
|
||||
where the number of bits is specified via a template parameter,
|
||||
e.g. Int<128>, or perhaps the Standard will eventually supply
|
||||
int64 and int128);
|
||||
- Create your own generic time-stamper via a new class, and
|
||||
define the appropriate members (DataType, getTimeStamp(), and
|
||||
leftOlder()).
|
||||
*/
|
||||
typedef TimeStamper<unsigned long int> DefaultTimeStamper;
|
||||
|
||||
/**
|
||||
A simple basic event class that provides a time stamp for creation
|
||||
of the event. This class must be subclassed into a specific event
|
||||
(it can only be instantiated via a derived class since the
|
||||
constructor and destructor are protected), where data relevant to
|
||||
the event is stored.
|
||||
|
||||
The time stamp is the number of seconds since the first TimeStampedEvent
|
||||
was instantiated. This strategy ensures that the reference is always
|
||||
well defined and independent of compiler etc, is a relatively small
|
||||
number, and can be repeated.
|
||||
|
||||
\author Oliver Schoenborn
|
||||
\since Sept 2002
|
||||
*/
|
||||
template <class Stamper = DefaultTimeStamper>
|
||||
class TimeStampedEvent
|
||||
{
|
||||
public:
|
||||
/** Get creation time of this event. This is given as
|
||||
the number of seconds (or fraction thereof) since the
|
||||
first instantiation of a TimeStampedEvent object.
|
||||
\return seconds since first TimeStampedEvent object created
|
||||
*/
|
||||
const typename Stamper::DataType& getTimeStamp() const {return _timeStamp;}
|
||||
|
||||
/// Return true only if *this has a time stamp older than that of \a tse
|
||||
bool isOlderThan(const TimeStampedEvent& tse) const
|
||||
{
|
||||
return Stamper::leftOlder(_timeStamp, tse._timeStamp);
|
||||
}
|
||||
|
||||
/// Return true only if *this has a time stamp older than that of \a tse
|
||||
bool operator<(const TimeStampedEvent& tse) const {return isOlderThan(tse);}
|
||||
|
||||
protected:
|
||||
/// Create a TimeStampedEvent object.
|
||||
TimeStampedEvent(): _timeStamp( Stamper::getTimeStamp() ) {}
|
||||
/// Protected destructor will prevent user from calling delete
|
||||
/// on a pointer to a TimeStampedEvent.
|
||||
~TimeStampedEvent() {}
|
||||
|
||||
private: // data
|
||||
/// Creation time of current instance of event
|
||||
const typename Stamper::DataType _timeStamp;
|
||||
};
|
||||
|
||||
#endif // TIME_STAMPED_EVENT_H
|
|
@ -19,6 +19,10 @@
|
|||
#include <map>
|
||||
#include <string>
|
||||
#include <queue>
|
||||
#include "Listener.h"
|
||||
#include "EventSender.h"
|
||||
#include "TimeStampedEvent.h"
|
||||
#include "PolymorphEvent.h"
|
||||
|
||||
namespace fsm = boost::statechart;
|
||||
|
||||
|
|
|
@ -8,8 +8,6 @@ typedef struct MDCLIENT {
|
|||
|
||||
|
||||
typedef std::map<int,mdLiveClient*> ClientsByHandle;
|
||||
typedef std::map<int,mdDataClient*> DataClientsByHandle;
|
||||
typedef std::map<int,mdInstrument*> InstrumentsByHandle;
|
||||
|
||||
class masterDaemonConfig {
|
||||
|
||||
|
@ -27,7 +25,6 @@ public:
|
|||
mdMachine *machine[MAX_CLIEVER];
|
||||
|
||||
ClientsByHandle allClients;
|
||||
DataClientsByHandle clients;
|
||||
|
||||
date epoch(MD_EPOCH);
|
||||
int debugThreshold,nClients,nClievers,
|
||||
|
|
|
@ -61,9 +61,8 @@
|
|||
using namespace std;
|
||||
using boost::asio::ip::udp;
|
||||
|
||||
#define MAX_CLIENTS 1000
|
||||
#define MAX_CLIENTS 10
|
||||
#define MAX_CLIEVER 1
|
||||
#define MAX_CLIENTS 200
|
||||
#define MAX_SERVERS 3 // Per Cliever cluster.
|
||||
#define MAX_DEBUG 1000 // Set the config parm higher than this to inhibit logNdebug(m...) where m < this
|
||||
#define MAX_DEVICE (((MAX_CLIEVER + 1) * MAX_INSTRUMENTS) + MAX_DATACLIENTS)
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
|
||||
/*!
|
||||
* \todo should be mdcommon.h
|
||||
*/
|
||||
|
||||
|
||||
#define INSTRUMENT 1
|
||||
#define MAX_DEVICE 5 // Machine, Up to 3 optical instruments and the US i/f (Phase II and later)
|
||||
#define MD_DATAGRAM_RESPONSE_SIZE 16 // First three bytes after header are ACK or NAK
|
||||
#define MD_DEFAULT_RULE 0
|
||||
// Our rendering of SCPI-99
|
||||
// Custom behaviors greater than this
|
||||
#define MD_DEFAULT_DEVICE_PROTOCOL 1
|
||||
#define MD_DEFAULT_IP "208.109.106.127"
|
||||
#define MD_EPOCH date()
|
||||
#define MD_HEARTBEAT 1 // Network peer heartbeat in seconds.
|
||||
#define MD_HEARTBEAT_SIZE 8 // Network peer heartbeat in seconds.
|
||||
#define MD_MAX_DATAGRAM (63*1024) // 1K short of the IPV4 max
|
||||
#define MD_NAME "AusReg Cliever"
|
||||
#define MD_VERSION " 1.0 "
|
||||
#define MD_REFRESH 10 // default milliseconds between telemetry frame updates
|
||||
#define MD_TYPE "EPP CLIENT-SERVER" // Change per your MD derivation
|
||||
#define MACHINE 0 // Null machine type impliss MD_TYPE
|
||||
#define OK 0
|
||||
#define OTHERCLIENT 2
|
||||
|
||||
enum md_units {
|
||||
|
||||
centimeters,
|
||||
millimeters,
|
||||
microns,
|
||||
nanometers,
|
||||
angstroms,
|
||||
volts,
|
||||
cubiccentemeter
|
||||
|
||||
};
|
||||
|
||||
enum md_datagrams {
|
||||
|
||||
HEARTBEAT,
|
||||
TELEMETRY
|
||||
|
||||
};
|
||||
|
||||
typedef
|
||||
struct mdHB {
|
||||
char msgType;
|
||||
char deviceType;
|
||||
int msgId;
|
||||
} MDHB;
|
|
@ -0,0 +1,82 @@
|
|||
#ifndef MD_EVENTS
|
||||
#define MD_EVENTS
|
||||
|
||||
class mdAttention: public TimeStampedEvent<>, public PolymorphEvent {
|
||||
|
||||
int idx;
|
||||
public:
|
||||
mdAttention( int count ) { idx = count; }
|
||||
virtual void send() const { sendTypedEvent(*this); }
|
||||
|
||||
};
|
||||
class mdClientBirth: public TimeStampedEvent<>, public PolymorphEvent {
|
||||
public:
|
||||
bool dgDetermined;
|
||||
int mdStdDevIdx;
|
||||
md_device clientType;
|
||||
std::string signature;
|
||||
boost::asio::ip::udp::endpoint ip;
|
||||
|
||||
mdDatagram dg;
|
||||
mdReply dgr;
|
||||
|
||||
mdClientBirth() {
|
||||
dgDetermined = false;
|
||||
mdStdDevIdx = -1;
|
||||
}
|
||||
virtual void send() const { sendTypedEvent(*this); }
|
||||
|
||||
};
|
||||
class mdClientDeath: public TimeStampedEvent<>, public PolymorphEvent {
|
||||
|
||||
public:
|
||||
virtual void send() const { sendTypedEvent(*this); }
|
||||
|
||||
};
|
||||
class mdDeviceCommand: public TimeStampedEvent<>, public PolymorphEvent {
|
||||
|
||||
public:
|
||||
virtual void send() const { sendTypedEvent(*this); }
|
||||
|
||||
};
|
||||
class mdIncoming: public TimeStampedEvent<>, public PolymorphEvent {
|
||||
|
||||
public:
|
||||
mdDatagram dg;
|
||||
boost::asio::ip::udp::endpoint ip;
|
||||
|
||||
mdIncoming(mdDGChannel *bus) {dg = *bus->inProcess;}
|
||||
|
||||
virtual void send() const { sendTypedEvent(*this); }
|
||||
|
||||
};
|
||||
class mdCDPulse: public TimeStampedEvent<>, public PolymorphEvent {
|
||||
|
||||
public:
|
||||
virtual void send() const { sendTypedEvent(*this); }
|
||||
|
||||
};
|
||||
class mdResponse: public TimeStampedEvent<>, public PolymorphEvent {
|
||||
public:
|
||||
int mdStdDevIdx;
|
||||
|
||||
md_dispatch_category dCat;
|
||||
mdDGChannel *bus;
|
||||
mdReply reply;
|
||||
boost::asio::ip::udp::endpoint ip;
|
||||
|
||||
mdResponse(mdDGChannel *c,udp::endpoint ep) :
|
||||
bus(c), ip(ep) { mdStdDevIdx = -1; }
|
||||
|
||||
virtual void send() const { sendTypedEvent(*this); }
|
||||
|
||||
};
|
||||
class mdTelemetryFrame: public TimeStampedEvent<>, public PolymorphEvent {
|
||||
public:
|
||||
int mdStdDevIdx;
|
||||
|
||||
mdTelemetryFrame() {mdStdDevIdx = -1;}
|
||||
|
||||
virtual void send() const { sendTypedEvent(*this); }
|
||||
};
|
||||
#endif
|
|
@ -0,0 +1,258 @@
|
|||
|
||||
#ifndef EVENT_SENDER_CC_TEMPLATE
|
||||
#define EVENT_SENDER_CC_TEMPLATE
|
||||
|
||||
/**
|
||||
\file
|
||||
Class template methods definition file.
|
||||
\copyright
|
||||
Copyright (C) 2002, 2003 Oliver Schoenborn
|
||||
|
||||
This software is provided 'as-is', without
|
||||
any express or implied warranty. In no event
|
||||
will the authors be held liable for any
|
||||
damages arising from the use of this
|
||||
software.
|
||||
|
||||
You can redistribute it and/or modify it
|
||||
under the terms found in the LICENSE file that
|
||||
is included in the library distribution.
|
||||
\endcopyright
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include "EventSender.h"
|
||||
|
||||
/**
|
||||
Get the unique instance of event sender for this type of event.
|
||||
Putting it in a member function insures that the instance
|
||||
cannot be accessed via one of the static methods before it has
|
||||
been created. See C++FAQ book for example of technique.
|
||||
*/
|
||||
template <typename EvType>
|
||||
EventSender<EvType>&
|
||||
EventSender<EvType>::instance()
|
||||
{
|
||||
static EventSender<EvType> eventSender;
|
||||
return eventSender;
|
||||
}
|
||||
|
||||
/// Send the event to each listener in the registry.
|
||||
template <typename EvType>
|
||||
void
|
||||
EventSender<EvType>::sendEvent(const EvType& event)
|
||||
{
|
||||
/*
|
||||
If isBusySending == true, then problem: an attempt
|
||||
is being made to send an EvType while one is already
|
||||
being sent to listeners. Since the same listeners will be
|
||||
called again with the new event, this could lead to an
|
||||
infinite loop.
|
||||
*/
|
||||
if (_isBusySending)
|
||||
throw IllegalSendError();
|
||||
|
||||
// nothing else to do if no listeners registered
|
||||
if (_registry.empty())
|
||||
{
|
||||
theseLogs.logN(1,"No %s event registered.",lisnrID().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
assert(!_isBusySending);
|
||||
_isBusySending = true;
|
||||
_eventIgnored = 0; // reset the event-ignored counter
|
||||
|
||||
// Send event to each listener currently in registry
|
||||
typename Registry::iterator registryIter = _registry.begin();
|
||||
for (typename Registry::iterator registryIter = _registry.begin();
|
||||
registryIter != _registry.end(); ++ registryIter)
|
||||
{
|
||||
theseLogs.logNdev(1,"Calling %s::processEventPublic",lisnrID(*registryIter).c_str());
|
||||
try
|
||||
{
|
||||
(*registryIter)->processEventPublic(event);
|
||||
}
|
||||
catch (const IllegalSendError&)
|
||||
{
|
||||
// propagate recursive flushes up the stack
|
||||
_isBusySending = false;
|
||||
cleanupQueues();
|
||||
throw;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
theseLogs.logNdebug(2,"BUG : %s::processEvent() threw an EXCEPTION of type %s", lisnrID(*registryIter).c_str(),typeid(e).name(),e.what());
|
||||
theseLogs.logNdebug(1,"....: The processEvent() must NOT leak ANY exception. \n\t\t\t Message is: ", e.what());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
theseLogs.logNdebug(1,"BUG : %s::processEvent() threw an EXCEPTION of UNKNOWN type (not derived from std::exception).",lisnrID(*registryIter).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
_isBusySending = false;
|
||||
// hold promise: the registration queue must
|
||||
// be empty when isBusySending is over
|
||||
cleanupQueues();
|
||||
}
|
||||
|
||||
/** When the EventSender is destroyed, every registered
|
||||
listener must first be deregistered.
|
||||
*/
|
||||
template<typename EvType>
|
||||
EventSender<EvType>::~EventSender()
|
||||
{
|
||||
// doesn't make sense to have EventSender destroyed while sending
|
||||
assert(!_isBusySending);
|
||||
// deregister every listener
|
||||
while (! _registry.empty())
|
||||
{
|
||||
_registry.front()->TListener::ignoreEvents();
|
||||
}
|
||||
}
|
||||
|
||||
/** Move listeners queued for registration into the list
|
||||
of active listeners, and remove listeners that are in
|
||||
the removal queue from the registry.
|
||||
*/
|
||||
template<typename EvType>
|
||||
void
|
||||
EventSender<EvType>::cleanupQueues()
|
||||
{
|
||||
assert(_isBusySending == false);
|
||||
|
||||
// register listeners that have been queued for registration
|
||||
while (! _registrationQueue.empty())
|
||||
{
|
||||
typename Registry::iterator registryIter = _registrationQueue.begin();
|
||||
theseLogs.logNdev(1,"Registering queued %s ",lisnrID(*registryIter).c_str());
|
||||
// splice node from registration queue to registry
|
||||
_registry.splice(_registry.end(), _registrationQueue, registryIter);
|
||||
// make sure no other copy left in queue
|
||||
assert(std::find(_registrationQueue.begin(),
|
||||
_registrationQueue.end(), _registry.back())
|
||||
== _registrationQueue.end());
|
||||
}
|
||||
|
||||
// remove listeners that have been queued for removal
|
||||
while (! _removalQueue.empty())
|
||||
{
|
||||
TListener* lisnr = _removalQueue.back();
|
||||
theseLogs.logNdev(1,"Removing queued %s ",lisnrID(lisnr).c_str());
|
||||
if (! removeFrom(_registry, lisnr) )
|
||||
theseLogs.logNdebug(1,"Listener %s not in registry, removal ignored.", lisnrID(lisnr).c_str());
|
||||
_removalQueue.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
/** Remove \a lisnr from \a container. Return true if the
|
||||
listener has been removed, false if it wasn't found in the
|
||||
container.
|
||||
*/
|
||||
template<typename EvType>
|
||||
bool
|
||||
EventSender<EvType>::removeFrom(Registry& container, TListener* lisnr)
|
||||
{
|
||||
// Find iterator for listener to be removed
|
||||
typename Registry::iterator removeIter
|
||||
= std::find(container.begin(), container.end(), lisnr);
|
||||
if ( removeIter != container.end() )
|
||||
{
|
||||
container.erase(removeIter);
|
||||
theseLogs.logNdebug(1,"%s removed from list",lisnrID(lisnr).c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
// listener not found anywhere
|
||||
theseLogs.logN(1,"%s NOT found in list",lisnrID(lisnr).c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Remove a Listener from this EventSender's list of listeners.
|
||||
This should only be called by Listener if it is currently
|
||||
registered or queued for registration.
|
||||
\note
|
||||
- Actual removal takes place just before send() returns, just
|
||||
after all listeners have processed the event, since the list of
|
||||
listeners must not change during a send() operation.
|
||||
|
||||
\pre \a lisnr is not null (not checked)
|
||||
\param lisnr the listener to remove from the registry
|
||||
*/
|
||||
template<typename EvType>
|
||||
void
|
||||
EventSender<EvType>::removeListener(TListener* lisnr)
|
||||
{
|
||||
if (_isBusySending)
|
||||
{
|
||||
if (! removeFrom(_registrationQueue, lisnr))
|
||||
{
|
||||
assert(std::find(_removalQueue.begin(),
|
||||
_removalQueue.end(), lisnr) == _removalQueue.end());
|
||||
_removalQueue.push_back(lisnr);
|
||||
|
||||
theseLogs.logNdev(1,"Putting %s on removal queue",lisnrID(lisnr).c_str());
|
||||
}
|
||||
else // nothing to do, already removed from registration queue
|
||||
{
|
||||
theseLogs.logNdev(1,"%s removed from registration queue",lisnrID(lisnr).c_str());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(_removalQueue.empty());
|
||||
assert(_registrationQueue.empty());
|
||||
const bool removed = removeFrom(_registry, lisnr);
|
||||
assert(removed);
|
||||
}
|
||||
}
|
||||
|
||||
/** Register a Listener with this EventSender. This should only be
|
||||
called by Listener if it is currently not registered or is
|
||||
queued for removal.
|
||||
\note
|
||||
- If this is called while a send() is in progress, actual
|
||||
registration takes place at the end of a send() operation,
|
||||
so that the registry of listeners will not change during the
|
||||
send().
|
||||
\pre \a lisnr is not null (not checked)
|
||||
\param lisnr the listener to add to the registry.
|
||||
*/
|
||||
template<typename EvType>
|
||||
void
|
||||
EventSender<EvType>::registerListener(TListener* lisnr)
|
||||
{
|
||||
if (_isBusySending)
|
||||
// use queues instead
|
||||
{
|
||||
// first see if it is on the removal queue
|
||||
if (! removeFrom(_removalQueue, lisnr))
|
||||
{
|
||||
// wasn't in removal queue, so put on registration queue
|
||||
// note that it shouldn't be possible to have listener
|
||||
// register itself if it is already in the queue or registered
|
||||
assert(std::find(_registrationQueue.begin(),
|
||||
_registrationQueue.end(), lisnr) == _registrationQueue.end());
|
||||
_registrationQueue.push_back(lisnr);
|
||||
theseLogs.logNdev(1,"Putting %s on registration queue ",lisnrID(lisnr).c_str());
|
||||
}
|
||||
else // nothing to do, already in queue
|
||||
{
|
||||
theseLogs.logNdev(1,"%s removed from registration queue",lisnrID(lisnr).c_str());
|
||||
}
|
||||
}
|
||||
else // safe to register immediately
|
||||
{
|
||||
// this method never called if already registerd, so assert this:
|
||||
assert(std::find(_registry.begin(), _registry.end(), lisnr)
|
||||
== _registry.end());
|
||||
|
||||
_registry.push_back(lisnr);
|
||||
theseLogs.logNdev(1,"Added (immediate) %s to listeners list ",lisnrID(lisnr).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif // EVENT_SENDER_CC_TEMPLATE
|
||||
|
|
@ -0,0 +1,258 @@
|
|||
|
||||
#ifndef EVENT_SENDER_CC_TEMPLATE
|
||||
#define EVENT_SENDER_CC_TEMPLATE
|
||||
|
||||
/**
|
||||
\file
|
||||
Class template methods definition file.
|
||||
\copyright
|
||||
Copyright (C) 2002, 2003 Oliver Schoenborn
|
||||
|
||||
This software is provided 'as-is', without
|
||||
any express or implied warranty. In no event
|
||||
will the authors be held liable for any
|
||||
damages arising from the use of this
|
||||
software.
|
||||
|
||||
You can redistribute it and/or modify it
|
||||
under the terms found in the LICENSE file that
|
||||
is included in the library distribution.
|
||||
\endcopyright
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include "EventSender.h"
|
||||
|
||||
/**
|
||||
Get the unique instance of event sender for this type of event.
|
||||
Putting it in a member function insures that the instance
|
||||
cannot be accessed via one of the static methods before it has
|
||||
been created. See C++FAQ book for example of technique.
|
||||
*/
|
||||
template <typename EvType>
|
||||
EventSender<EvType>&
|
||||
EventSender<EvType>::instance()
|
||||
{
|
||||
static EventSender<EvType> eventSender;
|
||||
return eventSender;
|
||||
}
|
||||
|
||||
/// Send the event to each listener in the registry.
|
||||
template <typename EvType>
|
||||
void
|
||||
EventSender<EvType>::sendEvent(const EvType& event)
|
||||
{
|
||||
/*
|
||||
If isBusySending == true, then problem: an attempt
|
||||
is being made to send an EvType while one is already
|
||||
being sent to listeners. Since the same listeners will be
|
||||
called again with the new event, this could lead to an
|
||||
infinite loop.
|
||||
*/
|
||||
if (_isBusySending)
|
||||
throw IllegalSendError();
|
||||
|
||||
// nothing else to do if no listeners registered
|
||||
if (_registry.empty())
|
||||
{
|
||||
theseLogs->logN(1,"No %s event registered.",lisnrID().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
assert(!_isBusySending);
|
||||
_isBusySending = true;
|
||||
_eventIgnored = 0; // reset the event-ignored counter
|
||||
|
||||
// Send event to each listener currently in registry
|
||||
typename Registry::iterator registryIter = _registry.begin();
|
||||
for (typename Registry::iterator registryIter = _registry.begin();
|
||||
registryIter != _registry.end(); ++ registryIter)
|
||||
{
|
||||
theseLogs->logNdev(1,"Calling %s::processEventPublic",lisnrID(*registryIter).c_str());
|
||||
try
|
||||
{
|
||||
(*registryIter)->processEventPublic(event);
|
||||
}
|
||||
catch (const IllegalSendError&)
|
||||
{
|
||||
// propagate recursive flushes up the stack
|
||||
_isBusySending = false;
|
||||
cleanupQueues();
|
||||
throw;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
theseLogs->logNdebug(0,2,"BUG : %s::processEvent() threw an EXCEPTION of type %s", lisnrID(*registryIter).c_str(),typeid(e).name(),e.what());
|
||||
theseLogs->logNdebug(0,1,"....: The processEvent() must NOT leak ANY exception. \n\t\t\t Message is: ", e.what());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
theseLogs->logNdebug(0,1,"BUG : %s::processEvent() threw an EXCEPTION of UNKNOWN type (not derived from std::exception).",lisnrID(*registryIter).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
_isBusySending = false;
|
||||
// hold promise: the registration queue must
|
||||
// be empty when isBusySending is over
|
||||
cleanupQueues();
|
||||
}
|
||||
|
||||
/** When the EventSender is destroyed, every registered
|
||||
listener must first be deregistered.
|
||||
*/
|
||||
template<typename EvType>
|
||||
EventSender<EvType>::~EventSender()
|
||||
{
|
||||
// doesn't make sense to have EventSender destroyed while sending
|
||||
assert(!_isBusySending);
|
||||
// deregister every listener
|
||||
while (! _registry.empty())
|
||||
{
|
||||
_registry.front()->TListener::ignoreEvents();
|
||||
}
|
||||
}
|
||||
|
||||
/** Move listeners queued for registration into the list
|
||||
of active listeners, and remove listeners that are in
|
||||
the removal queue from the registry.
|
||||
*/
|
||||
template<typename EvType>
|
||||
void
|
||||
EventSender<EvType>::cleanupQueues()
|
||||
{
|
||||
assert(_isBusySending == false);
|
||||
|
||||
// register listeners that have been queued for registration
|
||||
while (! _registrationQueue.empty())
|
||||
{
|
||||
typename Registry::iterator registryIter = _registrationQueue.begin();
|
||||
theseLogs->logNdev(1,"Registering queued %s ",lisnrID(*registryIter).c_str());
|
||||
// splice node from registration queue to registry
|
||||
_registry.splice(_registry.end(), _registrationQueue, registryIter);
|
||||
// make sure no other copy left in queue
|
||||
assert(std::find(_registrationQueue.begin(),
|
||||
_registrationQueue.end(), _registry.back())
|
||||
== _registrationQueue.end());
|
||||
}
|
||||
|
||||
// remove listeners that have been queued for removal
|
||||
while (! _removalQueue.empty())
|
||||
{
|
||||
TListener* lisnr = _removalQueue.back();
|
||||
theseLogs->logNdev(1,"Removing queued %s ",lisnrID(lisnr).c_str());
|
||||
if (! removeFrom(_registry, lisnr) )
|
||||
theseLogs->logNdebug(1000,1,"Listener %s not in registry, removal ignored.", lisnrID(lisnr).c_str());
|
||||
_removalQueue.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
/** Remove \a lisnr from \a container. Return true if the
|
||||
listener has been removed, false if it wasn't found in the
|
||||
container.
|
||||
*/
|
||||
template<typename EvType>
|
||||
bool
|
||||
EventSender<EvType>::removeFrom(Registry& container, TListener* lisnr)
|
||||
{
|
||||
// Find iterator for listener to be removed
|
||||
typename Registry::iterator removeIter
|
||||
= std::find(container.begin(), container.end(), lisnr);
|
||||
if ( removeIter != container.end() )
|
||||
{
|
||||
container.erase(removeIter);
|
||||
theseLogs->logNdebug(MAX_DEBUG,1,"%s removed from list",lisnrID(lisnr).c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
// listener not found anywhere
|
||||
theseLogs->logN(1,"%s NOT found in list",lisnrID(lisnr).c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Remove a Listener from this EventSender's list of listeners.
|
||||
This should only be called by Listener if it is currently
|
||||
registered or queued for registration.
|
||||
\note
|
||||
- Actual removal takes place just before send() returns, just
|
||||
after all listeners have processed the event, since the list of
|
||||
listeners must not change during a send() operation.
|
||||
|
||||
\pre \a lisnr is not null (not checked)
|
||||
\param lisnr the listener to remove from the registry
|
||||
*/
|
||||
template<typename EvType>
|
||||
void
|
||||
EventSender<EvType>::removeListener(TListener* lisnr)
|
||||
{
|
||||
if (_isBusySending)
|
||||
{
|
||||
if (! removeFrom(_registrationQueue, lisnr))
|
||||
{
|
||||
assert(std::find(_removalQueue.begin(),
|
||||
_removalQueue.end(), lisnr) == _removalQueue.end());
|
||||
_removalQueue.push_back(lisnr);
|
||||
|
||||
theseLogs->logNdev(1,"Putting %s on removal queue",lisnrID(lisnr).c_str());
|
||||
}
|
||||
else // nothing to do, already removed from registration queue
|
||||
{
|
||||
theseLogs->logNdev(1,"%s removed from registration queue",lisnrID(lisnr).c_str());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(_removalQueue.empty());
|
||||
assert(_registrationQueue.empty());
|
||||
const bool removed = removeFrom(_registry, lisnr);
|
||||
assert(removed);
|
||||
}
|
||||
}
|
||||
|
||||
/** Register a Listener with this EventSender. This should only be
|
||||
called by Listener if it is currently not registered or is
|
||||
queued for removal.
|
||||
\note
|
||||
- If this is called while a send() is in progress, actual
|
||||
registration takes place at the end of a send() operation,
|
||||
so that the registry of listeners will not change during the
|
||||
send().
|
||||
\pre \a lisnr is not null (not checked)
|
||||
\param lisnr the listener to add to the registry.
|
||||
*/
|
||||
template<typename EvType>
|
||||
void
|
||||
EventSender<EvType>::registerListener(TListener* lisnr)
|
||||
{
|
||||
if (_isBusySending)
|
||||
// use queues instead
|
||||
{
|
||||
// first see if it is on the removal queue
|
||||
if (! removeFrom(_removalQueue, lisnr))
|
||||
{
|
||||
// wasn't in removal queue, so put on registration queue
|
||||
// note that it shouldn't be possible to have listener
|
||||
// register itself if it is already in the queue or registered
|
||||
assert(std::find(_registrationQueue.begin(),
|
||||
_registrationQueue.end(), lisnr) == _registrationQueue.end());
|
||||
_registrationQueue.push_back(lisnr);
|
||||
theseLogs->logNdev(1,"Putting %s on registration queue ",lisnrID(lisnr).c_str());
|
||||
}
|
||||
else // nothing to do, already in queue
|
||||
{
|
||||
theseLogs->logNdev(1,"%s removed from registration queue",lisnrID(lisnr).c_str());
|
||||
}
|
||||
}
|
||||
else // safe to register immediately
|
||||
{
|
||||
// this method never called if already registerd, so assert this:
|
||||
assert(std::find(_registry.begin(), _registry.end(), lisnr)
|
||||
== _registry.end());
|
||||
|
||||
_registry.push_back(lisnr);
|
||||
theseLogs->logNdev(1,"Added (immediate) %s to listeners list ",lisnrID(lisnr).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif // EVENT_SENDER_CC_TEMPLATE
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
// guard need for compilers that require template source included in header
|
||||
#ifndef LISTENER_CC_TEMPLATE
|
||||
#define LISTENER_CC_TEMPLATE
|
||||
|
||||
#include "Listener.h"
|
||||
#include "EventSender.h"
|
||||
|
||||
/**
|
||||
\file
|
||||
Class method definition file.
|
||||
|
||||
\copyright
|
||||
Copyright (C) 2002, 2003 Oliver Schoenborn
|
||||
|
||||
This software is provided 'as-is', without
|
||||
any express or implied warranty. In no event
|
||||
will the authors be held liable for any
|
||||
damages arising from the use of this
|
||||
software.
|
||||
|
||||
You can redistribute it and/or modify it
|
||||
under the terms found in the LICENSE file that
|
||||
is included in the library distribution.
|
||||
\endcopyright
|
||||
*/
|
||||
|
||||
#include "Listener.h"
|
||||
#include "EventSender.h"
|
||||
|
||||
/** Tell EventSender<EvType> that this listener is ignoring the event received.
|
||||
This will increment a counter in EventSender<EvType>, such that a call to
|
||||
EventSender<EvType>::getNumIgnored() will return how many listeners ignored
|
||||
the event. Note however that the listener is not \em required to
|
||||
notify EventSender<EvType> that it is ignoring the event, hence this number
|
||||
is only a minimum. This method can be called more than once without
|
||||
screwing up the count. If called from outside a call to
|
||||
Listener<EvType>::processEvent(), nothing is done.
|
||||
*/
|
||||
template<typename EvType>
|
||||
void
|
||||
Listener<EvType>::ignoreThisEvent()
|
||||
{
|
||||
// only a valid call if processing an event
|
||||
if (! _processingEvent) return;
|
||||
|
||||
assert( EventSender<EvType>::isSending() );
|
||||
if (! _ignoringHeardEvent)
|
||||
{
|
||||
EventSender<EvType>::instance().incEventIgnored();
|
||||
_ignoringHeardEvent = true;
|
||||
}
|
||||
|
||||
//assert( EventSender<EvType>::isRegistered(this) == _registered);
|
||||
}
|
||||
|
||||
/** Tell EventSender<EvType> that this listener is not interested in hearing
|
||||
EvType events. This does nothing if already ignoring them.
|
||||
*/
|
||||
template<typename EvType>
|
||||
void
|
||||
Listener<EvType>::ignoreEvents()
|
||||
{
|
||||
if (_registered)
|
||||
{
|
||||
EventSender<EvType>::instance().removeListener(this);
|
||||
_registered = false;
|
||||
}
|
||||
|
||||
//assert( ! EventSender<EvType>::isRegistered(this) );
|
||||
}
|
||||
|
||||
/** Tell EventSender<EvType> that this listener wants to hear
|
||||
EvType events. This does nothing if already listening to them.
|
||||
*/
|
||||
template<typename EvType>
|
||||
void
|
||||
Listener<EvType>::listenForEvents()
|
||||
{
|
||||
if (!_registered)
|
||||
{
|
||||
EventSender<EvType>::instance().registerListener(this);
|
||||
_registered = true;
|
||||
}
|
||||
|
||||
//assert( EventSender<EvType>::isRegistered(this) );
|
||||
}
|
||||
|
||||
|
||||
#endif // LISTENER_CC_TEMPLATE
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,159 @@
|
|||
#include "cliever-md.h"
|
||||
|
||||
#include "log4cpp/Category.hh"
|
||||
#include "log4cpp/Appender.hh"
|
||||
#include "log4cpp/FileAppender.hh"
|
||||
#include "log4cpp/Layout.hh"
|
||||
#include "log4cpp/BasicLayout.hh"
|
||||
#include "log4cpp/Priority.hh"
|
||||
|
||||
using namespace log4cpp;
|
||||
|
||||
Appender *app;
|
||||
char mdLogWork[256];
|
||||
Category &root = Category::getRoot(),
|
||||
&md_core = Category::getInstance(std::string("md_core")),
|
||||
&md_dbug = Category::getInstance(std::string("md_dbug")),
|
||||
&md_devl = Category::getInstance(std::string("md_devl"));
|
||||
PatternLayout *layout;
|
||||
char *logPath,*mainLogFileName,xmlrpcLogFileName;
|
||||
|
||||
void mdLogger::init() {
|
||||
|
||||
const char *mainLogFileName = "auc-md.log",
|
||||
*xmlrpcLogFileName = "auc-xmlrpc.log";
|
||||
|
||||
logPath = new char [strlen(thisConfig->logPath) +
|
||||
strlen(xmlrpcLogFileName) + 2];
|
||||
|
||||
strcpy(logPath,thisConfig->logPath);
|
||||
strcat(logPath,"/");
|
||||
strcat(logPath,xmlrpcLogFileName);
|
||||
|
||||
thisConfig->xmlrpcLogpath = logPath;
|
||||
|
||||
logPath = new char [strlen(thisConfig->logPath) +
|
||||
strlen(mainLogFileName) + 1];
|
||||
|
||||
strcpy(logPath,thisConfig->logPath);
|
||||
strcat(logPath,"/");
|
||||
strcat(logPath,mainLogFileName);
|
||||
|
||||
thisConfig->logPath = logPath;
|
||||
|
||||
app = new FileAppender("default", std::string(logPath));
|
||||
layout = new PatternLayout();
|
||||
layout->setConversionPattern("%d %p %c %x: %m%n");
|
||||
app->setLayout(layout);
|
||||
|
||||
root.addAppender(app);
|
||||
root.setPriority(Priority::ERROR);
|
||||
|
||||
md_core.setPriority(Priority::INFO);
|
||||
md_core.setAdditivity(true);
|
||||
|
||||
md_dbug.setPriority(Priority::DEBUG);
|
||||
md_dbug.setAdditivity(true);
|
||||
|
||||
md_devl.setPriority(Priority::NOTSET);
|
||||
md_devl.setAdditivity(true);
|
||||
|
||||
}
|
||||
void mdLogger::logN(int n, const char *format, ...) {
|
||||
char buff[1024];
|
||||
void *args[4];
|
||||
int nthArg = 0;
|
||||
va_list lm;
|
||||
|
||||
va_start(lm,format);
|
||||
for (;nthArg<n;nthArg++) args[nthArg]=va_arg(lm,void *);
|
||||
va_end(lm);
|
||||
|
||||
switch(n) {
|
||||
case 0:
|
||||
strcpy(buff,format);
|
||||
break;
|
||||
case 1:
|
||||
sprintf(buff,format,args[0]);
|
||||
break;
|
||||
case 2:
|
||||
sprintf(buff,format,args[0],args[1]);
|
||||
break;
|
||||
case 3:
|
||||
sprintf(buff,format,args[0],args[1],args[2]);
|
||||
break;
|
||||
case 4:
|
||||
sprintf(buff,format,args[0],args[1],args[2],args[3]);
|
||||
break;
|
||||
case 5:
|
||||
sprintf(buff,format,args[0],args[1],args[2],args[3],args[4]);
|
||||
break;
|
||||
}
|
||||
md_core.info(buff);
|
||||
}
|
||||
void mdLogger::logNdebug(int m, int n, const char *format, ...) {
|
||||
char buff[1024];
|
||||
void *args[6];
|
||||
int nthArg = 0;
|
||||
va_list lm;
|
||||
|
||||
if (m < 0 || m > thisConfig->debugThreshold) return;
|
||||
|
||||
va_start(lm,format);
|
||||
for (;nthArg<n;nthArg++) args[nthArg]=va_arg(lm,void *);
|
||||
va_end(lm);
|
||||
|
||||
switch(n) {
|
||||
case 0:
|
||||
strcpy(buff,format);
|
||||
break;
|
||||
case 1:
|
||||
sprintf(buff,format,args[0]);
|
||||
break;
|
||||
case 2:
|
||||
sprintf(buff,format,args[0],args[1]);
|
||||
break;
|
||||
case 3:
|
||||
sprintf(buff,format,args[0],args[1],args[2]);
|
||||
break;
|
||||
case 4:
|
||||
sprintf(buff,format,args[0],args[1],args[2],args[3]);
|
||||
break;
|
||||
case 5:
|
||||
sprintf(buff,format,args[0],args[1],args[2],args[3],args[4]);
|
||||
break;
|
||||
}
|
||||
md_dbug.warn(buff);
|
||||
}
|
||||
void mdLogger::logNdev(int n, const char *format, ...) {
|
||||
char buff[1024];
|
||||
void *args[5];
|
||||
int nthArg = 0;
|
||||
va_list lm;
|
||||
|
||||
va_start(lm,format);
|
||||
for (;nthArg<n;nthArg++) args[nthArg]=va_arg(lm,void *);
|
||||
va_end(lm);
|
||||
|
||||
switch(n) {
|
||||
case 0:
|
||||
strcpy(buff,format);
|
||||
break;
|
||||
case 1:
|
||||
sprintf(buff,format,args[0]);
|
||||
break;
|
||||
case 2:
|
||||
sprintf(buff,format,args[0],args[1]);
|
||||
break;
|
||||
case 3:
|
||||
sprintf(buff,format,args[0],args[1],args[2]);
|
||||
break;
|
||||
case 4:
|
||||
sprintf(buff,format,args[0],args[1],args[2],args[3]);
|
||||
break;
|
||||
case 5:
|
||||
sprintf(buff,format,args[0],args[1],args[2],args[3],args[4]);
|
||||
break;
|
||||
}
|
||||
md_devl.warn(buff);
|
||||
}
|
Loading…
Reference in New Issue