diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 68498310..b446f79b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,9 +35,9 @@ jobs: opcache_gate: composer test:opcache - ts: zts ts_label: ZTS - # The file-cache relocator does not support ZTS payloads yet - # (issue #118): its tests self-skip on ZTS, so the non-skip gate - # excludes that group while still proving the SHM tests ran + # Since issue #118 the file-cache relocator supports ZTS payloads, + # so this gate covers the full opcache group (the script is the + # named alias the ZTS legs call; it no longer excludes anything) opcache_gate: composer test:opcache-zts steps: - uses: actions/checkout@v7 @@ -203,8 +203,8 @@ jobs: run: composer test # Same gates as the Linux legs (issue #124): the opcache/SHM tests must - # have RUN. As on Linux, the ZTS leg excludes the file-cache relocator - # group (no ZTS payload support yet, issue #118). + # have RUN. Since issue #118 the relocator group runs on ZTS too, so + # both legs cover the full opcache group. - name: Opcache/SHM coverage must not silently skip if: steps.artifacts.outputs.present == 'true' run: ${{ matrix.ts == 'zts' && 'composer test:opcache-zts' || 'composer test:opcache' }} @@ -384,12 +384,12 @@ jobs: include: - ts: nts ts_label: NTS - # ZTS excludes the relocator tests (no ZTS payload support yet, - # issue #118) but still gates the SHM coverage against silent skips opcache_args: --group opcache --fail-on-skipped - ts: zts ts_label: ZTS - opcache_args: --group opcache --exclude-group opcache-relocator --fail-on-skipped + # Since issue #118 the relocator tests run on ZTS too - both legs + # gate the full opcache group against silent skips + opcache_args: --group opcache --fail-on-skipped steps: - uses: actions/checkout@v7 diff --git a/AGENTS.md b/AGENTS.md index a1a3691e..341aefb0 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -131,8 +131,8 @@ PRs), or manually via `workflow_dispatch` against any branch. Darwin covers **NTS and ZTS**: the workflow's matrix crosses both architectures with both thread-safety modes (setup-php builds the ZTS PHP via `phpts: ts`). As on Linux, the ZTS artifacts reach EG/CG through the TSRM -offsets, and the opcache file-cache relocator stays unsupported on ZTS -(issue #118). After changing the generator on this branch, remember the 8.5 +offsets; the opcache file-cache relocator runs on ZTS since issue #118. +After changing the generator on this branch, remember the 8.5 line on `master` needs its own `workflow_dispatch` run to refresh its darwin artifacts. @@ -192,10 +192,12 @@ composer test:internal # destructive/segfault-prone group, process-isolated - `ZENGINE_STRICT_LAYOUT_CHECK=1` (set in the test bootstrap) makes `Core::init()` verify every struct layout against `layouts.json` before touching engine memory — the anti-segfault airbag. Keep it on in development. -- On **ZTS** builds the file-cache relocator tests (`opcache-relocator` group) - self-skip — ZTS payloads are not supported yet (issue #118). The non-skip - gate for the remaining opcache/SHM coverage is `composer test:opcache-zts`; - CI runs both release and debug test legs on NTS **and** ZTS. +- The file-cache relocator supports **ZTS** payloads since issue #118 (the + binary layout is thread-safety-agnostic: zend_file_cache.c has no ZTS + conditionals and every walked struct is layout-identical across the modes). + `composer test:opcache-zts` stays as the named alias CI's ZTS legs call; it + now runs the full opcache group, relocator tests included. CI runs both + release and debug test legs on NTS **and** ZTS. - `composer test:opcache-runner` runs the suite the way an opcache-enabled consumer does — `opcache.enable_cli=1` in the **runner process itself**, so every test file is compiled into shared memory (CI has a dedicated Linux job diff --git a/composer.json b/composer.json index f19d428b..b161e14c 100644 --- a/composer.json +++ b/composer.json @@ -41,7 +41,7 @@ "test": "phpunit", "test:internal": "phpunit --group internal --process-isolation", "test:opcache": "phpunit --group opcache --fail-on-skipped", - "test:opcache-zts": "phpunit --group opcache --exclude-group opcache-relocator --fail-on-skipped", + "test:opcache-zts": "phpunit --group opcache --fail-on-skipped", "test:opcache-runner": "phpunit --exclude-group performance --exclude-group internal --exclude-group opcache-incompatible", "test:performance": "phpunit --group performance --fail-on-skipped", "phpstan": "phpstan analyse", @@ -53,7 +53,7 @@ "test": "Run the test suite (segfault-prone internal group excluded)", "test:internal": "Run the segfault-prone internal test group with process isolation (use a debug PHP build)", "test:opcache": "Run the opcache/shared-memory tests and FAIL if any of them skipped (they are self-skipping when opcache is unavailable)", - "test:opcache-zts": "Same non-skip gate for ZTS builds: excludes the file-cache relocator tests, which do not support ZTS payloads yet (issue #118)", + "test:opcache-zts": "Same non-skip gate on ZTS builds - kept as the named alias CI's ZTS legs call; since issue #118 the file-cache relocator tests run there too", "test:opcache-runner": "Run the suite for an opcache-ACTIVE runner (opcache.enable_cli=1): excludes the usual performance/internal groups plus opcache-incompatible, the issue-linked tests that cannot hold when the runner's own files live in shared memory", "test:performance": "Run the excluded performance group (the 'zero FFI at call time' benchmark) and FAIL if it silently skipped - its verdict is timing-based, so the CI leg that runs it is informational", "phpstan": "Run static analysis at the maximum level", diff --git a/docs/opcache-binary.md b/docs/opcache-binary.md index 2aeb5a30..c121a365 100644 --- a/docs/opcache-binary.md +++ b/docs/opcache-binary.md @@ -191,12 +191,16 @@ $report->appliedMethods; // what actually happened, per entry `opcache.preload`-based features) keep rejecting Windows loudly, and the Windows half of the original platform ticket was retired when [#119](https://github.com/lisachenko/z-engine/issues/119) was rescoped to - macOS/arm64. ZTS payloads stay tracked in - [#118](https://github.com/lisachenko/z-engine/issues/118). + macOS/arm64. ZTS payloads are supported since + [#118](https://github.com/lisachenko/z-engine/issues/118): the file-cache + binary layout is thread-safety-agnostic (zend_file_cache.c has no ZTS + conditionals, and every struct the walker dereferences is layout-identical + across the modes — only EG/CG/module_entry differ, none of which appear in + a payload). - **Strict, never silent.** Anything the port cannot handle raises `unsupportedPayload` rather than writing a subtly corrupt binary; with every payload shape of the 8.4 walker now ported, that guard covers the platform - predicates above (Windows/32-bit, and ZTS until #118). Global functions, + predicates above (Windows/32-bit). Global functions, classes with constants, typed properties (union/intersection/DNF type lists included), trait-using classes (aliases and insteadof precedences included), closures and arrow functions (nested dynamic_func_defs included), diff --git a/src/OpCache/PayloadRelocator.php b/src/OpCache/PayloadRelocator.php index 3ed67d11..21b16cb1 100644 --- a/src/OpCache/PayloadRelocator.php +++ b/src/OpCache/PayloadRelocator.php @@ -32,9 +32,12 @@ /** * Turns the position-independent file-cache payload into a live in-memory * image and back, a faithful port of ext/opcache/zend_file_cache.c - * (unserialize = {@see relocate}, serialize = {@see derelocate}) for the - * linux-x64 non-thread-safe build. Thread-safe (ZTS) payloads use a different - * binary layout and are rejected until issue #118 lands ZTS-specific walking. + * (unserialize = {@see relocate}, serialize = {@see derelocate}) for 64-bit + * POSIX builds, NTS and ZTS alike: zend_file_cache.c has no thread-safety + * conditionals, and every struct the walker dereferences is layout-identical + * across the two modes (only EG/CG/module_entry differ on ZTS, none of which + * appear in a payload) - verified against the generated layouts.json of both + * targets (issue #118). * * In the file every interior pointer is stored as a byte offset from the * buffer start (SERIALIZE_PTR) and every interned string as a tagged offset @@ -97,12 +100,12 @@ final class PayloadRelocator * Whether the relocator can handle payloads of the running build at all * * The exact predicate the constructor enforces, exposed so callers (and the tests - * covering them) can skip cleanly instead of provoking the throw. Windows payloads - * are tracked in issue #119, ZTS ones in issue #118. + * covering them) can skip cleanly instead of provoking the throw. Windows opcache + * support is an intentional non-goal (issue #119 was rescoped to macOS/arm64). */ public static function isSupported(): bool { - return PHP_INT_SIZE === 8 && \DIRECTORY_SEPARATOR === '/' && !\ZEND_THREAD_SAFE; + return PHP_INT_SIZE === 8 && \DIRECTORY_SEPARATOR === '/'; } /** @@ -114,11 +117,6 @@ public function __construct(private readonly object $buffer, private readonly Ca if (PHP_INT_SIZE !== 8 || \DIRECTORY_SEPARATOR !== '/') { throw OpCacheException::unsupportedPayload('the relocator supports 64-bit non-Windows builds only'); } - if (\ZEND_THREAD_SAFE) { - throw OpCacheException::unsupportedPayload( - 'ZTS file-cache payloads use a different binary layout - tracked in issue #118', - ); - } $this->base = Core::addressOf(Core::addr($buffer)); $this->size = $metaInfo->memSize(); $this->strSectionBase = $this->base + $this->size; diff --git a/tests/OpCache/ClosureRelocationTest.php b/tests/OpCache/ClosureRelocationTest.php index 1e9e8d96..f7046fcc 100644 --- a/tests/OpCache/ClosureRelocationTest.php +++ b/tests/OpCache/ClosureRelocationTest.php @@ -34,8 +34,8 @@ protected function setUp(): void { if (!PayloadRelocator::isSupported()) { self::markTestSkipped( - 'The file-cache relocator supports 64-bit POSIX NTS payloads only' - . ' (ZTS is issue #118, Windows is issue #119)', + 'The file-cache relocator supports 64-bit POSIX payloads only' + . ' (Windows opcache support is an intentional non-goal, issue #119)', ); } } diff --git a/tests/OpCache/IteratorFuncsRelocationTest.php b/tests/OpCache/IteratorFuncsRelocationTest.php index b06f90c9..f85a2c21 100644 --- a/tests/OpCache/IteratorFuncsRelocationTest.php +++ b/tests/OpCache/IteratorFuncsRelocationTest.php @@ -37,8 +37,8 @@ protected function setUp(): void { if (!PayloadRelocator::isSupported()) { self::markTestSkipped( - 'The file-cache relocator supports 64-bit POSIX NTS payloads only' - . ' (ZTS is issue #118, Windows is issue #119)', + 'The file-cache relocator supports 64-bit POSIX payloads only' + . ' (Windows opcache support is an intentional non-goal, issue #119)', ); } } diff --git a/tests/OpCache/PropertyHookRelocationTest.php b/tests/OpCache/PropertyHookRelocationTest.php index 02460b7c..8755cee0 100644 --- a/tests/OpCache/PropertyHookRelocationTest.php +++ b/tests/OpCache/PropertyHookRelocationTest.php @@ -34,8 +34,8 @@ protected function setUp(): void { if (!PayloadRelocator::isSupported()) { self::markTestSkipped( - 'The file-cache relocator supports 64-bit POSIX NTS payloads only' - . ' (ZTS is issue #118, Windows is issue #119)', + 'The file-cache relocator supports 64-bit POSIX payloads only' + . ' (Windows opcache support is an intentional non-goal, issue #119)', ); } } diff --git a/tests/OpCache/ReflectionOpcacheFileTest.php b/tests/OpCache/ReflectionOpcacheFileTest.php index 362da386..16a7ad15 100644 --- a/tests/OpCache/ReflectionOpcacheFileTest.php +++ b/tests/OpCache/ReflectionOpcacheFileTest.php @@ -26,8 +26,8 @@ protected function setUp(): void { if (!PayloadRelocator::isSupported()) { self::markTestSkipped( - 'The file-cache relocator supports 64-bit POSIX NTS payloads only' - . ' (ZTS is issue #118, Windows is issue #119)', + 'The file-cache relocator supports 64-bit POSIX payloads only' + . ' (Windows opcache support is an intentional non-goal, issue #119)', ); } } diff --git a/tests/OpCache/RefreshWorkflowTest.php b/tests/OpCache/RefreshWorkflowTest.php index 1653d175..0b760db9 100644 --- a/tests/OpCache/RefreshWorkflowTest.php +++ b/tests/OpCache/RefreshWorkflowTest.php @@ -32,8 +32,8 @@ protected function setUp(): void { if (!PayloadRelocator::isSupported()) { self::markTestSkipped( - 'The file-cache relocator supports 64-bit POSIX NTS payloads only' - . ' (ZTS is issue #118, Windows is issue #119)', + 'The file-cache relocator supports 64-bit POSIX payloads only' + . ' (Windows opcache support is an intentional non-goal, issue #119)', ); } } diff --git a/tests/OpCache/SerializerRoundTripTest.php b/tests/OpCache/SerializerRoundTripTest.php index ef48234e..91140a69 100644 --- a/tests/OpCache/SerializerRoundTripTest.php +++ b/tests/OpCache/SerializerRoundTripTest.php @@ -32,8 +32,8 @@ protected function setUp(): void { if (!PayloadRelocator::isSupported()) { self::markTestSkipped( - 'The file-cache relocator supports 64-bit POSIX NTS payloads only' - . ' (ZTS is issue #118, Windows is issue #119)', + 'The file-cache relocator supports 64-bit POSIX payloads only' + . ' (Windows opcache support is an intentional non-goal, issue #119)', ); } } diff --git a/tests/OpCache/TraitRelocationTest.php b/tests/OpCache/TraitRelocationTest.php index 171275c1..6d274907 100644 --- a/tests/OpCache/TraitRelocationTest.php +++ b/tests/OpCache/TraitRelocationTest.php @@ -34,8 +34,8 @@ protected function setUp(): void { if (!PayloadRelocator::isSupported()) { self::markTestSkipped( - 'The file-cache relocator supports 64-bit POSIX NTS payloads only' - . ' (ZTS is issue #118, Windows is issue #119)', + 'The file-cache relocator supports 64-bit POSIX payloads only' + . ' (Windows opcache support is an intentional non-goal, issue #119)', ); } } diff --git a/tests/OpCache/TypeListRelocationTest.php b/tests/OpCache/TypeListRelocationTest.php index 0f5aebe2..ecd5c938 100644 --- a/tests/OpCache/TypeListRelocationTest.php +++ b/tests/OpCache/TypeListRelocationTest.php @@ -33,8 +33,8 @@ protected function setUp(): void { if (!PayloadRelocator::isSupported()) { self::markTestSkipped( - 'The file-cache relocator supports 64-bit POSIX NTS payloads only' - . ' (ZTS is issue #118, Windows is issue #119)', + 'The file-cache relocator supports 64-bit POSIX payloads only' + . ' (Windows opcache support is an intentional non-goal, issue #119)', ); } }