{
route(input,timer);
route(timer,output);
- registerEvent(&RateFilter::timeout, timer);
+ registerEvent(timer, &RateFilter::timeout);
}
void RateFilter::timeout()
{
route(input,idle_);
route(idle_,output);
- registerEvent(& ActiveFeeder::request, idle_);
+ registerEvent(idle_, & ActiveFeeder::request);
}
///////////////////////////////cci.e///////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
// senf::ppi::connector::InputConnector
+prefix_ senf::Packet senf::ppi::connector::InputConnector::read()
+{
+ return operator()();
+}
+
prefix_ senf::ppi::connector::OutputConnector & senf::ppi::connector::InputConnector::peer()
const
{
peer().enqueue(p);
}
+prefix_ void senf::ppi::connector::OutputConnector::write(Packet p)
+{
+ operator()(p);
+}
+
prefix_ senf::ppi::connector::InputConnector & senf::ppi::connector::OutputConnector::peer()
const
{
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 operator()(); ///< Get a packet
/**< This member is the primary method to access received
data. On passive connectors, this operator will just
logic error in the module implementation and an
exception is raised. */
+ Packet read(); ///< Alias for \ref operator()()
+
OutputConnector & peer() const;
queue_iterator begin() const; ///< Access queue begin (head)
: public virtual Connector
{
public:
- void operator()(Packet p); ///< Send out a packet
+ void operator()(Packet p); ///< Send out a packet
+
+ void write(Packet p); ///< Alias for \ref operator()()
InputConnector & peer() const;
: timer ( senf::ClockService::milliseconds(d_) ),
n ( n_ )
{
- registerEvent( &TimerTest::tick, timer );
+ registerEvent( timer, &TimerTest::tick );
}
};
The PPI interface is designed to be as simple as possible. It provides sane defaults for all
configurable parameters to simplify getting started. It also automates all resource
- management. Especially to simplify resource management, the PPI will take many configuration
- objects by value. Even though this is not as efficient, it frees the user from most resource
- management chores. This decision does not affect the runtime performance since it only affects
- the configuration step.
+ management. The throttling infrastructure handles blocking conditions (like input exhaustion)
+ automatically
\section packets Packets
///////////////////////////////////////////////////////////////////////////
// senf::ppi::module::Module
+#ifndef DOXYGEN
+
template <class Source, class Target>
prefix_ senf::ppi::Route<Source, Target> &
senf::ppi::module::Module::route(Source & source, Target & target)
new Route<Source,Target>(*this, source, target))));
}
-template <class Target, class Descriptor>
-prefix_ void senf::ppi::module::Module::registerEvent(Target target, Descriptor & descriptor)
+#else
+prefix_ senf::ppi::Route<connector::InputConnector, connector::OutputConnector> &
+senf::ppi::module::Module::route(connector::InputConnector & input,
+ connector::OutputConnector & output)
+{}
+prefix_ senf::ppi::Route<connector::InputConnector, EventDescriptor> &
+senf::ppi::module::Module::route(connector::InputConnector & input, EventDescriptor & output)
+{}
+#endif
+
+#ifndef DOXYGEN
+
+template <class Descriptor, class Target>
+prefix_ void senf::ppi::module::Module::registerEvent(Descriptor & descriptor, Target target)
{
eventManager().registerEvent(
*this,
descriptor.enabled(true);
}
+#else
+template <class Target>
+prefix_ void senf::ppi::module::Module::registerEvent(Target target,
+ EventDescriptor & descriptor)
+{}
+#endif
+
///////////////////////////////////////////////////////////////////////////
// senf::ppi::module::detail namespace members
///< Define flow information
/**< Using the route() and noroute() members, the
information flow within the module is defined. Routing
- may be specified either between inputs, outputs and
- events. The routing information is used to perform
- automatic throttling. The throttling behavior may
- however be controlled manually.
+ may be defined between inputs, outputs and events. The
+ routing information is used to perform automatic
+ throttling. The throttling behavior may however be
+ controlled manually.
Even if no automatic throttling is desired <em>it is
- vital to define the flow information for all inputs and
- outputs</em>. Without flow information important
+ essential to define the flow information for all inputs
+ and outputs</em>. Without flow information important
internal state of the module cannot be
initialized. This includes, explicitly defining
terminal inputs and outputs using noroute. Event
- routing however is optional.
+ routing is optional however.
The return value may be used to alter routing
parameters like throttling parameters.
-
+
\param[in] source Data source, object which controls
incoming data (connector or event)
\param[in] target Data target, object which controls
outgoing data (connector or event)
- \returns Route instance describing this route */
+ \returns Route instance describing this route
+ \note The real implementation is not provided by three
+ overloads but by a single template member */
Route<connector::InputConnector, EventDescriptor> &
route(connector::InputConnector & input, EventDescriptor & output);
///< Define flow information
- /**< \see \ref route() */
+ /**< Route from a connector to an event. Routing from a
+ connector to an event defines the event as the
+ conceptual 'receiver' of the data. This means, the
+ event is controlling the processing of received data
+ packets (Example: Routing from an input to an IOEvent
+ defines, that input data will be processed whenever the
+ event is signaled.).
+
+ This event routing allows to automatically
+ enable/disable the event on throttling notifications.
+
+ \see \ref route() */
Route<EventDescriptor, connector::OutputConnector> &
route(EventDescriptor & input, connector::OutputConnector & output);
///< Define flow information
- /**< \see \ref route() */
+ /**< Route from an event to a connector. Routing from an
+ event to a connector defeines the event as the
+ conceptual 'source' of the data. THis means, the event
+ controls how packets are sent (Example: Routing from an
+ IOEVent to an output defines, that output data will be
+ generated whenever the event is signaled).
+
+ This event routing allows to automatically
+ enable/disable the event on throttling notifications.
+
+ \see \ref route() */
#endif
void noroute(connector::Connector & connector); ///< Define terminal connectors
\param[in] connector Terminal connector to declare */
- template <class Target, class Descriptor>
- void registerEvent(Target target, Descriptor & descriptor);
+#ifndef DOXYGEN
+ template <class Descriptor, class Target>
+ void registerEvent(Descriptor & descriptor, Target target);
+#else
+ template <class Target>
+ void registerEvent(Target target, EventDescriptor & descriptor);
///< Register an external event
/**< The \a target argument may be either an arbitrary
callable object or it may be a member function pointer
allows to access detailed information on the event
delivered.
- The \a descriptor describes the event to signal. This
-
- may be a timer event or some type of I/O event on a
- file descriptor or socket.
+ The \a descriptor describes the event to signal like a
+ timer event or some type of I/O event on a file
+ descriptor or socket.
\param[in] target The handler to call whenever the
event is signaled
\param[in] descriptor The type of event to register */
+#endif
ClockService::clock_type time() const; ///< Time-stamp of the currently processing event
/**< If available, this returns the scheduled time of the
TestModule() {
noroute(output);
- registerEvent(&TestModule::onEvent, event);
+ registerEvent(event, &TestModule::onEvent);
}
void onEvent() {
public:
virtual ~RouteBase();
+#ifdef DOXYGEN
+ Source & source() const; ///< Routing source
+ /**< \note The real implementation is in the \c
+ BaseRouteImplementation template in \c Route.ih. This
+ class is internal and not documented. */
+ Target & target() const; ///< Routing target
+ /**< \note The real implementation is in the \c
+ BaseRouteImplementation template in \c Route.ih. This
+ class is internal and not documented. */
+#endif
+
protected:
RouteBase(module::Module & module);
Route instances are created by Module::route statements. The Route class provides an
interface to manipulate the flow processing.
- The concrete interface provided depends on the type of route. If the route is a forwarding
- route, it will be based on ForwardingRoute otherwise it will be based directly on
- RouteBase.
+ Depending on the type of route, one of the following classes will be a baseclass:
+
+ <dl> <dt>ForwardingRoute</dt><dd>If the route is a \e forwarding route. This is a route
+ which forwards throttling notifications. This is the case, if one of the route endpoints is
+ a notify source (a connector::ActiveConnector) and the other is a
+ notify target (a connector::PassiveConnector or an EventDescriptor).
+
+ <dt>RouteBase</dt><dd>If the route is not a forwarding route, it is based directly on the
+ generic route base class</dd></dl>
*/
template <class Source, class Target>
class Route
passiveIn.onRequest(&RouteTester::inputRequest);
passiveOut.onRequest(&RouteTester::outputRequest);
- registerEvent(&RouteTester::onEvent, event);
+ registerEvent(event, &RouteTester::onEvent);
activeIn.onThrottle(&RouteTester::throttleRequest);
activeIn.onUnthrottle(&RouteTester::unthrottleRequest);
ActiveSocketReader(Handle handle)
: handle_(handle), event_(handle_, IOEvent::Read), reader_()
{
- registerEvent( &ActiveSocketReader::read, event_ );
+ registerEvent( event_, &ActiveSocketReader::read );
route(event_, output);
}
prefix_ senf::ppi::module::ActiveSocketWriter<Writer>::ActiveSocketWriter(Handle handle)
: handle_(handle), event_(handle_, IOEvent::Write), writer_()
{
- registerEvent( &ActiveSocketWriter::write, event_ );
+ registerEvent( event_, &ActiveSocketWriter::write );
route(input, event_);
}
env.Default(libsenf)
env.Alias('install_all', env.Install('$LIBINSTALLDIR', libsenf))
-env.AlwaysBuild(
- env.Alias('deb', [], [ checkLocalConf,
- updateRevision,
- "$BUILDPACKAGE_COMMAND" ]))
-
-env.AlwaysBuild(
- env.Alias('debsrc', [], [ updateRevision,
- "$BUILDPACKAGE_COMMAND -S" ]))
-
-env.AlwaysBuild(
- env.Alias('debbin', [], [ checkLocalConf,
- updateRevision,
- "$BUILDPACKAGE_COMMAND -nc" ]))
-
env.Clean('all', [ os.path.join(path,f)
for path, subdirs, files in os.walk('.')
for pattern in env['CLEAN_PATTERNS']
for f in fnmatch.filter(files,pattern) ])
-env.AlwaysBuild(env.Alias('linklint', [ 'all_docs' ], [
+env.AlwaysBuild(env.Alias('deb', [], [
+ checkLocalConf,
+ updateRevision,
+ "$BUILDPACKAGE_COMMAND" ]))
+
+env.AlwaysBuild(env.Alias('debsrc', [], [
+ updateRevision,
+ "$BUILDPACKAGE_COMMAND -S" ]))
+
+env.AlwaysBuild(env.Alias('debbin', [], [
+ checkLocalConf,
+ updateRevision,
+ "$BUILDPACKAGE_COMMAND -nc" ]))
+
+env.AlwaysBuild(env.Alias('linklint', [], [
'rm -rf linklint',
'linklint -doc linklint -net -limit 99999999 `find -type d -name html -printf "/%P/@ "`',
- '[ -r linklint/errorX.html ] && python linklint_addnames.py <linklint/errorX.html >linklint/errorX.html.new',
- '[ -r linklint/errorX.html.new ] && mv linklint/errorX.html.new linklint/errorX.html',
- '[ -r linklint/errorAX.html ] && python linklint_addnames.py <linklint/errorAX.html >linklint/errorAX.html.new',
- '[ -r linklint/errorAX.html.new ] && mv linklint/errorAX.html.new linklint/errorAX.html',
+ '[ ! -r linklint/errorX.html ] || python linklint_addnames.py <linklint/errorX.html >linklint/errorX.html.new',
+ '[ ! -r linklint/errorX.html.new ] || mv linklint/errorX.html.new linklint/errorX.html',
+ '[ ! -r linklint/errorAX.html ] || python linklint_addnames.py <linklint/errorAX.html >linklint/errorAX.html.new',
+ '[ ! -r linklint/errorAX.html.new ] || mv linklint/errorAX.html.new linklint/errorAX.html',
'@echo -e "\\nLokal link check results: linklint/index.html"',
'@echo -e "Remote link check results: linklint/urlindex.html\\n"'
]))
+
+env.AlwaysBuild(env.Alias('fixlinks', [ 'linklint' ], [
+ '[ ! -r linklint/errorX.txt -o ! -r linklint/errorAX.txt ] || python doclib/fix-links.py -s .svn -s linklint -s debian linklint/errorX.txt linklint/errorAX.txt',
+]))
+
+env.Clean('all', env.Dir('linklint'))
rm -f ../svn-update.log
echo '$ scons -k all'
-scons -k all
+scons -k all && scons fixlinks
echo -n '# Build completed at '; date --utc
exec >../upload.log 2>&1
--- /dev/null
+#!/usr/bin/python
+
+import sys,os.path,fnmatch, HTMLParser, getopt
+
+class HTMLFilter(HTMLParser.HTMLParser):
+
+ def __init__(self, out=None):
+ HTMLParser.HTMLParser.__init__(self)
+ self._out = out
+ self._collect = False
+ self._data = ""
+
+ def startCollect(self):
+ self._collect = True
+ self._data = ""
+
+ def endCollect(self):
+ self._collect = False
+ return self._data
+
+ def collecting(self):
+ return self._collect
+
+ def handle_starttag(self,tag,attrs):
+ m = getattr(self,'_s_'+tag.upper(),None)
+ if m:
+ m(attrs)
+ else:
+ self.emit_starttag(tag,attrs)
+
+ def handle_endtag(self,tag):
+ m = getattr(self,'_e_'+tag.upper(),None)
+ if m:
+ m()
+ else:
+ self.emit_endtag(tag)
+
+ def handle_data(self,data):
+ if self._collect:
+ self._data += data
+ if self._out:
+ self._out.write(data)
+
+ def handle_charref(self,name):
+ self.handle_data(name)
+
+ def handle_entityref(self,name):
+ self.handle_data(name)
+
+ def emit_starttag(self,tag,attrs):
+ self.handle_data('<%s%s>' % (tag, "".join([' %s="%s"' % attr for attr in attrs])))
+
+ def emit_endtag(self,tag):
+ self.handle_data('</%s>' % tag)
+
+
+class AnchorIndex:
+
+ def __init__(self, skipdirs = ('.svn',)):
+ self._anchors = {}
+ self._skipdirs = skipdirs
+
+ def build(self):
+ sys.stderr.write("Building anchor index ")
+ nf = 0
+ for dirname, subdirs, files in os.walk('.'):
+ for d in self._skipdirs:
+ if d in subdirs:
+ subdirs.remove(d)
+ for f in fnmatch.filter(files,'*.html'):
+ nf += 1
+ path = os.path.normpath(os.path.join(dirname, f))
+ self._addAnchor(f, path)
+ self._extractAnchors(path)
+ sys.stderr.write(" Done.\n")
+ dups = 0
+ for k in self._anchors.keys():
+ if not self._anchors[k]:
+ dups += 1
+ del self._anchors[k]
+ sys.stderr.write("%d unique anchors in %d files (%d duplicates)\n"
+ % (len(self._anchors), nf, dups))
+
+ def _addAnchor(self, anchor, path):
+ if self._anchors.has_key(anchor):
+ self._anchors[anchor] = None
+ else:
+ self._anchors[anchor] = path
+ if len(self._anchors) % 100 == 0:
+ sys.stderr.write('.')
+
+ def __getitem__(self, key):
+ return self._anchors.get(key)
+
+ class AnchorExtractor(HTMLFilter):
+
+ def __init__(self):
+ HTMLFilter.__init__(self)
+ self._anchors = {}
+
+ def _s_A(self,attrs):
+ attrs = dict(attrs)
+ if attrs.has_key('name'):
+ self._anchors[attrs['name']] = None
+
+ def anchors(self):
+ return self._anchors.keys()
+
+ def _extractAnchors(self, f):
+ extractor = AnchorIndex.AnchorExtractor()
+ extractor.feed(file(f).read())
+ extractor.close()
+ for anchor in extractor.anchors():
+ self._addAnchor(anchor, f)
+
+
+class LinkFixer:
+
+ def __init__(self, skipdirs=('.svn',)):
+ self._index = AnchorIndex(skipdirs)
+
+ def init(self):
+ self._index.build()
+ self._files = 0
+ self._found = 0
+ self._fixed = 0
+
+ class LinkFilter(HTMLFilter):
+
+ def __init__(self, index, key, topdir, out):
+ HTMLFilter.__init__(self, out)
+ self._index = index
+ self._key = key
+ self._topdir = topdir
+ self._skip_a = False
+ self._found = 0
+ self._fixed = 0
+
+ def _s_A(self, attrs):
+ self._skip_a = False
+ if self._key in dict(attrs).get('href',''):
+ self._found += 1
+ ix = [ i for i, attr in enumerate(attrs) if attr[0] == 'href' ][0]
+ target = attrs[ix][1]
+ if '#' in target:
+ anchor = target.split('#')[1]
+ target = self._index[anchor]
+ if target:
+ target = '%s#%s' % (target, anchor)
+ else:
+ target = self._index[os.path.split(target)[1]]
+ if target:
+ self._fixed += 1
+ attrs[ix] = ('href', os.path.join(self._topdir,target))
+ else:
+ self._skip_a = True
+ return
+ self.emit_starttag('a',attrs)
+
+ def _e_A(self):
+ if self._skip_a:
+ self._skip_a = False
+ else:
+ self.emit_endtag('a')
+
+ def stats(self):
+ return (self._found, self._fixed)
+
+ def fix(self, path, target):
+ self._files += 1
+ data = file(path).read()
+ filt = LinkFixer.LinkFilter(self._index,
+ target,
+ "../" * (len(os.path.split(path)[0].split("/"))),
+ file(path,"w"))
+ filt.feed(data)
+ filt.close()
+ self._found += filt.stats()[0]
+ self._fixed += filt.stats()[1]
+
+ def stats(self):
+ return (self._files, self._found, self._fixed)
+
+
+(opts, args) = getopt.getopt(sys.argv[1:], "s:")
+if len(args) != 2:
+ sys.stderr.write("""Usage:
+ fix-links.py [-s skip-dir]... <errrorX.txt> <errorAX.txt>
+
+Process the 'errorX.txt' and 'errorAX.txt' files as generated by
+'linklint': Check all invalid links and try to find the correct
+target. If a target is found, the link is changed accordingly,
+otherwise the link is removed.
+
+To find anchors, fix-links.py generates a complete index of all
+anchors defined in any HTML file in the current directory or some
+subdirectory. The directories named 'skiped-dir' (at any level) will
+not be scanned for '*.html' files.
+""")
+ sys.exit(1)
+
+skipdirs = [ val for opt, val in opts if opt == '-s' ]
+
+fixer = LinkFixer(skipdirs)
+fixer.init()
+
+target = None
+for l in file(args[0]):
+ l = l.rstrip()
+ if l.startswith('/'):
+ target = '#' + os.path.split(l)[1]
+ elif l.startswith(' /') and not l.endswith('/'):
+ sys.stderr.write("%s\n" % l)
+ fixer.fix(l[5:], target)
+
+for l in file(args[1]):
+ l = l.rstrip()
+ if l.startswith('/'):
+ target = l.split('#')[1]
+ elif l.startswith(' /') and not l.endswith('/'):
+ sys.stderr.write("%s\n" % l)
+ fixer.fix(l[5:], target)
+
+files, found, fixed = fixer.stats()
+
+sys.stderr.write("""
+Files processed : %5d
+Links processed : %5d
+Links fixed : %5d
+Links removed : %5d
+""" % (files, found, fixed, found-fixed))
# libraries are provided by the distribution, you probably don't need
# to specify any parameters. If your configuration is more complex,
# refer to the <a
-# href="http://www.boost.org/tools/build/v1/build_system.htm">Boost.Build</a>
+# href="http://www.boost.org/tools/build/v2/index.html">Boost.Build</a>
# documentation for a definition of the terms used above (toolset,
# variant, runtime ...).
#