Skip to content

Conversation

@trowski
Copy link
Member

@trowski trowski commented Mar 1, 2025

This adds a Context implementation which uses pcntl_fork to create another process. This is a strategy which we abandoned some time ago due to the issues with copying parent context into a child, however there are particular case where that behavior can be advantageous.

This context is NOT added to DefaultContextFactory, and in fact has warnings against its use in the class docblock.

@danog Can you please check if this works for you in Psalm.

@danog
Copy link
Contributor

danog commented Mar 1, 2025

This does not work in psalm, because runContext is queueing a callback onto the event loop, which causes an immediate The event loop is already running error when hitting EventLoop::run(); unwrapping the callback fixes the issue.

@danog
Copy link
Contributor

danog commented Mar 1, 2025

Additionally, I added some extra error handling logic to handle segfaults in child processes (commonly caused by JIT usage in psalm), would love to see that in this impl as well: https://github.com/vimeo/psalm/blob/fc437245b15a7220de107bc191a3559fdbf94595/src/Psalm/Internal/Fork/ForkContext.php#L61

@danog
Copy link
Contributor

danog commented Mar 1, 2025

checkExit should probably also be executed within the constructor in a finally block as well, as vimeo/psalm#11310 is caused by a crash quite possibly before the initial IPC handshake is completed, haven't further looked into this yet...

@trowski
Copy link
Member Author

trowski commented Mar 1, 2025

This does not work in psalm, because runContext is queueing a callback onto the event loop, which causes an immediate The event loop is already running error when hitting EventLoop::run(); unwrapping the callback fixes the issue.

My local test was running from {main}, so I missed that. Unfortunately running this new context through the usual test suite crashes and burns, of course because we're forking the test process.

I removed the event loop queuing from runContext and updated ForkContext with the recent changes you made. Give it another try when you get a chance.

@kelunik
Copy link
Member

kelunik commented Mar 2, 2025

What is the use case you mentioned?

@trowski
Copy link
Member Author

trowski commented Mar 2, 2025

What is the use case you mentioned?

@danog Can you please elaborate on how you're using this in Psalm?

@danog
Copy link
Contributor

danog commented Mar 3, 2025

I'm using this in psalm to avoid serializing and sending tens of megabytes of data structures containing information about the codebase post-scanning, when starting the analysis phase.

@danog
Copy link
Contributor

danog commented Mar 7, 2025

https://github.com/danog/parallel/tree/fork-context contains some more improvements and enables (most) unit tests, working OK in Psalm!

@danog
Copy link
Contributor

danog commented Mar 16, 2025

Ping @trowski :)

public static function isSupported(): bool
{
return \function_exists('pcntl_fork')
&& !EventLoop::getDriver() instanceof UvDriver;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Docs say it's not compatible with extension based event loops, but we only check for UV here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this needs fixing, @trowski mind bumping

Serializer $serializer = new NativeSerializer(),
): void {
/** @noinspection PhpUnusedLocalVariableInspection */
$argc = \count($argv);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did this code change in this PR?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. The call to EventLoop::run() was removed because the event loop is already running when called from ForkContext
  2. Added the ability to pass a particular serializer instance, also used in ForkContext.


public function testImmediateJoin(): void
{
// tmp
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about these?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@danog This was copied from your code, can you explain?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't have a clear explanation for these specific failures yet, but the current state is better than the initial state of the PR which completely disabled tests

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

4 participants