/**
* @file Sched.cc
*
* Imlpementation of event scheduler
*
* Copyright (c) 2016 - 2018, Peter Helfer
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <string>
#include "Sched.hh"
namespace Sched {
enum EventDataType {
NONE,
UINT,
DBLE,
VOID_PTR
};
struct EventData {
union {
uint u;
double d;
void *v;
};
EventData() {}
EventData(uint u) : u(u) {}
EventData(double d) : d(d) {}
EventData(void *v) : v(v) {}
};
union Callback {
NoneCallback n;
UintCallback u;
DbleCallback d;
VoidPtrCallback v;
};
/**
* A scheduled event
*/
struct Event {
double time;
EventDataType type;
Callback cb;
EventData data;
Event *next;
Event(
double time,
EventDataType type,
Callback cb,
EventData data)
: time(time),
type(type),
cb(cb),
data(data),
next(NULL)
{}
};
/**
* List of scheduled events.
*/
static Event *nextEvent = NULL;
/**
* Schedule an event
* @param time Time for which event will be scheduled
* @param cb Callback function
* @param data Event Data
*/
void scheduleEvent(
double time,
EventDataType type,
Callback cb,
EventData data)
{
Event *newEv = new Event(time, type, cb, data);
// Find event after which to insert new event
//
Event *prevEv = nextEvent;
while (prevEv != NULL &&
prevEv->next != NULL
&& prevEv->next->time <= time)
{
prevEv = prevEv->next;
}
// Insert it
//
if (prevEv == NULL) {
newEv->next = nextEvent;
nextEvent = newEv;
} else {
newEv->next = prevEv->next;
prevEv->next = newEv;
}
}
void scheduleEvent(
double time,
NoneCallback ncb)
{
Callback cb;
cb.n = ncb;
scheduleEvent(time, NONE, cb, EventData());
}
void scheduleEvent(
double time,
UintCallback ucb,
uint data)
{
Callback cb;
cb.u = ucb;
EventData d;
d.u = data;
scheduleEvent(time, UINT, cb, d);
}
void scheduleEvent(
double time,
DbleCallback dcb,
double data)
{
Callback cb;
cb.d = dcb;
EventData d;
d.d = data;
scheduleEvent(time, DBLE, cb, d);
}
void scheduleEvent(
double time,
VoidPtrCallback vcb,
void *data)
{
Callback cb;
cb.v = vcb;
EventData d;
d.v = data;
scheduleEvent(time, VOID_PTR, cb, d);
}
/**
* Clear all scheduled events
*/
void clearEvents()
{
for (Event *ev = nextEvent; ev != NULL; ev = ev->next) {
delete ev;
}
nextEvent = NULL;
}
/**
* Process a scheduled event.
*/
static void processEvent(Event *event, double now)
{
switch(event->type) {
case NONE:
event->cb.n(event->time, now);
break;
case UINT:
event->cb.u(event->time, now, event->data.u);
break;
case DBLE:
event->cb.d(event->time, now, event->data.d);
break;
case VOID_PTR:
event->cb.v(event->time, now, event->data.v);
break;
default:
abort();
}
}
/**
* Process all events scheduled at or before the specified time
*/
void processEvents(double now)
{
while (nextEvent != NULL && nextEvent->time <= now) {
Event *ev = nextEvent;
processEvent(ev, now);
nextEvent = ev->next;
delete ev;
}
}
}