linux: Don't use timer_repeat_until for linux "irq" polling

Use a simpler counter system to prioritize tasks and irqs when busy.

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
Kevin O'Connor 2021-04-21 19:50:58 -04:00
parent 92fe116dc7
commit acd94909bc
1 changed files with 9 additions and 29 deletions

View File

@ -18,8 +18,6 @@ static struct {
uint32_t last_read_time; uint32_t last_read_time;
// Fields for converting from a systime to ticks // Fields for converting from a systime to ticks
time_t start_sec; time_t start_sec;
// Maximum absolute time that can be spent in timer_dispatch()
uint32_t timer_repeat_until;
// Time of next software timer (also used to convert from ticks to systime) // Time of next software timer (also used to convert from ticks to systime)
uint32_t next_wake_counter; uint32_t next_wake_counter;
struct timespec next_wake; struct timespec next_wake;
@ -126,28 +124,25 @@ timer_kick(void)
TimerInfo.next_wake_counter = timespec_to_time(TimerInfo.next_wake); TimerInfo.next_wake_counter = timespec_to_time(TimerInfo.next_wake);
} }
#define TIMER_IDLE_REPEAT_TICKS timer_from_us(500) #define TIMER_IDLE_REPEAT_COUNT 100
#define TIMER_REPEAT_TICKS timer_from_us(100) #define TIMER_REPEAT_COUNT 20
#define TIMER_MIN_TRY_TICKS timer_from_us(2) #define TIMER_MIN_TRY_TICKS timer_from_us(2)
#define TIMER_DEFER_REPEAT_TICKS timer_from_us(5)
// Invoke timers // Invoke timers
static uint32_t static uint32_t
timer_dispatch_many(void) timer_dispatch_many(void)
{ {
uint32_t tru = TimerInfo.timer_repeat_until, prev_lrt = 0; uint32_t repeat_count = TIMER_REPEAT_COUNT;
for (;;) { for (;;) {
// Run the next software timer // Run the next software timer
uint32_t next = sched_timer_dispatch(); uint32_t next = sched_timer_dispatch();
repeat_count--;
uint32_t lrt = TimerInfo.last_read_time; uint32_t lrt = TimerInfo.last_read_time;
if (!timer_is_before(lrt, next) && !timer_is_before(tru, lrt) if (!timer_is_before(lrt, next) && repeat_count)
&& lrt != prev_lrt) {
// Can run next timer without overhead of calling timer_read_time() // Can run next timer without overhead of calling timer_read_time()
prev_lrt = lrt;
continue; continue;
}
uint32_t now = timer_read_time(); uint32_t now = timer_read_time();
int32_t diff = next - now; int32_t diff = next - now;
@ -155,15 +150,13 @@ timer_dispatch_many(void)
// Schedule next timer normally. // Schedule next timer normally.
return next; return next;
if (unlikely(timer_is_before(tru, now))) { if (unlikely(!repeat_count)) {
// Check if there are too many repeat timers // Check if there are too many repeat timers
if (diff < (int32_t)(-timer_from_us(100000))) if (diff < (int32_t)(-timer_from_us(100000)))
try_shutdown("Rescheduled timer in the past"); try_shutdown("Rescheduled timer in the past");
if (sched_tasks_busy()) { if (sched_tasks_busy())
TimerInfo.timer_repeat_until = now + TIMER_REPEAT_TICKS; return now;
return now + TIMER_DEFER_REPEAT_TICKS; repeat_count = TIMER_IDLE_REPEAT_COUNT;
}
TimerInfo.timer_repeat_until = tru = now + TIMER_IDLE_REPEAT_TICKS;
} }
// Next timer in the past or near future - wait for it to be ready // Next timer in the past or near future - wait for it to be ready
@ -172,19 +165,6 @@ timer_dispatch_many(void)
} }
} }
// Make sure timer_repeat_until doesn't wrap 32bit comparisons
void
timer_task(void)
{
uint32_t lrt = TimerInfo.last_read_time;
irq_disable();
if (timer_is_before(TimerInfo.timer_repeat_until, lrt))
TimerInfo.timer_repeat_until = lrt;
irq_enable();
}
DECL_TASK(timer_task);
// Invoke timers
static void static void
timer_dispatch(void) timer_dispatch(void)
{ {