Skip to content

Make vm_interrupt and timed_out atomic #7937

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

Closed
wants to merge 8 commits into from

Conversation

morrisonlevi
Copy link
Contributor

@morrisonlevi morrisonlevi commented Jan 12, 2022

On Windows these are already set from another thread and should be
atomic. On Linux it is unclear to me if this should be done based on
the existing code.

However, extensions which use vm interrupts are very likely to do the
same thing that Windows is doing: set a vm_interrupt from another
thread.

This combination suggests to me that this change is overdue.

This change is pretty trivial: I expect any issues to arise from from build
system changes or adding compiler flags, etc.

@morrisonlevi
Copy link
Contributor Author

morrisonlevi commented Apr 6, 2022

The largest issue here is that the vm_interrupt global is in a header and the layout needs to be ABI and source compatible between C and C++. At this time, this cannot be done cleanly across platforms. Both C and C++ have atomic_int, atomic_bool, etc, but critically in C++ all implementors (major ones, at least) have defined these as std::atomic<int>, std::atomic<bool>, etc which means they cannot be used in an extern "C" {} section. This is the first major hurdle.

The second is that there is no ABI guarantee in the standard that int and _Atomic(int) and std::atomic<int> have the same size, alignment, and layout. There are discussions about this for C++23 and C23 and there are some issues out there, though I'm not sure we'd actually hit any of them with a simple atomic_bool.

Here are two options I can think of to fix this:

  1. Check size, alignment, and layout during configuration, and enable atomics if and only if they match and define them as maybe_atomic_bool or something. Platforms which don't match would behave as today (not atomic). Additionally, every header file would have to be made directly C++ compatible, and all extensions would have to stop including PHP headers in extern "C" {} sections.
  2. Move it out of the globals and provide a non-inline API for it which is then implemented using C atomics. This is probably at least a slight annoyance for extensions which trigger interrupts, but the end-result for such extensions is better: the atomicity will actually be enforced.

Honestly, the latter sounds like a better option to me. Thoughts?

Rough API, inspired by the C atomics APIs but without user-provided memory orderings (would use seq_cst):

bool zend_vm_interrupt_compare_exchange(zend_executor_globals *, bool *expected, bool desired);
bool zend_vm_interrupt_exchange(zend_executor_globals *, bool desired);
bool zend_vm_interrupt_load(const zend_executor_globals *);
bool zend_vm_interrupt_store(zend_executor_globals *, bool desired);

I'm not sure about using zend_executor_globals * as the pointer, but often these are referred to by other threads so we can't just assume "use the current thread". Need to provide some handle, not sure what that should look like.

@morrisonlevi
Copy link
Contributor Author

Nikita suggested I look into using only atomic operations, not an atomic type, to see how that goes. I'll try that the next time I get a moment to work on it.

@morrisonlevi morrisonlevi force-pushed the atomic-vm-interrupt branch from c2f9d4f to e6a6ac9 Compare April 7, 2022 21:24
This is done by adding a new zend_atomic_bool type. The type
definition is only available for compiler alignment and size info; it
should be treated as opaque and only the zend_atomic_bool_* family of
functions should be used.

Note that directly using atomic_bool is complicated. All C++ compilers
stdlibs that I checked typedef atomic_bool to std::atomic<bool>, which
can't be used in an extern "C" section, and there's at least one usage
of this in core, and probably more outside of it.

So, instead check that atomic_bool has the same size and alignment as
native bool and if so we'll cast it.
@morrisonlevi morrisonlevi force-pushed the atomic-vm-interrupt branch from e6a6ac9 to 54c37e8 Compare April 7, 2022 21:46
@morrisonlevi
Copy link
Contributor Author

Closing in favor of a fresh PR.

@morrisonlevi morrisonlevi deleted the atomic-vm-interrupt branch April 8, 2022 16:31
@Krinkle
Copy link

Krinkle commented Dec 14, 2022

For future reference, the fresh PR is at #8327

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants