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

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

Closed
5 tasks done
237dmitry opened this issue Jan 28, 2024 · 29 comments
Closed
5 tasks done

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

237dmitry opened this issue Jan 28, 2024 · 29 comments
Labels
Resolution-Answered The question is answered.

Comments

@237dmitry
Copy link

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

@237dmitry 237dmitry added the Needs-Triage The issue is new and needs to be triaged by a work group. label Jan 28, 2024
@mklement0
Copy link
Contributor

mklement0 commented Jan 28, 2024

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

  • On Windows, a Start-Process-launched lives on independently of the PowerShell session that launched it; the only exceptions I'm aware of are:

  • On Unix-like platforms, by contrast, a child process is by default killed if its parent is killed (loosely speaking; see @rhubarb-geek-nz's comment below for details; also, -NoNewWindow is invariably implied, because launching a process in a new terminal window is not supported).

    • If you want a process to be detached from the caller, use Start-Process nohup '...' - see example 8 from the docs for an example call and @rhubarb-geek-nz's comment below.

@rhubarb-geek-nz
Copy link

rhubarb-geek-nz commented Jan 28, 2024

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
Copy link
Contributor

mklement0 commented Jan 28, 2024

Thanks, @rhubarb-geek-nz (the nohup example actually originated in the discussion in #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
Copy link
Author

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
Copy link

  • 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
Copy link

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
Copy link
Contributor

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
Copy link
Contributor

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
Copy link

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
Copy link

rhubarb-geek-nz commented Jan 28, 2024

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
Copy link
Author

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
Copy link
Author

237dmitry commented Jan 28, 2024

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
Copy link
Contributor

mklement0 commented Jan 28, 2024

@237dmitry, what happens on Windows is this:

  • alacritty.exe is a GUI-subsystem application...
  • ... which - unusually - explicitly attaches to the caller's console (which allows it to print diagnostic messages to that console with the --print-events CLI option, for instance.
  • When you exit the PowerShell session while the launched Alacritty process is still alive, the latter prevents the console from closing (because Alacritty is still attached to it).
  • Forcefully terminating the console - whether via Ctrl+C or by simply closing the console window - then terminates the Alacritty process too.

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:

  • I'm not sure whether Start-Process can or even should try to prevent this scenario.
  • Note that you get the same behavior in interactive cmd.exe sessions.

@237dmitry
Copy link
Author

@mklement0

Start-Process -WindowStyle hidden

Thank you. I'll definitely try this.

@mklement0
Copy link
Contributor

mklement0 commented Jan 28, 2024

@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
Copy link

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

This comment was marked as resolved.

@237dmitry
Copy link
Author

I did not tried this yet in pwsh scripts

nohup sleep 1 0</dev/null 2>&1 1>/dev/null

@mklement0
Copy link
Contributor

mklement0 commented Jan 28, 2024

@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
Copy link
Author

237dmitry commented Jan 28, 2024

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
Copy link
Contributor

@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
Copy link

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
Copy link
Contributor

@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
Copy link

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
Copy link
Contributor

mklement0 commented Jan 28, 2024

  • According to the linked PR, it's not the parent process making the decision as to whether to allocate a console for a console-subsystem executable: it is the kernel ("every application that is stamped with the IMAGE_SUBSYSTEM_WINDOWS_CUI subsystem in its PE header will be allocated a console by kernel32.")

  • The design goal appears to be: Via an application manifest specifying a newly introduced console-allocation policy (detached), allow creation of executables that:

    • act like console-subsystem applications when called from an existing console (including the synchronous execution behavior that that entails in shells)
    • act like GUI-subsystem applications otherwise (possibly running invisibly)

@rhubarb-geek-nz
Copy link

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
Copy link
Contributor

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).

@SteveL-MSFT SteveL-MSFT added Resolution-Answered The question is answered. and removed Needs-Triage The issue is new and needs to be triaged by a work group. labels Jan 29, 2024
Copy link
Contributor

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

Copy link
Contributor

microsoft-github-policy-service bot commented Jan 31, 2024

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

🔗 https://aka.ms/PSRepoFeedback

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Resolution-Answered The question is answered.
Projects
None yet
Development

No branches or pull requests

4 participants