Avoid stdio in SIGINT handler

* admin/merge-gnulib (GNULIB_MODULES): Add ignore-value.
* lib/gnulib.mk, m4/gnulib-comp.m4: Regenerate.
* lib/ignore-value.h: New file, from gnulib.
* src/keyboard.c: Include it.
(write_stdout, read_stdin): New functions.
(handle_interrupt): Use them instead of printf and getchar,
and avoid fflush when handling signals.
This commit is contained in:
Paul Eggert 2016-01-03 15:00:49 -08:00
parent 861022ff5f
commit e79b06e6de
5 changed files with 108 additions and 28 deletions

View file

@ -32,7 +32,7 @@ GNULIB_MODULES='
dtoastr dtotimespec dup2 environ execinfo faccessat dtoastr dtotimespec dup2 environ execinfo faccessat
fcntl fcntl-h fdatasync fdopendir filemode fstatat fsync fcntl fcntl-h fdatasync fdopendir filemode fstatat fsync
getloadavg getopt-gnu gettime gettimeofday gitlog-to-changelog getloadavg getopt-gnu gettime gettimeofday gitlog-to-changelog
intprops largefile lstat ignore-value intprops largefile lstat
manywarnings memrchr mkostemp mktime manywarnings memrchr mkostemp mktime
pipe2 pselect pthread_sigmask putenv qcopy-acl readlink readlinkat pipe2 pselect pthread_sigmask putenv qcopy-acl readlink readlinkat
sig2str socklen stat-time stdalign stddef stdio sig2str socklen stat-time stdalign stddef stdio

View file

@ -21,7 +21,7 @@
# the same distribution terms as the rest of that program. # the same distribution terms as the rest of that program.
# #
# Generated by gnulib-tool. # Generated by gnulib-tool.
# Reproduce by: gnulib-tool --import --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --avoid=close --avoid=dup --avoid=fchdir --avoid=flexmember --avoid=fstat --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow --avoid=open --avoid=openat-die --avoid=opendir --avoid=raise --avoid=save-cwd --avoid=select --avoid=setenv --avoid=sigprocmask --avoid=stdarg --avoid=stdbool --avoid=threadlib --avoid=unsetenv --makefile-name=gnulib.mk --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt binary-io byteswap c-ctype c-strcase careadlinkat close-stream count-one-bits count-trailing-zeros crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 dtoastr dtotimespec dup2 environ execinfo faccessat fcntl fcntl-h fdatasync fdopendir filemode fstatat fsync getloadavg getopt-gnu gettime gettimeofday gitlog-to-changelog intprops largefile lstat manywarnings memrchr mkostemp mktime pipe2 pselect pthread_sigmask putenv qcopy-acl readlink readlinkat sig2str socklen stat-time stdalign stddef stdio stpcpy strftime strtoimax strtoumax symlink sys_stat sys_time time time_r time_rz timegm timer-time timespec-add timespec-sub unsetenv update-copyright utimens vla warnings # Reproduce by: gnulib-tool --import --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --avoid=close --avoid=dup --avoid=fchdir --avoid=flexmember --avoid=fstat --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow --avoid=open --avoid=openat-die --avoid=opendir --avoid=raise --avoid=save-cwd --avoid=select --avoid=setenv --avoid=sigprocmask --avoid=stdarg --avoid=stdbool --avoid=threadlib --avoid=unsetenv --makefile-name=gnulib.mk --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt binary-io byteswap c-ctype c-strcase careadlinkat close-stream count-one-bits count-trailing-zeros crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 dtoastr dtotimespec dup2 environ execinfo faccessat fcntl fcntl-h fdatasync fdopendir filemode fstatat fsync getloadavg getopt-gnu gettime gettimeofday gitlog-to-changelog ignore-value intprops largefile lstat manywarnings memrchr mkostemp mktime pipe2 pselect pthread_sigmask putenv qcopy-acl readlink readlinkat sig2str socklen stat-time stdalign stddef stdio stpcpy strftime strtoimax strtoumax symlink sys_stat sys_time time time_r time_rz timegm timer-time timespec-add timespec-sub unsetenv update-copyright utimens vla warnings
MOSTLYCLEANFILES += core *.stackdump MOSTLYCLEANFILES += core *.stackdump
@ -567,6 +567,13 @@ EXTRA_libgnu_a_SOURCES += group-member.c
## end gnulib module group-member ## end gnulib module group-member
## begin gnulib module ignore-value
EXTRA_DIST += ignore-value.h
## end gnulib module ignore-value
## begin gnulib module intprops ## begin gnulib module intprops

