From 416769918cd95620eef60615049a12d4c36f262d Mon Sep 17 00:00:00 2001
From: g0dil <g0dil@wiback.org>
Date: Mon, 20 Oct 2008 20:28:51 +0000
Subject: [PATCH] PPI: Delayed connect and disconnect Scheduler: EventEvent
 hook Scheduler: Simple task priorities

---
 PPI/Connectors.cc                             |  19 ++-
 PPI/Connectors.cci                            |  10 +-
 PPI/Connectors.hh                             |   7 +-
 PPI/Connectors.test.cc                        | 117 +++++++++++++++
 PPI/Mainpage.dox                              |   2 +-
 PPI/Module.cci                                |   9 --
 PPI/Module.hh                                 |   4 +-
 PPI/ModuleManager.cc                          |  14 +-
 PPI/ModuleManager.cci                         |  57 ++++++++
 PPI/ModuleManager.hh                          |  27 ++++
 PPI/Setup.cci                                 |   1 +
 Scheduler/EventEvent.cc                       |  93 ++++++++++++
 Scheduler/EventEvent.cci                      |  98 +++++++++++++
 Scheduler/EventEvent.hh                       | 136 ++++++++++++++++++
 .../{FileDispatcher.cci => EventEvent.ih}     |  55 +++++--
 Scheduler/EventManager.cc                     |  11 +-
 Scheduler/FIFORunner.cc                       | 102 ++++++++-----
 Scheduler/FIFORunner.cci                      |  41 +++++-
 Scheduler/FIFORunner.hh                       |  21 ++-
 Scheduler/FdEvent.hh                          |   6 +-
 Scheduler/Scheduler.cc                        |  22 +--
 Scheduler/Scheduler.hh                        |   2 +
 Scheduler/Scheduler.test.cc                   |  11 ++
 Socket/Mainpage.dox                           |  30 ++--
 24 files changed, 781 insertions(+), 114 deletions(-)
 create mode 100644 Scheduler/EventEvent.cc
 create mode 100644 Scheduler/EventEvent.cci
 create mode 100644 Scheduler/EventEvent.hh
 rename Scheduler/{FileDispatcher.cci => EventEvent.ih} (53%)

diff --git a/PPI/Connectors.cc b/PPI/Connectors.cc
index ab1a03825..a39857ef5 100644
--- a/PPI/Connectors.cc
+++ b/PPI/Connectors.cc
@@ -53,8 +53,23 @@ prefix_ void senf::ppi::connector::Connector::connect(Connector & target)
     peer_ = & target;
     target.peer_ = this;
 
-    if (ModuleManager::instance().running())
-        v_init();
+    if (! initializationScheduled())
+        enqueueInitializable();
+    if (! peer().initializationScheduled())
+        peer().enqueueInitializable();
+}
+
+prefix_ void senf::ppi::connector::Connector::disconnect()
+{
+    SENF_ASSERT( peer_ );
+    Connector & peer (*peer_);
+    peer_ = 0;
+    peer.peer_ = 0;
+
+    if (! initializationScheduled())
+        enqueueInitializable();
+    if (! peer.initializationScheduled())
+        peer.enqueueInitializable();
 }
 
 prefix_ std::type_info const & senf::ppi::connector::Connector::packetTypeID()
diff --git a/PPI/Connectors.cci b/PPI/Connectors.cci
index 12c14a114..089600183 100644
--- a/PPI/Connectors.cci
+++ b/PPI/Connectors.cci
@@ -56,8 +56,11 @@ prefix_ senf::ppi::connector::Connector::Connector()
 
 prefix_ senf::ppi::connector::Connector::~Connector()
 {
-    if (connected())
+    if (connected()) {
+        Connector & peer (*peer_);
         peer_->peer_ = 0;
+        peer.v_init();
+    }
 }
 
 prefix_ bool senf::ppi::connector::Connector::connected()
@@ -74,11 +77,6 @@ prefix_ void senf::ppi::connector::Connector::setModule(module::Module & module)
     module_ = &module;
 }
 
-prefix_ void senf::ppi::connector::Connector::init()
-{
-    v_init();
-}
-
 ///////////////////////////////////////////////////////////////////////////
 // senf::ppi::connector::PassiveConnector
 
diff --git a/PPI/Connectors.hh b/PPI/Connectors.hh
index 0874551b5..e5ea9c91c 100644
--- a/PPI/Connectors.hh
+++ b/PPI/Connectors.hh
@@ -36,6 +36,7 @@
 #include "predecl.hh"
 #include "detail/Callback.hh"
 #include "Queueing.hh"
+#include "ModuleManager.hh"
 
 //#include "Connectors.mpp"
 ///////////////////////////////hh.p////////////////////////////////////////
@@ -122,7 +123,7 @@ namespace connector {
         to the containing module)
      */
     class Connector
