senf::scheduler Namespace Reference

The Scheduler interface. 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.

1. 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:

These instance are owned and managed by the user of the scheduler not by the scheduler so the RAII concept can be used.
class SomeServer
{
    SomeSocketHandle handle_;
    senf::scheduler::FdEvent event_;

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 initiallyEnabled flag argument is set to 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.

2. Specifying handlers

All handlers are specified as generic Boost.Function 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 Boost.Bind:

// 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),
                                handle, senf::scheduler::FdEvent::EV_READ);
 // Timeout function
void timeout( int n) {..}
// Call timeout() handler with argument 'n'
senf::scheduler::TimerEvent timer ("name", boost::bind(&timeout, n),
                                   senf::ClockService::now() + senf::ClockService::seconds(1));

To use member-functions as callbacks, use either Boost.Bind 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.

3. Executing the Scheduler

To enter the scheduler main-loop, call

This call will only return in two cases:

Additional generic functions provide information and scheduler parameters.

4. Event objects and container classes

As the event objects are 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,
                                         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_;
};

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 must be created via new and that the pointer containers themselves are not copyable (ok, they are, if the elements are cloneable ...). See Boost.PointerContainer for the pointer container library reference.

5. 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 (SIGURG) must 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 will certainly happen since the watchdog signal is generated periodically (which does not necessarily generate a watchdog event ...)
Additional signals (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.

6. Namespaces

namespace   detail

7. Classes

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   BlockSignals
  Temporarily block all signals. More...
class   SignalEvent
  UNIX signal event. More...
class   TimerEvent
  Deadline timer event. More...
class   TimerEventProxy
  Deadline timer proxy. More...

8. Functions

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

9. Function Documentation

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

Definition at line 36 of file ConsoleDir.cc.

bool senf::scheduler::
empty ()

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

Definition at line 140 of file Scheduler.cc.

senf::ClockService::clock_type 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).

Definition at line 37 of file Scheduler.cci.

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.

Definition at line 50 of file FdEvent.cti.

bool senf::scheduler::
haveScalableHiresTimers ()

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

See also:
hiresTimers()

Definition at line 73 of file Scheduler.cci.

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 150 of file Scheduler.cc.

void senf::scheduler::
loresTimers ()

Switch back to using epoll for timing.

See also:
hiresTimers()

Definition at line 67 of file Scheduler.cci.

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

Return (approximate) current time.

This call will return the current time as far as it is already known to the scheduler. If the scheduler is running, this will return eventTime(), otherwise it will return ClockService::now(). While the scheduler is running, this will reduce the number of system calls.

Definition at line 62 of file Scheduler.cc.

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 91 of file Scheduler.cc.

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 110 of file Scheduler.cc.

bool senf::scheduler::
running ()

true, if scheduler is running, false otherwise

Definition at line 57 of file Scheduler.cc.

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 47 of file Scheduler.cc.

bool senf::scheduler::
usingHiresTimers ()

Return true, if using hires times, false otherwise.

See also:
hiresTimers()

Definition at line 82 of file Scheduler.cci.

bool senf::scheduler::
watchdogAbort ()

Get current watchdog abort on event status.

Definition at line 62 of file Scheduler.cci.

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.

Definition at line 57 of file Scheduler.cci.

unsigned senf::scheduler::
watchdogEvents ()

Number of watchdog events.

calling watchtogEvents() will reset the counter to 0

Definition at line 52 of file Scheduler.cci.

unsigned senf::scheduler::
watchdogTimeout ()

Current watchdog timeout in milliseconds.

Definition at line 47 of file Scheduler.cci.

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

Set watchdog timeout to ms milliseconds.

Setting the watchdog timeout to 0 will disable the watchdog.

Definition at line 42 of file Scheduler.cci.

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 52 of file Scheduler.cc.