>From 7350126db02071f7a1dbf2406082c395f9d5073d Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Tue, 2 Jul 2019 23:44:12 -0700 Subject: [PATCH 3/4] Avoid interleaving stderr in most of Lisp-code Emacs * lisp/startup.el (command-line): * src/keyboard.c (Fcommand_error_default_function): * src/print.c (debug_print): Use line-buffered-debugging-output. * src/print.c (Fline_buffered_debugging_output): New function. (init_print_once): Define it. * src/sysdep.c (errstream): Now extern. --- doc/lispref/streams.texi | 15 +++++++++++++-- etc/NEWS | 6 ++++++ lisp/startup.el | 6 +++--- src/keyboard.c | 4 ++-- src/print.c | 21 +++++++++++++++++---- src/sysdep.c | 2 +- src/sysstdio.h | 1 + 7 files changed, 43 insertions(+), 12 deletions(-) diff --git a/doc/lispref/streams.texi b/doc/lispref/streams.texi index 600639f244..761c7d40f0 100644 --- a/doc/lispref/streams.texi +++ b/doc/lispref/streams.texi @@ -535,11 +535,21 @@ Output Streams @defun external-debugging-output character This function can be useful as an output stream when debugging. It writes @var{character} to the standard error stream. +It uses the system default buffering (either unbuffered or line-buffered). +@end defun + +@anchor{line-buffered-debugging-output} +@defun line-buffered-debugging-output character +This function can be useful as an output stream when debugging. +It writes @var{character} to the standard error stream. +It uses line buffering if available, as this works better than +unbuffered when processes other than Emacs are simultaneously writing +to the error stream. For example @example @group -(print "This is the output" #'external-debugging-output) +(print "This is the output" #'line-buffered-debugging-output) @print{} This is the output @result{} "This is the output" @end group @@ -587,7 +597,8 @@ Output Functions In the functions below, @var{stream} stands for an output stream. (See the previous section for a description of output streams. Also -@xref{external-debugging-output}, a useful stream value for debugging.) +@xref{external-debugging-output} and @xref{line-buffered-debugging-output}, +useful stream values for debugging.) If @var{stream} is @code{nil} or omitted, it defaults to the value of @code{standard-output}. diff --git a/etc/NEWS b/etc/NEWS index abbece374a..1dfec126ed 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -2031,6 +2031,12 @@ between two strings. ** 'print-quoted' now defaults to t, so if you want to see '(quote x)' instead of 'x you will have to bind it to nil where applicable. ++++ +** New function line-buffered-debugging-output which outputs to the +standard error stream using line-buffering than available. This works +better than external-debugging-output when processes other than Emacs +are simultaneously writing to the standard error stream. + +++ ** Numbers formatted via '%o' or '%x' are now formatted as signed integers. This avoids problems in calls like '(read (format "#x%x" -1))', and is diff --git a/lisp/startup.el b/lisp/startup.el index 7759ed5aed..977591c02a 100644 --- a/lisp/startup.el +++ b/lisp/startup.el @@ -1016,7 +1016,7 @@ command-line ;; Although in most usage we are going to cryptically abort a moment ;; later anyway, due to missing required bidi data files (eg bug#13430). (if (null simple-file-name) - (let ((standard-output 'external-debugging-output) + (let ((standard-output 'line-buffered-debugging-output) (lispdir (expand-file-name "../lisp" data-directory))) (princ "Warning: Could not find simple.el or simple.elc") (terpri) @@ -1244,8 +1244,8 @@ command-line (get (car error) 'error-message) (mapconcat (lambda (obj) (prin1-to-string obj t)) (cdr error) ", ")))) - 'external-debugging-output) - (terpri 'external-debugging-output) + 'line-buffered-debugging-output) + (terpri 'line-buffered-debugging-output) (setq initial-window-system nil) (kill-emacs))) diff --git a/src/keyboard.c b/src/keyboard.c index 56916e0cb4..c635372d15 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -1014,9 +1014,9 @@ DEFUN ("command-error-default-function", Fcommand_error_default_function, || (!IS_DAEMON && FRAME_INITIAL_P (sf)) || noninteractive) { - print_error_message (data, Qexternal_debugging_output, + print_error_message (data, Qline_buffered_debugging_output, SSDATA (context), signal); - Fterpri (Qexternal_debugging_output, Qnil); + Fterpri (Qline_buffered_debugging_output, Qnil); Fkill_emacs (make_fixnum (-1)); } else diff --git a/src/print.c b/src/print.c index df45cb27ce..012c535644 100644 --- a/src/print.c +++ b/src/print.c @@ -771,7 +771,7 @@ DEFUN ("print", Fprint, Sprint, 1, 2, 0, } DEFUN ("external-debugging-output", Fexternal_debugging_output, Sexternal_debugging_output, 1, 1, 0, - doc: /* Write CHARACTER to stderr. + doc: /* Write CHARACTER to stderr using system-dependent buffering. You can call `print' while debugging emacs, and pass it this function to make it write to the debugging output. */) (Lisp_Object character) @@ -781,6 +781,18 @@ DEFUN ("external-debugging-output", Fexternal_debugging_output, Sexternal_debugg return character; } +DEFUN ("line-buffered-debugging-output", Fline_buffered_debugging_output, + Sline_buffered_debugging_output, 1, 1, 0, + doc: /* Write CHARACTER to stderr using line-buffering if possible. +You can call `print' while debugging emacs, and pass it this function +to make it write to the debugging output. */) + (Lisp_Object character) +{ + CHECK_FIXNUM (character); + printchar_to_stream (XFIXNUM (character), errstream ()); + return character; +} + /* This function is never called. Its purpose is to prevent print_output_debug_flag from being optimized away. */ @@ -839,7 +851,7 @@ DEFUN ("redirect-debugging-output", Fredirect_debugging_output, Sredirect_debugg void debug_print (Lisp_Object arg) { - Fprin1 (arg, Qexternal_debugging_output); + Fprin1 (arg, Qline_buffered_debugging_output); errputs ("\r\n"); } @@ -2206,11 +2218,12 @@ print_interval (INTERVAL interval, Lisp_Object printcharfun) void init_print_once (void) { - /* The subroutine object for external-debugging-output is kept here - for the convenience of the debugger. */ + /* These subroutine objects are kept here for debugger convenience. */ DEFSYM (Qexternal_debugging_output, "external-debugging-output"); + DEFSYM (Qline_buffered_debugging_output, "line-buffered-debugging-output"); defsubr (&Sexternal_debugging_output); + defsubr (&Sline_buffered_debugging_output); } void diff --git a/src/sysdep.c b/src/sysdep.c index 2bd7f1afd2..cf7699d43e 100644 --- a/src/sysdep.c +++ b/src/sysdep.c @@ -2784,7 +2784,7 @@ safe_strsignal (int code) /* Return the error output stream. */ -static FILE * +FILE * errstream (void) { FILE *err = buferr; diff --git a/src/sysstdio.h b/src/sysstdio.h index 87568c86fd..966a5abd7f 100644 --- a/src/sysstdio.h +++ b/src/sysstdio.h @@ -25,6 +25,7 @@ #define EMACS_SYSSTDIO_H extern FILE *emacs_fopen (char const *, char const *); +extern FILE *errstream (void); extern void errputc (int); extern void errputs (char const *); extern void errprintf (char const *, ...) ATTRIBUTE_FORMAT_PRINTF (1, 2); -- 2.21.0