Skip to content
New issue

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

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

Already on GitHub? # to your account

Does $! work? #375

Open
DocMAX opened this issue Nov 9, 2023 · 1 comment
Open

Does $! work? #375

DocMAX opened this issue Nov 9, 2023 · 1 comment

Comments

@DocMAX
Copy link

DocMAX commented Nov 9, 2023

I try to run some exe.. myapp.exe & echo $!.
The returned PID is not the exes one, but another busybox.exe instance.
Can it be fixed or isn't $! supported at all?

@rmyorston
Copy link
Owner

When a Unix shell needs to run a command in the background it:

  • Uses fork(2) to create a new process as a duplicate of the current shell. This is necessary to set up the correct execution environment for the new process. The value of $! is set to the PID of this process.
  • The shell in the child process figures out what needs to be run and calls exec(2) to execute the required command in that process, replacing the second shell.

Windows doesn't have separate fork() and exec() functions, instead it has spawn() functions in the C runtime and CreateProcess() in the WIN32 API. These create a new process and execute a binary within it.

busybox-w32 has to work with what's available to it. Thus, when the shell has to execute a background command:

  • It uses spawn() to create a copy of the current shell. The PID of this process is put in $!.
  • The second shell figures out which binary needs to be run and uses another spawn() to execute it. There is no exec(2) on Windows.

On Unix there are two processes involved, on Windows there are three. On Windows:

~ $ ./sleep 100 &
[1] 3220
~ $ ps
  988  1204 rmy       0:00  1h08   sh -l
 3220   988 rmy       0:00  0:11   sh --fs 0000019C
 2820  3220 rmy       0:00  0:11   sleep.exe
~ $

(The output of ps has been edited to show only the relevant processes.)

The PID reported for the background command is 3220, but that's the second shell. The PID of the actual command here is 2820.

That's what happens when an external program has to be run. As an optimisation, if the second shell finds that the required command is a BusyBox applet it can emulate exec(2) by running the main function of the applet in the current process. In this case we get:

~ $ sleep 100 &
[1] 1616
~ $ ps
  988  1204 rmy       0:00  1h08   sh -l
 1616   988 rmy       0:00  0:03   sleep 100
~ $

There are only two processes and $! has the correct PID.

Can it be fixed for external commands? I haven't come up with anything yet.

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants