Skip to content

True async api stable #19142

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

Open
wants to merge 367 commits into
base: master
Choose a base branch
from
Open

Conversation

EdmondDantes
Copy link

TrueAsync engine API

The TrueAsync engine API defines a pluggable interface that lets extensions register different async backends while the core supplies standardized primitives.

Key Components

  • Events: Low‑level representation of sockets, timers and other readiness sources
  • Coroutines: Stackful tasks
  • Scopes: Hierarchical lifetime management enabling grouped cancellation
  • Wakers: Event‑completion handlers that resume suspended coroutines

PR for https://wiki.php.net/rfc/true_async_engine_api

  - Update network_async_wait_socket() to use modern async API with waker pattern
  - Replace async_wait_socket() calls with network_async_wait_socket() in all socket functions
  - Affected PHP functions: socket_read, socket_send, socket_recv, socket_sendto, socket_recvfrom, socket_connect,
  socket_accept
  - Add comprehensive test suite in ext/async/tests/socket_ext/ covering TCP/UDP operations and concurrent
  scenarios
- Fix segfault in multi_timer_cb() due to uninitialized callback pointer
- Add robust error handling in curl_async_setup() with proper cleanup
- Implement proper cleanup paths for socket events in error scenarios
- Fix memory leaks in callback registration failures
- Add missing dispose() calls and hash table cleanup

✨ Enhanced documentation:
- Add detailed MULTI HANDLE FLOW comments
- Document event-driven architecture principles
- Clarify lifecycle management for event objects

This refactoring significantly improves stability and eliminates potential
crashes while maintaining the new event-driven architecture.
# Conflicts:
#	Zend/zend_exceptions.h

require "zend_constants.stub.php";

class CancellationException implements Throwable
Copy link
Member

Choose a reason for hiding this comment

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

Can this not just inherit from Exception ?

Copy link

Choose a reason for hiding this comment

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

IMO the naming is off. CancellationException should either be an instance of Exception or should become a Cancellation - new root Throwable next to Exception and Error.

This is especially dangerous if catching Exception will not catch the CancellationException.

Copy link
Author

@EdmondDantes EdmondDantes Jul 17, 2025

Choose a reason for hiding this comment

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

Hello.
The CancellationException is intended for situations where execution must be stopped unconditionally.
Such an exception may only be caught for the purpose of rethrowing it.

Therefore, code that attempts to catch Exception must never catch CancellationException.
Incorrect handling of CancellationException is a known issue, and this is a simple way to mitigate it.

The ideal solution would be to introduce a special additional syntax block, similar to finally, but triggered only for CancellationException.

Such a solution would be logically perfect and clean, but it would require far more changes.
Meanwhile, CancellationException is a typical solution to this problem and is widely used in other languages.

Copy link

Choose a reason for hiding this comment

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

I'm not having a problem with its function, just the naming is confusing. I agree that the type of error represented by the CancellationException should not be caught by a } catch (\Exception $e) block. The problem is that, because of the naming clash, reading the code will suggest that it will get caught, due to its name ending with *Exception. Developers will have to remember this special case and I'm wondering if there is a better way of naming it so that we can avoid introducing this memoization requirement.

Choose a reason for hiding this comment

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

I agree with what was exposed here. CancellationException indeed gives the impression that it should be treated as a regular Exception. If this is an exception that is not meant to be treated (if I understood correctly by Edmond's comment) it reminds me more of something closer to a panic() in Golang, for example, which basically shuts the entire application execution due to a very exceptional circunstance (even though you still can recover() from it).

Copy link

@jhonatanjacinto jhonatanjacinto Jul 18, 2025

Choose a reason for hiding this comment

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

By author's description it would need to be something in between. What is confusing to me is that he says "The CancellationException is intended for situations where execution must be stopped unconditionally. Such an exception may only be caught for the purpose of rethrowing it" and what it translates to me is that it is something that should be, in some sense, "throwable" (like an Exception/Error) but not totally "treateable" (such a Fatal Error or a panic() in golang which is recoverable in some situations, but not all of them).

However, at the same time, the CancellationException class implements Throwable which, theoretically, allows a try...catch block to capture it with a catch(Throwable $e), right? Which makes it "treateable". So, in order to name it properly, I think we should understand what the author expects from this implementation:

  1. Should "CancellationException" be treatable/catchable in a try...catch block or not?
  2. If not, definitelly it must be something else cause anything that is throwable can be captured in a try...catch block. Fatal Error? A panic equivalent new category of error in PHP? Don't know... but definitely not a "Throwable" implementation.
  3. If it's not a big deal to capture and handle this exception and there's only some weird edge cases where it would be bad to handle it (or it should be handled in a very particular way) I think it should inherit from Exception and the proper behaviour be document to let the developers know what needs to be done when handling this particular type.

Another thing is that I'm truly curious why handle this CancellationException as a normal Exception would be a problem. From the outside, I cannot imagine a reason for not being a regular exception in the language.

Copy link
Author

Choose a reason for hiding this comment

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

We can use CancelledError, like in Python. However, I’m not aware of any research showing that one clear name makes code better than another equally clear name.

Although modern languages don’t have an explicit division between catchable and uncatchable exceptions, such a distinction exists implicitly by convention.

From a semantic standpoint, operation cancellation has all the characteristics of an exception: it interrupts code execution, carries a stack trace, and so on.

Copy link

@eXsio eXsio Jul 19, 2025

Choose a reason for hiding this comment

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

The thing is that the name CancellationException suggests that it inherits from the root Exception class, which is not true. This is far from being clear, at least for me :)

Coming from Java, I tend to lean towards their understanding of the division between Exceptions and Errors (both originating from Throwable).

Exception is generally a kind of error you can recover from. Error, on the other hand, is generally not recoverable. You can intercept both of them by catching a Throwable, but in case of an Error there is usually very little we can do, except logging it and (if it's even possible at this point) notifying external systems about it, and then rethrowing it. Usually at this point JVM is cooked.

Copy link
Author

@EdmondDantes EdmondDantes Jul 19, 2025

Choose a reason for hiding this comment

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

I understand your logic.
But if we follow this path, then we might as well not implement this class here at all, and I can remove it from the PR.
Instead, we inherit CancellationError (CancelledError) from the Error class.

This solution has only one downside: if someone previously relied on the Error class, they now need to be aware that there's also Cancellation. But perhaps this isn’t a critical issue.

Or we could just change the name.
What do you think?

Copy link

@eXsio eXsio Jul 19, 2025

Choose a reason for hiding this comment

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

I don't know if there is any better idea in anyone's mind, but for sure CancellationError ( inheriting from Error) is way better than CancellationException in the context of its proposed purpose.

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.

6 participants