Skip to content

[PHP-wasm] Add support for concurrent popen calls#3486

Open
bgrgicak wants to merge 4 commits intowith-smtp-sinkfrom
update/use-php-wasm-popen-pclose
Open

[PHP-wasm] Add support for concurrent popen calls#3486
bgrgicak wants to merge 4 commits intowith-smtp-sinkfrom
update/use-php-wasm-popen-pclose

Conversation

@bgrgicak
Copy link
Copy Markdown
Collaborator

@bgrgicak bgrgicak commented Apr 14, 2026

Motivation for the change, related issues

The previous popen/pclose implementation used single global variables (wasm_popen_last_pid and wasm_pclose_ret) to track the spawned process PID and exit code. This meant concurrent writable popen() calls would clobber each other's state, producing wrong exit codes or closing the wrong process.

Additionally, popen/pclose interception relied on a VCWD_POPEN macro patch and explicit sed replacements in mail.c, which was fragile and didn't cover all call sites.

Implementation details

Linker-level wrapping replaces macro patching

Instead of patching VCWD_POPEN in zend_virtual_cwd.h and sed-replacing popen/pclose in mail.c, this PR uses --wrap=popen and --wrap=pclose linker flags. This transparently redirects all popen()/pclose() calls in the compiled C code to __wrap_popen/__wrap_pclose, which delegate to wasm_popen/wasm_pclose. For pclose, handles not created by wasm_popen fall through to the real libc pclose.

Per-fd PID tracking instead of globals

Replaces wasm_popen_last_pid and wasm_pclose_ret with an fd-to-pid mapping stored in the existing JS PHPWASM.processTable. Three new Emscripten library functions manage the mapping:

  • js_popen_set_pid_for_fd(fd, pid) — called by wasm_popen after spawning a process
  • js_popen_get_pid_for_fd(fd) — called by wasm_pclose to find which process to wait on
  • js_popen_clear_pid_for_fd(fd) — called by wasm_pclose before closing the file

This allows multiple popen handles to be open simultaneously without state corruption.

Emscripten library updates

Adds __wrap_popen, __wrap_pclose, and zif_pclose to the Asyncify import list and JSPI export list so the new wrapper functions can suspend correctly.

TODO

  • Recompile all PHP versions after PR review

Testing Instructions

  • CI

bgrgicak and others added 4 commits April 13, 2026 15:04
js_popen_store_pid -> js_popen_set_pid_for_fd
js_popen_lookup_pid -> js_popen_get_pid_for_fd
js_popen_remove_fd -> js_popen_clear_pid_for_fd

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Verifies that pclose returns the correct exit code for each
process when multiple popen handles are open simultaneously.
Also restricts concurrent popen tests to PHP 8.4 until all
versions are recompiled.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@bgrgicak bgrgicak self-assigned this Apr 14, 2026
@bgrgicak bgrgicak added [Package][@php-wasm] Universal [Type] Bug An existing feature does not function as intended labels Apr 14, 2026
@bgrgicak bgrgicak marked this pull request as ready for review April 14, 2026 08:25
@bgrgicak bgrgicak changed the title [PHP-wasm] Add suppor for concurrent popen calls [PHP-wasm] Add support for concurrent popen calls Apr 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Package][@php-wasm] Universal [Type] Bug An existing feature does not function as intended

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant