-
Notifications
You must be signed in to change notification settings - Fork 3k
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
[draft] erts: kill spawned child processes on VM exit #9453
base: master
Are you sure you want to change the base?
Conversation
CT Test Results 2 files 15 suites 13m 31s ⏱️ For more details on these failures, see this check. Results for commit f7c336f. ♻️ This comment has been updated with latest results. To speed up review, make sure that you have read Contributing to Erlang/OTP and that all checks pass. See the TESTING and DEVELOPMENT HowTo guides for details about how to run test locally. Artifacts// Erlang/OTP Github Action Bot |
9f87bc1
to
dba896f
Compare
Hello! I think that we can move forward with this. There is no need to have an option to disable it for now (unless our existing tests shows that it is needed...), but there needs to be testcases to test that it works as expected on both Unix and Windows. I do wonder however if we should send some other signal than |
Good point, TIL that sigkill is untrappable. Looking at I experimented a bit locally to see if |
8efd4f5
to
81abb88
Compare
Now includes a test for normal erl shutdown ( There are a few other flapping tests, I don't think this is related to my patch but can't say for sure... Running the tests on Windows is not going well for me, and it seems there's no CI for that yet? In theory my patch and the test will also run on win32 but I'd like to see that happen. |
81abb88
to
80f301a
Compare
If the grandchild is an Erlang node, it could communicate via Erlang distribution? Otherwise a file seem reasonable.
No, there is no github CI for that yet. I have a branch that I work on from time to time to try to bring it in, but the tests are not stable enough yet. Maybe you can temporarily use it as a base for your changes and you should atleast be able to see if your tests pass or fail? |
A couple of other things that popped into my mind: What do we do when someone does
I know that there are users that rely on being able to spawn daemon processes through |
Great! I'm working on that now, and learned that my proposed feature needs to be reimplemented separately for the win32 spawn driver.
That makes sense, the same principle applies IMHO and it feels consistent to attempt a direct termination any time Erlang will lose its connection to the child. I'll add this.
I see... Interestingly, the "&" in that test is only relevant for allowing os:cmd to return immediately, the shell job control seems to be unimportant. In other words, the test is equivalent to calling open_port and not waiting for the process to finish, so this syntax is more a convenience than a special use case. But it would definitely indicate an intention to start a daemon with no direct link to Erlang, +1 that we should respect this usage! As a tourist to the BEAM, all I can do is describe the options but I don't have instincts for which is the best way to go. We could preserve this "&" usage by only killing the immediate child process, which would be the shell. This still offers some benefits, since the application developer may be able to call open_port with spawn_executable, making their process the immediate child and causing it to be cleaned up without needing a wrapper script. It also simplifies reasoning about the "process group", killing exactly one child process is much more predictble. |
To some extent, I think there's a bigger problem here where we could have a whole new API for managing external processes - the current port API is neither powerful nor ergonomic. As @garazdawi mentioned, today it's not even possible to easily kill the process once you spawn it, and |
80f301a
to
a9b6e1c
Compare
I found that shell "&" assigns the background job to a new process group, which IMHO means that killing children by process group is back on the table. For now however, my patch is rewritten to kill only the direct child process. The latest branch also kills a port's child during port_close. Splitting this responsibility between the main VM process and the forker is causing a memory leak (and a leaky abstraction), and I'm imagining this can be resolved by sending another protocol message to the forker to allow it to perform cleanup such as killing the process, then freeing memory used to track the child. Introducing this new message has some small overhead but I don't see any obvious, existing means for the forker to detect that the port was closed by beam.
+1 that direct OS process management could be a nice addition to the core libraries, but the current iteration can be done without larger changes to the opaque port concept. |
Yes, this seems like a good approach. |
a9b6e1c
to
f7eee72
Compare
Demonstrate failing examples of how a spawned child process will continue after its port is closed or the VM dies.
Currently a no-op patch. This message will allow the forker to clean up internal resources and kill the child process in a later patch.
Previously, the forker start command would use the presence of port_id to indicate whether the caller had specified :exit_status to open_port. This no-op patch splits this out to an explicit second field `want_exit_status`, so that we can always track port_id. A later patch will use the os_pid->port_id mapping and needs all children tracked even when exit status was not requested.
If the forker's connection to the parent BEAM is broken or closed, react by killing all spawned children. When a spawned port is closed, kill the associated OS process. A concise demonstration of the problem being solved is to run the following command with and without the patch, then kill the BEAM. Without the patch, the "sleep" process will continue: erl -noshell -eval 'os:cmd("sleep 60")' TODO: * Needs a decision made between killing the process or process group. * Separate patch for win32
f7eee72
to
f7c336f
Compare
This is a very rough proof-of-concept for discussion, which ensures all children spawned with open_port are terminated along with the BEAM.
Will be discussed in https://erlangforums.com/t/open-port-and-zombie-processes