The new code is based on timestamps, rather than delays. This eliminates the need to update every timer in timer_process(), which cost a non-trivial amount of CPU time on low-end machines. This involved changes to every user of the timer code, so this change almost certainly introduces bugs.
134 lines
2.7 KiB
C
134 lines
2.7 KiB
C
#include "ibm.h"
|
|
|
|
#include "timer.h"
|
|
|
|
uint64_t TIMER_USEC;
|
|
uint32_t timer_target;
|
|
|
|
/*Enabled timers are stored in a linked list, with the first timer to expire at
|
|
the head.*/
|
|
static pc_timer_t *timer_head = NULL;
|
|
|
|
void timer_enable(pc_timer_t *timer)
|
|
{
|
|
pc_timer_t *timer_node = timer_head;
|
|
|
|
// pclog("timer->enable %p %i\n", timer, timer->enabled);
|
|
if (timer->enabled)
|
|
timer_disable(timer);
|
|
|
|
if (timer->next || timer->prev)
|
|
fatal("timer_enable - timer->next\n");
|
|
|
|
timer->enabled = 1;
|
|
|
|
/*List currently empty - add to head*/
|
|
if (!timer_head)
|
|
{
|
|
timer_head = timer;
|
|
timer->next = timer->prev = NULL;
|
|
timer_target = timer_head->ts_integer;
|
|
return;
|
|
}
|
|
|
|
timer_node = timer_head;
|
|
|
|
while (1)
|
|
{
|
|
/*Timer expires before timer_node. Add to list in front of timer_node*/
|
|
if (TIMER_LESS_THAN(timer, timer_node))
|
|
{
|
|
timer->next = timer_node;
|
|
timer->prev = timer_node->prev;
|
|
timer_node->prev = timer;
|
|
if (timer->prev)
|
|
timer->prev->next = timer;
|
|
else
|
|
{
|
|
timer_head = timer;
|
|
timer_target = timer_head->ts_integer;
|
|
}
|
|
return;
|
|
}
|
|
|
|
/*timer_node is last in the list. Add timer to end of list*/
|
|
if (!timer_node->next)
|
|
{
|
|
timer_node->next = timer;
|
|
timer->prev = timer_node;
|
|
return;
|
|
}
|
|
|
|
timer_node = timer_node->next;
|
|
}
|
|
}
|
|
void timer_disable(pc_timer_t *timer)
|
|
{
|
|
// pclog("timer->disable %p\n", timer);
|
|
if (!timer->enabled)
|
|
return;
|
|
|
|
if (!timer->next && !timer->prev && timer != timer_head)
|
|
fatal("timer_disable - !timer->next\n");
|
|
|
|
timer->enabled = 0;
|
|
|
|
if (timer->prev)
|
|
timer->prev->next = timer->next;
|
|
else
|
|
timer_head = timer->next;
|
|
if (timer->next)
|
|
timer->next->prev = timer->prev;
|
|
timer->prev = timer->next = NULL;
|
|
}
|
|
static void timer_remove_head()
|
|
{
|
|
if (timer_head)
|
|
{
|
|
pc_timer_t *timer = timer_head;
|
|
// pclog("timer_remove_head %p %p\n", timer_head, timer_head->next);
|
|
timer_head = timer->next;
|
|
timer_head->prev = NULL;
|
|
timer->next = timer->prev = NULL;
|
|
timer->enabled = 0;
|
|
}
|
|
}
|
|
|
|
void timer_process()
|
|
{
|
|
if (!timer_head)
|
|
return;
|
|
|
|
while (1)
|
|
{
|
|
pc_timer_t *timer = timer_head;
|
|
|
|
if (!TIMER_LESS_THAN_VAL(timer, (uint32_t)tsc))
|
|
break;
|
|
|
|
timer_remove_head();
|
|
timer->callback(timer->p);
|
|
}
|
|
|
|
timer_target = timer_head->ts_integer;
|
|
}
|
|
|
|
void timer_reset()
|
|
{
|
|
pclog("timer_reset\n");
|
|
timer_target = 0;
|
|
tsc = 0;
|
|
timer_head = NULL;
|
|
}
|
|
|
|
void timer_add(pc_timer_t *timer, void (*callback)(void *p), void *p, int start_timer)
|
|
{
|
|
memset(timer, 0, sizeof(pc_timer_t));
|
|
|
|
timer->callback = callback;
|
|
timer->p = p;
|
|
timer->enabled = 0;
|
|
timer->prev = timer->next = NULL;
|
|
if (start_timer)
|
|
timer_set_delay_u64(timer, 0);
|
|
}
|