unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
From: Jim Porter <jporterbugs@gmail.com>
To: Eli Zaretskii <eliz@gnu.org>
Cc: 54062@debbugs.gnu.org
Subject: bug#54062: 29.0.50; [PATCH] Eshell should inform processes when a pipe is broken
Date: Sat, 19 Feb 2022 12:02:45 -0800	[thread overview]
Message-ID: <b7580ab3-7dd5-fa60-e017-56d84ab04408@gmail.com> (raw)
In-Reply-To: <83mtinz222.fsf@gnu.org>

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

On 2/19/2022 12:35 AM, Eli Zaretskii wrote:
>> From: Jim Porter <jporterbugs@gmail.com>
>> Date: Fri, 18 Feb 2022 20:20:10 -0800
>>
>> Consider the following shell command:
>>
>>     yes | sh -c 'read NAME'
>>
>> Ordinarily, you'd expect that `sh' reads a single "y", exits, and then
>> the next time `yes' tries to write, it finds that the pipe was broken.
>> However, that's not what happens in Eshell. Running the above and then
>> calling `M-x list-processes' will show that `yes' is still running.
>>
>> Attached is a patch (with a test) to fix this by telling Eshell to
>> signal SIGPIPE at the appropriate time.
> 
> SIGPIPE isn't supported on MS-Windows, so I think we should have a
> fallback there for platforms that don't support SIGPIPE.

Hmm, good point. Thinking about this some more, this also won't work for 
Tramp (which only supports `interrupt-process' as far as I can tell). I 
can think of a couple possible solutions.

One option would be to call `interrupt-process' instead, since that 
works in all cases I'm aware of. This isn't quite as nice as sending 
SIGPIPE (or equivalent) to let the process handle it how it wants, but 
at least `interrupt-process' has the same default behavior as SIGPIPE 
(i.e. terminate the process).

Another way would be to add a function like `process-break-pipe' (it 
could probably use a better name) that would close the read end of the 
process's output pipe, which - if I understand the Win32 API here - 
should trigger the right behavior on MS Windows too. It should work for 
Tramp too, although Tramp might need a bit of tweaking to handle this 
case. I've attached an outline of what this could look like; it applies 
on top of my previous patches.

One caveat is that the head process (`yes' in the example), would only 
see the "broken pipe" error on the *next* write after the one where 
Eshell detected the broken pipe. That's easy enough to fix for cases 
where we can signal SIGPIPE directly, but it's probably ok in general 
too: after all, processes don't generally know exactly when a SIGPIPE 
might occur, so it occurring slightly later shouldn't cause problems. 
(In theory, the tail process should call `process-break-pipe' as soon as 
it closes, but in Eshell, the tail process doesn't know what's feeding 
it input, so it can't easily do this.)

What do you think? Is this a sensible avenue to go down? There's 
probably room to discuss what the API should look like, but I wanted to 
be sure I was on the right track before I went too far.

[-- Attachment #2: process-break-pipe.patch --]
[-- Type: text/plain, Size: 1844 bytes --]

diff --git a/lisp/eshell/esh-proc.el b/lisp/eshell/esh-proc.el
index 86ae69978f..b833657c46 100644
--- a/lisp/eshell/esh-proc.el
+++ b/lisp/eshell/esh-proc.el
@@ -389,7 +389,12 @@ eshell-insertion-filter
                 (unwind-protect
                     (condition-case nil
                         (eshell-output-object data nil (cadr entry))
-                      (eshell-pipe-broken (signal-process proc 'SIGPIPE)))
+                      (eshell-pipe-broken
+                       ;; Note: this will trigger a broken pipe error
+                       ;; for the process the *next* time it tries to
+                       ;; write.  We could also opportunistically send
+                       ;; SIGPIPE here to notify the process sooner.
+                       (process-break-pipe proc)))
                   (setcar (nthcdr 4 entry) nil))))))))))
 
 (defun eshell-sentinel (proc string)
diff --git a/src/process.c b/src/process.c
index 94cc880097..12cd395cf3 100644
--- a/src/process.c
+++ b/src/process.c
@@ -2297,6 +2297,16 @@ create_pty (Lisp_Object process)
   p->pid = -2;
 }
 
+DEFUN ("process-break-pipe", Fprocess_break_up, Sprocess_break_pipe,
+       1, 1, 0,
+       doc: /* Close the read end of the process's output pipe. */)
+  (register Lisp_Object process)
+{
+  CHECK_PROCESS (process);
+  close_process_fd (&XPROCESS (process)->open_fd[READ_FROM_SUBPROCESS]);
+  return Qnil;
+}
+
 DEFUN ("make-pipe-process", Fmake_pipe_process, Smake_pipe_process,
        0, MANY, 0,
        doc: /* Create and return a bidirectional pipe process.
@@ -8615,6 +8625,7 @@ syms_of_process (void)
   defsubr (&Sset_process_buffer);
   defsubr (&Sprocess_buffer);
   defsubr (&Sprocess_mark);
+  defsubr (&Sprocess_break_pipe);
   defsubr (&Sset_process_filter);
   defsubr (&Sprocess_filter);
   defsubr (&Sset_process_sentinel);

  reply	other threads:[~2022-02-19 20:02 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-02-19  4:20 bug#54062: 29.0.50; [PATCH] Eshell should inform processes when a pipe is broken Jim Porter
2022-02-19  8:35 ` Eli Zaretskii
2022-02-19 20:02   ` Jim Porter [this message]
2022-02-19 20:19     ` Eli Zaretskii
2022-02-19 21:18       ` Jim Porter
2022-02-20  7:27         ` Eli Zaretskii
2022-02-20 20:17           ` Jim Porter
2022-02-21 17:15             ` Eli Zaretskii
2022-02-21 17:39               ` Lars Ingebrigtsen
2022-02-21 18:31                 ` Eli Zaretskii
2022-02-21 20:37                   ` Jim Porter
2022-02-22 13:09                     ` Eli Zaretskii
2022-02-22 16:49                       ` Jim Porter
2022-02-23 12:14                         ` Lars Ingebrigtsen
2022-02-24  5:20                           ` Jim Porter

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=b7580ab3-7dd5-fa60-e017-56d84ab04408@gmail.com \
    --to=jporterbugs@gmail.com \
    --cc=54062@debbugs.gnu.org \
    --cc=eliz@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).