Uh oh!
There was an error while loading. Please reload this page.
Add the Async Scheduler Hook API: a thin, policy-free concurrency core - #13
Closed
EdmondDantes wants to merge 1 commit into
Closed
Add the Async Scheduler Hook API: a thin, policy-free concurrency core#13EdmondDantes wants to merge 1 commit into
EdmondDantes wants to merge 1 commit into
Conversation
The engine gains the ability to activate a concurrent execution mode. A scheduler - a C extension or a PHP library - registers a set of hooks through a single call and takes control of concurrency. The core contains NO implementation: no scheduler, no queues, no event system; it is hook routing plus the minimal mechanism only the engine can perform (context switching, the GC destructor walker, the coroutine lifecycle status). Core ABI (Zend/zend_async_API.h): - zend_coroutine_t: lifecycle status packed into the flags word, modifier flags, object_offset for the single-allocation embed pattern (or a stored object pointer via OBJ_REF), an awaiting_info diagnostics hook. No embedded wait state. - scheduler slots registered once per process via a versioned struct: new_coroutine, enqueue_coroutine, suspend(from_main, is_bailout), resume, cancel, launch, shutdown, get_class_ce, call_on_main_stack, context accessors (userland zval keys + internal numeric keys with a core-owned key registry), intercept_fiber, gc_destructors, defer. - zend_async_microtask_t: a thin one-shot task (handler, dtor, 32-bit ref_count, named flag bits incl. is_cancelled). The queue is provider-owned; the defer slot only routes the pointer. - per-thread globals: state, current/main coroutine, live coroutine count, the in_scheduler_context flag, the PHP bridge hook storage. Engine integration: - the scheduler is not lazy: it launches right before the script code runs (main.c, phpdbg) and receives the after-main handover; after destructors the API deactivates. - fibers: intercept_fiber links a fiber to a coroutine (the hook returns the coroutine to bind, created by the scheduler, or NULL for the legacy low-level path). There is NO switching API: inside scheduler code (in_scheduler_context, set around hook invocations) the plain Fiber API on a bound fiber performs the direct context switch; in application code the same calls park the value and route through the hooks. Deferred starts take an owned deep copy of their arguments. Fiber::suspend() is unchanged. - GC: the destructor phase is an around-interceptor. The engine keeps the walker, the once-per-object guarantee and the phase cursor, and re-runs missed destructors after the hook as a safety net; the hook brackets the run with provider logic (open a completion group, run, await everything the destructors spawned, transitively). Each destructor executes as application code (the scheduler flag is dropped around it). The executor reaches the hook as a Closure over an unregistered internal function - unreachable from application code. PHP bridge (Zend/zend_scheduler_hook.c): final class Async\ SchedulerHook - hook-name constants, register(module, hooks) (throws when a scheduler is already registered), getModule(), defer() (forwards to the DEFER hook). Hooks are stored by numeric index in the per-thread globals; each slot is backed by a C thunk forwarding to the stored callable. Tests (Zend/tests/async, 13): registration semantics, constants, launch-at-registration, managed-fiber lifecycle through a plain-Fiber scheduler loop (start/suspend/resume/finish, throw at the suspension point, uncaught exception propagation, after-main drain, direct- inside/routed-outside context semantics), low-level fibers untouched by a null intercept, microtask forwarding, and a GC cycle whose destructors spawn managed fibers awaited by the hook. Full async, fibers and gc suites pass (194/194). RFC and integration reference: https://github.com/true-async/php-async-core-rfc
EdmondDantes added a commit
to true-async/php-async-core-rfc
that referenced
this pull request
Jul 3, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The engine gains the ability to activate a concurrent execution mode: a scheduler (a C extension or a PHP library) registers a set of hooks through a single call and takes control of concurrency. The core contains no implementation — no scheduler, no queues, no event system; it is hook routing plus the minimal mechanism only the engine can perform.
RFC: https://github.com/true-async/php-async-core-rfc/blob/main/RFC.md
Integration reference: https://github.com/true-async/php-async-core-rfc/blob/main/SCHEDULER.md
Tested: Zend/tests/async (13 tests) plus the full fibers and gc suites — 194/194.