2014-08-29 07:52:33 -07:00
|
|
|
/**
|
|
|
|
* @file event_queue.cpp
|
|
|
|
* This is a data structure which keeps track of all pending events
|
|
|
|
* Implemented as a linked list, which is fine since the number of
|
|
|
|
* pending events is pretty low
|
|
|
|
* todo: MAYBE migrate to a better data structure, but that's low priority
|
|
|
|
*
|
|
|
|
* this data structure is NOT thread safe
|
|
|
|
*
|
|
|
|
* @date Apr 17, 2014
|
|
|
|
* @author Andrey Belomutskiy, (c) 2012-2014
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "event_queue.h"
|
|
|
|
#include "efitime.h"
|
|
|
|
|
|
|
|
EventQueue::EventQueue() {
|
|
|
|
head = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool EventQueue::checkIfPending(scheduling_s *scheduling) {
|
|
|
|
return assertNotInList<scheduling_s>(head, scheduling);
|
|
|
|
}
|
|
|
|
|
2014-09-13 05:02:58 -07:00
|
|
|
void EventQueue::insertTask(scheduling_s *scheduling, uint64_t timeUs, schfunc_t callback, void *param) {
|
2014-08-29 07:52:33 -07:00
|
|
|
if (callback == NULL)
|
|
|
|
firmwareError("NULL callback");
|
2014-09-13 05:02:58 -07:00
|
|
|
|
2014-08-29 07:52:33 -07:00
|
|
|
int alreadyPending = checkIfPending(scheduling);
|
2014-11-07 21:07:22 -08:00
|
|
|
if (alreadyPending)
|
2014-08-29 07:52:33 -07:00
|
|
|
return;
|
|
|
|
|
2014-09-13 05:02:58 -07:00
|
|
|
scheduling->momentUs = timeUs;
|
2014-08-29 07:52:33 -07:00
|
|
|
scheduling->callback = callback;
|
|
|
|
scheduling->param = param;
|
|
|
|
|
|
|
|
LL_PREPEND(head, scheduling);
|
|
|
|
}
|
|
|
|
|
|
|
|
//void EventQueue::insertTask(scheduling_s *scheduling, int delayUs, schfunc_t callback, void *param) {
|
|
|
|
// insertTask(scheduling, getTimeNowUs(), delayUs, callback, param);
|
|
|
|
//}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the timestamp of the soonest pending action
|
|
|
|
*/
|
|
|
|
uint64_t EventQueue::getNextEventTime(uint64_t nowUs) {
|
|
|
|
scheduling_s * current;
|
|
|
|
// this is a large value which is expected to be larger than any real time
|
|
|
|
uint64_t result = EMPTY_QUEUE;
|
|
|
|
|
|
|
|
int counter = 0;
|
|
|
|
LL_FOREACH(head, current)
|
|
|
|
{
|
|
|
|
if (++counter > QUEUE_LENGTH_LIMIT) {
|
|
|
|
firmwareError("Is this list looped #2?");
|
|
|
|
return EMPTY_QUEUE;
|
|
|
|
}
|
2014-09-13 14:02:50 -07:00
|
|
|
if (current->momentUs <= nowUs) {
|
2014-09-13 18:02:52 -07:00
|
|
|
/**
|
|
|
|
* looks like we end up here after 'writeconfig' (which freezes the firmware) - we are late
|
|
|
|
* for the next scheduled event
|
|
|
|
*/
|
2014-09-14 14:03:05 -07:00
|
|
|
uint64_t mock = nowUs + 100;
|
2014-09-13 18:02:52 -07:00
|
|
|
if (mock < result)
|
|
|
|
result = mock;
|
|
|
|
} else {
|
|
|
|
if (current->momentUs < result)
|
|
|
|
result = current->momentUs;
|
2014-09-13 14:02:50 -07:00
|
|
|
}
|
2014-08-29 07:52:33 -07:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Invoke all pending actions prior to specified timestamp
|
2014-09-14 14:03:05 -07:00
|
|
|
* @return true if at least one action was executed
|
2014-08-29 07:52:33 -07:00
|
|
|
*/
|
2014-09-14 14:03:05 -07:00
|
|
|
bool EventQueue::executeAll(uint64_t now) {
|
2014-08-29 07:52:33 -07:00
|
|
|
scheduling_s * current, *tmp;
|
|
|
|
|
|
|
|
scheduling_s * executionList = NULL;
|
|
|
|
|
|
|
|
int counter = 0;
|
|
|
|
|
|
|
|
// we need safe iteration because we are removing elements inside the loop
|
|
|
|
LL_FOREACH_SAFE(head, current, tmp)
|
|
|
|
{
|
|
|
|
if (++counter > QUEUE_LENGTH_LIMIT) {
|
|
|
|
firmwareError("Is this list looped?");
|
2014-09-14 14:03:05 -07:00
|
|
|
return false;
|
2014-08-29 07:52:33 -07:00
|
|
|
}
|
|
|
|
if (current->momentUs <= now) {
|
|
|
|
LL_DELETE(head, current);
|
|
|
|
LL_PREPEND(executionList, current);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* we need safe iteration here because 'callback' might change change 'current->next'
|
|
|
|
* while re-inserting it into the queue from within the callback
|
|
|
|
*/
|
2014-09-14 14:03:05 -07:00
|
|
|
bool result = (executionList != NULL);
|
2014-08-29 07:52:33 -07:00
|
|
|
LL_FOREACH_SAFE(executionList, current, tmp)
|
2014-09-14 14:03:05 -07:00
|
|
|
{
|
2014-08-29 07:52:33 -07:00
|
|
|
current->callback(current->param);
|
2014-09-14 14:03:05 -07:00
|
|
|
}
|
|
|
|
return result;
|
2014-08-29 07:52:33 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
int EventQueue::size(void) {
|
|
|
|
scheduling_s *tmp;
|
|
|
|
int result;
|
|
|
|
LL_COUNT(head, tmp, result);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
scheduling_s *EventQueue::getForUnitText(int index) {
|
|
|
|
scheduling_s * current;
|
|
|
|
|
|
|
|
LL_FOREACH(head, current)
|
|
|
|
{
|
|
|
|
if (index == 0)
|
|
|
|
return current;
|
|
|
|
index--;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void EventQueue::clear(void) {
|
|
|
|
head = NULL;
|
|
|
|
}
|