-
Notifications
You must be signed in to change notification settings - Fork 3k
[RFC] subprocess-posix: use clone
in Linux and rfork_thread
in FreeBSD
#14973
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
Conversation
I feel like introducing such additional complex, platform-specific code is not worth it for a vague "lower overhead" in process creation (when is this a bottleneck??). |
I agree, we should evaluate whether it is needed using some test cases that show the actual difference. mpv, under normal operation, shouldn't spawn subprocesses, especially not ones that are performance critical. |
Well, I don't think it's complex. You can also have a look at the new handling of These APIs are also used by |
3e8da39
to
2f6617d
Compare
Agree with what's already said. I think there is no reason to maintain 2 additional platform-specific implementations for little benefit when the existing one works. Additionally from FreeBSD documentation: "The rfork_thread() function has been deprecated in favor of pthread_create(3)."
That's a separate issue and does not require the new process creation functions. |
Download the artifacts for this pull request: |
Not related IMO. The latter is for creating threads. The functionality used in the code cannot be achieved by
I don't consider they as two separated platform-specific implementations as they only differ in one single line of code of calling the API. As Linux has the de facto dominance, I think it's acceptable to optimize for it with little additional code complexity. You can consider the FreeBSD part as a side product. |
A microbenchmark: local utils = require 'mp.utils'
local start_time = mp.get_time()
for i = 1,1000 do
utils.subprocess_detached{
args = {"/bin/echo", "test"}
}
end
local end_time = mp.get_time()
print(end_time - start_time) Tested on Linux 6.11.0: Tested on FreeBSD 13.4: I think the performance improvement is nontrivial. |
5f3f9cd
to
b6dc978
Compare
It is non trivial, but, without commenting on the PR itself, on its own it doesn't necessarily carry a lot of weight. The use cases of mpv where hundreds of processes per second are not enough but (many) thousands is just what the doctor ordered are probably not all that common. You have a track record of good code, so that's a good start, but the couter argument is that it's currently (probably) good enough and known to work where needed, while new code does carry risks. But if the reviewers find the new code great, then such a perf improvement is certainly nice. |
Yeah, we can put this aside. |
clone
in Linux and rfork_thread
in FreeBSDclone
in Linux and rfork_thread
in FreeBSD
Worth noting that the new POSIX supports this use case: https://www.austingroupbugs.net/view.php?id=1044 |
Yes. But we still need to perform a double-fork in order to detach a child process. Is BTW in fact we can use pidfd with |
} | ||
|
||
// Returns 0 on any error, valid PID on success. | ||
// This function must be async-signal-safe, as it may be called from a fork(). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function must be async-signal-safe
Does it? Because currently it clearly isn't as it does allocations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment is not true because spawn_process
is not called after fork
anymore. I did not update the comment, sorry. Instead, it is still true that spawn_process_inner
need to be async-signal-safe.
But in any case, I agree with the rest. Seems not worth it unless there's actual use cases where this matters. |
With Also, posix_spawn has an option to reset all signal-handlers to default ( If |
The problem is that we still need to reap the zombies if we do not double-fork. |
FWIW for anyone who is still interested in subprocess creation stuff, you may be also interested in my another PR: ziglang/zig#22368. |
Ah, yeah... the zombies. Looked around a bit but it doesn't seem like posix_spawn has any flags/option to solve this. Maybe there's a better way to reap the child so we don't need to reparent it to pid 1? (Nothing that comes to mind though...) |
We can BTW we cannot assume orphans are reparented to pid 1. It's implementation-defined. And systemd handles orphans in a different way. See https://stackoverflow.com/a/40424702 |
I thought about doing it via SIGCHLD handler. But in either case, that's probably not an option since we'd also need to consider libmpv, I think. One other thing I thought was to collect the detached pids into a dynamic array and attempt to reap them every once in a while with Not sure where the reaping code should go. Would require the dynamic array to be global which has the usual threading issues too. So, yeah... |
I have no motivation to make it upstream anymore. Closing it. |
This PR introduces platform-specific implementations, namely
clone
in Linux andrfork_thread
in FreeBSD, to optimize subprocess creation.vfork
semantics is used in these implementations: virtual memory is shared between the parent and the child, and the execution of the parent suspends until the child terminates. (However,vfork
is not used because its behavior varies across platforms, and it's difficult to be used properly in C.) Besides lower overhead, this simplifies the result passing: no pipe is needed.