On 8/23/2022 4:37 AM, Eli Zaretskii wrote: >> Cc: larsi@gnus.org, emacs-devel@gnu.org >> From: Jim Porter >> Date: Mon, 22 Aug 2022 20:53:47 -0700 >> >> If Eshell tries to write to a process object and it fails, it gets >> treated as a broken pipe. Technically, it signals 'eshell-pipe-broken', >> but that's roughly equivalent to SIGPIPE. This is mainly so that in a >> pipeline like "foo | bar", if "bar" terminates, Eshell can inform "foo" >> of the fact; on POSIX systems, it would send SIGPIPE, but on MS Windows, >> it just calls 'delete-process'. This is important because we want to be >> sure that if you have a pipeline like "yes | head", the "yes" gets >> stopped once "head" is done. > > So you basically assume that _any_ problem in the pipe was due to > SIGPIPE? That could be too optimistic: it could be due to something > much more mundane and unrelated. (Technically Eshell assumes that any error raised from 'process-send-string' should *break* the pipe.) To be more cautious, we could say that we should only break the pipe if we get an error *and* the process we're writing to has terminated. See attached. >>> Not sure I understand completely what you are saying here, but AFAIR >>> writing to a closed pipe on MS-Windows will cause EINVAL errno. >> >> Indeed, it would be nice if we could force things so that an MS Windows >> program gets EINVAL for its WriteFile call, but because Eshell only >> interacts indirectly with the program's output, it's too late to do that >> by the time Eshell responds. > > I don't think I follow. When the write fails, we get an error and > propagate it all the way up to the caller. If we signal an error in a process filter, does Emacs inform the process that wrote that data of the error? My tests showed that it didn't, but maybe I was doing something wrong. The goal here is just to tell a process that the thing it's writing to is gone, and that it should give up. This is more complex than usual because of how many steps Eshell goes through: some process -> 'eshell-insertion-filter' process filter -> 'eshell-output-object' -> 'process-send-string' to another process Then, if 'process-send-string' signals an error, we need to relay that back to the original process somehow so that it stops (or possibly does something else appropriate). >>>> I could expand the comment to explain that this value is >>>> somewhat-arbitrary and just designed to match GNU/Linux. >>> >>> Yes, please. >> >> How does the attached look? > > Looks OK, but are you sure about the "128" part? shouldn't it be 256 > instead? And perhaps explain why you add 128 (or whatever). I think the idea is that it's setting the high bit of an unsigned 8-bit value. I'm sure that the final number (141) is right for GNU/Linux at least: $ yes | head; echo ${PIPESTATUS[0]} ${PIPESTATUS[1]} y ... 141 0 I tweaked the comment to explain this number in terms of "setting the high bit", which I hope should be clearer. >> Well, it depends on what we think users would expect. Currently, I don't >> think Eshell provides the necessary functionality to tell when the >> process "foo" fails (i.e. returns a non-zero exit status) in the >> pipeline "foo | bar". > > But we can do that, right? The information about the exit status is > available to the SIGCHLD handler or a similar interface. Yes, we could. Nothing in process.c would have to change to support this; it's just a limitation of how Eshell is programmed. In a pipeline like "yes | head", the 'eshell-last-command-status' of "yes" would be 141, but it would then get overwritten by "head"'s status (0). Eshell would need to track those in a list or something.