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:
parent
3767628dc5
commit
a8ffbb20da
3 changed files with 63 additions and 18 deletions
59
src/sysdep.c
59
src/sysdep.c
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
19
src/xdisp.c
19
src/xdisp.c
|
|
@ -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.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue