This commit is contained in:
Ren RenJuan 2014-01-03 07:51:51 +00:00
parent fa576a3e11
commit 8ae588ed40
18 changed files with 1614 additions and 5 deletions

View File

@ -40,6 +40,9 @@ cliever: build/drde-cliever
.c.o: .c.o:
$(Cc) -c $(CLFLAGS) -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 build/cliever.o: server/cliever-md.cpp include/*.h
$(CC) $(CFLAGS) server/cliever-md.cpp -c -o build/cliever.o $(SINCL) $(CC) $(CFLAGS) server/cliever-md.cpp -c -o build/cliever.o $(SINCL)

View File

@ -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

View File

@ -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.
*/

View File

@ -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

View File

@ -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

View File

@ -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).
*/

View File

@ -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).
*/

View File

@ -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

View File

@ -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

View File

@ -19,6 +19,10 @@
#include <map> #include <map>
#include <string> #include <string>
#include <queue> #include <queue>
#include "Listener.h"
#include "EventSender.h"
#include "TimeStampedEvent.h"
#include "PolymorphEvent.h"
namespace fsm = boost::statechart; namespace fsm = boost::statechart;

View File

@ -8,8 +8,6 @@ typedef struct MDCLIENT {
typedef std::map<int,mdLiveClient*> ClientsByHandle; typedef std::map<int,mdLiveClient*> ClientsByHandle;
typedef std::map<int,mdDataClient*> DataClientsByHandle;
typedef std::map<int,mdInstrument*> InstrumentsByHandle;
class masterDaemonConfig { class masterDaemonConfig {
@ -27,7 +25,6 @@ public:
mdMachine *machine[MAX_CLIEVER]; mdMachine *machine[MAX_CLIEVER];
ClientsByHandle allClients; ClientsByHandle allClients;
DataClientsByHandle clients;
date epoch(MD_EPOCH); date epoch(MD_EPOCH);
int debugThreshold,nClients,nClievers, int debugThreshold,nClients,nClievers,

View File

@ -61,9 +61,8 @@
using namespace std; using namespace std;
using boost::asio::ip::udp; using boost::asio::ip::udp;
#define MAX_CLIENTS 1000 #define MAX_CLIENTS 10
#define MAX_CLIEVER 1 #define MAX_CLIEVER 1
#define MAX_CLIENTS 200
#define MAX_SERVERS 3 // Per Cliever cluster. #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_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) #define MAX_DEVICE (((MAX_CLIEVER + 1) * MAX_INSTRUMENTS) + MAX_DATACLIENTS)

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);
}