-        : boost::noncopyable
+        : ModuleManager::Initializable, boost::noncopyable
     {
     public:
         Connector & peer() const;       ///< Get peer connected to this connector
@@ -130,6 +131,8 @@ namespace connector {
 
         bool connected() const;         ///< \c true, if connector connected, \c false otherwise
 
+        void disconnect();              ///< Disconnect connector from peer
+
     protected:
         Connector();
         virtual ~Connector();
@@ -140,8 +143,6 @@ namespace connector {
         virtual std::type_info const & packetTypeID();
 
         void setModule(module::Module & module);
-        void init();        
-        virtual void v_init() = 0;        
 
         Connector * peer_;
         module::Module * module_;
diff --git a/PPI/Connectors.test.cc b/PPI/Connectors.test.cc
index 6b95fc270..2e599ba8e 100644
--- a/PPI/Connectors.test.cc
+++ b/PPI/Connectors.test.cc
@@ -421,6 +421,123 @@ BOOST_AUTO_UNIT_TEST(connectorTest)
     }
 }
 
+BOOST_AUTO_UNIT_TEST(delayedConnect)
+{
+    {
+        debug::PassiveSource source;
+        debug::ActiveSink target;
+
+        ppi::init();
+
+        BOOST_CHECK( ! target.input );
+        BOOST_CHECK( ! target.request() );
+
+        ppi::connect(source, target);
+        ppi::init();
+
+        BOOST_CHECK( ! target.input );
+
+        senf::Packet p (senf::DataPacket::create());
+        source.submit(p);
+        BOOST_CHECK( target.request() == p );
+    }
+
+    {
+        debug::PassiveSource source;
+        debug::ActiveSink target;
+
+        ppi::init();
+
+        senf::Packet p (senf::DataPacket::create());
+        source.submit(p);
+
+        BOOST_CHECK( ! target.input );
+        BOOST_CHECK( ! target.request() );
+
+        ppi::connect(source, target);
+        ppi::init();
+
+        BOOST_CHECK( target.input );
+        BOOST_CHECK( target.request() == p );
+    }
+
+    {
+        debug::ActiveSource source;
+        debug::PassiveSink target;
+
+        ppi::init();
+
+        BOOST_CHECK( ! source.output );
+        SENF_CHECK_NO_THROW( source.output(senf::DataPacket::create()) );
+
+        ppi::connect(source, target);
+        ppi::init();
+        
+        BOOST_CHECK( source.output );
+
+        senf::Packet p (senf::DataPacket::create());
+        source.submit(p);
+
+        BOOST_CHECK( target.front() == p );        
+        BOOST_CHECK_EQUAL( target.size(), 1u );
+    }
+
+    {
+        debug::ActiveSource source;
+        debug::PassiveSink target;
+
+        ppi::init();
+
+        BOOST_CHECK( ! source.output );
+        SENF_CHECK_NO_THROW( source.output(senf::DataPacket::create()) );
+        target.throttle();
+
+        ppi::connect(source, target);
+        ppi::init();
+        
+        BOOST_CHECK( ! source.output );
+        target.unthrottle();
+        BOOST_CHECK( source.output );
+    }
+}
+
+BOOST_AUTO_UNIT_TEST(disconnect)
+{
+    {
+        debug::PassiveSource source;
+        debug::ActiveSink target;
+
+        ppi::connect(source, target);
+        ppi::init();
+
+        BOOST_CHECK( ! target.input );
+
+        senf::Packet p (senf::DataPacket::create());
+        source.submit(p);
+
+        BOOST_CHECK( target.input );
+        
+        target.input.disconnect();
+        ppi::init();
+        
+        BOOST_CHECK( ! target.input );
+    }
+    {
+        debug::ActiveSource source;
+        debug::PassiveSink target;
+
+        ppi::connect(source, target);
+        ppi::init();
+
+        BOOST_CHECK( source.output );
+
+        source.output.disconnect();
+        ppi::init();
+
+        BOOST_CHECK( ! source.output );
+    }
+}
+
 ///////////////////////////////cc.e////////////////////////////////////////
 #undef prefix_
 
diff --git a/PPI/Mainpage.dox b/PPI/Mainpage.dox
index 5afa6e0e5..99d25a8e2 100644
--- a/PPI/Mainpage.dox
+++ b/PPI/Mainpage.dox
@@ -221,7 +221,7 @@
     must be untyped (they accept arbitrary senf::Packet's, the optional tempalte argument is empty),
     or they both accept the same type of packet. This check is performed at runtime. 
 
-    To complete our simplified example: Lets connet senf::ppi::module::ActiveSocketReader and
+    To complete our simplified example: Lets connect senf::ppi::module::ActiveSocketReader and
     senf::ppi::module::PassiveSocketWriter to our example module:
 
     \code
diff --git a/PPI/Module.cci b/PPI/Module.cci
index 6a7be7329..de184f77a 100644
--- a/PPI/Module.cci
+++ b/PPI/Module.cci
@@ -38,15 +38,6 @@
 ////////////////////////////////////////
 // private members
 
-prefix_ void senf::ppi::module::Module::init()
-{
-    ConnectorRegistry::iterator i (connectorRegistry_.begin());
-    ConnectorRegistry::iterator i_end (connectorRegistry_.end());
-    for (; i != i_end; ++i)
-        (*i)->init();
-    v_init();
-}
-
 prefix_ void senf::ppi::module::Module::v_init()
 {}
 
diff --git a/PPI/Module.hh b/PPI/Module.hh
index 9c19e6c9f..1062fb07e 100644
--- a/PPI/Module.hh
+++ b/PPI/Module.hh
@@ -33,6 +33,7 @@
 #include <boost/ptr_container/ptr_vector.hpp>
 #include "../Scheduler/ClockService.hh"
 #include "predecl.hh"
+#include "ModuleManager.hh"
 
 //#include "Module.mpp"
 ///////////////////////////////hh.p////////////////////////////////////////
@@ -167,7 +168,7 @@ namespace module {
         \see \ref ppi_modules
      */
     class Module
-        : boost::noncopyable
+        : ModuleManager::Initializable, boost::noncopyable
     {
     public:
         virtual ~Module();
@@ -289,7 +290,6 @@ namespace module {
 
     private:
 #endif
-        void init();
         virtual void v_init();
 
 #ifndef DOXYGEN
diff --git a/PPI/ModuleManager.cc b/PPI/ModuleManager.cc
index 490bb010e..91a437333 100644
--- a/PPI/ModuleManager.cc
+++ b/PPI/ModuleManager.cc
@@ -28,6 +28,7 @@
 
 // Custom includes
 #include "../Scheduler/Scheduler.hh"
+#include "../Utils/membind.hh"
 #include "Module.hh"
 
 //#include "ModuleManager.mpp"
@@ -39,10 +40,11 @@
 
 prefix_ void senf::ppi::ModuleManager::init()
 {
-    ModuleRegistry::const_iterator i (moduleRegistry_.begin());
-    ModuleRegistry::const_iterator const i_end (moduleRegistry_.end());
-    for (; i != i_end; ++i)
-        (*i)->init();
+    while (! initQueue_.empty()) {
+        initQueue_.front()->v_init();
+        initQueue_.pop_front();
+    }
+    initRunner_.disable();
 }
 
 #ifndef DOXYGEN
@@ -67,7 +69,9 @@ prefix_ void senf::ppi::ModuleManager::run()
 // private members
 
 prefix_ senf::ppi::ModuleManager::ModuleManager()
-    : running_(false), terminate_(false)
+    : running_(false), terminate_(false), 
+      initRunner_ ("senf::ppi::init", membind(&ModuleManager::init, this), false, 
+                   scheduler::EventEvent::PRIORITY_LOW)
 {}
 
 ///////////////////////////////cc.e////////////////////////////////////////
diff --git a/PPI/ModuleManager.cci b/PPI/ModuleManager.cci
index fc7f7f9a0..db78d8572 100644
--- a/PPI/ModuleManager.cci
+++ b/PPI/ModuleManager.cci
@@ -50,12 +50,69 @@ prefix_ void senf::ppi::ModuleManager::unregisterModule(module::Module & module)
         moduleRegistry_.end());
 }
 
+prefix_ void senf::ppi::ModuleManager::registerInitializable(Initializable & i)
+{
+    initQueue_.push_back(&i);
+    initRunner_.enable();
+}
+
+prefix_ void senf::ppi::ModuleManager::unregisterInitializable(Initializable & i)
+{
+    initQueue_.erase(
+        std::remove(initQueue_.begin(), initQueue_.end(), & i),
+        initQueue_.end());
+    if (initQueue_.empty())
+        initRunner_.disable();
+}
+
+prefix_ bool senf::ppi::ModuleManager::initializableRegistered(Initializable const & i)
+    const
+{
+    return std::find(initQueue_.begin(), initQueue_.end(), &i) != initQueue_.end();
+}
+
 prefix_ bool senf::ppi::ModuleManager::running()
     const
 {
     return running_;
 }
 
+///////////////////////////////////////////////////////////////////////////
+// senf::ppi::ModuleManager::Initializable
+
+prefix_ senf::ppi::ModuleManager::Initializable::Initializable()
+{
+    enqueueInitializable();
+}
+
+prefix_ senf::ppi::ModuleManager::Initializable::~Initializable()
+{
+    dequeueInitializable();
+}
+
+prefix_ void senf::ppi::ModuleManager::Initializable::enqueueInitializable()
+{
+    moduleManager().registerInitializable(*this);
+}
+
+prefix_ void senf::ppi::ModuleManager::Initializable::dequeueInitializable()
+{
+    moduleManager().unregisterInitializable(*this);
+}
+
+prefix_ bool senf::ppi::ModuleManager::Initializable::initializationScheduled()
+    const
+{
+    return moduleManager().initializableRegistered(*this);
+}
+
+prefix_ senf::ppi::ModuleManager::ModuleManager &
+senf::ppi::ModuleManager::Initializable::moduleManager()
+    const
+{
+    return ModuleManager::instance();
+}
+
 ///////////////////////////////cci.e///////////////////////////////////////
 #undef prefix_
 
diff --git a/PPI/ModuleManager.hh b/PPI/ModuleManager.hh
index 6c8d291da..262dc4ce8 100644
--- a/PPI/ModuleManager.hh
+++ b/PPI/ModuleManager.hh
@@ -28,7 +28,9 @@
 
 // Custom includes
 #include <vector>
+#include <deque>
 #include "predecl.hh"
+#include "../Scheduler/Scheduler.hh"
 
 //#include "ModuleManager.mpp"
 ///////////////////////////////hh.p////////////////////////////////////////
@@ -44,6 +46,21 @@ namespace ppi {
     class ModuleManager
     {
     public:
+        ///////////////////////////////////////////////////////////////////////////
+        // Types
+
+        struct Initializable
+        {
+            Initializable();
+            virtual ~Initializable();
+            ModuleManager & moduleManager() const;
+            void enqueueInitializable();
+            void dequeueInitializable();
+            bool initializationScheduled() const;
+
+            virtual void v_init() = 0;
+        };
+
         ///////////////////////////////////////////////////////////////////////////
         ///\name Structors and default members
         ///@{
@@ -71,7 +88,12 @@ namespace ppi {
         void registerModule(module::Module & module);
         void unregisterModule(module::Module & module);
 
+        void registerInitializable(Initializable & i);
+        void unregisterInitializable(Initializable & i);
+        bool initializableRegistered(Initializable const & i) const;
+
         typedef std::vector<module::Module *> ModuleRegistry;
+        typedef std::deque<Initializable *> InitQueue;
 
 #ifndef DOXYGEN
         struct RunGuard;
@@ -82,7 +104,12 @@ namespace ppi {
         bool running_;
         bool terminate_;
 
+        InitQueue initQueue_;
+
+        scheduler::EventEvent initRunner_;
+
         friend class module::Module;
+        friend class Initializable;
     };
 
 
diff --git a/PPI/Setup.cci b/PPI/Setup.cci
index 5311aaa40..127a45f88 100644
--- a/PPI/Setup.cci
+++ b/PPI/Setup.cci
@@ -27,6 +27,7 @@
 
 // Custom includes
 #include "Connectors.hh"
+#include "Module.hh"
 #include "ModuleManager.hh"
 
 #define prefix_ inline
diff --git a/Scheduler/EventEvent.cc b/Scheduler/EventEvent.cc
new file mode 100644
index 000000000..f2d809721
--- /dev/null
+++ b/Scheduler/EventEvent.cc
@@ -0,0 +1,93 @@
+// $Id$
+//
+// Copyright (C) 2008 
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
+//     Stefan Bund <g0dil@berlios.de>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+/** \file
+    \brief EventEvent non-inline non-template implementation */
+
+#include "EventEvent.hh"
+#include "EventEvent.ih"
+
+// Custom includes
+
+//#include "EventEvent.mpp"
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// senf::scheduler::EventEvent
+
+prefix_ void senf::scheduler::EventEvent::v_run()
+{
+    cb_();
+}
+
+prefix_ char const * senf::scheduler::EventEvent::v_type()
+    const
+{
+    return "ee";
+}
+
+prefix_ std::string senf::scheduler::EventEvent::v_info()
+    const
+{
+    return "";
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::scheduler::detail::EventEventDispatcher
+
+prefix_ senf::scheduler::detail::EventEventDispatcher::~EventEventDispatcher()
+{
+    for (EventList::iterator i (events_.begin()); i != events_.end(); ++i)
+        FIFORunner::instance().dequeue(&(*i));
+}
+
+prefix_ prefix_ void senf::scheduler::detail::EventEventDispatcher::remove(EventEvent & event)
+{
+    EventList::iterator i (EventList::current(event));
+    if (i == events_.end())
+        return;
+    FIFORunner::instance().dequeue(&event);
+    events_.erase(i);
+}
+
+prefix_ void senf::scheduler::detail::EventEventDispatcher::prepareRun()
+{
+    for (EventList::iterator i (events_.begin()); i != events_.end(); ++i)
+        i->setRunnable();
+}
+
+
+///////////////////////////////cc.e////////////////////////////////////////
+#undef prefix_
+//#include "EventEvent.mpp"
+
+
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
diff --git a/Scheduler/EventEvent.cci b/Scheduler/EventEvent.cci
new file mode 100644
index 000000000..9cb6aceff
--- /dev/null
+++ b/Scheduler/EventEvent.cci
@@ -0,0 +1,98 @@
+// $Id$
+//
+// Copyright (C) 2008 
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
+//     Stefan Bund <g0dil@berlios.de>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+/** \file
+    \brief EventEvent inline non-template implementation */
+
+#include "EventEvent.ih"
+
+// Custom includes
+
+#define prefix_ inline
+///////////////////////////////cci.p///////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// senf::scheduler::EventEvent
+
+prefix_ senf::scheduler::EventEvent::EventEvent(std::string const & name, Callback const & cb,
+                                                bool initiallyEnabled,
+                                                detail::FIFORunner::TaskInfo::Priority priority)
+    : detail::FIFORunner::TaskInfo(name, priority), cb_ (cb)
+{
+    if (initiallyEnabled)
+        enable();
+}
+
+prefix_ senf::scheduler::EventEvent::~EventEvent()
+{
+    if (detail::EventEventDispatcher::alive())
+        disable();
+}
+
+prefix_ void senf::scheduler::EventEvent::disable()
+{
+    if (enabled())
+        detail::EventEventDispatcher::instance().remove(*this);
+}
+
+prefix_ void senf::scheduler::EventEvent::enable()
+{
+    if (! enabled())
+        detail::EventEventDispatcher::instance().add(*this);
+}
+
+prefix_ void senf::scheduler::EventEvent::action(Callback const & cb)
+{
+    cb_ = cb;
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::scheduler::detail::EventEventDispatcher
+
+prefix_ void senf::scheduler::detail::EventEventDispatcher::add(EventEvent & event)
+{
+    events_.push_back(event);
+    FIFORunner::instance().enqueue(&event);
+}
+
+prefix_ bool senf::scheduler::detail::EventEventDispatcher::empty()
+    const
+{
+    return events_.empty();
+}
+
+prefix_ senf::scheduler::detail::EventEventDispatcher::EventEventDispatcher()
+{}
+
+///////////////////////////////cci.e///////////////////////////////////////
+#undef prefix_
+
+
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
diff --git a/Scheduler/EventEvent.hh b/Scheduler/EventEvent.hh
new file mode 100644
index 000000000..4b0b27fe6
--- /dev/null
+++ b/Scheduler/EventEvent.hh
@@ -0,0 +1,136 @@
+// $Id$
+//
+// Copyright (C) 2008 
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
+//     Stefan Bund <g0dil@berlios.de>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+/** \file
+    \brief EventEvent public header */
+
+#ifndef HH_EventEvent_
+#define HH_EventEvent_ 1
+
+// Custom includes
+#include <boost/function.hpp>
+#include "../boost/intrusive/ilist_hook.hpp"
+#include "FIFORunner.hh"
+
+//#include "EventEvent.mpp"
+///////////////////////////////hh.p////////////////////////////////////////
+
+namespace senf {
+namespace scheduler {
+
+    namespace detail {
+        struct EventEventListTag;
+        typedef boost::intrusive::ilist_base_hook<EventEventListTag> EventEventListBase;
+        class EventEventDispatcher;
+    }
+
+    /** \brief Event hook event
+
+        This event is special: It is not a real event, it is a kind of hook which is called,
+        whenever any other event is signaled. Combining this with explicit priority specification,
+        this can be used to implement hooks which are called before or after any other callback.
+
+        \code
+        void beforeEventHook();
+        void afterEventHook();
+
+        senf::scheduler::EventEvent beforeEventHookEvent (
+            "beforeEventHook", beforeEventHook, true, senf::scheduler::EventEvent::PRIORITY_LOW);
+        senf::scheduler::EventEvent afterEventHookEvent (
+            "afterEventHook", afterEventHook, true, senf::scheduler::EventEvent::PRIORITY_HIGH);
+        \endcode
+
+        This usage assumes, that all ordinary events are registered with \c PRIORITY_NORMAL.
+
+        The EventEvent class is an implementation of the RAII idiom: The event will be automatically
+        unregistered in the EventEvent destructor. The EventEvent instance should be created within
+        the same scope or on a scope below where the callback is defined (e.g. if the callback is a
+        member function it should be defined as a class member).
+      */
+    class EventEvent
+        : public detail::FIFORunner::TaskInfo,
+          public detail::EventEventListBase
+    {
+    public:
+        ///////////////////////////////////////////////////////////////////////////
+        // Types
+
+        typedef boost::function<void ()> Callback;
+
+        ///////////////////////////////////////////////////////////////////////////
+        ///\name Structors and default members
+        ///@{
+
+        EventEvent(std::string const & name, Callback const & cb,
+                   bool initiallyEnabled = true, Priority priority = PRIORITY_NORMAL);
+                                        ///< Register an event hook
+                                        /**< Registers \a cb to be called whenever any other event
+                                             is signaled by the scheduler. If \a initiallyEnabled is
+                                             set \c false, the callback will not be enabled
+                                             automatically. Use enable() to do so.
+                                             \param[in] name Descriptive event name (purely
+                                                 informational)
+                                             \param[in] cb Callback to call
+                                             \param[in] initiallyEnabled if set \c false, do not
+                                                 enable callback automatically. 
+                                             \param[in] priority event priority, defaults to
+                                                 PRIORITY_NORMAL */
+        ~EventEvent();
+
+        ///@}
+        ///////////////////////////////////////////////////////////////////////////
+
+        void disable();                 ///< Disable event
+        void enable();                  ///< Enable event
+
+        void action(Callback const & cb); ///< Change event callback
+
+    protected:
+
+    private:
+        virtual void v_run();
+        virtual char const * v_type() const;
+        virtual std::string v_info() const;
+
+        Callback cb_;
+
+        friend class detail::EventEventDispatcher;
+    };
+
+}}
+
+///////////////////////////////hh.e////////////////////////////////////////
+#include "EventEvent.cci"
+//#include "EventEvent.ct"
+//#include "EventEvent.cti"
+#endif
+
+
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
diff --git a/Scheduler/FileDispatcher.cci b/Scheduler/EventEvent.ih
similarity index 53%
rename from Scheduler/FileDispatcher.cci
rename to Scheduler/EventEvent.ih
index 388c3d149..823b50b20 100644
--- a/Scheduler/FileDispatcher.cci
+++ b/Scheduler/EventEvent.ih
@@ -21,25 +21,54 @@
 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 /** \file
-    \brief FileDispatcher inline non-template implementation */
+    \brief EventEvent internal header */
 
-#include "FileDispatcher.ih"
+#ifndef IH_EventEvent_
+#define IH_EventEvent_ 1
 
 // Custom includes
+#include "../Utils/singleton.hh"
 
-#define prefix_ inline
-///////////////////////////////cci.p///////////////////////////////////////
+///////////////////////////////ih.p////////////////////////////////////////
 
-prefix_ int senf::scheduler::FileDispatcher::FileEvent::activeEvents()
-    const
-{
-    return 
-        (ReadTask::cb ? EV_READ : 0) | 
-        (WriteTask::cb ? EV_WRITE : 0);
-}
+namespace senf {
+namespace scheduler {
 
-///////////////////////////////cci.e///////////////////////////////////////
-#undef prefix_
+    void restart();
+
+namespace detail {
+    
+    class EventEventDispatcher
+        : public singleton<EventEventDispatcher>
+    {
+    public:
+        using singleton<EventEventDispatcher>::instance;
+        using singleton<EventEventDispatcher>::alive;
+
+        void add(EventEvent & event);
+        void remove(EventEvent & event);
+
+        void prepareRun();
+
+        bool empty() const;
+
+    private:
+        EventEventDispatcher();
+        ~EventEventDispatcher();
+
+        typedef boost::intrusive::ilist< 
+            EventEventListBase::value_traits<EventEvent>, false > EventList;
+
+        EventList events_;
+
+        friend void senf::scheduler::restart();
+        friend class singleton<EventEventDispatcher>;
+    };
+
+}}}
+
+///////////////////////////////ih.e////////////////////////////////////////
+#endif
 
 
 // Local Variables:
diff --git a/Scheduler/EventManager.cc b/Scheduler/EventManager.cc
index aaf1622a1..3f00cde72 100644
--- a/Scheduler/EventManager.cc
+++ b/Scheduler/EventManager.cc
@@ -43,11 +43,18 @@ prefix_ senf::scheduler::detail::EventManager::EventManager()
         .doc("List all scheduler events sorted by priority\n"
              "\n"
              "Columns:\n"
-             "    TP      event type: fd - file descriptor, tm - timer, si - UNIX signal\n"
+             "    TP      event type:\n"
+             "              fd  file descriptor\n"
+             "              tm  timer\n"
+             "              si  UNIX signal\n"
+             "              ee  event hook\n"
              "    NAME    descriptive event name\n"
              "    ADDRESS address of event class instance\n"
              "    RUNCNT  number of times, the event was called\n"
-             "    S       state: R - runnable, W - Waiting, '-' - event disabled\n"
+             "    S       state:\n"
+             "              R  runnable\n"
+             "              W  waiting\n"
+             "              -  event disabled\n"
              "    INFO    further event specific information");
 
     senf::console::sysdir().add("scheduler", consoleDir_());
diff --git a/Scheduler/FIFORunner.cc b/Scheduler/FIFORunner.cc
index 8510c0407..446859c74 100644
--- a/Scheduler/FIFORunner.cc
+++ b/Scheduler/FIFORunner.cc
@@ -59,6 +59,9 @@ prefix_ senf::scheduler::detail::FIFORunner::FIFORunner()
     sigaddset(&mask, SIGURG);
     if (sigprocmask(SIG_UNBLOCK, &mask, 0) < 0)
         SENF_THROW_SYSTEM_EXCEPTION("sigprocmask()");
+
+    tasks_.push_back(highPriorityEnd_);
+    tasks_.push_back(normalPriorityEnd_);
 }
 
 prefix_ senf::scheduler::detail::FIFORunner::~FIFORunner()
@@ -97,40 +100,66 @@ prefix_ void senf::scheduler::detail::FIFORunner::dequeue(TaskInfo * task)
     tasks_.erase(i);
 }
 
-namespace {
-    struct NullTask 
-        : public senf::scheduler::detail::FIFORunner::TaskInfo
-    {
-        NullTask() : senf::scheduler::detail::FIFORunner::TaskInfo ("<null>") {}
-        virtual void v_run() {};
-        virtual char const * v_type() const { return 0; }
-        virtual std::string v_info() const { return ""; }
-    };
+prefix_ void senf::scheduler::detail::FIFORunner::run()
+{
+    struct itimerspec timer;
+    timer.it_interval.tv_sec = watchdogMs_ / 1000;
+    timer.it_interval.tv_nsec = (watchdogMs_ % 1000) * 1000000ul;
+    timer.it_value.tv_sec = timer.it_interval.tv_sec;
+    timer.it_value.tv_nsec = timer.it_interval.tv_nsec;
+
+    if (timer_settime(watchdogId_, 0, &timer, 0) < 0)
+        SENF_THROW_SYSTEM_EXCEPTION("timer_settime()");
+
+    timer.it_interval.tv_sec = 0;
+    timer.it_interval.tv_nsec = 0;
+    timer.it_value.tv_sec = 0;
+    timer.it_value.tv_nsec = 0;
+    
+    try {
+        TaskList::iterator f (tasks_.begin());
+        TaskList::iterator l (TaskList::current(highPriorityEnd_));
+        run(f, l);
+
+        f = l; ++f;
+        l = TaskList::current(normalPriorityEnd_);
+        run(f, l);
+        
+        f = l; ++f;
+        l = tasks_.end();
+        run(f, l);
+    }
+    catch(...) {
+        timer_settime(watchdogId_, 0, &timer, 0);
+        throw;
+    }
+
+    if (timer_settime(watchdogId_, 0, &timer, 0) < 0)
+        SENF_THROW_SYSTEM_EXCEPTION("timer_settime()");
 }
 
-prefix_ void senf::scheduler::detail::FIFORunner::run()
+
+prefix_ void senf::scheduler::detail::FIFORunner::run(TaskList::iterator f, TaskList::iterator l)
 {
+    if (f == l)
+        // We'll have problems inserting NullTask between f and l below, so just explicitly bail out
+        return;
+
     // This algorithm is carefully adjusted to make it work even when arbitrary tasks are removed
     // from the queue
     // - Before we begin, we add a NullTask to the queue. The only purpose of this node is, to mark
     //   the current end of the queue. The iterator to this node becomes the end iterator of the
     //   range to process
-    // - We update the TaskInfo and move it to the end of the queue before calling the callback so
+    // - We update the TaskInfo and move it to the next queue Element before calling the callback so
     //   we don't access the TaskInfo if it is removed while the callback is running
     // - We keep the next to-be-processed node in a class variable which is checked and updated
     //   whenever a node is removed.
+
     NullTask null;
-    struct itimerspec timer;
-    timer.it_interval.tv_sec = watchdogMs_ / 1000;
-    timer.it_interval.tv_nsec = (watchdogMs_ % 1000) * 1000000ul;
-    timer.it_value.tv_sec = timer.it_interval.tv_sec;
-    timer.it_value.tv_nsec = timer.it_interval.tv_nsec;
-    tasks_.push_back(null);
+    tasks_.insert(l, null);
     TaskList::iterator end (TaskList::current(null));
-    next_ = tasks_.begin();
+    next_ = f;
     try {
-        if (timer_settime(watchdogId_, 0, &timer, 0) < 0)
-            SENF_THROW_SYSTEM_EXCEPTION("timer_settime()");
         while (next_ != end) {
             TaskInfo & task (*next_);
             if (task.runnable_) {
@@ -141,7 +170,7 @@ prefix_ void senf::scheduler::detail::FIFORunner::run()
 #           endif
                 TaskList::iterator i (next_);
                 ++ next_;
-                tasks_.splice(tasks_.end(), tasks_, i);
+                tasks_.splice(l, tasks_, i);
                 watchdogCount_ = 1;
                 task.run();
             }
@@ -151,24 +180,25 @@ prefix_ void senf::scheduler::detail::FIFORunner::run()
     }
     catch (...) {
         watchdogCount_ = 0;
-        timer.it_interval.tv_sec = 0;
-        timer.it_interval.tv_nsec = 0;
-        timer.it_value.tv_sec = 0;
-        timer.it_value.tv_nsec = 0;
-        timer_settime(watchdogId_, 0, &timer, 0);
-        tasks_.erase(end);
-        next_ = tasks_.end();
+        next_ = l;
         throw;
     }
     watchdogCount_ = 0;
-    timer.it_interval.tv_sec = 0;
-    timer.it_interval.tv_nsec = 0;
-    timer.it_value.tv_sec = 0;
-    timer.it_value.tv_nsec = 0;
-    if (timer_settime(watchdogId_, 0, &timer, 0) < 0)
-        SENF_THROW_SYSTEM_EXCEPTION("timer_settime()");
-    tasks_.erase(end);
-    next_ = tasks_.end();
+    next_ = l;
+}
+
+prefix_ senf::scheduler::detail::FIFORunner::TaskList::iterator
+senf::scheduler::detail::FIFORunner::priorityEnd(TaskInfo::Priority p)
+{
+    switch (p) {
+    case senf::scheduler::detail::FIFORunner::TaskInfo::PRIORITY_LOW : 
+        return tasks_.end();
+    case senf::scheduler::detail::FIFORunner::TaskInfo::PRIORITY_NORMAL : 
+        return TaskList::current(normalPriorityEnd_);
+    case senf::scheduler::detail::FIFORunner::TaskInfo::PRIORITY_HIGH : 
+        return TaskList::current(highPriorityEnd_);
+    }
+    return tasks_.begin();
 }
 
 prefix_ void senf::scheduler::detail::FIFORunner::watchdog(int, siginfo_t * si, void *)
diff --git a/Scheduler/FIFORunner.cci b/Scheduler/FIFORunner.cci
index 585bf6e99..b2f6fe61e 100644
--- a/Scheduler/FIFORunner.cci
+++ b/Scheduler/FIFORunner.cci
@@ -34,8 +34,12 @@
 #define prefix_ inline
 ///////////////////////////////cci.p///////////////////////////////////////
 
-prefix_ senf::scheduler::detail::FIFORunner::TaskInfo::TaskInfo(std::string const & name)
-    : Event(name), runnable_ (false)
+///////////////////////////////////////////////////////////////////////////
+//  senf::scheduler::detail::FIFORunner::TaskInfo
+
+prefix_ senf::scheduler::detail::FIFORunner::TaskInfo::TaskInfo(std::string const & name,
+                                                                Priority priority)
+    : Event(name), runnable_ (false), priority_ (priority)
 {}
 
 prefix_ senf::scheduler::detail::FIFORunner::TaskInfo::~TaskInfo()
@@ -65,9 +69,40 @@ prefix_ bool senf::scheduler::detail::FIFORunner::TaskInfo::v_enabled()
     return TaskListBase::linked();
 }
 
+///////////////////////////////////////////////////////////////////////////
+// senf::scheduler::detail::FIFORunner::NullTask
+
+prefix_ senf::scheduler::detail::FIFORunner::NullTask::NullTask()
+    : senf::scheduler::detail::FIFORunner::TaskInfo ("<null>") 
+{}
+
+prefix_ senf::scheduler::detail::FIFORunner::NullTask::~NullTask()
+{
+    if (TaskListBase::linked())
+        FIFORunner::instance().dequeue(this);
+}
+
+prefix_ void senf::scheduler::detail::FIFORunner::NullTask::v_run()
+{}
+
+prefix_ char const * senf::scheduler::detail::FIFORunner::NullTask::v_type()
+    const
+{
+    return 0;
+}
+
+prefix_ std::string senf::scheduler::detail::FIFORunner::NullTask::v_info()
+    const
+{
+    return "";
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::scheduler::detail::FIFORunner
+
 prefix_ void senf::scheduler::detail::FIFORunner::enqueue(TaskInfo * task)
 {
-    tasks_.push_back(*task);
+    tasks_.insert(priorityEnd(task->priority_), *task);
 #ifdef SENF_DEBUG
     std::stringstream ss;
     backtrace(ss, 32);
diff --git a/Scheduler/FIFORunner.hh b/Scheduler/FIFORunner.hh
index 40154d38f..8803f7590 100644
--- a/Scheduler/FIFORunner.hh
+++ b/Scheduler/FIFORunner.hh
@@ -61,7 +61,9 @@ namespace detail {
               public TaskListBase
         {
         public:
-            explicit TaskInfo(std::string const & name);
+            enum Priority { PRIORITY_LOW = 0, PRIORITY_NORMAL = 1, PRIORITY_HIGH = 2 };
+
+            explicit TaskInfo(std::string const & name, Priority priority=PRIORITY_NORMAL);
             virtual ~TaskInfo();
 
             void run();
@@ -76,6 +78,7 @@ namespace detail {
             virtual bool v_enabled() const;
 
             bool runnable_;
+            Priority priority_;
 #       ifdef SENF_DEBUG
             std::string backtrace_;
 #       endif
@@ -110,8 +113,24 @@ namespace detail {
 
         static void watchdog(int, siginfo_t *, void *);
 
+        TaskList::iterator priorityEnd(TaskInfo::Priority p);
+        void run(TaskList::iterator f, TaskList::iterator l);
+        
+        struct NullTask : public TaskInfo
+        {
+            NullTask();
+            ~NullTask();
+            virtual void v_run();;
+            virtual char const * v_type() const;
+            virtual std::string v_info() const;
+        };
+
         TaskList tasks_;
         TaskList::iterator next_;
+
+        NullTask normalPriorityEnd_;
+        NullTask highPriorityEnd_;
+        
         timer_t watchdogId_;
         unsigned watchdogMs_;
         std::string runningName_;
diff --git a/Scheduler/FdEvent.hh b/Scheduler/FdEvent.hh
index 78409f4fb..6080d0d5c 100644
--- a/Scheduler/FdEvent.hh
+++ b/Scheduler/FdEvent.hh
@@ -75,9 +75,9 @@ namespace scheduler {
         handles are provided.
 
         The FdEvent class is an implementation of the RAII idiom: The event will be automatically
-        unregistered in the FdEvent destructor. The TimerEvent instance should be created
-        within the same scope or on a scope below where the callback is defined (e.g. if the
-        callback is a member function it should be defined as a class member).
+        unregistered in the FdEvent destructor. The FdEvent instance should be created within the
+        same scope or on a scope below where the callback is defined (e.g. if the callback is a
+        member function it should be defined as a class member).
      */
     class FdEvent
 	: public detail::FIFORunner::TaskInfo,
diff --git a/Scheduler/Scheduler.cc b/Scheduler/Scheduler.cc
index 7ba69ef7c..74761daa1 100644
--- a/Scheduler/Scheduler.cc
+++ b/Scheduler/Scheduler.cc
@@ -35,7 +35,6 @@
 //#include "Scheduler.ih"
 
 // Custom includes
-#include "SignalEvent.hh"
 
 #define prefix_
 ///////////////////////////////cc.p////////////////////////////////////////
@@ -61,19 +60,22 @@ prefix_ void senf::scheduler::process()
         detail::TimerDispatcher::instance().blockSignals();
         detail::SignalDispatcher::instance().blockSignals();
         detail::FileDispatcher::instance().prepareRun();
+        detail::EventEventDispatcher::instance().prepareRun();
         detail::FIFORunner::instance().run();
     }
 }
 
 prefix_ void senf::scheduler::restart()
 {
-    detail::FdManager*        fdm (&detail::FdManager::instance());
-    detail::FIFORunner*       ffr (&detail::FIFORunner::instance());
-    detail::FdDispatcher*     fdd (&detail::FdDispatcher::instance());
-    detail::TimerDispatcher*  tdd (&detail::TimerDispatcher::instance());
-    detail::SignalDispatcher* sdd (&detail::SignalDispatcher::instance());
-    detail::FileDispatcher*   fld (&detail::FileDispatcher::instance());
-    
+    detail::FdManager*            fdm (&detail::FdManager::instance());
+    detail::FIFORunner*           ffr (&detail::FIFORunner::instance());
+    detail::FdDispatcher*         fdd (&detail::FdDispatcher::instance());
+    detail::TimerDispatcher*      tdd (&detail::TimerDispatcher::instance());
+    detail::SignalDispatcher*     sdd (&detail::SignalDispatcher::instance());
+    detail::FileDispatcher*       fld (&detail::FileDispatcher::instance());
+    detail::EventEventDispatcher* eed (&detail::EventEventDispatcher::instance());
+
+    eed->~EventEventDispatcher();
     fld->~FileDispatcher();
     sdd->~SignalDispatcher();
     tdd->~TimerDispatcher();
@@ -87,6 +89,7 @@ prefix_ void senf::scheduler::restart()
     new (tdd) detail::TimerDispatcher();
     new (sdd) detail::SignalDispatcher();
     new (fld) detail::FileDispatcher();
+    new (eed) detail::EventEventDispatcher();
 }
 
 prefix_ bool senf::scheduler::empty()
@@ -94,7 +97,8 @@ prefix_ bool senf::scheduler::empty()
     return detail::FdDispatcher::instance().empty() 
         && detail::TimerDispatcher::instance().empty()
         && detail::FileDispatcher::instance().empty()
-        && detail::SignalDispatcher::instance().empty();
+        && detail::SignalDispatcher::instance().empty()
+        && detail::EventEventDispatcher::instance().empty();
 }
 
 ///////////////////////////////////////////////////////////////////////////
diff --git a/Scheduler/Scheduler.hh b/Scheduler/Scheduler.hh
index af07c48de..7cf640981 100644
--- a/Scheduler/Scheduler.hh
+++ b/Scheduler/Scheduler.hh
@@ -32,6 +32,7 @@
 #include "FdEvent.hh"
 #include "TimerEvent.hh"
 #include "SignalEvent.hh"
+#include "EventEvent.hh"
 
 //#include "scheduler.mpp"
 ///////////////////////////////hh.p////////////////////////////////////////
@@ -64,6 +65,7 @@ namespace senf {
     \li senf::scheduler::FdEvent for file descriptor events
     \li senf::scheduler::TimerEvent for single-shot deadline timer events
     \li senf::scheduler::SignalEvent for UNIX signal events
+    \li senf::scheduler::EventEvent for a special event hook
 
     These instance are owned and managed by the user of the scheduler \e not by the scheduler so the
     RAII concept can be used.
diff --git a/Scheduler/Scheduler.test.cc b/Scheduler/Scheduler.test.cc
index e270b0603..a46aa18da 100644
--- a/Scheduler/Scheduler.test.cc
+++ b/Scheduler/Scheduler.test.cc
@@ -212,6 +212,12 @@ namespace {
         senf::scheduler::terminate();
     }
 
+    unsigned eventCount (0);
+
+    void eventeventhandler()
+    {
+        ++ eventCount;
+    }
 }
 
 BOOST_AUTO_UNIT_TEST(testScheduler)
@@ -236,6 +242,9 @@ BOOST_AUTO_UNIT_TEST(testScheduler)
 
     ///////////////////////////////////////////////////////////////////////////
 
+    senf::scheduler::EventEvent evev ("eventCounter", eventeventhandler, true,
+                                      senf::scheduler::EventEvent::PRIORITY_HIGH);
+
     {
         senf::scheduler::FdEvent fde1 ("testFdEvent", boost::bind(&callback, sock, _1),
                                       sock, senf::scheduler::FdEvent::EV_READ);
@@ -307,6 +316,8 @@ BOOST_AUTO_UNIT_TEST(testScheduler)
         BOOST_CHECK_NO_THROW( senf::scheduler::process() ); 
     } 
 
+    BOOST_CHECK_EQUAL( eventCount, 8u );
+
     ///////////////////////////////////////////////////////////////////////////
 
     close(sock);
diff --git a/Socket/Mainpage.dox b/Socket/Mainpage.dox
index 0a379c7d3..5485c7e76 100644
--- a/Socket/Mainpage.dox
+++ b/Socket/Mainpage.dox
@@ -30,7 +30,9 @@ namespace senf {
     \autotoc
     
     \section socket_intro Introduction
-
+    \seechapter \ref structure \n
+    \seechapter \ref usage
+    
     The socket library abstraction is based on several concepts:
 
     \li The basic visible interface is a \link handle_group handle object\endlink
@@ -40,12 +42,10 @@ namespace senf {
         protocol_group protocol classes \endlink
     \li There is a family of auxilliary \ref addr_group to supplement the socket library
 
-    \see
-        \ref structure \n
-        \ref usage
-
 
     \section socket_handle Socket Handles
+    \seechapter \ref handle_group \n
+    \seechapter \ref concrete_protocol_group
 
     The handle/body architecture provides automatic reference counted management of socket
     instances. This is the visible interface to the socket library.
@@ -53,30 +53,26 @@ namespace senf {
     Each specific protocol is used primarily via a protocol specific handle (a typedef
     symbol). However, more generic kinds of handles can be defined for more generic functionality.
 
-    \see 
-        \ref handle_group \n
-        \ref concrete_protocol_group
 
     
     \section socket_policy The Policy interface
+    \seechapter \ref policy_group
 
     The policy framework configures the exact features, a specific type of socket handle
     provides. This offers highly efficient access to the most important socket functions (like
     reading and writing). The policy interface however is a \e static, non-polymorphic interface.
 
-    \see
-        \ref policy_group
     
     \section socket_protocol The Protocol interface
+    \seechapter \ref protocol_group
+    
 
     The protocol interface provides further protocol dependent and (possibly) polymorphic access to
     further socket funcitonality. On the other hand, this type of interface is not as flexible,
     generic and fast as the policy interface.
 
-    \see
-        \ref protocol_group
-    
     \section socket_addr Auxilliary Addressing classes
+    \seechapter \ref addr_group
     
     To supplement the socket library, there are a multitude of addressing classes. These come in two
     basic groups:
@@ -87,18 +83,14 @@ namespace senf {
     corresponding low-level address, the socket addresses are based on the corresponding \c sockaddr
     structures. 
     
-    \see
-        \ref addr_group
-
     \section socket_further Going further
+    \seechapter \ref extend \n
+    \seechapter \ref implementation
 
     The socket library is highly flexible and extensible. The implementation is not restricted to
     plain BSD sockets: Any type of read/write communication can be wrapped into the socket library
     (one Example is the TapSocketHandle which provides access to a Linux \c tap device).
 
-    \see
-        \ref extend \n
-        \ref implementation
  */
 
 /** \page structure Overview of the Socket Library Structure
-- 
GitLab