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 <noreply@anthropic.com>
This commit is contained in:
Alexander Epaneshnikov 2026-06-11 11:07:43 +03:00 committed by Samuel Thibault
commit 7405455baf

View file

@ -24,6 +24,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h>
#include "espeakup.h" #include "espeakup.h"
@ -344,6 +345,19 @@ static void reinitialize_espeak(struct synth_t *s)
return; 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 struct espeak_entry_t *current = NULL;
static void queue_process_entry(struct synth_t *s) 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); free_espeak_entry(current);
current = NULL; current = NULL;
} else { } else {
if (error == EE_BUFFER_FULL) 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
fprintf(stderr, "espeak error: %d\n", error); 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();
} }
} }