diff options
author | Ben Longbons <b.r.longbons@gmail.com> | 2013-02-09 01:51:36 -0800 |
---|---|---|
committer | Ben Longbons <b.r.longbons@gmail.com> | 2013-02-12 20:21:34 -0800 |
commit | 80e36aa669274637bcd5956fbf4020dba1d4739c (patch) | |
tree | 2f5d3a63a5f7230ab73cd588e3493c0664a5a73b /src/common/timer.cpp | |
parent | 83b2e0b3ceda907b7186acfcc56c214fc04d9c13 (diff) | |
download | tmwa-80e36aa669274637bcd5956fbf4020dba1d4739c.tar.gz tmwa-80e36aa669274637bcd5956fbf4020dba1d4739c.tar.bz2 tmwa-80e36aa669274637bcd5956fbf4020dba1d4739c.tar.xz tmwa-80e36aa669274637bcd5956fbf4020dba1d4739c.zip |
Strictify timers
Diffstat (limited to 'src/common/timer.cpp')
-rw-r--r-- | src/common/timer.cpp | 288 |
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)); } |