Ensure watchdog always starts with the starting time of the thread. Add watchdog bark count. On the third bark, execute an unfixable error script if present.

This commit is contained in:
Mike Brady
2018-12-04 17:25:15 +00:00
parent 9ddef563ad
commit 277d401d24
7 changed files with 75 additions and 26 deletions
+9 -14
View File
@@ -136,8 +136,7 @@ static void help(void) {
void set_alsa_out_dev(char *dev) { alsa_out_dev = dev; }
//assuming pthread cancellation is disabled
// assuming pthread cancellation is disabled
int open_mixer() {
int response = 0;
if (hardware_mixer) {
@@ -181,7 +180,7 @@ int open_mixer() {
return response;
}
//assuming pthread cancellation is disabled
// assuming pthread cancellation is disabled
void close_mixer() {
if (alsa_mix_handle) {
snd_mixer_close(alsa_mix_handle);
@@ -189,7 +188,7 @@ void close_mixer() {
}
}
//assuming pthread cancellation is disabled
// assuming pthread cancellation is disabled
void do_snd_mixer_selem_set_playback_dB_all(snd_mixer_elem_t *mix_elem, double vol) {
if (snd_mixer_selem_set_playback_dB_all(mix_elem, vol, 0) != 0) {
debug(1, "Can't set playback volume accurately to %f dB.", vol);
@@ -200,7 +199,7 @@ void do_snd_mixer_selem_set_playback_dB_all(snd_mixer_elem_t *mix_elem, double v
}
static int init(int argc, char **argv) {
// for debugging
// for debugging
snd_output_stdio_attach(&output, stdout, 0);
// debug(2,"audio_alsa init called.");
@@ -506,8 +505,7 @@ static int init(int argc, char **argv) {
} else {
debug(1, "alsa: no hardware mixer selected.");
}
usleep(100000); // see if it makes a difference
alsa_mix_handle = NULL;
return response;
}
@@ -517,7 +515,7 @@ static void deinit(void) {
stop();
}
//assuming pthread cancellation is disabled
// assuming pthread cancellation is disabled
int actual_open_alsa_device(void) {
// the alsa mutex is already acquired when this is called
const snd_pcm_uframes_t minimal_buffer_headroom =
@@ -884,11 +882,10 @@ int actual_open_alsa_device(void) {
break;
}
}
usleep(100000); // see if it makes a difference
return 0;
}
int open_alsa_device(void) {
int open_alsa_device(void) {
int result;
int oldState;
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldState); // make this un-cancellable
@@ -911,10 +908,9 @@ static void start(int i_sample_rate, int i_sample_format) {
frame_index = 0;
measurement_data_is_valid = 0;
usleep(100000); // see if it makes a difference
}
//assuming pthread cancellation is disabled
// assuming pthread cancellation is disabled
int my_snd_pcm_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) {
int ret;
snd_pcm_status_t *alsa_snd_pcm_status;
@@ -1165,7 +1161,6 @@ static void flush(void) {
measurement_data_is_valid = 0;
alsa_handle = NULL;
}
usleep(100000); // see if it makes a difference
debug_mutex_unlock(&alsa_mutex, 3);
pthread_cleanup_pop(0); // release the mutex
pthread_setcancelstate(oldState, NULL);
@@ -1303,6 +1298,6 @@ void do_mute(int mute_state_requested) {
close_mixer();
}
}
mute_request_pending = 0;
mute_request_pending = 0;
pthread_setcancelstate(oldState, NULL);
}
+32
View File
@@ -739,6 +739,38 @@ void command_start(void) {
}
}
}
void command_execute(const char *command) {
// this has a cancellation point if waiting is enabled
if (command) {
/*Spawn a child to run the program.*/
pid_t pid = fork();
if (pid == 0) { /* child process */
int argC;
char **argV;
if (poptParseArgvString(command, &argC, (const char ***)&argV) !=
0) // note that argV should be free()'d after use, but we expect this fork to exit
// eventually.
debug(1, "Can't decipher command arguments in \"%s\".", command);
else {
// debug(1,"Executing command %s",command);
execv(argV[0], argV);
warn("Execution of command \"%s\" failed to start", command);
debug(1, "Error executing command \"%s\".", command);
exit(127); /* only if execv fails */
}
} else {
if (config.cmd_blocking) { /* pid!=0 means parent process and if blocking is true, wait for
process to finish */
pid_t rc = waitpid(pid, 0, 0); /* wait for child to exit */
if (rc != pid) {
warn("Execution of command \"%s\" returned an error.", command);
debug(1, "Command \"%s\" finished with error %d", command, errno);
}
}
// debug(1,"Continue after on-unfixable command");
}
}
}
void command_stop(void) {
// this has a cancellation point if waiting is enabled
+2 -1
View File
@@ -148,7 +148,7 @@ typedef struct {
int debugger_show_relative_time; // in the debug message, display the time since the last one
int statistics_requested, use_negotiated_latencies;
enum playback_mode_type playback_mode;
char *cmd_start, *cmd_stop, *cmd_set_volume;
char *cmd_start, *cmd_stop, *cmd_set_volume, *cmd_unfixable;
int cmd_blocking, cmd_start_returns_output;
double tolerance; // allow this much drift before attempting to correct it
enum stuffing_type packet_stuffing;
@@ -296,6 +296,7 @@ int config_set_lookup_bool(config_t *cfg, char *where, int *dst);
void command_start(void);
void command_stop(void);
void command_execute(const char *command);
void command_set_volume(double volume);
int mkpath(const char *path, mode_t mode);
+3 -2
View File
@@ -84,11 +84,12 @@ typedef struct {
SOCKADDR remote, local;
volatile int stop;
volatile int running;
volatile uint64_t watchdog_bark_time;
volatile int watchdog_barks; // number of times the watchdog has timed out and done something
time_t playstart;
pthread_t thread, timer_requester, rtp_audio_thread, rtp_control_thread, rtp_timing_thread,
player_watchdog_thread;
volatile int64_t watchdog_bark_time;
// pthread_t *ptp;
// buffers to delete on exit
signed short *tbuf;
+23 -9
View File
@@ -283,11 +283,25 @@ void *player_watchdog_thread_code(void *arg) {
uint64_t ct = config.timeout; // go from int to 64-bit int
if (time_since_last_bark >= ct) {
debug(1, "Connection %d: As Yeats almost said, \"Too long a silence / can make a stone "
"of the heart\".",
conn->connection_number);
conn->stop = 1;
pthread_cancel(conn->thread);
conn->watchdog_barks++;
if (conn->watchdog_barks == 1) {
debug(1, "Connection %d: As Yeats almost said, \"Too long a silence / can make a stone "
"of the heart\".",
conn->connection_number);
conn->stop = 1;
pthread_cancel(conn->thread);
} else if (conn->watchdog_barks == 3) {
if (config.cmd_unfixable) {
warn("Connection %d: An unfixable error has been detected. Executing the "
"\"run_this_if_an_unfixable_error_is_detected\" command.",
conn->connection_number);
command_execute(config.cmd_unfixable);
} else {
warn("Connection %d: An unfixable error has been detected. \"No "
"run_this_if_an_unfixable_error_is_detected\" command provided -- nothing done.",
conn->connection_number);
}
}
}
}
}
@@ -2144,7 +2158,8 @@ void msg_cleanup_function(void *arg) {
static void *rtsp_conversation_thread_func(void *pconn) {
rtsp_conn_info *conn = pconn;
// create the watchdog mutex and start the watchdog thread;
// create the watchdog mutex, initialise the watchdog time and start the watchdog thread;
conn->watchdog_bark_time = get_absolute_time_in_fp();
pthread_mutex_init(&conn->watchdog_mutex, NULL);
pthread_create(&conn->player_watchdog_thread, NULL, &player_watchdog_thread_code, (void *)conn);
@@ -2393,12 +2408,11 @@ void rtsp_listen_loop(void) {
tv.tv_usec = 0;
if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (const char *)&tv, sizeof tv) == -1)
debug(1, "Error %d setting send timeout for rtsp writeback.", errno);
tv.tv_sec = 30; // 30 seconds read timeout
tv.tv_usec = 0;
if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv, sizeof tv) == -1)
if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv, sizeof tv) == -1)
debug(1, "Error %d setting send timeout for rtsp writeback.", errno);
#ifdef IPV6_V6ONLY
// some systems don't support v4 access on v6 sockets, but some do.
+1
View File
@@ -53,6 +53,7 @@ sessioncontrol =
{
// run_this_before_play_begins = "/full/path/to/application and args"; // make sure the application has executable permission. If it's a script, include the shebang (#!/bin/...) on the first line
// run_this_after_play_ends = "/full/path/to/application and args"; // make sure the application has executable permission. If it's a script, include the shebang (#!/bin/...) on the first line
// run_this_if_an_unfixable_error_is_detected = "/full/path/to/application and args"; // if a problem occurs that can't be cleared. It might restart the whole device.
// wait_for_completion = "no"; // set to "yes" to get Shairport Sync to wait until the "run_this..." applications have terminated before continuing
// allow_session_interruption = "no"; // set to "yes" to allow another device to interrupt Shairport Sync while it's playing from an existing audio source
// session_timeout = 120; // wait for this number of seconds after a source disappears before terminating the session and becoming available again.
+5
View File
@@ -721,6 +721,11 @@ int parse_options(int argc, char **argv) {
config.cmd_stop = (char *)str;
}
if (config_lookup_string(config.cfg,
"sessioncontrol.run_this_if_an_unfixable_error_is_detected", &str)) {
config.cmd_unfixable = (char *)str;
}
if (config_lookup_string(config.cfg, "sessioncontrol.wait_for_completion", &str)) {
if (strcasecmp(str, "no") == 0)
config.cmd_blocking = 0;