PowerShell / PowerShell

PowerShell for every system!
https://microsoft.com/PowerShell
MIT License
44.7k stars 7.24k forks source link

Exiting pwsh kills the process that was started with Start-Process #21149

Closed 237dmitry closed 8 months ago

237dmitry commented 8 months ago

Prerequisites

Steps to reproduce

  1. Start an application from pwsh with Start-Process
  2. Exit from pwsh
$ Start-Process mousepad   # starts mousepad
$ exit                     # will exit pwsh and kill mousepad

This behavior occurs on Linux and Windows.

On Windows it is not always possible to reproduce, depending on the application.

No problem:

$ Start-Process notepad
$ exit

Hangs console window (conhost), killing it (Ctrl-C) kills alacritty too:

$ Start-Process alacritty
$ exit    # hangs, Ctrl-C

Expected behavior

Process started with Start-Process should not depend on pwsh

Actual behavior

Process started with Start-Process terminates when pwsh closes

Error details

No errors

Environment data

On Linux: pwsh 7.5.0-preview.1
On Windows: pwsh 7.4.1

Visuals

No response

mklement0 commented 8 months ago

@jborean93 has more in-depth knowledge in this area, but I think this comes down to platform differences:

rhubarb-geek-nz commented 8 months ago

Going back in history, how Windows ran an EXE depended on the SUBSYSTEM of the EXE. If it was compiled with /SUBSYSTEM:CONSOLE it was considered a command line app and the command processor would wait for it to exit. If it did not have that SUBSYSTEM it was assumed to be a GUI app, and when started it was effectively detached.

Start-Process does indeed say

Example 8: Create a detached process on Linux

# Runs for 2 minutes and appends output to ./nohup.out
Start-Process nohup 'pwsh -noprofile -c "1..120 | % { Write-Host . -NoNewline; sleep 1 }"'

Unfortunately nohup does have side effects such as appending to nohup.out, but as the name says its role is to prevent SIGHUP from killing the process.

mklement0 commented 8 months ago

Thanks, @rhubarb-geek-nz (the nohup example actually originated in the discussion in https://github.com/PowerShell/PowerShell/issues/16001).

Re Windows console-subsystem applications: What you're describing applies to direct invocation, but Start-Process by design creates a new console window by default (as such it is the analog to cmd.exe's built-in start command), and in local invocations these windows are detached from the caller.

237dmitry commented 8 months ago

This is not a good workaround with /usr/bin/nohup. Why rofi, dmenu, any launchers do start processes without nohup?

What about windows? The problem also exists.

rhubarb-geek-nz commented 8 months ago
  • On Unix-like platforms, by contrast, a child process is always killed if its parent is killed

Is this true? In UNIX you may have a process group sharing a common controlling terminal. When the controlling terminal is disconnected it sends SIGHUP to all processes with that controlling terminal. The default behaviour for SIGHUP is to terminate the process, the program "nohup" breaks this connection by preventing the SIGHUP signal. Nohup does not actually remove the process from the controlling terminal

rhubarb-geek-nz commented 8 months ago

Why rofi, dmenu, any launchers do start processes without nohup?

Most likely because they are UNIX programs without layers of dotnet and windows compatibility, and simply using fork/exec.

mklement0 commented 8 months ago

Thanks for the clarification re process groups, @rhubarb-geek-nz - I've updated the wording in my earlier comment (meant to be a summary of sorts) and added a link to yours.

@237dmitry, there is no problem on Windows that I'm aware of, except the constraints mentioned earlier: use of -NoNewWindow and use in remoting. #16001 offers (nontrivial) workarounds for the latter, but if you feel that Start-Process itself should support creating detached processes in remote sessions too, I suggest creating a focused feature request to that effect.

mklement0 commented 8 months ago

Similarly, @237dmitry, it may be worth creating a separate feature request for building the functionality of nohup directly into Start-Process on Unix-like platforms - either by default or via a new switch.

rhubarb-geek-nz commented 8 months ago

If you are not looking for portable code then simply use bash -c 'command... &'

$ ps
  PID TTY          TIME CMD
30308 pts/0    00:00:00 bash
30578 pts/0    00:00:00 ps
$ pwsh
PowerShell 7.4.1
PS> bash -c 'sleep 10 &'
PS> exit
$ ps
  PID TTY          TIME CMD
30308 pts/0    00:00:00 bash
30607 pts/0    00:00:00 sleep
30654 pts/0    00:00:00 ps

shows sleep is still running after powershell exit

rhubarb-geek-nz commented 8 months ago

One downside of Windows itself is the assumption that everything needs Windows and that command line programs need console windows. Often on a Windows update or an installation of an MSI you get console windows flashing up for fractions of a second, it is rather unfortunate.

237dmitry commented 8 months ago

here is no problem on Windows that I'm aware

Conhost window wont be closed until I press Ctrl-C. After pressing conhost and alacritty windows close together.

ss

237dmitry commented 8 months ago

simply use bash -c 'command... &'

This works like Start-Process. I'm using a script to launch a new alacritty terminal instance with different profiles (bash, pwsh, mc, htop, musikcube). There are variables and Start-Process is a more convenient way to do this. Using nohup has disadvantages, since it outputs messages to the console, and I have not yet been able to redirect them to /dev/null.

PS. I want to switch from Tilix to Alacritty.

