1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-28 00:01:33 -08:00

Avoid interleaving stderr in a few cases

* src/sysdep.c (buferr): New static var.
(init_standard_fds) [_PC_PIPE_BUF]: Initialize it.
(errstream, errputc, verrprintf, errwrite): New functions.
(close_output_streams): Check buferr status too.
* src/xdisp.c: Include sysstdio.h instead of stdio.h.
(message_to_stderr, vmessage): Use the new functions
to avoid interleaving stderr.
This commit is contained in:
Paul Eggert 2019-07-13 09:39:09 -07:00
parent 3767628dc5
commit a8ffbb20da
3 changed files with 63 additions and 18 deletions

View file

@ -232,6 +232,10 @@ force_open (int fd, int flags)
}
}
/* A stream that is like stderr, except line buffered. It is NULL
during startup, or if line buffering is not in use. */
static FILE *buferr;
/* Make sure stdin, stdout, and stderr are open to something, so that
their file descriptors are not hijacked by later system calls. */
void
@ -244,6 +248,14 @@ init_standard_fds (void)
force_open (STDIN_FILENO, O_WRONLY);
force_open (STDOUT_FILENO, O_RDONLY);
force_open (STDERR_FILENO, O_RDONLY);
/* Set buferr if possible on platforms defining _PC_PIPE_BUF, as
they support the notion of atomic writes to pipes. */
#ifdef _PC_PIPE_BUF
buferr = fdopen (STDERR_FILENO, "w");
if (buferr)
setvbuf (buferr, NULL, _IOLBF, 0);
#endif
}
/* Return the current working directory. The result should be freed
@ -2769,6 +2781,46 @@ safe_strsignal (int code)
return signame;
}
/* Output to stderr. */
/* Return the error output stream. */
static FILE *
errstream (void)
{
FILE *err = buferr;
if (!err)
return stderr;
fflush_unlocked (stderr);
return err;
}
/* These functions are like fputc, vfprintf, and fwrite,
except that they output to stderr and buffer better on
platforms that support line buffering. This avoids interleaving
output when Emacs and other processes write to stderr
simultaneously, so long as the lines are short enough. When a
single diagnostic is emitted via a sequence of calls of one or more
of these functions, the caller should arrange for the last called
function to output a newline at the end. */
void
errputc (int c)
{
fputc_unlocked (c, errstream ());
}
void
verrprintf (char const *fmt, va_list ap)
{
vfprintf (errstream (), fmt, ap);
}
void
errwrite (void const *buf, ptrdiff_t nbuf)
{
fwrite_unlocked (buf, 1, nbuf, errstream ());
}
/* Close standard output and standard error, reporting any write
errors as best we can. This is intended for use with atexit. */
void
@ -2782,9 +2834,10 @@ close_output_streams (void)
/* Do not close stderr if addresses are being sanitized, as the
sanitizer might report to stderr after this function is invoked. */
if (ADDRESS_SANITIZER
? fflush (stderr) != 0 || ferror (stderr)
: close_stream (stderr) != 0)
bool err = buferr && (fflush (buferr) != 0 || ferror (buferr));
if (err | (ADDRESS_SANITIZER
? fflush (stderr) != 0 || ferror (stderr)
: close_stream (stderr) != 0))
_exit (EXIT_FAILURE);
}

View file

@ -25,6 +25,9 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include "unlocked-io.h"
extern FILE *emacs_fopen (char const *, char const *);
extern void errputc (int);
extern void verrprintf (char const *, va_list) ATTRIBUTE_FORMAT_PRINTF (1, 0);
extern void errwrite (void const *, ptrdiff_t);
extern void close_output_streams (void);
#if O_BINARY

View file

@ -10714,7 +10714,7 @@ message_to_stderr (Lisp_Object m)
if (noninteractive_need_newline)
{
noninteractive_need_newline = false;
putc ('\n', stderr);
errputc ('\n');
}
if (STRINGP (m))
{
@ -10728,21 +10728,10 @@ message_to_stderr (Lisp_Object m)
else
s = m;
/* We want to write this out with a single call so that
output doesn't interleave with other processes writing to
stderr at the same time. */
{
int length = min (INT_MAX, SBYTES (s) + 1);
char *string = xmalloc (length);
memcpy (string, SSDATA (s), length - 1);
string[length - 1] = '\n';
fwrite (string, 1, length, stderr);
xfree (string);
}
errwrite (SDATA (s), SBYTES (s));
}
else if (!cursor_in_echo_area)
putc ('\n', stderr);
if (STRINGP (m) || !cursor_in_echo_area)
errputc ('\n');
}
/* The non-logging version of message3.