The Scheduler Implementation

The implentation architecture now is based on a set of dispatchers, one for each type of event.

Overview

The scheduler utilizes the following components

  • There is a dispatcher for each event type. This dispatcher manages the event specific registration and unregistration. The dispatcher is owns the event (and task) objects.
  • Every registered event is represented by an event specific event class instance.
  • The Dispatcher ultimately registeres with the senf::scheduler::detail::FdManager. Since the event-loop is based on epoll() (it could easily be changed to be based on select() or poll()), all events must ultimately be represented by some type of file descriptor (not necessarily a different file descriptor for each event).

All these classes are singletons.

Dispatchers

There is a dispatcher for each event type

  • senf::scheduler::detail::FdDispatcher manages poll-able file descriptors. This does not include real files.
  • senf::scheduler::detail::FileDispatcher manages disk files
  • senf::scheduler::detail::TimerDispatcher manages timers
  • senf::scheduler::detail::SignalDispatcher manages UNIX signals

Each dispatcher has a specific API and the integration into the main-loop is not standardized for performance reasons.

The Dispatcher does not own the event instances, instead those instances are owned by the respective object creating the event. The implementation uses boost::intrusive containeres to manage the events. This makes the Scheduler itself be completely devoid of dynamic memory allocations.

The main loop

The application mainloop senf::scheduler::process() is constructed by calling the correct members of all these classes repeatedly in the correct order:

  • First dispatchers are set up
  • then the senf::scheduler::FdManager is called to wait for an event
  • After cleaning up the dispatchers,
  • the senf::scheduler::FIFORunner is called to executed all now runnable tasks.