summaryrefslogtreecommitdiff
path: root/src/common/timer.cpp
diff options
context:
space:
mode:
authorBen Longbons <b.r.longbons@gmail.com>2012-08-30 16:16:25 -0700
committerBen Longbons <b.r.longbons@gmail.com>2012-08-30 17:03:31 -0700
commit41974ae5265fbc23a06f276f9e008d5dad020e0b (patch)
tree9d595215172e87e2d83b74f7bf3430b3040e780e /src/common/timer.cpp
parent21742909143df9159b2401c3e2a39cc0b2bad620 (diff)
downloadtmwa-41974ae5265fbc23a06f276f9e008d5dad020e0b.tar.gz
tmwa-41974ae5265fbc23a06f276f9e008d5dad020e0b.tar.bz2
tmwa-41974ae5265fbc23a06f276f9e008d5dad020e0b.tar.xz
tmwa-41974ae5265fbc23a06f276f9e008d5dad020e0b.zip
Rename files for C++ conversion. Does not compile.
After updating, you can remove these files, as shown in 'git status': Untracked files: (use "git add <file>..." to include in what will be committed) src/map/magic-interpreter-lexer.c src/map/magic-interpreter-parser.c src/map/magic-interpreter-parser.h
Diffstat (limited to 'src/common/timer.cpp')
-rw-r--r--src/common/timer.cpp257
1 files changed, 257 insertions, 0 deletions
diff --git a/src/common/timer.cpp b/src/common/timer.cpp
new file mode 100644
index 0000000..66aaa9b
--- /dev/null
+++ b/src/common/timer.cpp
@@ -0,0 +1,257 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include "timer.hpp"
+#include "utils.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;
+
+/// 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;
+
+
+static uint32_t gettick_cache;
+static uint8_t gettick_count = 0;
+
+uint32_t gettick_nocache (void)
+{
+ 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 ();
+}
+
+static void push_timer_heap (timer_id index)
+{
+ 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;
+}
+
+static timer_id top_timer_heap (void)
+{
+ if (!timer_heap || !timer_heap[0])
+ return -1;
+ return timer_heap[1];
+}
+
+static timer_id 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_id add_timer (tick_t tick, timer_func func, custom_id_t id, custom_data_t data)
+{
+ 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;
+}
+
+timer_id add_timer_interval (tick_t tick, timer_func func, custom_id_t id,
+ custom_data_t data, 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;
+}
+
+void delete_timer (timer_id id, timer_func func)
+{
+ if (id == 0 || id >= timer_data_num)
+ {
+ fprintf (stderr, "delete_timer error : no such timer %d\n", id);
+ abort ();
+ }
+ if (timer_data[id].func != func)
+ {
+ fprintf (stderr, "Timer mismatch\n");
+ abort ();
+ }
+ // "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)
+{
+ return timer_data[tid].tick += tick;
+}
+
+struct TimerData *get_timer (timer_id tid)
+{
+ return &timer_data[tid];
+}
+
+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;
+
+ while ((i = top_timer_heap ()) != (timer_id)-1)
+ {
+ // while the heap is not empty and
+ if (DIFF_TICK (timer_data[i].tick, tick) > 0)
+ {
+ /// Return the time until the next timer needs to goes off
+ nextmin = DIFF_TICK (timer_data[i].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)
+ {
+ 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;
+ }
+ }
+
+ if (nextmin < 10)
+ nextmin = 10;
+ return nextmin;
+}