Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stop admitting output from an interrupted process #131

Open
shouya opened this issue Oct 1, 2022 · 6 comments · Fixed by #139
Open

Stop admitting output from an interrupted process #131

shouya opened this issue Oct 1, 2022 · 6 comments · Fixed by #139

Comments

@shouya
Copy link

shouya commented Oct 1, 2022

Hi, I'm having a problem with elixir formatting.

So most Erlang-based programs, like mix format - the Elixir formatter, only prints a control message when the user sends an interrupt signal to the process, where the user is expected to press ^C again to really quit the program. The control message looks like the following:

$ iex
Erlang/OTP 24 [erts-12.1] [source] [64-bit] [smp:16:16] [ds:16:16:10] [async-threads:1] [jit]

Interactive Elixir (1.12.3) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)>
BREAK: (a)bort (A)bort with dump (c)ontinue (p)roc info (i)nfo
       (l)oaded (v)ersion (k)ill (D)b-tables (d)istribution
^C%
$

(In above demo, I pressed ^C for the first time after the prompt iex(1)> (not echoed), and the second time after the control message is printed)

I understand this style of interrupting output is atypical among unix programs. However, it doesn't play well with apheleia. What occurs to my workflow is that when I quickly modify+save multiple times in a succession, then at some point, it's likely apheleia would replace the whole buffer with following text and saved it in the file.

BREAK: (a)bort (A)bort with dump (c)ontinue (p)roc info (i)nfo
       (l)oaded (v)ersion (k)ill (D)b-tables (d)istribution

It is annoying because when that happens I have to undo the override and save again more slowly. Fortunately, I found a way to mitigate the situation by modifying the apheleia--make-process function:

@@ -305,7 +305,7 @@ purposes. FORMATTER is nil if the command being run does not
 correspond to a formatter."
   (when (process-live-p apheleia--current-process)
     (message "Interrupting %s" apheleia--current-process)
-    (interrupt-process apheleia--current-process)
+    (kill-process apheleia--current-process)
     (accept-process-output apheleia--current-process 0.1 nil 'just-this-one)
     (when (process-live-p apheleia--current-process)
       (kill-process apheleia--current-process)))

So I suppose the problem can be solved in one of two ways:

  1. stop accepting the output from an interrupted process
  2. simply kill the process instead of interrupting it in the first place

I'm modifying with the second method because it simply worked for me. However, I guess the first method may be more ideal without disrupting the typical flow for other nicely behaving formatters. However, I'm fairly new to emacs-lisp programming so I don't know how it should be done.

Could you provide me some help on the problem? Thanks.

@shouya shouya changed the title Stop admitting output from interrupted process Stop admitting output from an interrupted process Oct 1, 2022
@raxod502
Copy link
Member

raxod502 commented Oct 5, 2022

What is the exit status of the formatter when it is interrupted in this manner? I would assume that when the program is interrupted, it should exit with nonzero status, and any of its output should be ignored by Apheleia.

Is it possible that Apheleia is failing to deregister the process filter from the old process once it has been abandoned, and output from that old abandoned process still gets written to the same buffer that is used for the new process? I think that would explain the behavior you are seeing. Obviously, that would be a bug we should fix in Apheleia.

@shouya
Copy link
Author

shouya commented Oct 6, 2022

What is the exit status of the formatter when it is interrupted in this manner?

When mix format is interrupted once, it doesn't quit but rather printing the control message. If it's interrupted once again, the formatter exits with status 0.

Is it possible that Apheleia is failing to deregister the process filter from the old process once it has been abandoned, and output from that old abandoned process still gets written to the same buffer that is used for the new process?

Sorry I'm not familiar with process filtering in emacs, so I can't be certain that this is what happens. I'm glad to test the hypothesis if you can give me some testing steps to follow.

@raxod502
Copy link
Member

If it's interrupted once again, the formatter exits with status 0.

Ah, that's probably part of the problem. Normally if a program exits with status 0 it means all is well and execution completed successfully. So Apheleia is probably assuming that whatever was outputted is valid output.

However if Apheleia is interrupting the process, it should be ignoring the output even if the exit status is 0, so let me take a quick look and see if I can figure out what is going on.

@raxod502
Copy link
Member

Ok yeah, so I haven't put together a repro for the issue, so I haven't tested, but I believe #139 should fix this, give it a try. Basically, when Apheleia spawns a process, it sets a process sentinel as a callback that gets invoked with the exit status once the process exits. If the user invokes another formatting operation before the process is done, the existing one is aborted and the new one is started. However the existing process still exits (usually with nonzero exit status, due to the abort) and the callback is invoked with that exit status. So in the case that the exit status is (unusually) zero, the malformed output is interpreted as a valid formatting result. However, we know in the case of interrupting a formatting run that we don't actually want to use the result anyway. So before interrupting the process, we set an attribute on the process plist that tells the callback to ignore the results after termination.

raxod502 added a commit that referenced this issue Oct 25, 2022
@shouya
Copy link
Author

shouya commented Nov 12, 2022

Hi @raxod502, thanks for the fix. I've been using the fixed version for more than a week. So far the same problem still appears though probably less frequently. I can remember seeing it two to three times during my intensive use these days. So I suspect there may still be some edge case scenario or race condition.

@raxod502
Copy link
Member

Hmm, ok, will reopen to continue tracking that bit then.

@raxod502 raxod502 reopened this Nov 27, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging a pull request may close this issue.

2 participants