senf::scheduler Namespace Reference

The Scheduler interface. More...

Namespaces

 detail
 

Classes

class  BlockSignals
 Temporarily block all signals. More...
 
class  EventHook
 Event hook event. More...
 
class  FdEvent
 File descriptor event. More...
 
class  IdleEvent
 
struct  LogTimeSource
 scheduler specific time source for Utils/Logger framework More...
 
class  SignalEvent
 UNIX signal event. More...
 
class  TimerEvent
 Deadline timer event. More...
 
class  TimerEventProxy
 Deadline timer proxy. More...
 

Functions

console::ScopedDirectoryconsoleDir ()
 
template<class Handle >
int get_descriptor (Handle const &handle)
 Get file descriptor from handle object. More...
 
void restart ()
 Restart scheduler. More...
 
void process ()
 Event handler main loop. More...
 
bool running ()
 true, if scheduler is running, false otherwise More...
 
void terminate ()
 Called by callbacks to terminate the main loop. More...
 
void yield ()
 Immediately rescheduler. More...
 
ClockService::clock_type const & eventTime ()
 Return timestamp of last event. More...
 
ClockService::clock_type const & now ()
 Return (approximate) current time. More...
 
ClockService::clock_type nowDiff (ClockService::clock_type const &older)
 Returns (approximate) time difference between 'older' and now() More...
 
CyclicTimestamp const & eventTimestamp ()
 Returns the FIFOrunners current event timestamp (1ms precision) More...
 
void watchdogCallback (detail::FIFORunner::WatchdogCallback const &cb)
 Set watchdog hanging callback. More...
 
void watchdogTimeout (unsigned ms)
 Set watchdog timeout to ms milliseconds. More...
 
unsigned watchdogTimeout ()
 Current watchdog timeout in milliseconds. More...
 
unsigned watchdogEvents ()
 Number of watchdog events. More...
 
void watchdogAbort (bool flag)
 Enable/disable abort on watchdog event. More...
 
bool watchdogAbort ()
 Get current watchdog abort on event status. More...
 
void hiresTimers ()
 Switch to using hi resolution timers. More...
 
void loresTimers ()
 Switch back to using epoll for timing. More...
 
bool haveScalableHiresTimers ()
 return true, if timerfd() timing is available, false otherwise More...
 
bool usingHiresTimers ()
 Return true, if using hires times, false otherwise. More...
 
bool empty ()
 Return true, if no event is registered, false otherwise. More...
 

Detailed Description

The Scheduler interface.

The scheduler API is comprised of two parts:

Events are registered via the respective event class. The (global) functions are used to enter the application main-loop or query for global information.

Event classes

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 responsible 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
\li senf::scheduler::SignalEvent for UNIX signal events
\li senf::scheduler::EventHook 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.
class SomeServer
{
SomeSocketHandle handle_;
public:
SomeServer(SomeSocketHandle handle)
: handle_ (handle),
event_ ("SomeServer handler", senf::membind(&SomeServer::readData, this),
handle, senf::scheduler::FdEvent::EV_READ)
{}
void readData(int events)
{
// read data from handle_, check for eof and so on.
}
};
The event is defined as a class member variable. When the event member is initialized in the
constructor, the event is automatically registered (except if the optional \a initiallyEnabled
flag argument is set to \c false). The destructor will automatically remove the event from the
%scheduler and ensure, that no dead code is called accidentally.

The process is the same for the other event types or when registering multiple events. For
detailed information on the constructor arguments and other features see the event class
documentation referenced below.

Specifying handlers

All handlers are specified as generic <a
href="http://www.boost.org/doc/libs/release/libs/functional/index.html">Boost.Function</a>
objects. This allows to pass any callable as a handler. Depending on the type of handler,
some additional arguments may be passed to the handler by the %scheduler.

If you need to pass additional information to your handler, use <a
href="http://www.boost.org/doc/libs/release/libs/bind/bind.html">Boost.Bind</a>:
// Handle callback function
void callback(UDPv4ClientSocketHandle handle, senf::Scheduler::EventId event) {..}
// Pass 'handle' as additional first argument to callback()
senf::scheduler::FdEvent event ("name", boost::bind(&callback, handle, _1),
// Timeout function
void timeout( int n) {..}
// Call timeout() handler with argument 'n'
senf::scheduler::TimerEvent timer ("name", boost::bind(&timeout, n),
To use member-functions as callbacks, use either <a
href="http://www.boost.org/doc/libs/release/libs/bind/bind.html">Boost.Bind</a> or senf::membind()
// e.g. in Foo::Foo() constructor:
Foo::Foo()
: handle_ (...),
readevent_ ("Foo read", senf::membind(&Foo::callback, this),
handle_, senf::scheduler::FdEvent::EV_READ)
{ ... }
The handler is identified by an arbitrary, user specified name. This name is used in error
messages to identify the failing handler.

Executing the Scheduler

To enter the %scheduler main-loop, call
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.

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:
#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,
}
void callback(int fd, int events)
{
FdEvent & event (fdEvents_[fd]);
// ...
if (complete)
fdEvents_.remove(fd)
}
private:
boost::ptr_map<int, FdEvent> fdEvents_;
};
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/release/libs/ptr_container/doc/ptr_container.html">Boost.PointerContainer</a>
for the pointer container library reference.

Signals and the Watchdog

To secure against blocking callbacks, the %scheduler implementation includes a watchdog
timer. This timer will produce a warning message on the standard error stream when a single
callback is executing for more than the watchdog timeout value. Since the %scheduler
implementation is completely single threaded, we cannot terminate the callback but at least we
can produce an informative message and optionally the program can be aborted.

