summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2019-07-13 09:39:09 -0700
committerPaul Eggert <eggert@cs.ucla.edu>2019-07-13 16:53:21 -0700
commita8ffbb20da67b20a85ddca38e20c609144c3bef3 (patch)
tree3ce64362d7d1a8b14f0a5ea4286ea6af27109de2 /src
parent3767628dc534e64cdc21bdff16d5dd4726feacd2 (diff)
downloademacs-a8ffbb20da67b20a85ddca38e20c609144c3bef3.tar.gz
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.
Diffstat (limited to 'src')
-rw-r--r--src/sysdep.c59
-rw-r--r--src/sysstdio.h3
-rw-r--r--src/xdisp.c19
3 files changed, 63 insertions, 18 deletions
diff --git a/src/sysdep.c b/src/sysdep.c
index 99d3ee60698..4c3d546962c 100644
--- a/src/sysdep.c
+++ b/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);
}
diff --git a/src/sysstdio.h b/src/sysstdio.h
index 68ae043fe33..5303e8a15b2 100644
--- a/src/sysstdio.h
+++ b/src/sysstdio.h
@@ -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
diff --git a/src/xdisp.c b/src/xdisp.c
index 7f0d577cebc..50f6443f6b2 100644
--- a/src/xdisp.c
+++ b/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.