emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] master a8ffbb2 1/4: Avoid interleaving stderr in a few cas


From: Paul Eggert
Subject: [Emacs-diffs] master a8ffbb2 1/4: Avoid interleaving stderr in a few cases
Date: Sat, 13 Jul 2019 19:53:27 -0400 (EDT)

branch: master
commit a8ffbb20da67b20a85ddca38e20c609144c3bef3
Author: Paul Eggert <address@hidden>
Commit: Paul Eggert <address@hidden>

    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.
---
 src/sysdep.c   | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 src/sysstdio.h |  3 +++
 src/xdisp.c    | 19 ++++---------------
 3 files changed, 63 insertions(+), 18 deletions(-)

diff --git a/src/sysdep.c b/src/sysdep.c
index 99d3ee6..4c3d546 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 68ae043..5303e8a 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 7f0d577..50f6443 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.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]