The watchdog is controlled using the watchdogTimeout(), watchdogEvents() and watchdogAbort().
functions.

The watchdog is implemented using a free running interval timer. The watchdog signal (\c SIGURG)
must \e not be blocked. If signals need to be blocked for some reason, those regions will not be
checked by the watchdog. If a callback blocks, the watchdog has no chance to interrupt the
process.

\warning Since the watchdog is free running for performance reasons, every callback must expect
    signals to happen. Signals \e will certainly happen since the watchdog signal is generated
    periodically (which does not necessarily generate a watchdog event ...)

Additional signals (\c SIGALRM) may occur when using using hires timers on kernel/glibc
combinations which do not support timerfd(). On such systems, hires timers are implemented using
POSIX timers which generate a considerable number of additional signals.
Todo:
Fix the file support to use threads (?) fork (?) and a pipe so it works reliably even over e.g. NFS.

Function Documentation

◆ consoleDir()

senf::console::ScopedDirectory & senf::scheduler::consoleDir ( )

Definition at line 27 of file ConsoleDir.cc.

◆ empty()

bool senf::scheduler::empty ( )

Return true, if no event is registered, false otherwise.

Definition at line 126 of file Scheduler.cc.

◆ eventTime()

ClockService::clock_type const& senf::scheduler::eventTime ( )

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 not the time it should have been delivered (in the case of timers).

◆ eventTimestamp()

CyclicTimestamp const& senf::scheduler::eventTimestamp ( )

Returns the FIFOrunners current event timestamp (1ms precision)

This call will return the current timestamp of the FIFORunner as far as it is already known to the scheduler. Note: The scheduler must be running() for this time to be accurate.

◆ get_descriptor()

template<class Handle >
int senf::scheduler::get_descriptor ( Handle const &  handle)

Get file descriptor from handle object.

This function will query the handle for it's file descriptor. The real implementation must be provided by a freestanding function retrieve_filehandle(Handle const & h) within the namespace of Handle.

◆ haveScalableHiresTimers()

bool senf::scheduler::haveScalableHiresTimers ( )

return true, if timerfd() timing is available, false otherwise

See also
hiresTimers()

◆ hiresTimers()

void senf::scheduler::hiresTimers ( )

Switch to using hi resolution timers.

By default, timers are implemented directly using epoll. This however restricts the timer resolution to that of the kernel HZ value.

High resolution timers are implemented either using POSIX timers or, when available, using the Linux special timerfd() syscall.

POSIX timers are delivered using signals. A high timer load this increases the signal load considerably. timerfd()'s are delivered on a file descriptor and thus don't have such a scalability issue.

Warning
The timer source must not be switched from a scheduler callback

Definition at line 136 of file Scheduler.cc.

◆ loresTimers()

void senf::scheduler::loresTimers ( )

Switch back to using epoll for timing.

See also
hiresTimers()

◆ now()

ClockService::clock_type const& senf::scheduler::now ( )

Return (approximate) current time.

This call will return the current time as far as it is already known to the scheduler. Note: The scheduler must be running() for this time to be accurate.

◆ nowDiff()

ClockService::clock_type senf::scheduler::nowDiff ( ClockService::clock_type const &  older)

Returns (approximate) time difference between 'older' and now()

Note: The scheduler must be running() for this time to be accurate.

◆ process()

void senf::scheduler::process ( )

Event handler main loop.

This member must be called at some time to enter the event handler main loop. Only while this function is running any events are handled. The call will return if

  • a callback calls terminate()
  • the run queue becomes empty.

Definition at line 77 of file Scheduler.cc.

◆ restart()

void senf::scheduler::restart ( )

Restart scheduler.

This call will restart all scheduler dispatchers (timers, signals, file descriptors). This is necessary after a fork().

Warning
This call will remove all registered events from the scheduler

Definition at line 96 of file Scheduler.cc.

◆ running()

bool senf::scheduler::running ( )

true, if scheduler is running, false otherwise

Definition at line 43 of file Scheduler.cc.

◆ terminate()

void senf::scheduler::terminate ( )

Called by callbacks to terminate the main loop.

This member may be called by any callback to tell the main loop to terminate. The main loop will return to it's caller after the currently running callback returns.

Definition at line 38 of file Scheduler.cc.

◆ usingHiresTimers()

bool senf::scheduler::usingHiresTimers ( )

Return true, if using hires times, false otherwise.

See also
hiresTimers()

◆ watchdogAbort() [1/2]

void senf::scheduler::watchdogAbort ( bool  flag)

Enable/disable abort on watchdog event.

Calling watchdogAbort(true) will enable aborting the program execution on a watchdog event.

◆ watchdogAbort() [2/2]

bool senf::scheduler::watchdogAbort ( )

Get current watchdog abort on event status.

◆ watchdogCallback()

void senf::scheduler::watchdogCallback ( detail::FIFORunner::WatchdogCallback const &  cb)

Set watchdog hanging callback.

Specifies the callback to be called when a hanging task is detected.

◆ watchdogEvents()

unsigned senf::scheduler::watchdogEvents ( )

Number of watchdog events.

calling watchtogEvents() will reset the counter to 0

◆ watchdogTimeout() [1/2]

void senf::scheduler::watchdogTimeout ( unsigned  ms)

Set watchdog timeout to ms milliseconds.

Setting the watchdog timeout to 0 will disable the watchdog.

◆ watchdogTimeout() [2/2]

unsigned senf::scheduler::watchdogTimeout ( )

Current watchdog timeout in milliseconds.

◆ yield()

void senf::scheduler::yield ( )

Immediately rescheduler.

Calling yield() will cause the scheduler to terminate the current queue run and immediately rescheduler all pending tasks.

Definition at line 48 of file Scheduler.cc.