From e56f09afdbd4bd920e4a1f3b03e29eaccd954dac Mon Sep 17 00:00:00 2001 From: Kamil Dudka Date: Tue, 6 Sep 2016 17:38:26 +0200 Subject: [PATCH] ls: allow interruption when reading slow directories Postpone installation of signal handlers until they're needed. That is right before the first escape sequence is printed. * src/ls.c (signal_setup): A new function refactored from main() to set and restore signal handlers. (main): Move signal handler setup to put_indicator() so that the default signal handling is untouched as long as possible. Adjusted condition for restoring signal handlers to reflect the change. (put_indicator): Install signal handlers if called for the very first time. It uses the same code that was in main() prior to this commit. * NEWS: Mention the improvement. See https://bugzilla.redhat.com/1365933 Fixes http://bugs.gnu.org/24232 Upstream-commit: 5445f7811ff945ea13aa2a0fd797eb4c0a0e4db0 Signed-off-by: Kamil Dudka --- src/ls.c | 161 ++++++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 93 insertions(+), 68 deletions(-) diff --git a/src/ls.c b/src/ls.c index a89c87a..1300938 100644 --- a/src/ls.c +++ b/src/ls.c @@ -1246,13 +1246,12 @@ process_signals (void) } } -int -main (int argc, char **argv) -{ - int i; - struct pending *thispend; - int n_files; +/* Setup signal handlers if INIT is true, + otherwise restore to the default. */ +static void +signal_setup (bool init) +{ /* The signals that are trapped, and the number of such signals. */ static int const sig[] = { @@ -1280,8 +1279,77 @@ main (int argc, char **argv) enum { nsigs = ARRAY_CARDINALITY (sig) }; #if ! SA_NOCLDSTOP - bool caught_sig[nsigs]; + static bool caught_sig[nsigs]; +#endif + + int j; + + if (init) + { +#if SA_NOCLDSTOP + struct sigaction act; + + sigemptyset (&caught_signals); + for (j = 0; j < nsigs; j++) + { + sigaction (sig[j], NULL, &act); + if (act.sa_handler != SIG_IGN) + sigaddset (&caught_signals, sig[j]); + } + + act.sa_mask = caught_signals; + act.sa_flags = SA_RESTART; + + for (j = 0; j < nsigs; j++) + if (sigismember (&caught_signals, sig[j])) + { + act.sa_handler = sig[j] == SIGTSTP ? stophandler : sighandler; + sigaction (sig[j], &act, NULL); + } +#else + for (j = 0; j < nsigs; j++) + { + caught_sig[j] = (signal (sig[j], SIG_IGN) != SIG_IGN); + if (caught_sig[j]) + { + signal (sig[j], sig[j] == SIGTSTP ? stophandler : sighandler); + siginterrupt (sig[j], 0); + } + } #endif + } + else /* restore. */ + { +#if SA_NOCLDSTOP + for (j = 0; j < nsigs; j++) + if (sigismember (&caught_signals, sig[j])) + signal (sig[j], SIG_DFL); +#else + for (j = 0; j < nsigs; j++) + if (caught_sig[j]) + signal (sig[j], SIG_DFL); +#endif + } +} + +static inline void +signal_init (void) +{ + signal_setup (true); +} + +static inline void +signal_restore (void) +{ + signal_setup (false); +} + +int +main (int argc, char **argv) +{ + int i; + struct pending *thispend; + int n_files; initialize_main (&argc, &argv); set_program_name (argv[0]); @@ -1317,46 +1385,6 @@ main (int argc, char **argv) || (is_colored (C_MISSING) && (format == long_format || format == security_format))) check_symlink_color = true; - - /* If the standard output is a controlling terminal, watch out - for signals, so that the colors can be restored to the - default state if "ls" is suspended or interrupted. */ - - if (0 <= tcgetpgrp (STDOUT_FILENO)) - { - int j; -#if SA_NOCLDSTOP - struct sigaction act; - - sigemptyset (&caught_signals); - for (j = 0; j < nsigs; j++) - { - sigaction (sig[j], NULL, &act); - if (act.sa_handler != SIG_IGN) - sigaddset (&caught_signals, sig[j]); - } - - act.sa_mask = caught_signals; - act.sa_flags = SA_RESTART; - - for (j = 0; j < nsigs; j++) - if (sigismember (&caught_signals, sig[j])) - { - act.sa_handler = sig[j] == SIGTSTP ? stophandler : sighandler; - sigaction (sig[j], &act, NULL); - } -#else - for (j = 0; j < nsigs; j++) - { - caught_sig[j] = (signal (sig[j], SIG_IGN) != SIG_IGN); - if (caught_sig[j]) - { - signal (sig[j], sig[j] == SIGTSTP ? stophandler : sighandler); - siginterrupt (sig[j], 0); - } - } -#endif - } } if (dereference == DEREF_UNDEFINED) @@ -1467,32 +1495,21 @@ main (int argc, char **argv) print_dir_name = true; } - if (print_with_color) + if (print_with_color && used_color) { int j; - if (used_color) - { - /* Skip the restore when it would be a no-op, i.e., - when left is "\033[" and right is "m". */ - if (!(color_indicator[C_LEFT].len == 2 - && memcmp (color_indicator[C_LEFT].string, "\033[", 2) == 0 - && color_indicator[C_RIGHT].len == 1 - && color_indicator[C_RIGHT].string[0] == 'm')) - restore_default_color (); - } + /* Skip the restore when it would be a no-op, i.e., + when left is "\033[" and right is "m". */ + if (!(color_indicator[C_LEFT].len == 2 + && memcmp (color_indicator[C_LEFT].string, "\033[", 2) == 0 + && color_indicator[C_RIGHT].len == 1 + && color_indicator[C_RIGHT].string[0] == 'm')) + restore_default_color (); + fflush (stdout); - /* Restore the default signal handling. */ -#if SA_NOCLDSTOP - for (j = 0; j < nsigs; j++) - if (sigismember (&caught_signals, sig[j])) - signal (sig[j], SIG_DFL); -#else - for (j = 0; j < nsigs; j++) - if (caught_sig[j]) - signal (sig[j], SIG_DFL); -#endif + signal_restore (); /* Act on any signals that arrived before the default was restored. This can process signals out of order, but there doesn't seem to @@ -4512,6 +4529,14 @@ put_indicator (const struct bin_str *ind) if (! used_color) { used_color = true; + + /* If the standard output is a controlling terminal, watch out + for signals, so that the colors can be restored to the + default state if "ls" is suspended or interrupted. */ + + if (0 <= tcgetpgrp (STDOUT_FILENO)) + signal_init (); + prep_non_filename_text (); } -- 2.13.5