50
lib/ignore-value.h Normal file
View file

@ -0,0 +1,50 @@
/* ignore a function return without a compiler warning. -*- coding: utf-8 -*-
Copyright (C) 2008-2016 Free Software Foundation, Inc.
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
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* Written by Jim Meyering, Eric Blake and Pádraig Brady. */
/* Use "ignore_value" to avoid a warning when using a function declared with
gcc's warn_unused_result attribute, but for which you really do want to
ignore the result. Traditionally, people have used a "(void)" cast to
indicate that a function's return value is deliberately unused. However,
if the function is declared with __attribute__((warn_unused_result)),
gcc issues a warning even with the cast.
Caution: most of the time, you really should heed gcc's warning, and
check the return value. However, in those exceptional cases in which
you're sure you know what you're doing, use this function.
For the record, here's one of the ignorable warnings:
"copy.c:233: warning: ignoring return value of 'fchown',
declared with attribute warn_unused_result". */
#ifndef _GL_IGNORE_VALUE_H
#define _GL_IGNORE_VALUE_H
/* Normally casting an expression to void discards its value, but GCC
versions 3.4 and newer have __attribute__ ((__warn_unused_result__))
which may cause unwanted diagnostics in that case. Use __typeof__
and __extension__ to work around the problem, if the workaround is
known to be needed. */
#if 3 < __GNUC__ + (4 <= __GNUC_MINOR__)
# define ignore_value(x) \
(__extension__ ({ __typeof__ (x) __x = (x); (void) __x; }))
#else
# define ignore_value(x) ((void) (x))
#endif
#endif

View file

