From df56732ffbfb021996a6c995b0dbfd3cfd9c23c1 Mon Sep 17 00:00:00 2001 From: Rogerio Goncalves Date: Tue, 29 Oct 2024 11:58:35 +0000 Subject: [PATCH] sched: Improve timer vs task priority check (#417) Rename sched_tasks_busy() to sched_check_set_tasks_busy() and change it to only return true if tasks are active (running or requested) for two consecutive calls. This makes it less likely that timers will yield to tasks except when tasks really are notably backlogged. This also makes it less likely that multiple steppers controlling the same rail will be interrupted by tasks mid-step. This should slightly improve the timing, and make it less likely that a halt during homing/probing will occur with these steppers taking a different number of total steps. Signed-off-by: Kevin O'Connor Co-authored-by: Kevin O'Connor --- src/avr/timer.c | 2 +- src/generic/armcm_timer.c | 2 +- src/generic/timer_irq.c | 2 +- src/linux/timer.c | 2 +- src/sched.c | 16 ++++++++++------ src/sched.h | 2 +- 6 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/avr/timer.c b/src/avr/timer.c index fb8738cc4..d306b7214 100644 --- a/src/avr/timer.c +++ b/src/avr/timer.c @@ -197,7 +197,7 @@ ISR(TIMER1_COMPA_vect) uint16_t now = timer_get(); if ((int16_t)(next - now) < (int16_t)(-timer_from_us(1000))) try_shutdown("Rescheduled timer in the past"); - if (sched_tasks_busy()) { + if (sched_check_set_tasks_busy()) { timer_repeat_set(now + TIMER_REPEAT_TICKS); next = now + TIMER_DEFER_REPEAT_TICKS; goto done; diff --git a/src/generic/armcm_timer.c b/src/generic/armcm_timer.c index ef38680a9..e77081804 100644 --- a/src/generic/armcm_timer.c +++ b/src/generic/armcm_timer.c @@ -137,7 +137,7 @@ timer_dispatch_many(void) // Check if there are too many repeat timers if (diff < (int32_t)(-timer_from_us(1000))) try_shutdown("Rescheduled timer in the past"); - if (sched_tasks_busy()) { + if (sched_check_set_tasks_busy()) { timer_repeat_until = now + TIMER_REPEAT_TICKS; return TIMER_DEFER_REPEAT_TICKS; } diff --git a/src/generic/timer_irq.c b/src/generic/timer_irq.c index 40e9336b2..7c2e871bd 100644 --- a/src/generic/timer_irq.c +++ b/src/generic/timer_irq.c @@ -55,7 +55,7 @@ timer_dispatch_many(void) // Check if there are too many repeat timers if (diff < (int32_t)(-timer_from_us(1000))) try_shutdown("Rescheduled timer in the past"); - if (sched_tasks_busy()) { + if (sched_check_set_tasks_busy()) { timer_repeat_until = now + TIMER_REPEAT_TICKS; return now + TIMER_DEFER_REPEAT_TICKS; } diff --git a/src/linux/timer.c b/src/linux/timer.c index 21be01312..8eda62a54 100644 --- a/src/linux/timer.c +++ b/src/linux/timer.c @@ -152,7 +152,7 @@ timer_dispatch(void) // Check if there are too many repeat timers if (diff < (int32_t)(-timer_from_us(100000))) try_shutdown("Rescheduled timer in the past"); - if (sched_tasks_busy()) + if (sched_check_set_tasks_busy()) return; repeat_count = TIMER_IDLE_REPEAT_COUNT; } diff --git a/src/sched.c b/src/sched.c index 44cce558e..51d159bc6 100644 --- a/src/sched.c +++ b/src/sched.c @@ -1,6 +1,6 @@ // Basic scheduling functions and startup/shutdown code. // -// Copyright (C) 2016-2021 Kevin O'Connor +// Copyright (C) 2016-2024 Kevin O'Connor // // This file may be distributed under the terms of the GNU GPLv3 license. @@ -19,7 +19,7 @@ static struct timer periodic_timer, sentinel_timer, deleted_timer; static struct { struct timer *timer_list, *last_insert; - int8_t tasks_status; + int8_t tasks_status, tasks_busy; uint8_t shutdown_status, shutdown_reason; } SchedStatus = {.timer_list = &periodic_timer, .last_insert = &periodic_timer}; @@ -205,11 +205,15 @@ sched_wake_tasks(void) SchedStatus.tasks_status = TS_REQUESTED; } -// Check if tasks need to be run +// Check if tasks busy (called from low-level timer dispatch code) uint8_t -sched_tasks_busy(void) +sched_check_set_tasks_busy(void) { - return SchedStatus.tasks_status >= TS_REQUESTED; + // Return busy if tasks never idle between two consecutive calls + if (SchedStatus.tasks_busy >= TS_REQUESTED) + return 1; + SchedStatus.tasks_busy = SchedStatus.tasks_status; + return 0; } // Note that a task is ready to run @@ -243,7 +247,7 @@ run_tasks(void) irq_disable(); if (SchedStatus.tasks_status != TS_REQUESTED) { // Sleep processor (only run timers) until tasks woken - SchedStatus.tasks_status = TS_IDLE; + SchedStatus.tasks_status = SchedStatus.tasks_busy = TS_IDLE; do { irq_wait(); } while (SchedStatus.tasks_status != TS_REQUESTED); diff --git a/src/sched.h b/src/sched.h index 0a2bdc4bc..9ec96631e 100644 --- a/src/sched.h +++ b/src/sched.h @@ -31,7 +31,7 @@ void sched_del_timer(struct timer *del); unsigned int sched_timer_dispatch(void); void sched_timer_reset(void); void sched_wake_tasks(void); -uint8_t sched_tasks_busy(void); +uint8_t sched_check_set_tasks_busy(void); void sched_wake_task(struct task_wake *w); uint8_t sched_check_wake(struct task_wake *w); uint8_t sched_is_shutdown(void);