Utils/Daemon: Add warning when the scheduler has registered events at a fork()
g0dil [Wed, 1 Oct 2008 12:46:35 +0000 (12:46 +0000)]
Scheduler: Documentation update

git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@920 270642c3-0616-0410-b53a-bc976706d245

16 files changed:
Packets/Packet.cti
Packets/Packet.hh
Packets/Packet.test.cc
Packets/PacketImpl.cc
Packets/PacketImpl.cci
Packets/PacketImpl.cti
Packets/PacketImpl.hh
Packets/PacketInterpreter.cti
Packets/PacketInterpreter.hh
Scheduler/FdEvent.hh
Scheduler/Mainpage.dox
Scheduler/Scheduler.cc
Scheduler/Scheduler.hh
Utils/Daemon/Daemon.cc
doclib/Doxyfile.global
senf.dict

index fac31c0..cfd8919 100644 (file)
@@ -135,6 +135,12 @@ prefix_ void senf::Packet::finalizeTo()
     ptr()->finalizeTo(p ? p.ptr() : last().ptr());
 }
 
+template <class Annotation>
+prefix_ Annotation & senf::Packet::annotation()
+{
+    return ptr()->annotation<Annotation>();
+}
+
 ///////////////////////////////////////////////////////////////////////////
 // senf::ConcretePacket<PacketType>
 
