From 9aa1bf4680f23c0db8d8b3edba966d1120c306a7 Mon Sep 17 00:00:00 2001 From: Andre Noll Date: Thu, 6 Oct 2022 16:11:55 +0200 Subject: [PATCH 1/1] play: Shut down alsa on input EOF. para_play leaks a lot of memory on exit because we didn't bother to shut down the alsa subsystem. While this is harmless from the correctness point of view, it does make it harder to spot real memory leaks. Rework the error handling to always shut down alsa via kill_stream(). Combine play_post_monitor() and session_post_monitor() because they are small enough and the latter was badly named anyway. --- play.c | 61 ++++++++++++++++++---------------------------------------- 1 file changed, 19 insertions(+), 42 deletions(-) diff --git a/play.c b/play.c index f04cf842..c9a9f7d7 100644 --- a/play.c +++ b/play.c @@ -1091,39 +1091,6 @@ static void session_update_time_string(char *str, unsigned len) i9e_print_status_bar(str, len); } -/* - * If we are about to die we must call i9e_close() to reset the terminal. - * However, i9e_close() must be called in *this* context, i.e. from - * play_task.post_monitor() rather than from i9e_post_monitor(), because - * otherwise i9e would access freed memory upon return. So the play task must - * stay alive until the i9e task terminates. - * - * We achieve this by sending a fake SIGTERM signal via i9e_signal_dispatch() - * and reschedule. In the next iteration, i9e->post_monitor returns an error and - * terminates. Subsequent calls to i9e_get_error() then return negative and we - * are allowed to call i9e_close() and terminate as well. - */ -static int session_post_monitor(__a_unused struct sched *s) -{ - int ret; - - if (pt->background) - detach_stdout(); - else - attach_stdout(__FUNCTION__); - ret = i9e_get_error(); - if (ret < 0) { - kill_stream(); - i9e_close(); - para_log = stderr_log; - free(ici.history_file); - return ret; - } - if (get_playback_state() == 'X') - i9e_signal_dispatch(SIGTERM); - return 0; -} - static void play_pre_monitor(struct sched *s, __a_unused void *context) { char state; @@ -1162,18 +1129,24 @@ static unsigned get_time_string(char **result) ); } -static int play_post_monitor(struct sched *s, __a_unused void *context) +static int play_post_monitor(__a_unused struct sched *s, __a_unused void *context) { - int ret; + int ret, i9e_error; + if (pt->background) + detach_stdout(); + else + attach_stdout(__FUNCTION__); + i9e_error = i9e_get_error(); ret = eof_cleanup(); - if (ret < 0) { - pt->rq = CRT_TERM_RQ; - return 0; - } - ret = session_post_monitor(s); - if (ret < 0) - goto out; + if (pt->rq == CRT_TERM_RQ || i9e_error < 0) /* com_quit() or CTRL+D */ + kill_stream(); /* terminate receiver/filter/writer */ + if ((ret < 0 || pt->rq == CRT_TERM_RQ) && i9e_error >= 0) + i9e_signal_dispatch(SIGTERM); /* terminate the i9e task */ + if (ret < 0) /* unexpected error from the writer node */ + return ret; + if (ret != 0 && i9e_error < 0) /* eof, and i9e has died */ + return i9e_error; if (!pt->wn.btrn && !pt->fn.btrn) { char state = get_playback_state(); if (state == 'P' || state == 'R' || state == 'F') { @@ -1243,6 +1216,10 @@ int main(int argc, char *argv[]) }, &sched); ret = schedule(&sched); sched_shutdown(&sched); + i9e_close(); + wipe_receiver_node(); + para_log = stderr_log; + free(ici.history_file); if (ret < 0) PARA_ERROR_LOG("%s\n", para_strerror(-ret)); return ret < 0? EXIT_FAILURE : EXIT_SUCCESS; -- 2.39.5