From 7405455baf4a20f0f8e31a057ecbb59f64f636e8 Mon Sep 17 00:00:00 2001 From: Alexander Epaneshnikov Date: Thu, 11 Jun 2026 11:07:43 +0300 Subject: [PATCH] espeak: back off before retrying after any espeak error When processing an entry failed, only EE_BUFFER_FULL throttled before the retry; any other persistent error (e.g. EE_INTERNAL_ERROR after espeak was terminated) made queue_process_entry retry the same entry in a tight loop with no sleep, burning a whole CPU while printing to a stderr that points to /dev/null in daemon mode. Factor the one-second throttle out into espeak_wait_retry() and apply it to every failed entry. The wake_stop condition variable still interrupts the wait immediately when a flush comes in. Co-Authored-By: Claude --- src/espeak.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/src/espeak.c b/src/espeak.c index 41a7e99..f6b4d1e 100644 --- a/src/espeak.c +++ b/src/espeak.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "espeakup.h" @@ -344,6 +345,19 @@ static void reinitialize_espeak(struct synth_t *s) return; } +/* Wait for up to a second before retrying an entry which could not be + * processed, so that we do not busy-loop on a persistent error. Called + * and returns with queue_guard held. Wakes up immediately if a stop is + * requested. */ +static void espeak_wait_retry(void) +{ + struct timespec timeout; + + clock_gettime(CLOCK_REALTIME, &timeout); + timeout.tv_sec++; + pthread_cond_timedwait(&wake_stop, &queue_guard, &timeout); +} + static struct espeak_entry_t *current = NULL; static void queue_process_entry(struct synth_t *s) { @@ -419,17 +433,13 @@ static void queue_process_entry(struct synth_t *s) free_espeak_entry(current); current = NULL; } else { - if (error == EE_BUFFER_FULL) - { - /* Give speak a little break before retrying */ - struct timespec timeout; - clock_gettime(CLOCK_REALTIME, &timeout); - timeout.tv_sec++; - /* But wake up immediately if we have to stop */ - pthread_cond_timedwait(&wake_stop, &queue_guard, &timeout); - } - else + if (error != EE_BUFFER_FULL) fprintf(stderr, "espeak error: %d\n", error); + /* The entry stays queued and will be retried. Give espeak a + * little break before that, whatever the error: previously only + * EE_BUFFER_FULL throttled, and any other persistent error made + * us retry the same entry in a tight loop, burning a whole CPU. */ + espeak_wait_retry(); } }