|
43 | 43 | #ifdef HAVE_UNISTD_H
|
44 | 44 | #include <unistd.h>
|
45 | 45 | #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 |
46 | 54 |
|
47 | 55 | ZEND_API void (*zend_execute_ex)(zend_execute_data *execute_data);
|
48 | 56 | ZEND_API void (*zend_execute_internal)(zend_execute_data *execute_data, zval *return_value);
|
@@ -171,6 +179,20 @@ void init_executor(void) /* {{{ */
|
171 | 179 | EG(vm_interrupt) = 0;
|
172 | 180 | EG(timed_out) = 0;
|
173 | 181 |
|
| 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 | + |
174 | 196 | EG(exception) = NULL;
|
175 | 197 | EG(prev_exception) = NULL;
|
176 | 198 |
|
@@ -396,6 +418,14 @@ void shutdown_executor(void) /* {{{ */
|
396 | 418 | bool fast_shutdown = is_zend_mm() && !EG(full_tables_cleanup);
|
397 | 419 | #endif
|
398 | 420 |
|
| 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 | + |
399 | 429 | zend_try {
|
400 | 430 | zend_stream_shutdown();
|
401 | 431 | } zend_end_try();
|
@@ -1314,8 +1344,18 @@ ZEND_API ZEND_NORETURN void ZEND_FASTCALL zend_timeout(void) /* {{{ */
|
1314 | 1344 | /* }}} */
|
1315 | 1345 |
|
1316 | 1346 | #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 |
1317 | 1356 | static void zend_timeout_handler(int dummy) /* {{{ */
|
1318 | 1357 | {
|
| 1358 | +#endif |
1319 | 1359 | #ifndef ZTS
|
1320 | 1360 | if (EG(timed_out)) {
|
1321 | 1361 | /* Die on hard timeout */
|
@@ -1415,6 +1455,36 @@ static void zend_set_timeout_ex(zend_long seconds, bool reset_signals) /* {{{ */
|
1415 | 1455 | zend_error_noreturn(E_ERROR, "Could not queue new timer");
|
1416 | 1456 | return;
|
1417 | 1457 | }
|
| 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 | + } |
1418 | 1488 | #elif defined(HAVE_SETITIMER)
|
1419 | 1489 | {
|
1420 | 1490 | struct itimerval t_r; /* timeout requested */
|
|
0 commit comments