// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/** \file
- \brief Conenctors public header */
+ \brief Connectors public header */
/** \defgroup connectors Connector classes
senf::ppi::PassiveInput and senf::ppi::PassiveOutput.
*/
-#ifndef HH_Conenctors_
-#define HH_Conenctors_ 1
+#ifndef HH_Connectors_
+#define HH_Connectors_ 1
// Custom includes
+#include <deque>
#include <boost/utility.hpp>
-
-//#include "Conenctors.mpp"
+#include <boost/scoped_ptr.hpp>
+#include "Utils/SafeBool.hh"
+#include "Packets/Packets.hh"
+#include "predecl.hh"
+#include "detail/Callback.hh"
+#include "Queueing.hh"
+
+//#include "Connectors.mpp"
///////////////////////////////hh.p////////////////////////////////////////
namespace senf {
namespace ppi {
+namespace connector {
/** \brief Connector baseclass
: boost::noncopyable
{
public:
- Connector & peer(); ///< Get peer connected to this connector
- Module & module(); ///< Get this connectors containing module
+ Connector & peer() const; ///< Get peer connected to this connector
+ module::Module & module() const; ///< Get this connectors containing module
protected:
- // here to protect
Connector();
- ~Connector();
+ virtual ~Connector();
+
+ void connect(Connector & target);
+
+ private:
+ void setModule(module::Module & module);
+
+ Connector * peer_;
+ module::Module * module_;
+
+ friend class module::Module;
};
/** \brief Passive connector baseclass
notifications
The accumulative throttling state is generated by combining all sub-states.
-
- \ingroup connectors
*/
class PassiveConnector
: public virtual Connector
operation is to be performed. */
- bool throttled(); ///< Get accumulative throttling state
- bool nativeThrottled(); ///< Get native throttling state
+ bool throttled() const; ///< Get accumulative throttling state
+ bool nativeThrottled() const; ///< Get native throttling state
void throttle(); ///< Set native throttling
void unthrottle(); ///< Revoke native throttling
+ ActiveConnector & peer() const;
+
+ protected:
+ PassiveConnector();
+
+ void emit();
+
+ private:
+ // Called by the routing to change the remote throttling state
void notifyThrottle(); ///< Forward a throttling notification to this connector
void notifyUnthrottle(); ///< Forward an unthrottling notification to this connector
- ActiveConnector & peer();
+ // Internal members to emit throttling notifications
+ void emitThrottle();
+ void emitUnthrottle();
- protected:
- // here to protect
- PassiveConnector();
- ~PassiveConnector();
+ // Called after unthrottling the connector
+ virtual void v_unthrottleEvent();
+
+ typedef detail::Callback<>::type Callback;
+ Callback callback_;
+
+ bool remoteThrottled_;
+ bool nativeThrottled_;
+
+ friend class senf::ppi::detail::ForwardForwardingRouteImplementation;
+ friend class senf::ppi::detail::BackwardForwardingRouteImplementation;
};
/** \brief Active connector baseclass
Active connectors do not handle any throttling state, they just receive the
notifications. These notifications should then either be processed by the module or be
forwarded to other connectors.
-
- \ingroup connectors
*/
class ActiveConnector
: public virtual Connector
{
+ typedef detail::Callback<>::type Callback;
public:
template <class Handler>
- void onThrottle(Handler); ///< Register throttle notification handler
+ void onThrottle(Handler handler); ///< Register throttle notification handler
/**< The handler register here will be called, whenever a
throttle notification comes in. The \a handler argument
is either an arbitrary callable object or it is a
\param[in] handler Handler to call on throttle
notifications. */
+ void onThrottle();
template <class Handler>
- void onUnthrottle(Handler); ///< Register unthrottle notification handler
+ void onUnthrottle(Handler handler); ///< Register unthrottle notification handler
/**< The handler register here will be called, whenever an
unthrottle notification comes in. The \a handler
argument is either an arbitrary callable object or it
holds this input. In the second case, the pointer will
automatically be bound to the containing instance.
- \param[in] handler Handler to call on unthrottle
+ \param[in] handle Handler to call on unthrottle
notifications. */
+ void onUnthrottle();
- PassiveConnector & peer();
+ PassiveConnector & peer() const;
protected:
- // here to protect
- PassiveConnector();
- ~PassiveConnector();
+ ActiveConnector();
+
+ private:
+ // called by the peer() to forward throttling notifications
+ void notifyThrottle();
+ void notifyUnthrottle();
+
+ // called by ForwardingRoute to register a new route
+ void registerRoute(ForwardingRoute & route);
+
+ Callback throttleCallback_;
+ Callback unthrottleCallback_;
+
+ typedef std::vector<ForwardingRoute*> NotifyRoutes;
+ NotifyRoutes notifyRoutes_;
+
+ friend class senf::ppi::ForwardingRoute;
+ friend class PassiveConnector;
};
/** \brief Input connector baseclass
packets in batches or generating multiple output packets from a single input packet. The
queues have the potential to greatly simplify the module implementations.
- \ingroup connectors
+ \implementation Which container to use?
+ \li list has good insertion and deletion properties on both ends but it costs a dynamic
+ memory allocation for every insertion. A very good property is, that iterators stay
+ valid across insertions/deletions
+ \li vector is fast and has good amortized dynamic allocation properties. However, it is
+ quite unusable as a queue
+ \li deque has comparable dynamic allocation properties as vector but also has good
+ insertion/removal properties on both ends.
+
+ So probably we will use a deque. I'd like a container which keeps iterators intact on
+ isertion/deletion but I believe that list is just to expensive since every packet will
+ be added to the queue before it can be processed.
*/
class InputConnector
: public virtual Connector
{
+ typedef std::deque<Packet> Queue;
public:
- typedef unspecified queue_iterator; ///< Iterator type of the embedded queue
- typedef unspecified size_type; ///< Unsigned type representing the number of queue elements
+ typedef Queue::const_iterator queue_iterator; ///< Iterator type of the embedded queue
+ typedef Queue::size_type size_type; ///< Unsigned type for counting queue elements
- Packet::ptr operator(); ///< Get a packet
+ Packet operator()(); ///< Get a packet
/**< This member is the primary method to access received
data. On passive connectors, this operator will just
dequeue a packet from the packet queue. If the
request cannot be fulfilled, this is considered to be a
logic error in the module implementation and an
exception is raised. */
- operator unspecified_boolean_type (); ///< Check packet availability
- /**< Using any input connector in a boolean context will
- check, wether an input request can be fulfilled. This
- is always possible if the queue is non-empty. If the
- input is active, it also returns when the connected
- passive output is not throttled so new packets can be
- requested.
- Calling the operator() member is an error if this test
- returns \c false
+ OutputConnector & peer() const;
- \returns \c true if operator() can be called, \c false
- otherwise */
- operator ! (); ///< Check packet availability
- /**< Inverse of the boolean conversion operator
- \returns \c false if operator() can be called, \c true
- otherwise */
+ queue_iterator begin() const; ///< Access queue begin (head)
+ queue_iterator end() const; ///< Access queue past-the-end (tail)
+ Packet peek() const; ///< Return head element from the queue
- OutputConnector & peer();
+ size_type queueSize() const; ///< Return number of elements in the queue
+ bool empty() const; ///< Return queueSize() == 0
- queue_iterator begin(); ///< Access queue begin (head)
- queue_iterator end(); ///< Access queue past-the-end (tail)
- Packet::ptr head(); ///< Return head element from the queue
+ protected:
+ InputConnector();
+
+ private:
+ void enqueue(Packet p);
+
+ virtual void v_requestEvent();
+ virtual void v_enqueueEvent();
+ virtual void v_dequeueEvent();
- size_type queueSize(); ///< Return number of elements in the queue
- bool empty(); ///< Return queueSize() == 0
+ Queue queue_;
- protected:
- // here to protect
- PassiveConnector();
- ~PassiveConnector();
+ friend class OutputConnector;
};
/** \brief Output connector baseclass
An output connector sends out packets. It may be either an ActiveConnector or a
PassiveConnector. An output connector does \e not have an built-in queueing, it relies on
the queueing of the connected input.
-
- \ingroup connectors
*/
class OutputConnector
: public virtual Connector
{
public:
- void operator(Packet::ptr); ///< Send out a packet
+ void operator()(Packet p); ///< Send out a packet
- InputConnector & peer();
+ InputConnector & peer() const;
protected:
- // here to protect
- PassiveConnector();
- ~PassiveConnector();
+ OutputConnector();
};
+
+ ///@{
+ ///\addtogroup connectors
/** \brief Combination of PassiveConnector and InputConnector
- \ingroup connectors
+ The PassiveInput automatically controls the connectors throttling state using a queueing
+ discipline. The standard queueing discipline is ThresholdQueueing, which throttles the
+ connection whenever the queue length reaches the high threshold and unthrottles the
+ connection when the queue reaches the low threshold. The default queueing discipline is
+ <tt>ThresholdQueueing(1,0)</tt> which will throttle the input whenever the queue is
+ non-empty.
*/
class PassiveInput
- : public PassiveConnector, public InputConnector
+ : public PassiveConnector, public InputConnector,
+ public SafeBool<PassiveInput>
{
public:
- ActiveOutput & peer();
+ PassiveInput();
+
+ ActiveOutput & peer() const;
+
+ bool boolean_test() const;
template <class QDisc>
- QDisc const & qdisc(QDisc const & disc);
+ void qdisc(QDisc const & disc); ///< Change the queueing discipline
+ /**< The queueing discipline is a class which provides the
+ QueueingDiscipline interface.
+
+ \param[in] disc New queueing discipline */
+
+ private:
+ void v_enqueueEvent();
+ void v_dequeueEvent();
+ void v_unthrottleEvent();
+
+ boost::scoped_ptr<QueueingDiscipline> qdisc_;
};
/** \brief Combination of PassiveConnector and OutputConnector
-
- \ingroup connectors
*/
class PassiveOutput
- : public PassiveConnector, public OutputConnector
+ : public PassiveConnector, public OutputConnector,
+ public SafeBool<PassiveOutput>
{
public:
- ActiveInput & peer();
+ ActiveInput & peer() const;
+
+ bool boolean_test() const;
+
+ void connect(ActiveInput & target);
+
+ friend class ActiveInput;
};
/** \brief Combination of ActiveConnector and InputConnector
-
- \ingroup connectors
*/
class ActiveInput
- : public ActiveConnector, public InputConnector
+ : public ActiveConnector, public InputConnector,
+ public SafeBool<ActiveInput>
{
public:
- void request(); ///< request more packets without dequeing any packet
+ PassiveOutput & peer() const;
+
+ bool boolean_test() const;
- PassiveOutput & peer();
+ void request(); ///< request more packets without dequeuing any packet
+
+ private:
+ void v_requestEvent();
};
/** \brief Combination of ActiveConnector and OutputConnector
-
- \ingroup connectors
*/
class ActiveOutput
- : public ActiveConnector, public OutputConnector
+ : public ActiveConnector, public OutputConnector,
+ public SafeBool<ActiveOutput>
{
public:
- ActiveInput & peer();
+ PassiveInput & peer() const;
+
+ bool boolean_test() const;
+
+ void connect(PassiveInput & target);
};
-}}
+ ///@}
+
+}}}
///////////////////////////////hh.e////////////////////////////////////////
-//#include "Conenctors.cci"
-//#include "Conenctors.ct"
-//#include "Conenctors.cti"
+#include "Connectors.cci"
+//#include "Connectors.ct"
+#include "Connectors.cti"
#endif
\f
// c-file-style: "senf"
// indent-tabs-mode: nil
// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// comment-column: 40
// End: