Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: CI

on:
push:
branches: [master]
pull_request:
branches: [master]

jobs:
build:
name: PHP ${{ matrix.php }} - ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest]
php: ['8.1', '8.2', '8.3', '8.4', '8.5']

steps:
- uses: actions/checkout@v4

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
tools: none

- name: Build extension
run: |
phpize
./configure --enable-eventloop
make -j$(nproc 2>/dev/null || sysctl -n hw.ncpu)

- name: Run tests
run: make test TESTS="-q --show-diff"

- name: Verify extension loads
run: php -d extension=modules/eventloop.so -m | grep eventloop
1 change: 1 addition & 0 deletions eventloop.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
# include <signal.h>
#endif

#include "php_eventloop_compat.h"
#include "eventloop_arginfo.h"

ZEND_DECLARE_MODULE_GLOBALS(eventloop)
Expand Down
4 changes: 2 additions & 2 deletions eventloop_cb.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
static zend_string *eventloop_generate_id(void)
{
char buf[24];
int len;

len = snprintf(buf, sizeof(buf), "eL%" PRIx64, EVENTLOOP_G(next_id)++);
int len = snprintf(buf, sizeof(buf), "eL%" PRIx64, EVENTLOOP_G(next_id)++);

return zend_string_init(buf, len, 0);
}

Expand Down
5 changes: 4 additions & 1 deletion eventloop_suspension.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#ifdef HAVE_FIBERS
#include "zend_exceptions.h"
#include "zend_enum.h"
#include "php_eventloop_compat.h"
#include "eventloop_arginfo.h"

typedef struct _eventloop_suspension_obj {
Expand Down Expand Up @@ -41,6 +42,8 @@ static zend_object *suspension_create_object(zend_class_entry *ce)
zend_object_std_init(&suspension->std, ce);
object_properties_init(&suspension->std, ce);

suspension->std.handlers = &suspension_object_handlers;

ZVAL_NULL(&suspension->fiber_zv);
suspension->pending = false;
suspension->suspended = false;
Expand Down Expand Up @@ -207,7 +210,7 @@ void eventloop_suspension_init(void)
{
eventloop_suspension_ce = register_class_EventLoop_Suspension();
eventloop_suspension_ce->create_object = suspension_create_object;
eventloop_suspension_ce->default_object_handlers = &suspension_object_handlers;
EVENTLOOP_SET_DEFAULT_HANDLERS(eventloop_suspension_ce, &suspension_object_handlers);

memcpy(&suspension_object_handlers, zend_get_std_object_handlers(),
sizeof(zend_object_handlers));
Expand Down
88 changes: 88 additions & 0 deletions php_eventloop_compat.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* Copyright (c) 2026 Aleksandr Cherednikov
* Licensed under the MIT License. See LICENSE for details.
*/

#ifndef PHP_EVENTLOOP_COMPAT_H
#define PHP_EVENTLOOP_COMPAT_H

#include "php.h"
#include "zend_API.h"

/*
* Compatibility shims for building across PHP 8.1 – 8.5+.
*
* The extension targets PHP >= 8.1 (Fibers). Internal Zend APIs evolved
* between releases, so we polyfill the newer signatures here and let
* each call-site use a single, modern spelling.
*/

/* ------------------------------------------------------------------ */
/* zend_register_internal_class_with_flags() — added in PHP 8.4 */
/* In 8.1-8.3 we register + set flags manually. */
/* ------------------------------------------------------------------ */
#if PHP_VERSION_ID < 80400
static inline zend_class_entry *zend_register_internal_class_with_flags(
zend_class_entry *ce, zend_class_entry *parent, uint32_t flags)
{
zend_class_entry *registered = zend_register_internal_class_ex(ce, parent);
registered->ce_flags |= flags;
return registered;
}
#endif

/* ------------------------------------------------------------------ */
/* ce->default_object_handlers — added in PHP 8.3 */
/* ------------------------------------------------------------------ */
#if PHP_VERSION_ID >= 80300
# define EVENTLOOP_SET_DEFAULT_HANDLERS(ce, h) \
(ce)->default_object_handlers = (h)
#else
# define EVENTLOOP_SET_DEFAULT_HANDLERS(ce, h) \
/* not available before 8.3 — handlers set in create_object */
#endif

/* ------------------------------------------------------------------ */
/* Fiber suspend / resume internal API */
/* */
/* PHP 8.4+ exposes zend_fiber_suspend() / zend_fiber_resume() with a */
/* three-arg signature. Earlier versions do not export these symbols, */
/* so we call the userland Fiber::suspend() / $fiber->resume() via */
/* zend_call_method, which performs the same context switch. */
/* ------------------------------------------------------------------ */
#include "zend_fibers.h"
#include "zend_interfaces.h"

#if PHP_VERSION_ID < 80400

static inline void eventloop_compat_fiber_suspend(
zend_fiber *fiber, zval *value, zval *return_value)
{
(void)fiber; /* Fiber::suspend() operates on the active fiber */
if (value && Z_TYPE_P(value) != IS_NULL) {
zend_call_method_with_1_params(NULL, zend_ce_fiber, NULL, "suspend", return_value, value);
} else {
zend_call_method_with_0_params(NULL, zend_ce_fiber, NULL, "suspend", return_value);
}
}

static inline void eventloop_compat_fiber_resume(
zend_fiber *fiber, zval *value, zval *error)
{
zval fiber_zv, retval;
(void)error;
ZVAL_OBJ(&fiber_zv, &fiber->std);
if (value && Z_TYPE_P(value) != IS_NULL) {
zend_call_method_with_1_params(&fiber_zv, zend_ce_fiber, NULL, "resume", &retval, value);
} else {
zend_call_method_with_0_params(&fiber_zv, zend_ce_fiber, NULL, "resume", &retval);
}
zval_ptr_dtor(&retval);
}

# define zend_fiber_suspend(f, v, r) eventloop_compat_fiber_suspend((f), (v), (r))
# define zend_fiber_resume(f, v, e) eventloop_compat_fiber_resume((f), (v), (e))

#endif /* PHP_VERSION_ID < 80400 */

#endif /* PHP_EVENTLOOP_COMPAT_H */
Loading