index af45ff2..58264f8 100644 (file)
@@ -314,6 +314,14 @@ namespace senf {
         
         ///@}
 
+        ///\name Annotations
+        ///@{
+        
+        template <class Annotation>
+        Annotation & annotation();
+
+        ///@}
+
         ///\name Other methods
         ///@{
 
@@ -331,11 +339,12 @@ namespace senf {
                                              when using a packet in a boolean context. */
 
         void finalizeThis();            ///< Update calculated fields
-                                        /**< This call will update all calculated fields of the
-                                             packet. This includes checksums, payload size fields or
-                                             other fields, which can be set from other information
-                                             in the packet. Each concrete packet type should
-                                             document, which fields are set by finalize().
+                                        /**< The finalize() fammily of members will update
+                                             calculated packet fields: checksums, size fields and so
+                                             on. This includes any field, which can be set from
+                                             other information in the packet. Each concrete packet
+                                             type should document, which fields are set by
+                                             finalize().
 
                                              finalizeThis() will \e only process the current
                                              header. Even if only changing fields in this protocol,
@@ -345,37 +354,56 @@ namespace senf {
 
         template <class Other>
         void finalizeTo();              ///< Update calculated fields
-                                        /**< This call will update all calculated fields of the
-                                             packet. This includes checksums, payload size fields or
-                                             other fields, which can be set from other information
-                                             in the packet. Each concrete packet type should
-                                             document, which fields are set by finalize().
+                                        /**< The finalize() fammily of members will update
+                                             calculated packet fields: checksums, size fields and so
+                                             on. This includes any field, which can be set from
+                                             other information in the packet. Each concrete packet
+                                             type should document, which fields are set by
+                                             finalize().
 
                                              finalizeTo() will automatically process all
-                                             packets/headers/interpreters from the first occurrence
-                                             of packet type \a Other backwards up to \c this. */
+                                             packets/headers/interpreters from the \e first
+                                             occurrence of packet type \a Other (beginning at \c
+                                             this packet searching forward towards deeper nested
+                                             packets) backwards up to \c this. 
+                                             
+                                             This call is equivalent to
+                                             \code
+                                             p.finalizeTo(p.next<Other>())
+                                             \endcode */
 
         void finalizeTo(Packet other);  ///< Update calculated fields
-                                        /**< This call will update all calculated fields of the
-                                             packet. This includes checksums, payload size fields or
-                                             other fields, which can be set from other information
-                                             in the packet. Each concrete packet type should
-                                             document, which fields are set by finalize().
+                                        /**< The finalize() fammily of members will update
+                                             calculated packet fields: checksums, size fields and so
+                                             on. This includes any field, which can be set from
+                                             other information in the packet. Each concrete packet
+                                             type should document, which fields are set by
+                                             finalize().
 
-                                             finalizeAll(other) will automatically process all
-                                             packets/headers/interpreters from \a other backwards up
-                                             to \c this. */
+                                             finalizeTo(other) will automatically process all
+                                             packets/headers/interpreters beginning at \a other
+                                             backwards towards outer packets up to \c this. */
 
         void finalizeAll();             ///< Update calculated fields
-                                        /**< This call will update all calculated fields of the
-                                             packet. This includes checksums, payload size fields or
-                                             other fields, which can be set from other information
-                                             in the packet. Each concrete packet type should
-                                             document, which fields are set by finalize().
+                                        /**< The finalize() fammily of members will update
+                                             calculated packet fields: checksums, size fields and so
+                                             on. This includes any field, which can be set from
+                                             other information in the packet. Each concrete packet
+                                             type should document, which fields are set by
+                                             finalize().
 
                                              finalizeAll() will automatically process all
                                              packets/headers/interpreters from the end of the chain
-                                             backwards up to \c this. */
+                                             (the most inner packet) backwards up to \c this. 
+                                             
+                                             This call is equivalent to
+                                             \code
+                                             p.finalizeTo(p.last())
+                                             \endcode 
+                                             
+                                             Beware, that finalizeAll() will \e not finalize any
+                                             headers before \c this, it will \e only process inner
+                                             headers. */
 
         void dump(std::ostream & os) const; ///< Write out a printable packet representation
                                         /**< This method is provided mostly to help debugging packet
index 70b3e1d..b88993e 100644 (file)
@@ -109,6 +109,15 @@ namespace {
         senf::PacketRegistry<RegTag>::RegistrationProxy<BarPacket> registerBar(2u);
     }
 
+    struct IntAnnotation {
+        int value;
+    };
+
+    struct ComplexAnnotation {
+        std::string s;
+        int i;
+    };
+
 }
 
 BOOST_AUTO_UNIT_TEST(packet)
@@ -116,6 +125,10 @@ BOOST_AUTO_UNIT_TEST(packet)
     senf::Packet packet (FooPacket::create());
     BarPacket::createAfter(packet);
 
+    SENF_CHECK_NO_THROW( packet.annotation<IntAnnotation>().value = 0xDEADBEEF );
+    ComplexAnnotation & ca (packet.annotation<ComplexAnnotation>());
+    ca.s = "dead beef";
+    ca.i = 0x12345678;
     BOOST_REQUIRE( packet );
     BOOST_CHECK( packet.next() );
     BOOST_CHECK( ! packet.next().next(senf::nothrow) );
index 2bd41be..5b5e12f 100644 (file)
 #define prefix_
 ///////////////////////////////cc.p////////////////////////////////////////
 
+unsigned senf::detail::AnnotationIndexerBase::maxAnnotations (0);
+
 ///////////////////////////////////////////////////////////////////////////
 // senf::detail::PacketImpl
 
+prefix_ senf::detail::PacketImpl::~PacketImpl()
+{
+    // We increment refcount_ to ensure, release() won't call delete again
+    ++refcount_;
+    eraseInterpreters(interpreters_.begin(), interpreters_.end());
+    Annotations::const_iterator  i (annotations_.begin());
+    Annotations::const_iterator const i_end (annotations_.end());
+    std::vector<bool>::iterator small (AnnotationIndexerBase::small().begin());
+    for (; i != i_end; ++i, ++small)
+        if (! *small && *i)
+            delete *i;
+}
+
 // This function has a problem being inlined. Somehow, often when calling this, the size of the 
 // resulting inlined code would be huge. Need to further debug this.
 
index 40489bf..9b8a277 100644 (file)
 #define prefix_ inline
 ///////////////////////////////cci.p///////////////////////////////////////
 
+///////////////////////////////////////////////////////////////////////////
+// senf::detail::AnnotationIndexerBase
+
+prefix_ std::vector<bool> & senf::detail::AnnotationIndexerBase::small()
+{
+    static std::vector<bool> smalls;
+    return smalls;
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::detail::AnnotationP
+
+prefix_ senf::detail::AnnotationP::~AnnotationP()
+{}
+
 // Memory management:
 //
 // * The PacketImpl destructor will *explicitly* clean-up the interpreters_ list by removing
 // senf::detail::PacketImpl
 
 prefix_ senf::detail::PacketImpl::PacketImpl()
-    : refcount_(0)
+    : refcount_(0), annotations_(AnnotationIndexerBase::maxAnnotations, 0)
 {}
 
 prefix_ senf::detail::PacketImpl::PacketImpl(size_type size, byte initValue)
-    : refcount_(0), data_(size,initValue)
+    : refcount_(0), data_(size,initValue), annotations_(AnnotationIndexerBase::maxAnnotations, 0)
 {}
 
-prefix_ senf::detail::PacketImpl::~PacketImpl()
-{
-    // We increment refcount_ to ensure, release() won't call delete again
-    ++refcount_;
-    eraseInterpreters(interpreters_.begin(), interpreters_.end());
-}
-
 // rerference/memory management
 
 prefix_ void senf::detail::PacketImpl::add_ref(refcount_t n)
index a00a8e3..21956f1 100644 (file)
 ///////////////////////////////cti.p///////////////////////////////////////
 
 ///////////////////////////////////////////////////////////////////////////
+// senf::detail::AnnotationIndexer<Annotation>
+
+template <class Annotation>
+prefix_ senf::detail::AnnotationIndexer<Annotation>::AnnotationIndexer()
+    : index_ (maxAnnotations++)
+{
+    small().push_back(Small);
+}
+
+template <class Annotation>
+prefix_ unsigned senf::detail::AnnotationIndexer<Annotation>::index()
+{
+    return AnnotationIndexer::instance().index_;
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::detail::GetAnnotation<Annotation,Small>
+
+template <class Annotation, bool Small>
+prefix_ Annotation & senf::detail::GetAnnotation<Annotation,Small>::get(AnnotationP * & p)
+{
+    if (!p)
+        p = new TAnnotationP<Annotation>();
+    return static_cast< TAnnotationP<Annotation>* >(p)->annotation;
+}
+
+/*
+template <class Annotation>
+prefix_ Annotation & senf::detail::GetAnnotation<Annotation, true>::get(AnnotationP * & p)
+{
+    return * reinterpret_cast<Annotation*>(p);
+}
+*/
+
+///////////////////////////////////////////////////////////////////////////
 // senf::detail::PacketImpl
 
 // Data container
@@ -46,9 +81,18 @@ prefix_ void senf::detail::PacketImpl::insert(PacketData * self, iterator pos, F
 
 template <class InputIterator>
 prefix_ senf::detail::PacketImpl::PacketImpl(InputIterator first, InputIterator last)
-    : refcount_(0), data_(first,last)
+    : refcount_(0), data_(first,last), annotations_(AnnotationIndexerBase::maxAnnotations, 0)
 {}
 
+// Annotations
+
+template <class Annotation>
+prefix_ Annotation & senf::detail::PacketImpl::annotation()
+{
+    return GetAnnotation<Annotation>::get(
+        annotations_[AnnotationIndexer<Annotation>::index()]);
+}
+
 ///////////////////////////////cti.e///////////////////////////////////////
 #undef prefix_
 
index 871b9ec..1d1373f 100644 (file)
 
 // Custom includes
 #include <memory>
+#include <vector>
 #include <boost/utility.hpp>
 #include "../Utils/pool_alloc_mixin.hh"
 #include "PacketTypes.hh"
+#include "../Utils/singleton.hh"
 
 //#include "PacketImpl.mpp"
 ///////////////////////////////hh.p////////////////////////////////////////
 namespace senf {
 namespace detail {
 
+    struct AnnotationIndexerBase
+    {
+        static unsigned maxAnnotations;
+        static std::vector<bool> & small();
+    };
+
+    template <class Annotation>
+    struct AnnotationIndexer 
+        : public senf::singleton< AnnotationIndexer<Annotation> >, 
+          public AnnotationIndexerBase
+    {
+        AnnotationIndexer();
+        unsigned index_;
+        static unsigned index();
+        static bool const Small = (sizeof(Annotation) <= sizeof(void*));
+    };
+
+    struct AnnotationP
+    {
+        virtual ~AnnotationP();
+    };
+
+    template <class Annotation>
+    struct TAnnotationP
+        : public AnnotationP
+    {
+        Annotation annotation;
+    };
+
+    template <class Annotation, bool Small = AnnotationIndexer<Annotation>::Small>
+    struct GetAnnotation
+    {
+        static Annotation & get(AnnotationP * & p);
+    };
+
+/*
+    template <class Annotation>
+    struct GetAnnotation<Annotation, true>
+    {
+        static Annotation & get(AnnotationP * & p);
+    };
+*/
+
     /** \brief Internal: Packet data storage
 
         \internal
@@ -103,6 +148,10 @@ namespace detail {
         void erase(PacketData * self, iterator first, iterator last);
         void clear(PacketData * self);
 
+        // Annotations
+        template <class Annotation>
+        Annotation & annotation();
+
         /** \brief Internal: Keep PacketImpl instance alive
 
             \internal
@@ -121,6 +170,9 @@ namespace detail {
         refcount_t refcount_;
         raw_container data_;
         interpreter_list interpreters_;
+        
+        typedef std::vector<AnnotationP*> Annotations;
+        Annotations annotations_;
 
         void eraseInterpreters(interpreter_list::iterator b, interpreter_list::iterator e);
         void updateIterators(PacketData * self, difference_type pos, difference_type n);
index 672436f..f542015 100644 (file)
@@ -50,6 +50,12 @@ prefix_ typename senf::PacketInterpreter<Type>::ptr senf::PacketInterpreterBase:
         static_cast< PacketInterpreter<Type>* >(this));
 }
 
+template <class Annotation>
+prefix_ Annotation & senf::PacketInterpreterBase::annotation()
+{
+    return impl().annotation<Annotation>();
+}
+
 ///////////////////////////////////////////////////////////////////////////
 // senf::PacketInterpreter<PacketType>
 
index 24f29c2..790c600 100644 (file)
@@ -162,6 +162,14 @@ namespace senf {
         
         ///@}
 
+        ///\name Annotations
+        ///@{
+
+        template <class Annotation>
+        Annotation & annotation();
+
+        ///@}
+
         ///\name Access to the abstract interface
         ///@{
 
index 90ddc7a..d574351 100644 (file)
@@ -171,6 +171,12 @@ namespace scheduler {
         friend class detail::FileDispatcher;
     };
 
+    /** \brief Get file descriptor from handle object
+
+        This function will query the \a handle for it's file descriptor. The real implementation
+        must be provided by a freestanding function \c retrieve_filehandle(Handle const & h) within
+        the namespace of \a Handle.
+     */
     template <class Handle>
     int get_descriptor(Handle const & handle);
 }}
index 054af2e..e67784a 100644 (file)
     \autotoc
 
     \section scheduler_scheduler The Scheduler
+    \seechapter \ref senf::scheduler
 
-    The Scheduler is based on the RAII principle: Every event is represented by a class
-    instance. The event is registered in the constructor and removed by the destructor of that
-    instance. This implementation automatically links the lifetime of an event with the lifetime of
-    the object resposible for it's creation.
-    
-    The Scheduler supports the following types of events::
+    The %scheduler provides a single threaded event dispatch architecture with reliable task
+    queueing using FIFO scheduling. The %scheduler provides event handling for
 
     \li File descriptors
     \li Timers
     \li UNIX signals
 
-    \see \ref senf::scheduler
-
-
     \section scheduler_clockservice The ClockService
+    \seechapter senf::ClockService
 
     To support precise event timing, the senf::ClockService class implements a reliable monotonous
     time source. It is based on the high precision POSIX clock and adds support for reliable
     conversion between an abstract clock type and absolute date/time
 
-    \see senf::ClockService
-
-
     \section scheduler_helpers Miscellaneous helpers
 
     To ease the use of the Scheduler there are some additional helpers managing callbacks and
         is met (e.g. number of chars read or a specific character sequence is found in the input).
     \li senf::WriteHelper writes data to an arbitrary file descriptor until all provided data has
         been written.
-
     
     \section scheduler_i Implementation
+    \seechapter \ref scheduler_implementation
 
     senf::Scheduler is only a wrapper around the real implementation. The real implementation is now
     based on a modular dispatcher architecture
 
-    \see \ref scheduler_implementation
  */
 
 /** \page scheduler_implementation The Scheduler Implementation
index 1d7b28b..7ba69ef 100644 (file)
@@ -89,6 +89,14 @@ prefix_ void senf::scheduler::restart()
     new (fld) detail::FileDispatcher();
 }
 
+prefix_ bool senf::scheduler::empty()
+{
+    return detail::FdDispatcher::instance().empty() 
+        && detail::TimerDispatcher::instance().empty()
+        && detail::FileDispatcher::instance().empty()
+        && detail::SignalDispatcher::instance().empty();
+}
+
 ///////////////////////////////////////////////////////////////////////////
 // senf::schedulerLogTimeSource
 
index 3329426..af07c48 100644 (file)
@@ -42,8 +42,9 @@ namespace senf {
 
     The %scheduler API is comprised of two parts:
 
-    \li Specific event classes, one for each type of event.
-    \li Some generic functions implemented in the \ref senf::scheduler namespace.
+    \li Specific \ref sched_objects, one for each type of event.
+    \li Some <a href="#autotoc-7.">generic functions</a> implemented in the \ref senf::scheduler
+        namespace.
 
     Events are registered via the respective event class. The (global) functions are used to enter
     the application main-loop or query for global information.
@@ -53,7 +54,12 @@ namespace senf {
 
     \section sched_objects Event classes
 
-    Every event registration is represented by a class instance of an event specific class:
+    The Scheduler is based on the RAII principle: Every event is represented by a class
+    instance. The event is registered in the constructor and removed by the destructor of that
+    instance. This implementation automatically links the lifetime of an event with the lifetime of
+    the object resposible for it's creation.
+
+    Every event registration is represented by an instance of an event specific class:
 
     \li senf::scheduler::FdEvent for file descriptor events
     \li senf::scheduler::TimerEvent for single-shot deadline timer events
@@ -128,6 +134,65 @@ namespace senf {
     The handler is identified by an arbitrary, user specified name. This name is used in error
     messages to identify the failing handler.
 
+
+    \section sched_exec Executing the Scheduler
+
+    To enter the scheduler main-loop, call
+    
+    \code
+    senf::scheduler::process();
+    \endcode
+
+    This call will only return in two cases:
+
+    \li When a handler calls senf::scheduler::terminate()
+    \li When there is no active file descriptor or timer event.
+
+    Additional <a href="#autotoc-7.">generic functions</a> provide information and %scheduler
+    parameters.
+
+    \section sched_container Event objects and container classes
+
+    As the event objects are \e not copyable, they cannot be placed into ordinary
+    containers. However, it is quite simple to use pointer containers to hold event instances:
+
+    \code
+    #include <boost/ptr_container/ptr_map.hpp>
+    #include <boost/bind.hpp>
+    
+    class Foo
+    {
+    public:
+        void add(int fd)
+        {
+            fdEvents.insert(
+                fd, 
+                new senf::scheduler::FdEvent("foo", boost::bind(&callback, this, fd, _1), fd, 
+                                             senf::scheduler::FdEvent::EV_READ) );
+        }
+
+        void callback(int fd, int events)
+        {
+            FdEvent & event (fdEvents_[fd]);
+
+            // ...
+
+            if (complete)
+                fdEvents_.remove(fd)
+        }
+
+    private:
+        boost::ptr_map<int, FdEvent> fdEvents_;
+    };
+    \endcode
+
+    The pointer container API is (almost) completely identical to the corresponding standard library
+    container API. The only difference is, that all elements added to the container \e must be
+    created via \c new and that the pointer containers themselves are \e not copyable (ok, they are,
+    if the elements are cloneable ...). See <a
+    href="http://www.boost.org/doc/libs/1_36_0/libs/ptr_container/doc/ptr_container.html">Boost.PointerContainer</a>
+    for the pointer container library reference.
+
     \todo Fix the file support to use threads (?) fork (?) and a pipe so it works reliably even
         over e.g. NFS.
   */
@@ -149,7 +214,7 @@ namespace scheduler {
      */
     void terminate(); 
 
-    /** \brief Return date/time of last event
+    /** \brief Return timestamp of last event
 
         This is the timestamp, the last event has been signaled. This is the real time at which the
         event is delivered \e not the time it should have been delivered (in the case of timers). 
@@ -173,6 +238,9 @@ namespace scheduler {
      */
     void restart(); 
 
+    /** \brief Return \c true, if any event is registered, \c false otherwise. */
+    bool empty();
+
     /** \brief %scheduler specific time source for Utils/Logger framework
 
         This time source may be used to provide timing information for log messages within the
index 2b09cc0..d6b8d91 100644 (file)
@@ -363,6 +363,15 @@ prefix_ void senf::Daemon::fork()
     ::sigemptyset(&cldsig);
     LIBC_CALL( ::sigaddset, (&cldsig, SIGCHLD) );
     LIBC_CALL( ::sigprocmask, (SIG_BLOCK, &cldsig, &oldsig) );
+
+    if (! senf::scheduler::empty() )
+        std::cerr << 
+            "\n"
+            "*** WARNING ***\n"
+            "Scheduler not empty before fork(). THIS MUST NOT HAPPEN.\n"
+            "The scheduler will be reinitialized by the fork() and lose all registrations.\n"
+            "*** WARNING ***\n"
+            "\n";
     
     LIBC_CALL_RV( pid, ::fork, () );
 
index f589bbf..9603551 100644 (file)
@@ -190,7 +190,8 @@ ALIASES                = "fixme=\xrefitem fixme \"Fix\" \"Fixmes\"" \
                          "idea=\xrefitem idea \"Idea\" \"Ideas\"" \
                          "implementation=\par \"Implementation note:\"" \
                          "doc=\xrefitem doc \"Documentation request\" \"Documentation Requests\"" \
-                         "autotoc=\htmlonly <div id=\"autotoc\"></div> \endhtmlonly"
+                         "autotoc=\htmlonly <div id=\"autotoc\"></div> \endhtmlonly" \
+                         "seechapter=<b>\htmlonly &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&rarr;&nbsp;\endhtmlonly see </b>"
 
 # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C 
 # sources only. Doxygen will then generate output that is more tailored for C. 
index e8d5956..42a609b 100644 (file)
--- a/senf.dict
+++ b/senf.dict
@@ -60,6 +60,7 @@ checksumPresent
 CIDR
 classsenf
 ClientSocketHandle
+cloneable
 CloneSource
 cmd
 cmdadd
@@ -76,6 +77,7 @@ ConnectedCommunicationPolicy
 ConnectedRawV
 ConnectedUDPv
 const
+copyable
 CPPDEFINES
 CPPPATH
 createAfter
@@ -528,6 +530,7 @@ templated
 ThresholdQueueing
 ThrottleBarrier
 tigris
+timestamp
 todo
 tokenizes
 TokensRange