Generic single-file implementation of an EDF scheduler suitable for deeply embedded systems. "OLGa" is a reference to the fact that it has a logarithmic asymptotic complexity.
Simply copy olga_scheduler.hpp (C++) or olga_scheduler.h (C) into your project tree and you are ready to roll.
The only dependency is the CAVL header-only library.
The usage instructions are provided in the comments. The code is fully covered by manual tests with full state space exploration.
For development-related instructions please refer to the CI configuration files. To release a new version, simply create a new tag.
#include "olga_scheduler.h"
#include <inttypes.h>
#include <stdio.h>
#include <time.h>
#include <unistd.h>
static int64_t get_microseconds(olga_t* sched)
{
(void)sched;
struct timespec ts;
(void)clock_gettime(CLOCK_MONOTONIC, &ts);
return ((int64_t)ts.tv_sec * 1000000) + (ts.tv_nsec / 1000);
}
static void handler(olga_t* sched, olga_event_t* event, int64_t now)
{
uint64_t* counter = (uint64_t*)event->user;
++*counter;
printf("counter=%" PRIu64 " now=%" PRId64 "\n", *counter, now);
// Keep events triggering exactly at 1 Hz.
olga_defer(sched, event->deadline + 1000000, event->user, handler, event);
}
int main(void)
{
olga_t sched;
olga_init(&sched, NULL, get_microseconds);
uint64_t counter = 0;
olga_event_t event = OLGA_EVENT_INIT;
olga_defer(&sched, sched.now(&sched) + 1000000, &counter, handler, &event);
for (;;) {
olga_spin_result_t spin_result = olga_spin(&sched);
(void)spin_result; // Optional performance information here.
const struct timespec delay = { .tv_sec = 0, .tv_nsec = 1000 * 1000 };
(void)nanosleep(&delay, NULL); // Do something else here: IO multiplexing, update scheduler stats, etc.
if (counter > 10) {
olga_cancel(&sched, &event);
puts("Event canceled");
break;
}
}
return 0;
}#include "olga_scheduler.hpp"
#include <chrono>
#include <cstdint>
#include <iostream>
#include <thread>
int main()
{
using namespace std::chrono_literals;
olga_scheduler::EventLoop<std::chrono::steady_clock> loop;
std::uint64_t counter = 0;
auto evt = loop.repeat(1s, [&](const auto& arg) {
++counter;
std::cout << "counter=" << counter
<< " now=" << arg.approx_now.time_since_epoch().count()
<< '\n';
if (counter > 10) {
arg.event.cancel();
}
});
while (!loop.isEmpty()) {
(void)loop.spin();
std::this_thread::sleep_for(1ms); // Do something else here.
}
return 0;
}.jpg)