Skip to content

Commit 78d13eb

Browse files
committed
fix: support for timeouts with ZTS on Linux
1 parent b73e1db commit 78d13eb

File tree

3 files changed

+80
-0
lines changed

3 files changed

+80
-0
lines changed

Zend/zend_execute_API.c

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,14 @@
4343
#ifdef HAVE_UNISTD_H
4444
#include <unistd.h>
4545
#endif
46+
#if defined(ZTS) && defined(HAVE_TIMER_CREATE)
47+
#include <time.h>
48+
// Musl Libc defines this macro, glibc does not
49+
// According to "man 2 timer_create" this field should always be available, but it's not
50+
# ifndef sigev_notify_thread_id
51+
# define sigev_notify_thread_id _sigev_un._tid
52+
# endif
53+
#endif
4654

4755
ZEND_API void (*zend_execute_ex)(zend_execute_data *execute_data);
4856
ZEND_API void (*zend_execute_internal)(zend_execute_data *execute_data, zval *return_value);
@@ -171,6 +179,20 @@ void init_executor(void) /* {{{ */
171179
EG(vm_interrupt) = 0;
172180
EG(timed_out) = 0;
173181

182+
#if defined(ZTS) && defined(HAVE_TIMER_CREATE)
183+
struct sigevent sev;
184+
sev.sigev_notify = SIGEV_THREAD_ID;
185+
sev.sigev_value.sival_ptr = &EG(timer);
186+
sev.sigev_signo = SIGIO;
187+
sev.sigev_notify_thread_id = gettid();
188+
189+
if (timer_create(CLOCK_THREAD_CPUTIME_ID, &sev, &EG(timer)) != 0)
190+
fprintf(stderr, "error %d while creating timer\n", errno);
191+
# ifdef TIMER_DEBUG
192+
else fprintf(stderr, "timer created for thread %d\n", gettid());
193+
# endif
194+
#endif
195+
174196
EG(exception) = NULL;
175197
EG(prev_exception) = NULL;
176198

@@ -396,6 +418,14 @@ void shutdown_executor(void) /* {{{ */
396418
bool fast_shutdown = is_zend_mm() && !EG(full_tables_cleanup);
397419
#endif
398420

421+
#if defined(ZTS) && defined(HAVE_TIMER_CREATE)
422+
if (timer_delete(EG(timer)) != 0)
423+
fprintf(stderr, "error %d while deleting timer\n", errno);
424+
# ifdef TIMER_DEBUG
425+
else fprintf(stderr, "timer deleted for thread %d\n", gettid());
426+
# endif
427+
#endif
428+
399429
zend_try {
400430
zend_stream_shutdown();
401431
} zend_end_try();
@@ -1314,8 +1344,18 @@ ZEND_API ZEND_NORETURN void ZEND_FASTCALL zend_timeout(void) /* {{{ */
13141344
/* }}} */
13151345

13161346
#ifndef ZEND_WIN32
1347+
#if defined(ZTS) && defined(HAVE_TIMER_CREATE)
1348+
static void zend_timeout_handler(int dummy, siginfo_t *si, void *uc) /* {{{ */
1349+
{
1350+
if (si->si_value.sival_ptr != &EG(timer)) {
1351+
fprintf(stderr, "ignoring timeout signal SIGIO received on thread %d\n", gettid());
1352+
1353+
return;
1354+
}
1355+
#else
13171356
static void zend_timeout_handler(int dummy) /* {{{ */
13181357
{
1358+
#endif
13191359
#ifndef ZTS
13201360
if (EG(timed_out)) {
13211361
/* Die on hard timeout */
@@ -1415,6 +1455,36 @@ static void zend_set_timeout_ex(zend_long seconds, bool reset_signals) /* {{{ */
14151455
zend_error_noreturn(E_ERROR, "Could not queue new timer");
14161456
return;
14171457
}
1458+
#elif defined(ZTS) && defined(HAVE_TIMER_CREATE)
1459+
timer_t timer = EG(timer);
1460+
struct itimerspec its;
1461+
1462+
its.it_value.tv_sec = seconds;
1463+
its.it_value.tv_nsec = 0;
1464+
its.it_interval.tv_sec = 0;
1465+
its.it_interval.tv_nsec = 0;
1466+
1467+
if (timer_settime(timer, 0, &its, NULL) != 0) {
1468+
fprintf(stderr, "unable to set timer on thread %d\n", gettid());
1469+
1470+
return;
1471+
}
1472+
# ifdef TIMER_DEBUG
1473+
else fprintf(stderr, "timer set for thread %d (%ld seconds)\n", gettid(), seconds);
1474+
# endif
1475+
1476+
if (reset_signals) {
1477+
sigset_t sigset;
1478+
struct sigaction act;
1479+
1480+
act.sa_sigaction = zend_timeout_handler;
1481+
sigemptyset(&act.sa_mask);
1482+
act.sa_flags = SA_ONSTACK | SA_SIGINFO;
1483+
sigaction(SIGIO, &act, NULL);
1484+
sigemptyset(&sigset);
1485+
sigaddset(&sigset, SIGIO);
1486+
sigprocmask(SIG_UNBLOCK, &sigset, NULL);
1487+
}
14181488
#elif defined(HAVE_SETITIMER)
14191489
{
14201490
struct itimerval t_r; /* timeout requested */

Zend/zend_globals.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222

2323

2424
#include <setjmp.h>
25+
#if defined(ZTS) && defined(HAVE_TIMER_CREATE)
26+
#include <time.h>
27+
#endif
2528

2629
#include "zend_globals_macros.h"
2730

@@ -266,6 +269,10 @@ struct _zend_executor_globals {
266269
uint32_t num_errors;
267270
zend_error_info **errors;
268271

272+
#if defined(ZTS) && defined(HAVE_TIMER_CREATE)
273+
timer_t timer;
274+
#endif
275+
269276
void *reserved[ZEND_MAX_RESERVED_RESOURCES];
270277
};
271278

configure.ac

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -743,6 +743,9 @@ fi
743743
dnl Check for openpty. It may require linking against libutil or libbsd.
744744
PHP_CHECK_FUNC(openpty, util, bsd)
745745

746+
dnl Check for timer_create
747+
PHP_CHECK_FUNC(timer_create, rt)
748+
746749
dnl General settings.
747750
dnl ----------------------------------------------------------------------------
748751
PHP_CONFIGURE_PART(General settings)

0 commit comments

Comments
 (0)