summaryrefslogtreecommitdiff
path: root/src/common/timer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/timer.cpp')
-rw-r--r--src/common/timer.cpp288
1 files changed, 83 insertions, 205 deletions
diff --git a/src/common/timer.cpp b/src/common/timer.cpp
index 92d284c..219efd9 100644
--- a/src/common/timer.cpp
+++ b/src/common/timer.cpp
@@ -1,270 +1,148 @@
#include "timer.hpp"
+#include <sys/stat.h>
#include <sys/time.h>
+#include <cassert>
#include <cstring>
+#include <queue>
+
#include "cxxstdio.hpp"
#include "utils.hpp"
#include "../poison.hpp"
-static
-struct TimerData *timer_data;
-static
-uint32_t timer_data_max, timer_data_num;
-static
-timer_id *free_timer_list;
-static
-uint32_t free_timer_list_max, free_timer_list_pos;
+struct TimerData
+{
+ /// When it will be triggered
+ tick_t tick;
+ /// What will be done
+ timer_func func;
+ /// Repeat rate - 0 for oneshot
+ interval_t interval;
+};
+
+struct TimerCompare
+{
+ /// implement "less than"
+ bool operator() (TimerData *l, TimerData *r)
+ {
+ // C++ provides a max-heap, but we want
+ // the smallest tick to be the head (a min-heap).
+ return l->tick > r->tick;
+ }
+};
-/// Okay, I think I understand this structure now:
-/// the timer heap is a magic queue that allows inserting timers and then popping them in order
-/// designed to copy only log2(N) entries instead of N
-// timer_heap[0] is the size (greatest index into the heap)
-// timer_heap[1] is the first actual element
-// timer_heap_max increases 256 at a time and never decreases
-static
-uint32_t timer_heap_max = 0;
-/// FIXME: refactor the code to put the size in a separate variable
-//nontrivial because indices get multiplied
static
-timer_id *timer_heap = NULL;
+std::priority_queue<TimerData *, std::vector<TimerData *>, TimerCompare> timer_heap;
-static
-uint32_t gettick_cache;
-static
-uint8_t gettick_count = 0;
+tick_t gettick_cache;
-uint32_t gettick_nocache(void)
+tick_t milli_clock::now(void) noexcept
{
struct timeval tval;
// BUG: This will cause strange behavior if the system clock is changed!
// it should be reimplemented in terms of clock_gettime(CLOCK_MONOTONIC, )
gettimeofday(&tval, NULL);
- gettick_count = 255;
- return gettick_cache = tval.tv_sec * 1000 + tval.tv_usec / 1000;
-}
-
-uint32_t gettick(void)
-{
- if (gettick_count--)
- return gettick_cache;
- return gettick_nocache();
+ return gettick_cache = tick_t(std::chrono::seconds(tval.tv_sec)
+ + std::chrono::duration_cast<std::chrono::milliseconds>(
+ std::chrono::microseconds(tval.tv_usec)));
}
static
-void push_timer_heap(timer_id index)
+void push_timer_heap(TimerData *td)
{
- if (timer_heap == NULL || timer_heap[0] + 1 >= timer_heap_max)
- {
- timer_heap_max += 256;
- RECREATE(timer_heap, timer_id, timer_heap_max);
- memset(timer_heap + (timer_heap_max - 256), 0, sizeof(timer_id) * 256);
- }
-// timer_heap[0] is the greatest index into the heap, which increases
- timer_heap[0]++;
-
- timer_id h = timer_heap[0]-1, i = (h - 1) / 2;
- while (h)
- {
- // avoid wraparound problems, it really means this:
- // timer_data[index].tick >= timer_data[timer_heap[i+1]].tick
- if ( DIFF_TICK(timer_data[index].tick, timer_data[timer_heap[i+1]].tick) >= 0)
- break;
- timer_heap[h + 1] = timer_heap[i + 1];
- h = i;
- i = (h - 1) / 2;
- }
- timer_heap[h + 1] = index;
+ timer_heap.push(td);
}
static
-timer_id top_timer_heap(void)
+TimerData *top_timer_heap(void)
{
- if (!timer_heap || !timer_heap[0])
- return -1;
- return timer_heap[1];
+ if (timer_heap.empty())
+ return nullptr;
+ return timer_heap.top();
}
static
-timer_id pop_timer_heap(void)
+void pop_timer_heap(void)
{
- if (!timer_heap || !timer_heap[0])
- return -1;
- timer_id ret = timer_heap[1];
- timer_id last = timer_heap[timer_heap[0]];
- timer_heap[0]--;
-
- uint32_t h, k;
- for (h = 0, k = 2; k < timer_heap[0]; k = k * 2 + 2)
- {
- if (DIFF_TICK(timer_data[timer_heap[k + 1]].tick, timer_data[timer_heap[k]].tick) > 0)
- k--;
- timer_heap[h + 1] = timer_heap[k + 1], h = k;
- }
- if (k == timer_heap[0])
- timer_heap[h + 1] = timer_heap[k], h = k - 1;
-
- uint32_t i = (h - 1) / 2;
- while (h)
- {
- if (DIFF_TICK(timer_data[timer_heap[i + 1]].tick, timer_data[last].tick) <= 0)
- break;
- timer_heap[h + 1] = timer_heap[i + 1];
- h = i;
- i = (h - 1) / 2;
- }
- timer_heap[h + 1] = last;
-
- return ret;
+ timer_heap.pop();
}
-timer_id add_timer(tick_t tick, timer_func func, custom_id_t id, custom_data_t data)
+TimerData *add_timer(tick_t tick, timer_func func)
{
- timer_id i;
-
- if (free_timer_list_pos)
- {
- // Retrieve a freed timer id instead of a new one
- // I think it should be possible to avoid the loop somehow
- do
- {
- i = free_timer_list[--free_timer_list_pos];
- }
- while (i >= timer_data_num && free_timer_list_pos > 0);
- }
- else
- i = timer_data_num;
-
- // I have no idea what this is doing
- if (i >= timer_data_num)
- for (i = timer_data_num; i < timer_data_max && timer_data[i].type; i++)
- ;
- if (i >= timer_data_num && i >= timer_data_max)
- {
- if (timer_data_max == 0)
- {
- timer_data_max = 256;
- CREATE(timer_data, struct TimerData, timer_data_max);
- }
- else
- {
- timer_data_max += 256;
- RECREATE(timer_data, struct TimerData, timer_data_max);
- memset(timer_data + (timer_data_max - 256), 0,
- sizeof(struct TimerData) * 256);
- }
- }
- timer_data[i].tick = tick;
- timer_data[i].func = func;
- timer_data[i].id = id;
- timer_data[i].data = data;
- timer_data[i].type = TIMER_ONCE_AUTODEL;
- timer_data[i].interval = 1000;
- push_timer_heap(i);
- if (i >= timer_data_num)
- timer_data_num = i + 1;
- return i;
+ return add_timer_interval(tick, std::move(func), interval_t::zero());
}
-timer_id add_timer_interval(tick_t tick, timer_func func, custom_id_t id,
- custom_data_t data, interval_t interval)
+TimerData *add_timer_interval(tick_t tick, timer_func func, interval_t interval)
{
- timer_id tid = add_timer(tick, func, id, data);
- timer_data[tid].type = TIMER_INTERVAL;
- timer_data[tid].interval = interval;
- return tid;
+ assert (interval >= interval_t::zero());
+
+ TimerData *td = new TimerData();
+ td->tick = tick;
+ td->func = std::move(func);
+ td->interval = interval;
+ push_timer_heap(td);
+ return td;
}
-void delete_timer(timer_id id, timer_func func)
+static
+void do_nothing(TimerData *, tick_t)
{
- if (id == 0 || id >= timer_data_num)
- {
- FPRINTF(stderr, "delete_timer error : no such timer %d\n", id);
- abort();
- }
-#ifndef delete_timer
- if (timer_data[id].func != func)
- {
- FPRINTF(stderr, "Timer mismatch\n");
- abort();
- }
-#endif
- // "to let them disappear" - is this just in case?
- timer_data[id].func = NULL;
- timer_data[id].type = TIMER_ONCE_AUTODEL;
- timer_data[id].tick -= 60 * 60 * 1000;
}
-tick_t addtick_timer(timer_id tid, interval_t tick)
+void delete_timer(TimerData *td)
{
- return timer_data[tid].tick += tick;
-}
+ assert (td != nullptr);
-struct TimerData *get_timer(timer_id tid)
-{
- return &timer_data[tid];
+ td->func = do_nothing;
+ td->interval = interval_t::zero();
}
interval_t do_timer(tick_t tick)
{
- timer_id i;
/// Number of milliseconds until it calls this again
// this says to wait 1 sec if all timers get popped
- interval_t nextmin = 1000;
+ interval_t nextmin = std::chrono::seconds(1);
- while ((i = top_timer_heap()) != (timer_id)-1)
+ while (TimerData *td = top_timer_heap())
{
// while the heap is not empty and
- if (DIFF_TICK(timer_data[i].tick, tick) > 0)
+ if (td->tick > tick)
{
/// Return the time until the next timer needs to goes off
- nextmin = DIFF_TICK(timer_data[i].tick, tick);
+ nextmin = td->tick - tick;
break;
}
pop_timer_heap();
- if (timer_data[i].func)
- {
- if (DIFF_TICK(timer_data[i].tick, tick) < -1000)
- {
- // If we are too far past the requested tick, call with the current tick instead to fix reregistering problems
- timer_data[i].func(i, tick, timer_data[i].id, timer_data[i].data);
- }
- else
- {
- timer_data[i].func(i, timer_data[i].tick, timer_data[i].id, timer_data[i].data);
- }
- }
- switch (timer_data[i].type)
+
+ // If we are too far past the requested tick, call with the current tick instead to fix reregistering problems
+ if (td->tick + std::chrono::seconds(1) < tick)
+ td->func(td, tick);
+ else
+ td->func(td, td->tick);
+
+ if (td->interval == interval_t::zero())
{
- case TIMER_ONCE_AUTODEL:
- timer_data[i].type = TIMER_NONE;
- if (free_timer_list_pos >= free_timer_list_max)
- {
- free_timer_list_max += 256;
- RECREATE(free_timer_list, uint32_t, free_timer_list_max);
- memset(free_timer_list + (free_timer_list_max - 256),
- 0, 256 * sizeof(uint32_t));
- }
- free_timer_list[free_timer_list_pos++] = i;
- break;
- case TIMER_INTERVAL:
- if (DIFF_TICK(timer_data[i].tick, tick) < -1000)
- {
- timer_data[i].tick = tick + timer_data[i].interval;
- }
- else
- {
- timer_data[i].tick += timer_data[i].interval;
- }
- push_timer_heap(i);
- break;
+ delete td;
+ continue;
}
+ if (td->tick + std::chrono::seconds(1) < tick)
+ td->tick = tick + td->interval;
+ else
+ td->tick += td->interval;
+ push_timer_heap(td);
}
- if (nextmin < 10)
- nextmin = 10;
- return nextmin;
+ return std::max(nextmin, std::chrono::milliseconds(10));
+}
+
+tick_t file_modified(const char *name)
+{
+ struct stat buf;
+ if (stat(name, &buf))
+ return tick_t();
+ return tick_t(std::chrono::seconds(buf.st_mtime));
}