@ -91,6 +91,7 @@ AC_DEFUN([gl_EARLY],
# Code from module gettimeofday: # Code from module gettimeofday:
# Code from module gitlog-to-changelog: # Code from module gitlog-to-changelog:
# Code from module group-member: # Code from module group-member:
# Code from module ignore-value:
# Code from module include_next: # Code from module include_next:
# Code from module intprops: # Code from module intprops:
# Code from module inttypes-incomplete: # Code from module inttypes-incomplete:
@ -905,6 +906,7 @@ AC_DEFUN([gl_FILE_LIST], [
lib/gettimeofday.c lib/gettimeofday.c
lib/gl_openssl.h lib/gl_openssl.h
lib/group-member.c lib/group-member.c
lib/ignore-value.h
lib/intprops.h lib/intprops.h
lib/inttypes.in.h lib/inttypes.in.h
lib/lstat.c lib/lstat.c

View file

@ -64,6 +64,8 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
#include <ignore-value.h>
#ifdef HAVE_WINDOW_SYSTEM #ifdef HAVE_WINDOW_SYSTEM
#include TERM_HEADER #include TERM_HEADER
#endif /* HAVE_WINDOW_SYSTEM */ #endif /* HAVE_WINDOW_SYSTEM */
@ -10206,6 +10208,21 @@ deliver_interrupt_signal (int sig)
deliver_process_signal (sig, handle_interrupt_signal); deliver_process_signal (sig, handle_interrupt_signal);
} }
/* Output MSG directly to standard output, without buffering. Ignore
failures. This is safe in a signal handler. */
static void
write_stdout (char const *msg)
{
ignore_value (write (STDOUT_FILENO, msg, strlen (msg)));
}
/* Read a byte from stdin, without buffering. Safe in signal handlers. */
static int
read_stdin (void)
{
char c;
return read (STDIN_FILENO, &c, 1) == 1 ? c : EOF;
}
/* If Emacs is stuck because `inhibit-quit' is true, then keep track /* If Emacs is stuck because `inhibit-quit' is true, then keep track
of the number of times C-g has been requested. If C-g is pressed of the number of times C-g has been requested. If C-g is pressed
@ -10242,9 +10259,9 @@ handle_interrupt (bool in_signal_handler)
sigemptyset (&blocked); sigemptyset (&blocked);
sigaddset (&blocked, SIGINT); sigaddset (&blocked, SIGINT);
pthread_sigmask (SIG_BLOCK, &blocked, 0); pthread_sigmask (SIG_BLOCK, &blocked, 0);
fflush (stdout);
} }
fflush (stdout);
reset_all_sys_modes (); reset_all_sys_modes ();
#ifdef SIGTSTP #ifdef SIGTSTP
@ -10260,8 +10277,9 @@ handle_interrupt (bool in_signal_handler)
/* Perhaps should really fork an inferior shell? /* Perhaps should really fork an inferior shell?
But that would not provide any way to get back But that would not provide any way to get back
to the original shell, ever. */ to the original shell, ever. */
printf ("No support for stopping a process on this operating system;\n"); write_stdout ("No support for stopping a process"
printf ("you can continue or abort.\n"); " on this operating system;\n"
"you can continue or abort.\n");
#endif /* not SIGTSTP */ #endif /* not SIGTSTP */
#ifdef MSDOS #ifdef MSDOS
/* We must remain inside the screen area when the internal terminal /* We must remain inside the screen area when the internal terminal
@ -10272,46 +10290,49 @@ handle_interrupt (bool in_signal_handler)
the code used for auto-saving doesn't cope with the mark bit. */ the code used for auto-saving doesn't cope with the mark bit. */
if (!gc_in_progress) if (!gc_in_progress)
{ {
printf ("Auto-save? (y or n) "); write_stdout ("Auto-save? (y or n) ");
fflush (stdout); c = read_stdin ();
if (((c = getchar ()) & ~040) == 'Y') if ((c & 040) == 'Y')
{ {
Fdo_auto_save (Qt, Qnil); Fdo_auto_save (Qt, Qnil);
#ifdef MSDOS #ifdef MSDOS
printf ("\r\nAuto-save done"); write_stdout ("\r\nAuto-save done");
#else /* not MSDOS */ #else
printf ("Auto-save done\n"); write_stdout ("Auto-save done\n");
#endif /* not MSDOS */ #endif
} }
while (c != '\n') c = getchar (); while (c != '\n')
c = read_stdin ();
} }
else else
{ {
/* During GC, it must be safe to reenable quitting again. */ /* During GC, it must be safe to reenable quitting again. */
Vinhibit_quit = Qnil; Vinhibit_quit = Qnil;
write_stdout
(
#ifdef MSDOS #ifdef MSDOS
printf ("\r\n"); "\r\n"
#endif /* not MSDOS */ #endif
printf ("Garbage collection in progress; cannot auto-save now\r\n"); "Garbage collection in progress; cannot auto-save now\r\n"
printf ("but will instead do a real quit after garbage collection ends\r\n"); "but will instead do a real quit"
fflush (stdout); " after garbage collection ends\r\n");
} }
#ifdef MSDOS #ifdef MSDOS
printf ("\r\nAbort? (y or n) "); write_stdout ("\r\nAbort? (y or n) ");
#else /* not MSDOS */ #else
printf ("Abort (and dump core)? (y or n) "); write_stdout ("Abort (and dump core)? (y or n) ");
#endif /* not MSDOS */ #endif
fflush (stdout); c = read_stdin ();
if (((c = getchar ()) & ~040) == 'Y') if ((c & ~040) == 'Y')
emacs_abort (); emacs_abort ();
while (c != '\n') c = getchar (); while (c != '\n')
c = read_stdin ();
#ifdef MSDOS #ifdef MSDOS
printf ("\r\nContinuing...\r\n"); write_stdout ("\r\nContinuing...\r\n");
#else /* not MSDOS */ #else /* not MSDOS */
printf ("Continuing...\n"); write_stdout ("Continuing...\n");
#endif /* not MSDOS */ #endif /* not MSDOS */
fflush (stdout);
init_all_sys_modes (); init_all_sys_modes ();
} }
else else