Replies: 5 comments 7 replies
-
Going to split into several subthreads:
Except for pcntl_waitpid() which is buggy, this is fine as long as the waitpid() is from the same request as the spawn. I strongly believe that's a desirable requirement, but that is a separate discussion. All lightprocess requests for a request currently come from the same thread; if that changes in the future, we do support a distinct concept of 'request local', and we would need to use that instead. |
Beta Was this translation helpful? Give feedback.
-
This is probably long-term desirable; however:
|
Beta Was this translation helpful? Give feedback.
-
This is a plain bug. |
Beta Was this translation helpful? Give feedback.
-
Yep, all the CLI server stuff. This is a pre-existing problem, but we won't be making it worse here. Naively, I would want a single request to be able to use multiple lightprocess workers simultaneously; I don't know how practical this is when looking at all requests together though - e.g:
|
Beta Was this translation helpful? Give feedback.
-
I strongly believe this is the desirable approach:
Doing otherwise would also require:
I also don't think this should be considered a blocker on implementation:
|
Beta Was this translation helpful? Give feedback.
-
Hi all, recently I am working on HSL Subprocess API. However, there are some issues in existing implementations of PHP style subprocess API. The rest of this article includes some ideas based on private chat between @fredemmott and me.
Existing Implementation
Unlike PHP's single threading mode, HHVM's server mode runs in a multithreaded environment. Unfortunately, the
fork
system call is unsafe in multithreaded environment. As a workaround, HHVM introduced a settingServer.LightProcessCount
. When LightProcessCount is greater than zero, HHVM would pre-fork some worker processes before additional threads creation, andproc_open
or other functions would send a request to a worker process via a UNIX socket, letting the worker process to actually spawn the subprocesses thatproc_open
asked.Issues
Issue 1: Waitpid from the main process
As demonstrated in #9015 (comment) , worker processes are creating zombies, because the current
pcntl_waitpid
implementation directly callswait4
given a PID created by the worker processes, therefore, the PID is actually the grand child of the HHVM's main process, whilewait4
requires the PID is a direct child of the caller process.Issue 2: Waitpid from the wrong worker process
Alternatively, we can also let worker processes, not the main process, call
wait4
. However, currently the worker processes are associated with HHVM threads, not the PID. That is to say, even if we let a worker process executewait4
, ifproc_open
is called in one thread thenpcntl_waitpid
is called by another thread, then it is very likely to turn the subprocess into a zombie becausewait4
might not be called by the same worker process.Solutions
Option 1: Switch to the native
posix_spawn
This could eliminate some but not all the motivation behind the pre-forked light processes, because unlike
fork
,posix_spawn
is expected to be compatible with multithreading mode. However the other motivation of pre-forked light processes is to separate the permissions, as when running HHVM in CLI server mode, the lightprocess master is part of the CLI client process, not the HHVM server.Since anyway we must spawn subprocesses from processes other than the CLI server process, either from the CLI client process or light weight worker processes, we would still have to deal the issue to find the right caller of
wait4
, even if we switch the underlying implementation to the nativeposix_spawn
.Option 2: Use exact a single worker process
This approach would result bad performance because currently some of worker processes are used to turn blocking operations into non-blocking, including
OS\open()
and anything using theHSL_CLI_INVOKE
.Option 3: Build an additional pid -> worker process mapping
If we build an additional pid to worker process mapping, we could ensure a
waitpid
command is always handled by the same worker process that created the PID. However, this approaches seems conflicting with existing usage ofLightProcess::setThreadLocalAfdtOverride
, which assigns a light process to a thread-local variable.Option 4: Mimic one process per request behavior
The current thread to worker process mapping works well if the
waitpid
andproc_open
calls are from the same request (and we are going to move thewait4
call to the associated worker process), because currently we always associate the same thread with a request. For subprocesses that live longer than a request, we might want to turn the subprocess into a daemon process, mimicking PHP's one process per request behavior, so that the PID would always be cleaned up.Related topics
OS\
design notesBeta Was this translation helpful? Give feedback.
All reactions