From 52b81656dedfc8d0492b6ee43333d86440a46e8c Mon Sep 17 00:00:00 2001 From: Marko Lindqvist Date: Sun, 26 Jun 2022 02:12:58 +0300 Subject: [PATCH 15/20] Rework readline cleanup on server quit - Introduce readline_atexit() - Call rl_callback_handler_remove() from readline_atexit() - Do not register rl_callback_handler_remove() as atexit function - Free last input line (the one where the "quit" command was given) in readline_atexit() - Call readline_atexit() from server_quit(), before exit() This clear things before any atexit handlers installed by tools wrapping freeciv - Also register readline_atexit() as atexit function, to make sure it gets called at least once even when server_quit() is bypassed for any reason See osdn #44948 Signed-off-by: Marko Lindqvist --- server/sernet.c | 56 ++++++++++++++++++++++++++++++++++------------- server/sernet.h | 6 +++-- server/srv_main.c | 1 + 3 files changed, 46 insertions(+), 17 deletions(-) diff --git a/server/sernet.c b/server/sernet.c index 71fa69cf6f..915e6bce91 100644 --- a/server/sernet.c +++ b/server/sernet.c @@ -161,39 +161,65 @@ static void handle_stdin_close(void) #define HISTORY_LENGTH 100 static char *history_file = NULL; - static bool readline_handled_input = FALSE; - static bool readline_initialized = FALSE; +static char *current_internal = NULL; /***************************************************************************** Readline callback for input. *****************************************************************************/ static void handle_readline_input_callback(char *line) { - char *line_internal; - - if (no_input) + if (no_input) { return; + } - if (!line) { - handle_stdin_close(); /* maybe print an 'are you sure?' message? */ + if (line == NULL) { + handle_stdin_close(); /* maybe print an 'are you sure?' message? */ return; } - if (line[0] != '\0') + if (line[0] != '\0') { add_history(line); + } - con_prompt_enter(); /* just got an 'Enter' hit */ - line_internal = local_to_internal_string_malloc(line); - (void) handle_stdin_input(NULL, line_internal); - free(line_internal); - free(line); - + con_prompt_enter(); /* just got an 'Enter' hit */ + current_internal = local_to_internal_string_malloc(line); + free(line); /* This is already freed if we exit() with /quit command */ + (void) handle_stdin_input(NULL, current_internal); + free(current_internal); /* Since handle_stdin_input() returned, + * we can be sure this was not freed in atexit. */ readline_handled_input = TRUE; } #endif /* FREECIV_HAVE_LIBREADLINE */ +/***************************************************************************** + Clear readline stuff at exit. To cater for as many different cases as + possible, we call this both like any function call from server_quit() + before exit(), and as a atexit handler. Former is to get everything + cleared already before exit(), before any other atexit handler comes + to play. Latter is to make sure that the function gets called also when + in those rare cases where we exit some other way than server_quit() - + that's important for always restoring terminal to a working state. + + That means that in usual case this function gets called twice. + Make sure that it doesn't try double frees or similar when that happens. +*****************************************************************************/ +void readline_atexit(void) +{ +#ifdef FREECIV_HAVE_LIBREADLINE + if (readline_initialized) { + rl_callback_handler_remove(); + readline_initialized = FALSE; + } + + if (current_internal != NULL) { + free(current_internal); + current_internal = NULL; + } +#endif /* FREECIV_HAVE_LIBREADLINE */ +} + /**************************************************************************** Close the connection (very low-level). See also server_conn_close_callback(). @@ -541,7 +567,7 @@ enum server_events server_sniff_all_input(void) rl_attempted_completion_function = freeciv_completion; readline_initialized = TRUE; - atexit(rl_callback_handler_remove); + atexit(readline_atexit); } } #endif /* FREECIV_HAVE_LIBREADLINE */ diff --git a/server/sernet.h b/server/sernet.h index 015844d3b8..fcbe8e60ef 100644 --- a/server/sernet.h +++ b/server/sernet.h @@ -1,4 +1,4 @@ -/********************************************************************** +/*********************************************************************** Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -42,8 +42,10 @@ int server_make_connection(int new_sock, void handle_conn_pong(struct connection *pconn); void handle_client_heartbeat(struct connection *pconn); +void readline_atexit(void); + #ifdef __cplusplus } #endif /* __cplusplus */ -#endif /* FC__SERNET_H */ +#endif /* FC__SERNET_H */ diff --git a/server/srv_main.c b/server/srv_main.c index 8c7178a998..872d7202b7 100644 --- a/server/srv_main.c +++ b/server/srv_main.c @@ -1802,6 +1802,7 @@ void server_quit(void) free_nls(); con_log_close(); cmdline_option_values_free(); + readline_atexit(); exit(EXIT_SUCCESS); } -- 2.35.1