Maximus5 / conemu-inside

An example, how to embed http://conemu.github.io/ into another graphical application
57 stars 42 forks source link

When ConEmu Process Is Killed, Console Is Detached Rather Than Killed #14

Closed hypersw closed 8 years ago

hypersw commented 8 years ago

The control has a function to kill the console emulator. What it does is actually kill the ConEmu process it has started. Expected behavior: the payload process is also killed within the console. Actual behavior: the payload process lives, a detached console window is shown which goes on running the process.

There were numerous complaints on this matter from GE users, as aborting a certain git command does not actually abort it as expected but goes on running in a detached window.

STR: winforms branch, run ConEmuInside.csproj output, the ControlShowcaseForm appears with cmd running. Press the Choice button, it kills the prev terminal and opens a new one. The prev cmd terminal would be running in a detached console window.

Maximus5 commented 8 years ago

Absolutely wrong approach. When you terminate the process, only that process is terminated. It's indisputable. Ex. you run git add -p, and terminate git.exe. Why do you think that perl.exe (spawned from git.exe) must be killed? User (or dev) says "kil the process", but not a "kill the process tree"!

Solution: want to kill whole console? Use GuiMacro to close the console first! This is the only valid way.

hypersw commented 8 years ago

So if you kill Visual Studio, all of the ReSharper helper invisible processes should be left running, hence and forever? Or killing the root chrome.exe should leave its invisible workers until you reboot? It's a questionable point, much depending on what relation the processes are in. If they're tightly coupled, I try to design children watch their parents die usually. With git, definitely a well-authored tool chain should clean up if you kill whatever command you have started as an entry point. Speaking of ConEmu, the point in detaching consoles is that when ConEmu crashes (a few times a week), all its FARs and CMDs are not immediately lost.

The terminal-in-a-control is quite a different thing. For I doubt there're many scenarios when you want its controls falling out as separate console windows when smth happens to the parent process.

Yet reliability is the worst thing here. Enumerating a process tree is not a trivial thing in C#, to kill them all processes, but anyway this makes a race condition if called early, when ConEmu is still spawning the child. Might enumerate at the moment when ConEmu has no children yet, then ConEmu starts the process, then ConEmu is killed and the process remains. Any other way it's not possible to achieve synchronous killing I'm afraid (like with async gui-macro). Which is a very nice thing to have if you're about to reuse the control immediately for a new terminal.

Maximus5 commented 8 years ago

If you kill mintty, does the bash terminates? If you kill git, does the perl terminates? If you kill explorer.exe, does the Visual Studio terminates? If terminal crashes does the significant job have to be broken in the indeterminate state? No. This is non-default behavior for any program. So, the dev of parent process must use api and features properly, that's all.

Maximus5 commented 8 years ago

You haven't to kill process tree. But you have to close the console instead of termination the terminal process.

One more. If you kill remote client, do processes on the server side terminate?

hypersw commented 8 years ago

So it's fifty-fifty in all these cases (and remote case is fifty-fifty on itself, often server is to drop processing when connection breaks, the whole tree of course). Depends on how the processes are related. ConEmu shouldn't make hard choices by default, though doesn't mean it can't do it at all.

What's the specific action you mean for closing the console? I'm afraid I don't know how to do it synchronously on the main thread.

Maximus5 commented 8 years ago

Close(1,1); Close(0,1) After these two functions you may terminate your app. ConEmu will terminate itself.

hypersw commented 8 years ago

We can't call GuiMacro synchronously in-process. So it might mean calling the command-line version…

Maximus5 commented 8 years ago

BTW, ConEmu is "independent" host, and if GUI part crashes, user will never lose their work! They even may start new ConEmu instance and reattach torn consoles back.

Maximus5 commented 8 years ago

We can't call GuiMacro synchronously in-process.

Well, I can implement exported function in ConEmuCD.dll

hypersw commented 8 years ago

Yes, for full ConEmu process that's a nice choice of behavior.

But here I need to implement smth reliable I believe. Which better have synchronous execution.

Example scenario: we're running terminal in the control upon some user action, user clicks a button which means canceling this activity and immediately running the new one. A typical GUI app would do this on the GUI thread in the same function, tell terminal to get killed and spawn the new one. Now it's important that the first process is out before the second one runs, as they might be taking filesystem locks or sharing any other resources. Which means that stopping a terminal better be a synchronous action.

hypersw commented 8 years ago

ConEmuCD is nice, if this function won't deadlock on the main thread, would close the console if it's running, or prevent it from running if ConEmu hasn't started the child process yet.

Maximus5 commented 8 years ago
  1. When user clicks the button, the parent process must tell the terminal to terminate all spawned console processes. It must be obvious, that TerminateProcess will never tell terminal to do that.
  2. Synchronous or asynchronous, that actually does not matter. The parent waits for termination in either case.
  3. I've suggested to implement new special exported function, to simplify termination and synchronization.
Maximus5 commented 8 years ago

If console has not been started yet, you may kill terminal process. Otherwise you know PID of console server process, which you may pass to proposed function. ConEmuCD can't know precisely which consoles are started without dead lock possibility, because only GUI have that information. So, it would be your responsibility to tell the function, which "console" you want to kill.

hypersw commented 8 years ago

Hmm, I've tried out a few options here. I got an emulation for synchronous GuiMacro execution (which runs the message pump in case of a STA thread while a background thread does its job), and I think it might actually do for now.

This results in killing the terminal emulator itself, as a result of Close 1 1 or Close 0 1 execution.

Just for info, what's the best approach to killing just the payload console process without killing the terminal window? Suppose we got the :c mode, we want to stop git payload but let user read the terminal output and the "press enter or esc" as usual, as if it were canceled with user's Ctrl+C. I can think of GetInfo Root -> PID -> Kill, but maybe there's an option on the Close command for that?

Maximus5 commented 8 years ago

https://conemu.github.io/en/GuiMacro.html#Break

hypersw commented 8 years ago

Ah, good! I'm not very much into these console signals stuff, which one would be the best to implement the Abort action, Ctrl+C or Ctrl+Break? Suppose it's the git command in GE. Also I believe a console program might ignore this signal altogether, right? But probably that shan't be a concern.

Maximus5 commented 8 years ago

As in linux, Windows console applications may choose what to do on CtrlC/CtrlBreak. Try the difference on ping, for example. I think, CrrlC is better choice for cross-platform applications like git.