mirror of
https://github.com/linux-speakup/espeakup.git
synced 2026-08-09 09:19:09 +02:00
softsynth: bound the wait for espeak to acknowledge a stop request
request_espeak_stop() waited forever for the espeak thread to acknowledge the stop. If espeak-ng is wedged inside the audio output (e.g. an ALSA device blocked or stuck returning EBUSY, as reported in issue #62), the acknowledgement never comes, and the softsynth thread stops draining /dev/softsynth forever. Speakup's kernel buffer then fills up and console output stalls, which matches the "blocks dmesg output after a couple of pages" observation in issue #45. The process goes silent and only SIGKILL gets rid of it. Wait at most 10 seconds for the acknowledgement (a normal cancellation takes milliseconds; the timeout can only trigger when espeak is truly stuck). On timeout, exit with a clear message so that the init system respawns espeakup in a clean state: our systemd unit already has Restart=always. A one-second restart beats an unkillable silent daemon, and was explicitly requested by the reporter of issue #62. Helps: https://github.com/linux-speakup/espeakup/issues/45 Helps: https://github.com/linux-speakup/espeakup/issues/62 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
38075367ab
commit
a3a08f9ba0
1 changed files with 25 additions and 2 deletions
|
|
@ -24,6 +24,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/select.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "espeakup.h"
|
||||
|
|
@ -223,15 +224,37 @@ static void process_buffer_acsint(struct synth_t *s, char *buf, ssize_t length)
|
|||
}
|
||||
}
|
||||
|
||||
/* How long to wait for the espeak thread to acknowledge a stop request
|
||||
* before concluding that espeak is wedged beyond in-process recovery. */
|
||||
static const int stopAckTimeout = 10;
|
||||
|
||||
static void request_espeak_stop(void)
|
||||
{
|
||||
struct timespec timeout;
|
||||
int err = 0;
|
||||
|
||||
pthread_mutex_lock(&queue_guard);
|
||||
stop_requested = 1;
|
||||
pthread_cond_signal(&runner_awake); // Wake runner, if necessary.
|
||||
pthread_cond_signal(&wake_stop); // Wake runner, if necessary.
|
||||
while (should_run && stop_requested)
|
||||
clock_gettime(CLOCK_REALTIME, &timeout);
|
||||
timeout.tv_sec += stopAckTimeout;
|
||||
while (should_run && stop_requested && err != ETIMEDOUT)
|
||||
// wait for acknowledgement.
|
||||
pthread_cond_wait(&stop_acknowledged, &queue_guard);
|
||||
err = pthread_cond_timedwait(&stop_acknowledged, &queue_guard,
|
||||
&timeout);
|
||||
if (should_run && stop_requested) {
|
||||
/* The espeak thread is stuck in a call into espeak, most likely
|
||||
* on a wedged audio device. There is no way to recover from
|
||||
* within the process: exit so that the init system can respawn
|
||||
* us in a clean state, rather than staying silent, ignoring
|
||||
* SIGTERM, and stalling the whole console by not draining
|
||||
* /dev/softsynth anymore. Use _exit because exit could hang in
|
||||
* library destructors while the audio device is wedged. */
|
||||
fprintf(stderr, "espeakup: espeak did not acknowledge a stop "
|
||||
"request within %d seconds, aborting\n", stopAckTimeout);
|
||||
_exit(3);
|
||||
}
|
||||
pthread_mutex_unlock(&queue_guard);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue