From 040e1a5ad6e31a4064f81fdd297f3ec894d16ea6 Mon Sep 17 00:00:00 2001 From: John Zaitseff Date: Tue, 9 Aug 2011 23:20:56 +1000 Subject: [PATCH] Rework the signal handler Rework the signal handler to be somewhat more unsafe, but conceptually cleaner, in operation. It now ends the use of Curses, then reraises the signal. Remove almost all references to abort_game. --- src/exch.c | 15 --------------- src/game.c | 42 ++++++----------------------------------- src/globals.c | 3 +-- src/globals.h | 4 +--- src/help.c | 6 ------ src/intf.c | 43 +++++++++++++++++++++++++++--------------- src/intf.h | 11 +++++------ src/move.c | 52 +++------------------------------------------------ src/trader.c | 2 +- 9 files changed, 45 insertions(+), 133 deletions(-) diff --git a/src/exch.c b/src/exch.c index d426608..9535ff5 100644 --- a/src/exch.c +++ b/src/exch.c @@ -211,9 +211,6 @@ void exchange_stock (void) break; default: - if (abort_game) - return; - beep(); } } @@ -259,9 +256,6 @@ void visit_bank (void) char *buf; - if (abort_game) - return; - buf = malloc(BUFSIZE); if (buf == NULL) { err_exit_nomem(); @@ -334,9 +328,6 @@ void visit_bank (void) break; default: - if (abort_game) - return; - beep(); } } @@ -491,9 +482,6 @@ void trade_shares (int num, bool *bid_used) char *buf; - if (abort_game) - return; - assert(num >= 0 && num < MAX_COMPANIES); assert(company[num].on_map); @@ -593,9 +581,6 @@ void trade_shares (int num, bool *bid_used) break; default: - if (abort_game) - return; - beep(); } } diff --git a/src/game.c b/src/game.c index 18a6837..3e13573 100644 --- a/src/game.c +++ b/src/game.c @@ -126,9 +126,6 @@ void init_game (void) while (number_players == 0) { int choice = ask_number_players(); - if (abort_game) - return; - if (choice == ERR) { abort_game = true; return; @@ -136,9 +133,6 @@ void init_game (void) } else if (choice == 0) { choice = ask_game_number(); - if (abort_game) - return; - if (choice != ERR) { game_num = choice; @@ -168,9 +162,6 @@ void init_game (void) ask_player_names(); - if (abort_game) - return; - deltxwin(); // "Number of players" window txrefresh(); @@ -230,6 +221,7 @@ void init_game (void) } quit_selected = false; + abort_game = false; } @@ -285,9 +277,6 @@ static int ask_number_players (void) break; default: - if (abort_game) - return ERR; - beep(); } } @@ -344,9 +333,6 @@ int ask_game_number (void) break; default: - if (abort_game) - return ERR; - beep(); } } @@ -362,9 +348,6 @@ int ask_game_number (void) void ask_player_names (void) { - if (abort_game) - return; - if (number_players == 1) { // Ask for the player's name @@ -379,9 +362,6 @@ void ask_player_names (void) while (true) { int ret = gettxstr(curwin, &player[0].name, NULL, false, 2, x, w, attr_input_field); - if (abort_game) - return; - if (ret == OK && strlen(player[0].name) != 0) { break; } else { @@ -391,7 +371,7 @@ void ask_player_names (void) newtxwin(5, 44, 6, WCENTER, true, attr_normal_window); mvwaddstr(curwin, 2, 2, "Do you need any instructions?"); - if (answer_yesno(curwin, attr_keycode) == true) { + if (answer_yesno(curwin, attr_keycode)) { show_help(); } @@ -452,9 +432,6 @@ void ask_player_names (void) break; case ERR: - if (abort_game) - return; - beep(); break; @@ -491,7 +468,7 @@ void ask_player_names (void) newtxwin(5, 50, 6, WCENTER, true, attr_normal_window); mvwaddstr(curwin, 2, 2, "Does any player need instructions?"); - if (answer_yesno(curwin, attr_keycode) == true) { + if (answer_yesno(curwin, attr_keycode)) { show_help(); } } @@ -510,8 +487,10 @@ void end_game (void) char *buf; - if (abort_game) + if (abort_game) { + // init_game() was cancelled by user return; + } buf = malloc(BUFSIZE); if (buf == NULL) { @@ -531,9 +510,6 @@ void end_game (void) show_status(i); } - if (abort_game) - return; - if (number_players == 1) { l_strfmon(buf, BUFSIZE, "%1n", total_value(0)); @@ -595,9 +571,6 @@ void show_map (bool closewin) int n, x, y; - if (abort_game) - return; - newtxwin(MAX_Y + 4, WIN_COLS, 1, WCENTER, true, attr_map_window); // Draw various borders @@ -697,9 +670,6 @@ void show_status (int num) int i, line; - if (abort_game) - return; - assert(num >= 0 && num < number_players); newtxwin(MAX_COMPANIES + 15, WIN_COLS, 1, WCENTER, true, diff --git a/src/globals.c b/src/globals.c index af8e74e..3deab67 100644 --- a/src/globals.c +++ b/src/globals.c @@ -84,13 +84,12 @@ bool game_loaded = false; // True if game was loaded from disk int game_num = 0; // Game number (1-9) bool quit_selected = false; // Is a player trying to quit the game? +bool abort_game = false; // Abort game without declaring winner? bool option_no_color = false; // True if --no-color was specified bool option_dont_encrypt = false; // True if --dont-encrypt was specified int option_max_turn = 0; // Max. turns if --max-turn was specified -volatile sig_atomic_t abort_game = false; // Abort game as quickly as possible? - /***********************************************************************/ // End of file diff --git a/src/globals.h b/src/globals.h index 135a717..db19be3 100644 --- a/src/globals.h +++ b/src/globals.h @@ -33,7 +33,6 @@ #include -#include /************************************************************************ @@ -196,12 +195,11 @@ extern bool game_loaded; // True if game was loaded from disk extern int game_num; // Game number (1-9) extern bool quit_selected; // Is a player trying to quit the game? +extern bool abort_game; // Abort game without declaring winner? extern bool option_no_color; // True if --no-color was specified extern bool option_dont_encrypt; // True if --dont-encrypt was specified extern int option_max_turn; // Max. turns if --max-turn was specified -extern volatile sig_atomic_t abort_game; // Abort game as quickly as possible? - #endif /* included_GLOBALS_H */ diff --git a/src/help.c b/src/help.c index 938848c..4f9a520 100644 --- a/src/help.c +++ b/src/help.c @@ -162,9 +162,6 @@ void show_help (void) bool done = false; - if (abort_game) - return; - // Count how many pages appear in the help text for (numpages = 0; help_text[numpages] != NULL; numpages++) ; @@ -359,9 +356,6 @@ void show_help (void) break; default: - if (abort_game) - return; - curpage++; done = (curpage == numpages); } diff --git a/src/intf.c b/src/intf.c index a486ab5..461587c 100644 --- a/src/intf.c +++ b/src/intf.c @@ -112,8 +112,9 @@ static void init_title (void); Parameters: sig - Signal number Returns: (nothing) - This function handles termination signals (like SIGINT and SIGTERM) by - setting the global variable abort_game to true. + This function handles termination signals (like SIGINT, SIGTERM and + SIGQUIT) by clearing the screen, uninstalling itself and reraising the + signal. */ static void sigterm_handler (int sig); @@ -163,6 +164,9 @@ void init_screen (void) if (sigaction(SIGTERM, &sa, NULL) == -1) { errno_exit("sigaction(SIGTERM)"); } + if (sigaction(SIGQUIT, &sa, NULL) == -1) { + errno_exit("sigaction(SIGQUIT)"); + } // Initialise the screen initscr(); @@ -312,13 +316,26 @@ void init_title (void) void sigterm_handler (int sig) { - /* Note that sigterm_handler() simply sets a volatile variable - instead of directly terminating, as functions like endwin() and - end_screen() are NOT reentrant. A side-effect of doing this, - however, is that the main program needs to have abort_game checks - scattered all over it. */ + struct sigaction sa; - abort_game = true; + + /* The following Curses functions are NOT async-signal-safe (ie, are + not reentrant) as they may well call malloc() or free(). However, + it does allow us to terminate with the correct signal without + having convoluted code in the main program. */ + + curs_set(CURS_ON); + clear(); + refresh(); + endwin(); + + // Reraise the same signal, using the system-default handler + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sa.sa_handler = SIG_DFL; + + sigaction(sig, &sa, NULL); + raise(sig); } @@ -705,10 +722,8 @@ int gettxline (WINDOW *win, char *buf, int bufsize, bool *restrict modified, key = wgetch(win); if (key == ERR) { - if (abort_game) { - ret = ERR; - done = true; - } + // Do nothing on ERR + ; } else if ((key == KEY_DEFAULTVAL1 || key == KEY_DEFAULTVAL2) && defaultval != NULL && len == 0) { // Initialise buffer with the default value @@ -1512,7 +1527,7 @@ int gettxlong (WINDOW *win, long int *restrict result, long int min, /***********************************************************************/ // answer_yesno: Wait for a Yes/No answer -int answer_yesno (WINDOW *win, chtype attr_keys) +bool answer_yesno (WINDOW *win, chtype attr_keys) { int key; bool done; @@ -1539,8 +1554,6 @@ int answer_yesno (WINDOW *win, chtype attr_keys) if (key == 'Y' || key == 'N') { done = true; - } else if (abort_game) { - return ERR; } else { beep(); } diff --git a/src/intf.h b/src/intf.h index 2887925..6301c2a 100644 --- a/src/intf.h +++ b/src/intf.h @@ -534,17 +534,16 @@ extern int gettxlong (WINDOW *win, long int *restrict result, long int min, Function: answer_yesno - Wait for a Yes/No answer Parameters: win - Window to use (should be curwin) attr_keys - Window rendition to use for key choices - Returns: int - 1 if Yes was selected, 0 if No, ERR if error + Returns: bool - True if Yes was selected, false if No This function prompts the user by printing " [Y/N] " using appropriate character renditions ("Y" and "N" in attr_keys, the rest in the current rendition), then waits for the user to press either "Y" (for Yes) or - "N" (for No) on the keyboard, then prints the answer using A_BOLD. If - "Y" was selected, 1 is returned, if "N", 0 is returned. ERR is - returned if abort_game becomes true. Note that the cursor becomes - invisible after calling this function. + "N" (for No) on the keyboard, then prints the answer using A_BOLD. + True is returned if "Y" was selected, false if "N". Note that the + cursor becomes invisible after calling this function. */ -extern int answer_yesno (WINDOW *win, chtype attr_keys); +extern bool answer_yesno (WINDOW *win, chtype attr_keys); /* diff --git a/src/move.c b/src/move.c index 8d41845..3db159b 100644 --- a/src/move.c +++ b/src/move.c @@ -159,9 +159,6 @@ void select_moves (void) bool unique; - if (abort_game) - return; - // How many empty spaces are there in the galaxy map? count = 0; for (x = 0; x < MAX_X; x++) { @@ -321,9 +318,6 @@ selection_t get_move (void) break; default: - if (abort_game) - return SEL_QUIT; - beep(); } } @@ -341,13 +335,10 @@ selection_t get_move (void) // Ask the player to confirm their choice mvwaddstr(curwin, 2, 22, "Are you sure?"); - if (answer_yesno(curwin, attr_keycode) != true) { + if (! answer_yesno(curwin, attr_keycode)) { selection = SEL_NONE; } - if (abort_game) - return SEL_QUIT; - // Save the game if required if (selection == SEL_SAVE) { bool saved = false; @@ -406,9 +397,6 @@ selection_t get_move (void) break; default: - if (abort_game) - return SEL_QUIT; - beep(); } } @@ -456,13 +444,12 @@ selection_t get_move (void) void process_move (selection_t selection) { - if (abort_game) - return; - if (selection == SEL_QUIT) { // The players want to end the game quit_selected = true; + } + if (quit_selected || abort_game) { deltxwin(); // "Select move" window deltxwin(); // Galaxy map window txrefresh(); @@ -508,9 +495,6 @@ void process_move (selection_t selection) assign_vals(x, y, left, right, up, down); } - if (abort_game) - return; - if (IS_MAP_COMPANY(left) && IS_MAP_COMPANY(up) && left != up) { galaxy_map[x][y] = left; @@ -518,9 +502,6 @@ void process_move (selection_t selection) assign_vals(x, y, left, right, up, down); } - if (abort_game) - return; - if (IS_MAP_COMPANY(left) && IS_MAP_COMPANY(down) && left != down) { galaxy_map[x][y] = left; @@ -528,9 +509,6 @@ void process_move (selection_t selection) assign_vals(x, y, left, right, up, down); } - if (abort_game) - return; - if (IS_MAP_COMPANY(right) && IS_MAP_COMPANY(up) && right != up) { galaxy_map[x][y] = right; @@ -538,9 +516,6 @@ void process_move (selection_t selection) assign_vals(x, y, left, right, up, down); } - if (abort_game) - return; - if (IS_MAP_COMPANY(right) && IS_MAP_COMPANY(down) && right != down) { galaxy_map[x][y] = right; @@ -548,9 +523,6 @@ void process_move (selection_t selection) assign_vals(x, y, left, right, up, down); } - if (abort_game) - return; - if (IS_MAP_COMPANY(up) && IS_MAP_COMPANY(down) && up != down) { galaxy_map[x][y] = up; @@ -559,9 +531,6 @@ void process_move (selection_t selection) } } - if (abort_game) - return; - // See if an existing company can be expanded nearby = (IS_MAP_COMPANY(left) ? left : (IS_MAP_COMPANY(right) ? right : @@ -627,9 +596,6 @@ void next_player (void) bool all_out; - if (abort_game) - return; - all_out = true; for (i = 0; i < number_players; i++) { if (player[i].in_game) { @@ -670,9 +636,6 @@ void bankrupt_player (bool forced) int i; - if (abort_game) - return; - /* It would be nice if we had functions that would do word-wrapping for us automatically! */ @@ -827,9 +790,6 @@ void merge_companies (map_val_t a, map_val_t b) char *buf; - if (abort_game) - return; - buf = malloc(BUFSIZE); if (buf == NULL) { err_exit_nomem(); @@ -992,9 +952,6 @@ void adjust_values (void) int which; - if (abort_game) - return; - // Declare a company bankrupt! if (randf() > (1.0 - COMPANY_BANKRUPTCY)) { which = randi(MAX_COMPANIES); @@ -1128,9 +1085,6 @@ void adjust_values (void) interest_rate /= randf() + INTEREST_RATE_DIVIDER; } - if (abort_game) - return; - // Calculate current player's debt player[current_player].debt *= interest_rate + 1.0; diff --git a/src/trader.c b/src/trader.c index 8ccc6e8..b47dda6 100644 --- a/src/trader.c +++ b/src/trader.c @@ -180,7 +180,7 @@ int main (int argc, char *argv[]) // Finish up... end_program(); - return abort_game ? EXIT_FAILURE : EXIT_SUCCESS; + return EXIT_SUCCESS; }