unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
From: Ioannis Kappas <ioannis.kappas@gmail.com>
To: 46388@debbugs.gnu.org
Subject: bug#46388: 27.1; emacs -batch does not output messages immediately when invoked outside of the command prompt
Date: Mon, 8 Feb 2021 21:42:09 +0000	[thread overview]
Message-ID: <CAMRHuGDC-XAznW-0YtpnCncFkxBRywx-jDgZ2eQf8UNdebR8Og@mail.gmail.com> (raw)
In-Reply-To: <CAMRHuGB-z+uiS7F71vaLU2L8X-W9BAwUH0+aSDvGz7HmBYmnqQ@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 3381 bytes --]

Some analysis follows

    Looking at the code, it appears that /message/s in -batch mode are
    delivered to the process' standard error by the
    [editfnc.c:message()]
      ->[xdisp.c:message3_nolog()]
        ->[xdispl.c:message_to_stderr()]
    function, i.e. messages are written to stderr. The latter function
    uses the standard fwrite and fputc calls to deliver the message to
    stderr.

    The buffering regime used for stderror on windows appears to be different
    depending whether a program was started from the command prompt or
    not. When started from the command prompt stderr is
    unbuffered, while there is a buffer employed otherwise and output
    is only delivered when that buffer is full.

    Below is a sample C program that can demonstrate the behaviour,
    which writes a single character to the standard output and then
exits after 2 seconds:

      #include <stdio.h>
      #include <unistd.h>
      #include <windows.h>

      int main()
      {

fwrite("t", 1, sizeof("t"), stderr);

sleep(2);

return 0;
      }


    | case | invoked from           | result
         |
    |------+------------------------+-------------------------------------------|
    |  1   | command prompt         | prints "t", then after 2 seconds exits |
    |  2   | outside command prompt | after about 2 seconds prints
"t", then exits |

    It appears that the buffer size used in #2 is 2048 bytes (i.e. the
    message is only immediately displayed when is more than 2048 bytes long).

    A solution thus to correct this behavior in emacs -batch on
    windows-nt would be to check if it is connected to the console,
    and when not, set stderr mode to unbuffered.

    A) Likely the win32 api provide GetConsoleMode() that can be used to
    check if a standard HANDLE is attached to the console. Given the
    STD_ERROR_HANDLE as an argument, it will  return non-zero if is
    attached to the console or a 0 otherwise, setting GetLastError()
to "The handle is
    invalid" message.

    B) To set stderr to an unbuffered mode, we can use standard C's
    setvbuf() with _IONBF (no buffering).

    C) The location where the descriptors are prepared for use in emacs
    appear to be at w32.c:init_ntproc().

    If the above analysis is correct, here is an example patch that
puts A/B/C together:

--- a/src/w32.c
+++ b/src/w32.c
@@ -10216,6 +10216,19 @@ init_ntproc (int dumping)
     else
       _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
     _fdopen (2, "w");
+
+    /* When in -batch mode, windows appears to buffer stderr when it
+       is invoked outside of the command prompt. This has the
+       undesired side effect that /message/s are not output unless the
+       buffer is full or emacs exits */
+    DWORD console_mode;
+    if (noninteractive &&
+ // stderr is not attached to the console
+ !GetConsoleMode (GetStdHandle(STD_ERROR_HANDLE), &console_mode))
+      {
+ // set stderr to unbuffered
+ setvbuf (stderr, NULL, _IONBF, 0);
+      }

  I have also attached an ert tests to capture the correct
  behavior. The test invokes an emacs -batch process which prints a
  /message/ and exits after five seconds. The test check immediately
  after two seconds if the batch process has output the message as
  expected. It can be invoked with:

: emacs.exe -batch -l ert -l batch-message-test.el -f
ert-run-tests-batch-and-exit

[-- Attachment #2: batch-message-test.el --]
[-- Type: application/octet-stream, Size: 1141 bytes --]

;;; -*- lexical-binding: t; -*-
(require 'ert)

(ert-deftest batch-message ()
  "Test that when invoking emacs in batch mode as a
subprocess (i.e. not directly from a terminal), /message/s are
flushed to output immediately. "
  (message ":system %s :version %s" system-configuration emacs-version)

  (with-temp-buffer 
    (let* ((proc-buf (current-buffer))

	   ;; start a new emacs process that will print a message,
	   ;; wait for five second and then exit.
	   (cmd (format "emacs -Q --batch --eval=\"%s\""
			'(progn (message \\\"hi\\\") 
				(sit-for 5))))
	   (proc (start-file-process-shell-command
                  "test/batch-message" proc-buf cmd))

	   (outputs '()))
      
      ;; capture emacs output
      (set-process-filter proc (lambda (proc output)
				 (push output outputs)))
      
      ;; wait for the process to start
      (sleep-for 2)
      (should (equal 'run (process-status proc)))
      ;; program should have printed out "hi\n"
      (should (equal '("hi\n") outputs))

      ;; kill process and wait for it to die
      (delete-process proc)
      (sleep-for 1))))


  reply	other threads:[~2021-02-08 21:42 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-02-08 21:20 bug#46388: 27.1; emacs -batch does not output messages immediately when invoked outside of the command prompt Ioannis Kappas
2021-02-08 21:42 ` Ioannis Kappas [this message]
2021-02-09  5:36   ` Eli Zaretskii
2021-02-09 20:15     ` Ioannis Kappas
2021-02-09 20:52       ` Eli Zaretskii
2021-02-09 21:14         ` Eli Zaretskii
     [not found]           ` <CAMRHuGC_p59uw_hmCL65Z0F1ZdFbVAf9MHcB-sX88bW6jchC-Q@mail.gmail.com>
2021-02-10 12:48             ` Ioannis Kappas
2021-02-10 15:57               ` Eli Zaretskii
2021-02-11  8:10                 ` Ioannis Kappas
2021-02-11 14:09                   ` Eli Zaretskii
2021-02-11 19:25                     ` Ioannis Kappas
2021-02-11 19:55                       ` Eli Zaretskii
2021-02-12 19:59                         ` Ioannis Kappas
2021-02-12 20:03                           ` Eli Zaretskii
2021-03-06 15:00                             ` Ioannis Kappas
2021-03-08  4:05                               ` Paul Eggert
2021-03-08  7:56                                 ` Ioannis Kappas
2021-03-11 14:27                                 ` Eli Zaretskii
2021-03-11 18:43                                   ` Paul Eggert
2021-02-11 21:15                     ` Paul Eggert
2021-02-09  3:38 ` Eli Zaretskii

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CAMRHuGDC-XAznW-0YtpnCncFkxBRywx-jDgZ2eQf8UNdebR8Og@mail.gmail.com \
    --to=ioannis.kappas@gmail.com \
    --cc=46388@debbugs.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).