diff --git a/.github/workflows/release-dev.yaml b/.github/workflows/release-dev.yaml index f2b2f2901b98..228865ac7812 100644 --- a/.github/workflows/release-dev.yaml +++ b/.github/workflows/release-dev.yaml @@ -36,6 +36,45 @@ jobs: uses: "./.github/workflows/wasix-pr.yaml" needs: version-check + create-libphp-release: + runs-on: ubuntu-latest + needs: + - build-and-test + - version-check + permissions: + contents: write + steps: + - name: Download libphp artifacts + uses: actions/download-artifact@v4 + with: + path: release-artifacts + + - name: Package libphp artifacts + run: | + TAG_NAME=${{github.ref_name}} + VERSION_NUMBER=${TAG_NAME#dev-} + + # Package 32-bit libphp + cd release-artifacts/libphp-wasix-32 + tar -czf ../libphp-wasix-32-${VERSION_NUMBER}.tar.gz * + cd ../.. + + # Package 64-bit libphp + cd release-artifacts/libphp-wasix-64 + tar -czf ../libphp-wasix-64-${VERSION_NUMBER}.tar.gz * + cd ../.. + + - name: Create GitHub Release + uses: softprops/action-gh-release@v1 + with: + files: | + release-artifacts/libphp-wasix-32-*.tar.gz + release-artifacts/libphp-wasix-64-*.tar.gz + draft: false + prerelease: true + generate_release_notes: true + token: ${{ secrets.GITHUB_TOKEN }} + release: runs-on: ubuntu-latest needs: diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index d01c8a376628..08b1d6329052 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -36,6 +36,45 @@ jobs: uses: "./.github/workflows/wasix-pr.yaml" needs: version-check + create-libphp-release: + runs-on: ubuntu-latest + needs: + - build-and-test + - version-check + permissions: + contents: write + steps: + - name: Download libphp artifacts + uses: actions/download-artifact@v4 + with: + path: release-artifacts + + - name: Package libphp artifacts + run: | + TAG_NAME=${{github.ref_name}} + VERSION_NUMBER=${TAG_NAME#dev-} + + # Package 32-bit libphp + cd release-artifacts/libphp-wasix-32 + tar -czf ../libphp-wasix-32-${VERSION_NUMBER}.tar.gz * + cd ../.. + + # Package 64-bit libphp + cd release-artifacts/libphp-wasix-64 + tar -czf ../libphp-wasix-64-${VERSION_NUMBER}.tar.gz * + cd ../.. + + - name: Create GitHub Release + uses: softprops/action-gh-release@v1 + with: + files: | + release-artifacts/libphp-wasix-32-*.tar.gz + release-artifacts/libphp-wasix-64-*.tar.gz + draft: false + prerelease: true + generate_release_notes: true + token: ${{ secrets.GITHUB_TOKEN }} + release: runs-on: ubuntu-latest needs: diff --git a/.github/workflows/wasix-pr.yaml b/.github/workflows/wasix-pr.yaml index e3db08d1a0b1..3a92c40a7e8e 100644 --- a/.github/workflows/wasix-pr.yaml +++ b/.github/workflows/wasix-pr.yaml @@ -41,7 +41,7 @@ jobs: sudo cp binaryen-version_123/bin/* /usr/bin/ - name: Install wasixcc - uses: wasix-org/wasixcc@main + uses: wasix-org/wasixcc@0.4.2 with: github_token: ${{ secrets.GITHUB_TOKEN }} sysroot-tag: v2026-02-16.1 @@ -69,10 +69,10 @@ jobs: - name: Build run: | - export SYSROOT=$(pwd)/sysroot/wasix-sysroot-eh/sysroot export PHP_WASIX_DEPS=$(pwd)/php-wasix-deps cd php bash wasix-configure-eh-${{ matrix.variant }}.sh || { cat config.log; exit -1; } + bash wasix-build-eh.sh - name: Setup Wasmer uses: wasmerio/setup-wasmer@v3.1 @@ -92,3 +92,73 @@ jobs: with: name: php-wasix-${{ matrix.variant }} path: php/sapi/cli/php.wasm + + build-libphp: + name: Build libphp + runs-on: ubuntu-latest + strategy: + matrix: + variant: ["32", "64"] + steps: + - name: Check out + uses: actions/checkout@v3 + with: + submodules: "recursive" + path: php + + - name: Check out php-wasix-deps + uses: actions/checkout@v3 + with: + repository: wasix-org/php-wasix-deps + submodules: "recursive" + path: php-wasix-deps + + - name: OS Setup (Ubuntu) + run: | + sudo apt-get update + sudo apt-get install -y build-essential wabt re2c curl xz-utils tar + npm i -g pnpm concurrently + + wget https://github.com/WebAssembly/binaryen/releases/download/version_123/binaryen-version_123-x86_64-linux.tar.gz + tar -xzf binaryen-version_123-x86_64-linux.tar.gz + sudo cp binaryen-version_123/bin/* /usr/bin/ + + - name: Install wasixcc + uses: wasix-org/wasixcc@0.4.2 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + sysroot-tag: v2026-02-16.1 + version: v0.3.0 + + - name: Tool Versions + run: | + echo wasixcc + wasixcc -v + echo '####################' + echo wasixar + wasixar -V + echo '####################' + echo wasixnm + wasixnm -V + echo '####################' + echo wasixranlib + wasixranlib -V + echo '####################' + echo wasm-opt + wasm-opt --version + echo '####################' + echo wasm-strip + wasm-strip --version + + - name: Build + run: | + export PHP_WASIX_DEPS=$(pwd)/php-wasix-deps + cd php + bash wasix-configure-libphp-${{ matrix.variant }}.sh || { cat config.log; exit -1; } + bash wasix-build-libphp.sh + + - name: Archive build + uses: actions/upload-artifact@v4 + with: + name: libphp-wasix-${{ matrix.variant }} + path: php/install diff --git a/.gitignore b/.gitignore index 590481cc9dfa..e545d4fe0b4e 100644 --- a/.gitignore +++ b/.gitignore @@ -227,6 +227,9 @@ php.wasm # Standard object files generated by Visual Studio *.obj +# Install dir +/install + # ------------------------------------------------------------------------------ # Tests # ------------------------------------------------------------------------------ diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index f26fb4a1b6b3..a3a3e5e85b5c 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -46,6 +46,7 @@ #include "zend_accelerator_util_funcs.h" #include "zend_accelerator_hash.h" #include "zend_file_cache.h" +#include "zend_atomic.h" #include "ext/pcre/php_pcre.h" #include "ext/standard/md5.h" #include "ext/hash/php_hash.h" @@ -143,6 +144,12 @@ static void preload_restart(void); # define INCREMENT(v) InterlockedIncrement64(&ZCSG(v)) # define DECREMENT(v) InterlockedDecrement64(&ZCSG(v)) # define LOCKVAL(v) (ZCSG(v)) +#elif defined(__wasi__) +static uint32_t accel_wasi_mem_usage = 0; +static uint32_t accel_wasi_restart_in = 0; +# define INCREMENT(v) __atomic_add_fetch(&accel_wasi_##v, 1, __ATOMIC_SEQ_CST) +# define DECREMENT(v) __atomic_sub_fetch(&accel_wasi_##v, 1, __ATOMIC_SEQ_CST) +# define LOCKVAL(v) __atomic_load_n(&accel_wasi_##v, __ATOMIC_SEQ_CST) #endif #define ZCG_KEY_LEN (MAXPATHLEN * 8) @@ -266,7 +273,7 @@ static ZEND_INI_MH(accel_include_path_on_modify) static inline void accel_restart_enter(void) { -#ifdef ZEND_WIN32 +#if defined(ZEND_WIN32) || defined(__wasi__) INCREMENT(restart_in); #elif !defined(__wasi__) struct flock restart_in_progress; @@ -285,7 +292,7 @@ static inline void accel_restart_enter(void) static inline void accel_restart_leave(void) { -#ifdef ZEND_WIN32 +#if defined(ZEND_WIN32) || defined(__wasi__) ZCSG(restart_in_progress) = false; DECREMENT(restart_in); #elif !defined(__wasi__) @@ -306,7 +313,7 @@ static inline void accel_restart_leave(void) static inline int accel_restart_is_active(void) { if (ZCSG(restart_in_progress)) { -#ifdef ZEND_WIN32 +#if defined(ZEND_WIN32) || defined(__wasi__) return LOCKVAL(restart_in) != 0; #elif !defined(__wasi__) struct flock restart_check; @@ -334,7 +341,7 @@ static inline int accel_restart_is_active(void) /* Creates a read lock for SHM access */ static inline zend_result accel_activate_add(void) { -#ifdef ZEND_WIN32 +#if defined(ZEND_WIN32) || defined(__wasi__) SHM_UNPROTECT(); INCREMENT(mem_usage); SHM_PROTECT(); @@ -357,7 +364,7 @@ static inline zend_result accel_activate_add(void) /* Releases a lock for SHM access */ static inline void accel_deactivate_sub(void) { -#ifdef ZEND_WIN32 +#if defined(ZEND_WIN32) || defined(__wasi__) if (ZCG(counted)) { SHM_UNPROTECT(); DECREMENT(mem_usage); @@ -380,7 +387,7 @@ static inline void accel_deactivate_sub(void) static inline void accel_unlock_all(void) { -#ifdef ZEND_WIN32 +#if defined(ZEND_WIN32) || defined(__wasi__) accel_deactivate_sub(); #elif !defined(__wasi__) if (lock_file == -1) { @@ -892,7 +899,7 @@ static inline void kill_all_lockers(struct flock *mem_usage_check) static inline bool accel_is_inactive(void) { -#ifdef ZEND_WIN32 +#if defined(ZEND_WIN32) || defined(__wasi__) /* on Windows, we don't need kill_all_lockers() because SAPIs that work on Windows don't manage child processes (and we can't do anything about hanging threads anyway); therefore @@ -2823,6 +2830,7 @@ static inline zend_result accel_find_sapi(void) "fuzzer", "frankenphp", "ngx-php", + "phpix", NULL }; const char **sapi_name; @@ -2921,6 +2929,10 @@ static zend_result zend_accel_init_shm(void) ZCSG(start_time) = zend_accel_get_time(); ZCSG(last_restart_time) = 0; ZCSG(restart_in_progress) = false; +#ifdef __wasi__ + __atomic_store_n(&accel_wasi_mem_usage, 0, __ATOMIC_SEQ_CST); + __atomic_store_n(&accel_wasi_restart_in, 0, __ATOMIC_SEQ_CST); +#endif for (i = 0; i < -HT_MIN_MASK; i++) { ZCSG(uninitialized_bucket)[i] = HT_INVALID_IDX; @@ -2942,7 +2954,7 @@ void accel_globals_ctor(zend_accel_globals *accel_globals) } #ifdef ZTS -static void accel_globals_dtor(zend_accel_globals *accel_globals) +void accel_globals_dtor(zend_accel_globals *accel_globals) { zend_string_free(accel_globals->key); } @@ -3118,11 +3130,6 @@ static void accel_move_code_to_huge_pages(void) int accel_startup(zend_extension *extension) { -#ifdef ZTS - accel_globals_id = ts_allocate_id(&accel_globals_id, sizeof(zend_accel_globals), (ts_allocate_ctor) accel_globals_ctor, (ts_allocate_dtor) accel_globals_dtor); -#else -#endif - #ifdef HAVE_JIT zend_jit_init(); #endif diff --git a/ext/opcache/ZendAccelerator.h b/ext/opcache/ZendAccelerator.h index fa040e3c7bd4..fdc7b2501650 100644 --- a/ext/opcache/ZendAccelerator.h +++ b/ext/opcache/ZendAccelerator.h @@ -329,6 +329,9 @@ zend_string* ZEND_FASTCALL accel_new_interned_string(zend_string *str); uint32_t zend_accel_get_class_name_map_ptr(zend_string *type_name); void accel_globals_ctor(zend_accel_globals *accel_globals); +#ifdef ZTS +void accel_globals_dtor(zend_accel_globals *accel_globals); +#endif END_EXTERN_C() diff --git a/ext/opcache/zend_accelerator_module.c b/ext/opcache/zend_accelerator_module.c index 2ffe7db2bb4e..c94da9ef5d75 100644 --- a/ext/opcache/zend_accelerator_module.c +++ b/ext/opcache/zend_accelerator_module.c @@ -410,7 +410,11 @@ static ZEND_MINIT_FUNCTION(zend_accelerator) // Run the ctor before registering the INI entries, as that will // read and set the values - accel_globals_ctor(&accel_globals); +#ifdef ZTS + accel_globals_id = ts_allocate_id(&accel_globals_id, sizeof(zend_accel_globals), (ts_allocate_ctor) accel_globals_ctor, (ts_allocate_dtor) accel_globals_dtor); +#else + accel_globals_ctor(&accel_globals); +#endif REGISTER_INI_ENTRIES(); diff --git a/ext/opcache/zend_file_cache.c b/ext/opcache/zend_file_cache.c index edcaf689ab7f..011c6a4f7d39 100644 --- a/ext/opcache/zend_file_cache.c +++ b/ext/opcache/zend_file_cache.c @@ -96,9 +96,15 @@ static int zend_file_cache_flock(int fd, int op) #elif defined(HAVE_FLOCK) # define zend_file_cache_flock flock #else -# define LOCK_SH 0 -# define LOCK_EX 1 -# define LOCK_UN 2 +# ifndef LOCK_SH +# define LOCK_SH 0 +# endif +# ifndef LOCK_EX +# define LOCK_EX 1 +# endif +# ifndef LOCK_UN +# define LOCK_UN 2 +# endif static int zend_file_cache_flock(int fd, int type) { return 0; diff --git a/ext/opcache/zend_shared_alloc.c b/ext/opcache/zend_shared_alloc.c index 4d97081fb053..c20033b4c5c5 100644 --- a/ext/opcache/zend_shared_alloc.c +++ b/ext/opcache/zend_shared_alloc.c @@ -29,6 +29,7 @@ #include #include "ZendAccelerator.h" #include "zend_shared_alloc.h" +#include "zend_atomic.h" #ifdef HAVE_UNISTD_H # include #endif @@ -63,6 +64,14 @@ int lock_file = -1; static char lockfile_name[MAXPATHLEN]; #endif +#ifdef __wasi__ +# ifdef ZTS +static MUTEX_T zend_shared_alloc_wasi_mutex; +# else +static zend_atomic_bool zend_shared_alloc_wasi_lock; +# endif +#endif + static const zend_shared_memory_handler_entry handler_table[] = { #ifdef USE_MMAP { "mmap", &zend_alloc_mmap_handlers }, @@ -181,12 +190,18 @@ int zend_shared_alloc_startup(size_t requested_size, size_t reserved_size) smm_shared_globals = &tmp_shared_globals; ZSMMG(shared_free) = requested_size - reserved_size; /* goes to tmp_shared_globals.shared_free */ -#ifndef __wasi__ #ifndef ZEND_WIN32 +#ifdef __wasi__ +#ifdef ZTS + zend_shared_alloc_wasi_mutex = tsrm_mutex_alloc(); +#else + ZEND_ATOMIC_BOOL_INIT(&zend_shared_alloc_wasi_lock, false); +#endif +#else zend_shared_alloc_create_lock(ZCG(accel_directives).lockfile_path); +#endif #else zend_shared_alloc_create_lock(); -#endif #endif if (ZCG(accel_directives).memory_model && ZCG(accel_directives).memory_model[0]) { @@ -325,10 +340,17 @@ void zend_shared_alloc_shutdown(void) ZSMMG(shared_segments) = NULL; g_shared_alloc_handler = NULL; #ifndef ZEND_WIN32 - close(lock_file); + if (lock_file >= 0) { + close(lock_file); + lock_file = -1; + } # ifdef ZTS +# ifdef __wasi__ + tsrm_mutex_free(zend_shared_alloc_wasi_mutex); +# else tsrm_mutex_free(zts_lock); +# endif # endif #endif } @@ -481,7 +503,14 @@ void zend_shared_alloc_lock(void) #ifdef ZEND_WIN32 zend_shared_alloc_lock_win32(); -#elif !defined(__wasi__) +#elif defined(__wasi__) +#ifdef ZTS + tsrm_mutex_lock(zend_shared_alloc_wasi_mutex); +#else + while (zend_atomic_bool_exchange_ex(&zend_shared_alloc_wasi_lock, true)) { + } +#endif +#else struct flock mem_write_lock; mem_write_lock.l_type = F_WRLCK; @@ -531,7 +560,13 @@ void zend_shared_alloc_unlock(void) #ifdef ZEND_WIN32 zend_shared_alloc_unlock_win32(); -#elif !defined(__wasi__) +#elif defined(__wasi__) +#ifdef ZTS + tsrm_mutex_unlock(zend_shared_alloc_wasi_mutex); +#else + zend_atomic_bool_store_ex(&zend_shared_alloc_wasi_lock, false); +#endif +#else if (fcntl(lock_file, F_SETLK, &mem_write_unlock) == -1) { zend_accel_error_noreturn(ACCEL_LOG_ERROR, "Cannot remove lock - %s (%d)", strerror(errno), errno); } diff --git a/wasix-build-libphp.sh b/wasix-build-libphp.sh new file mode 100755 index 000000000000..fe6c0e7dbfb3 --- /dev/null +++ b/wasix-build-libphp.sh @@ -0,0 +1,5 @@ +#! /usr/bin/env sh + +set -eou + +make -j16 install-headers install-sapi diff --git a/wasix-configure-eh.sh b/wasix-configure-eh.sh index ec029912a5d3..914496536fc8 100755 --- a/wasix-configure-eh.sh +++ b/wasix-configure-eh.sh @@ -7,6 +7,7 @@ if [ -f Makefile ]; then fi PHP_WASIX_DEPS=${PHP_WASIX_DEPS:-"../php-wasix-deps"} +WASIX_EXTRA_CONFIGURE_FLAGS=${WASIX_EXTRA_CONFIGURE_FLAGS:-""} export \ CURL_CFLAGS="-I$PHP_WASIX_DEPS/include/curl" \ @@ -52,7 +53,7 @@ export \ CXXFLAGS="-g -flto -O2" \ LIBS="-L$PHP_WASIX_DEPS/lib-eh --no-wasm-opt" \ WASIXCC_INCLUDE_CPP_SYMBOLS="yes" \ - WASIXCC_WASM_EXCEPTIONS="yes" \ + WASIXCC_WASM_EXCEPTIONS="legacy" \ PROG_SENDMAIL="/usr/bin/sendmail" ./buildconf --force @@ -65,6 +66,5 @@ export \ --enable-fiber-asm --with-curl --with-mysqli=mysqlnd --with-pdo-mysql=mysqlnd --with-zip --with-sodium \ --with-pgsql="$PHP_WASIX_DEPS"/pgsql-eh --with-pdo-pgsql="$PHP_WASIX_DEPS"/pgsql-eh --enable-intl \ --with-pdo-sqlite --enable-ftp --enable-igbinary --with-imagick \ + $WASIX_EXTRA_CONFIGURE_FLAGS \ --program-suffix=".wasm" - -./wasix-build-eh.sh diff --git a/wasix-configure-libphp-32.sh b/wasix-configure-libphp-32.sh new file mode 100755 index 000000000000..9d99e35197c9 --- /dev/null +++ b/wasix-configure-libphp-32.sh @@ -0,0 +1,8 @@ +#! /usr/bin/env sh + +set -eu + +export WASIX_64BIT_LONG_PATCH=no +export WASIX_EXTRA_CONFIGURE_FLAGS="--enable-zts --enable-embed=static --prefix=$(realpath ./install)" + +./wasix-configure-eh.sh diff --git a/wasix-configure-libphp-64.sh b/wasix-configure-libphp-64.sh new file mode 100755 index 000000000000..a0bf64d4751b --- /dev/null +++ b/wasix-configure-libphp-64.sh @@ -0,0 +1,8 @@ +#! /usr/bin/env sh + +set -eu + +export WASIX_64BIT_LONG_PATCH=yes +export WASIX_EXTRA_CONFIGURE_FLAGS="--enable-zts --enable-embed=static --prefix=$(realpath ./install)" + +./wasix-configure-eh.sh