This commit is contained in:
parent
fa576a3e11
commit
8ae588ed40
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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 <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;
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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