Skip to content

Unify control & data transfer between fibers #7120

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

Merged
merged 2 commits into from
Jun 9, 2021
Merged

Unify control & data transfer between fibers #7120

merged 2 commits into from
Jun 9, 2021

Conversation

kooldev
Copy link
Contributor

@kooldev kooldev commented Jun 8, 2021

Provides a unified channel to transfer control and data using zend_fiber_switch_context(). This allows the caller of zend_fiber_switch_context() to pass along data that is needed by the resumed fiber. The implementation of Fiber used to "helper" fields named value and exception in zend_fiber to achieve this. This only works if you know that the resumed fiber is a zend_fiber and it has different ways to pass values / errors. It also relies on EG(exception) to be present in some situations. We should avoid that and ensure that all communication between fibers uses a single channel.

The new zend_fiber_transfer struct has a value field that holds a zval for both "normal" and error case (in case of an error value has to be a Throwable). No dynamic memory allocations are needed for transfers, they can always live on the caller's stack. A transfer struct has to be allocated before calling zend_fiber_switch_context() and the context field must be set to the zend_fiber_context that should be resumed.

zend_fiber_transfer transfer = {
    .context = TARGET_FIBER /* The fiber to be resumed */
};

ZVAL_COPY(&transfer.value, SOME_DATA); /* Supply data to the fiber */

zend_fiber_switch_context(&transfer);

/* transfer struct is updated by the fiber that resumed us. */
printf("Resumed by: %p\n", transfer.context);
printf("Data type: %s\n", Z_TYPE(transfer.value));
printf("Is error: %d\n", (transfer.flags & ZEND_FIBER_TRANSFER_FLAG_ERROR) ? 1 : 0);

zval_ptr_dtor(&transfer.value);

After a fiber is resumed the transfer struct will hold context and data passed by the fiber that resumed us (the transfer is used as an INOUT param to avoid unnecessary memory copies and have the caller decide where to allocate memory for it). The context field now refers to the fiber that has resumed us. The value and flags fields are also set by the other fiber. If value is not used it must be freed using zval_ptr_dtor() to prevent memory leaks.

@trowski
Copy link
Member

trowski commented Jun 8, 2021

This generally looks good, but I wanted to test a couple of use-cases I have in mind to make sure this covers those. I'll do that either tonight or tomorrow.

The Asan stack pointers to update should be associated with the context that switched to this context, not the context that this function switched to.
Copy link
Member

@trowski trowski left a comment

Choose a reason for hiding this comment

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

After a minor fix to the ASan finish switch notification to use the context that resumed instead of the context that was originally switched into, this works exactly as I expected. 👍

@trowski trowski requested a review from krakjoe June 9, 2021 05:15
@trowski trowski merged commit fa3d198 into php:master Jun 9, 2021
@kooldev kooldev deleted the fiber-transition branch June 10, 2021 07:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants