Subject: Re: bug#56025: 29.0.50; em-extpipe-test-2 times out on EMBA and Cygwin

From: Jim Porter <[email-masked]>
Date: Sat, 25 Jun 2022 09:13:46 -0700

On 6/24/2022 10:34 PM, Eli Zaretskii wrote:
>> Cc: [email-masked], [email-masked]
>> From: Jim Porter <[email-masked]>
>> Date: Fri, 24 Jun 2022 16:03:13 -0700
>>
>> POSIX standard says[1] (thanks to Eliot Moss on the Cygwin mailing list
>> for citing this passage):
>>
>>     When [EOF is] received, all the bytes waiting to be read are
>>     immediately passed to the process without waiting for a <newline>, and
>>     the EOF is discarded. Thus, if there are no bytes waiting (that is,
>>     the EOF occurred at the beginning of a line), a byte count of zero
>>     shall be returned from the read(), representing an end-of-file
>>     indication.
> 
> Perhaps some reference to this should also be in the comments.

How about this patch? I added a reference to the specific section of the 
POSIX specification so that it's (hopefully) easy for people to look up 
if they need further details.
From 8664e6f3dc9e40d1fae8a44dc4c444ab40510a18 Mon Sep 17 00:00:00 2001
From: Jim Porter <[email-masked]>
Date: Fri, 24 Jun 2022 09:14:38 -0700
Subject: [PATCH] When closing an Eshell process target, send EOF three times

* lisp/eshell/esh-io.el (eshell-close-target): Send EOF 3 times.

* test/lisp/eshell/em-extpipe-tests.el (em-extpipe-tests--deftest):
Re-enable these tests on EMBA.

This patch is adapted by one from Ken Brown, who uncovered the reason
for this bug (bug#56025).
---
 lisp/eshell/esh-io.el                | 16 ++++++++++++++--
 test/lisp/eshell/em-extpipe-tests.el |  1 -
 2 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/lisp/eshell/esh-io.el b/lisp/eshell/esh-io.el
index 3644c1a18b..c035890ddf 100644
--- a/lisp/eshell/esh-io.el
+++ b/lisp/eshell/esh-io.el
@@ -276,8 +276,20 @@ eshell-close-target
    ;; If we're redirecting to a process (via a pipe, or process
    ;; redirection), send it EOF so that it knows we're finished.
    ((eshell-processp target)
-    (if (eq (process-status target) 'run)
-	(process-send-eof target)))
+    ;; According to POSIX.1-2017, section 11.1.9, sending EOF causes
+    ;; all bytes waiting to be read to be sent to the process
+    ;; immediately.  Thus, if there are any bytes waiting, we need to
+    ;; send EOF twice: once to flush the buffer, and a second time to
+    ;; cause the next read() to return a size of 0, indicating
+    ;; end-of-file to the reading process.  However, some platforms
+    ;; (e.g. Solaris) actually require sending a *third* EOF.  Since
+    ;; sending extra EOFs while the process is running shouldn't break
+    ;; anything, we'll just send the maximum we'd ever need.  See
+    ;; bug#56025 for further details.
+    (let ((i 0))
+      (while (and (<= (cl-incf i) 3)
+                  (eq (process-status target) 'run))
+        (process-send-eof target))))
 
    ;; A plain function redirection needs no additional arguments
    ;; passed.
diff --git a/test/lisp/eshell/em-extpipe-tests.el b/test/lisp/eshell/em-extpipe-tests.el
index 3b84d763ac..29f5dc0551 100644
--- a/test/lisp/eshell/em-extpipe-tests.el
+++ b/test/lisp/eshell/em-extpipe-tests.el
@@ -71,7 +71,6 @@ em-extpipe-tests--deftest
        (skip-unless shell-file-name)
        (skip-unless shell-command-switch)
        (skip-unless (executable-find shell-file-name))
-       (skip-unless (not (getenv "EMACS_EMBA_CI")))
        (let ((input ,input))
          (with-temp-eshell ,@body)))))
 
-- 
2.25.1