mklement0 commented 8 months ago

@237dmitry, what happens on Windows is this:

The workaround is to launch via a hidden aux. console window; e.g.:

Start-Process -WindowStyle hidden cmd '/c alacrity --config %APPDATA%\alacritty\pwsh.toml'

Pragmatically speaking, you could wrap the above in an alacritty function (which takes precedence over the external executable).

As for what should be done:

237dmitry commented 8 months ago

@mklement0

Start-Process -WindowStyle hidden

Thank you. I'll definitely try this.

mklement0 commented 8 months ago

@237dmitry, as for a Unix workaround:

You can silence nohup's console output as follows (using sleep as a sample command to run detached, as in @rhubarb-geek-nz's demonstration) - however, there is no way I know of to prevent creation of / appending to file nohup.out based on @rhubarb-geek-nz's tip, no nohup.out is created / appended to, due to redirection of stdout.

sh -c '{ nohup sleep 30 & } 2>/dev/null 1>&2'
rhubarb-geek-nz commented 8 months ago

On Linux nohup only writes to nohup.out if the stdout is directed at a terminal

$ nohup sleep 1
nohup: ignoring input and appending output to 'nohup.out'
$ nohup sleep 1 > /dev/null
nohup: ignoring input and redirecting stderr to stdout
mklement0 commented 8 months ago

Thanks, @rhubarb-geek-nz (I just tried to see that it also applies to macOS), so the solution that prevents use of nohup.out is (I've also updated the previous comment):

sh -c '{ nohup sleep 30 & } 2>/dev/null 1>&2'
237dmitry commented 8 months ago

I did not tried this yet in pwsh scripts

nohup sleep 1 0</dev/null 2>&1 1>/dev/null
mklement0 commented 8 months ago

@237dmitry:

From PowerShell, $null = nohup sleep 30 & works in principle, but would require you to manually clean up the job later.

If you don't mind nohup.out getting created, a more efficient Start-Process-based command is:

Start-Process nohup 'sleep 30' -RedirectStandardError /dev/null

The following should work and would prevent creation of nohup.out, but currently doesn't, due to the following bug:

Start-Process nohup 'sleep 30' -RedirectStandardOut /dev/null -RedirectStandardError /dev/null

Note: On macOS (as opposed to Linux), nohup doesn't print a status message to stderr, so it is sufficient to redirect stdout output in order for the command to both be silent and to prevent creation of file nohup.out:

# macOS only: prevents both console output and creation of file nohup.out
Start-Process nohup 'sleep 30' -RedirectStandardOut /dev/null
237dmitry commented 8 months ago

Start-Process nohup 'sleep 30' -RedirectStandardError /dev/null

Wau!!! Thank you very much!

start nohup -args "alacritty --config-file $HOME/.config/alacritty/htop.toml" -RedirectStandardError /dev/null

Works fine!

UPD. On Windows with -WindowStyle hidden also works!

Start-Process cmd -ArgumentList "/c alacritty --title $title --config-file $config" -WindowStyle Hidden
mklement0 commented 8 months ago

@rhubarb-geek-nz:

Re console-subsystem applications currently invariably creating a visible console window unless attached to an existing console - which notably manifests as an inability to invoke PowerShell itself hidden, see #3028 - there's a pending PR for a Console Application Policy (now 3+ years old, most recently amended in Dec 2023), proposing a way for applications to control their console-related behavior via their manifest:

rhubarb-geek-nz commented 8 months ago

Java solved the problem by having "java.exe" and "javaw.exe", so the first one was a console app, the second was a GUI app. However you may still want stdin/stdout/stderr attached.

mklement0 commented 8 months ago

@rhubarb-geek-nz, an express design goal of the linked PR is to avoid the need for separate executables going forward (the python.exe / pythonw.exe pair is another example). If I understand the PR correctly, an application using the detached policy would implicitly attach to a caller's existing console - if present.

rhubarb-geek-nz commented 8 months ago

If you use CreateProcess() with DETACHED_PROCESS it is the responsibility of the new process to call AllocConsole() if it wants a console window, rather than the parent making the assumption and using CREATE_NEW_CONSOLE. To add to the confusion there is also the CREATE_NO_WINDOW flag which is mutually exclusive with the previously mentioned flags.

mklement0 commented 8 months ago
rhubarb-geek-nz commented 8 months ago

That seems very convoluted and not in the right place at all, creating console windows should have nothing to do with the kernel. In the UNIX world controlling terminals are either system configured for serial ports or pseudo-terminals are created on demand at login by either rlogind, telnetd or sshd, or created when a new terminal window is opened (eg xterm, dtterm, gnome-terminal etc).

mklement0 commented 8 months ago

I'm not disagreeing; Windows has a lot of historical baggage, stemming from questionable initial design choices coupled with a commitment to backward compatibility - arguably, PowerShell itself has the same affliction (and I'm saying this as someone who is a fan of the fundamentals of PowerShell).

microsoft-github-policy-service[bot] commented 8 months ago

This issue has been marked as answered and has not had any activity for 1 day. It has been closed for housekeeping purposes.

microsoft-github-policy-service[bot] commented 8 months ago

📣 Hey @237dmitry, how did we do? We would love to hear your feedback with the link below! 🗣️

🔗 https://aka.ms/PSRepoFeedback

Microsoft Forms