Skip to content

Commit 3d83e9e

Browse files
committed
refactor, fix pcntl_fork()
1 parent 1d2a3c6 commit 3d83e9e

File tree

7 files changed

+145
-81
lines changed

7 files changed

+145
-81
lines changed

Zend/zend.c

Lines changed: 3 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -818,39 +818,6 @@ static void executor_globals_dtor(zend_executor_globals *executor_globals) /* {{
818818
}
819819
/* }}} */
820820

821-
# ifdef ZEND_TIMER
822-
static void zend_timer_create() /* {{{ */
823-
{
824-
# ifdef TIMER_DEBUG
825-
fprintf(stderr, "Trying to create timer on thread %d\n", (uintmax_t) EG(timer), sev.sigev_notify_thread_id);
826-
# endif
827-
828-
struct sigevent sev;
829-
sev.sigev_notify = SIGEV_THREAD_ID;
830-
sev.sigev_value.sival_ptr = &EG(timer);
831-
// The chosen signal must:
832-
// 1. not be used internally by libc
833-
// 2. be allowed to happen spuriously without consequences
834-
// 3. not be commonly used by applications, this excludes SIGALRM, SIGUSR1 and SIGUSR2
835-
// 4. not be used by profilers, this excludes SIGPROF
836-
// 5. not be used internally by runtimes of programs that can embed PHP, this excludes SIGURG, which is used by Go
837-
sev.sigev_signo = SIGIO;
838-
sev.sigev_notify_thread_id = (pid_t) syscall(SYS_gettid);
839-
840-
if (timer_create(CLOCK_THREAD_CPUTIME_ID, &sev, &EG(timer)) != 0) {
841-
EG(timer) = 0;
842-
zend_strerror_noreturn(E_ERROR, errno, "Could not create timer");
843-
}
844-
845-
# ifdef TIMER_DEBUG
846-
fprintf(stderr, "Timer %#jx created on thread %d\n", (uintmax_t) EG(timer), sev.sigev_notify_thread_id);
847-
# endif
848-
849-
sigaction(sev.sigev_signo, NULL, &EG(oldact));
850-
}
851-
/* }}} */
852-
# endif
853-
854821
static void zend_new_thread_end_handler(THREAD_T thread_id) /* {{{ */
855822
{
856823
zend_copy_ini_directives();
@@ -863,20 +830,9 @@ static void zend_new_thread_end_handler(THREAD_T thread_id) /* {{{ */
863830

864831
static void zend_thread_shutdown_handler(void) { /* {{{ */
865832
zend_interned_strings_dtor();
866-
867-
# ifdef ZEND_TIMER
868-
# ifdef TIMER_DEBUG
869-
fprintf(stderr, "Trying to delete timer %#jx thread %d\n", (uintmax_t) EG(timer), (pid_t) syscall(SYS_gettid));
870-
# endif
871-
872-
timer_t timer = EG(timer);
873-
if (timer == 0) zend_error_noreturn(E_ERROR, "Timer not created");
874-
875-
int err = timer_delete(timer);
876-
EG(timer) = 0;
877-
if (err != 0)
878-
zend_strerror_noreturn(E_ERROR, errno, "Could not delete timer");
879-
# endif
833+
#ifdef ZEND_TIMER
834+
zend_timer_delete();
835+
#endif
880836
}
881837
/* }}} */
882838
#endif

Zend/zend.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include "zend_smart_str_public.h"
4040
#include "zend_smart_string_public.h"
4141
#include "zend_signal.h"
42+
#include "zend_timer.h"
4243

4344
#define zend_sprintf sprintf
4445

Zend/zend_execute_API.c

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,15 @@
3737
#include "zend_weakrefs.h"
3838
#include "zend_inheritance.h"
3939
#include "zend_observer.h"
40-
#include "zend_timer.h"
4140
#ifdef HAVE_SYS_TIME_H
4241
#include <sys/time.h>
4342
#endif
4443
#ifdef HAVE_UNISTD_H
4544
#include <unistd.h>
4645
#endif
46+
#ifdef ZEND_TIMER
47+
#include <sys/syscall.h>
48+
#endif
4749

4850
ZEND_API void (*zend_execute_ex)(zend_execute_data *execute_data);
4951
ZEND_API void (*zend_execute_internal)(zend_execute_data *execute_data, zval *return_value);
@@ -387,27 +389,6 @@ ZEND_API void zend_shutdown_executor_values(bool fast_shutdown)
387389
zend_objects_store_free_object_storage(&EG(objects_store), fast_shutdown);
388390
}
389391

390-
#ifdef ZEND_TIMER
391-
static void zend_timer_settime(zend_long seconds) /* {{{ }*/
392-
{
393-
timer_t timer = EG(timer);
394-
395-
# ifdef TIMER_DEBUG
396-
fprintf(stderr, "Trying to set timer %#jx on thread %d (%ld seconds)\n", (uintmax_t) timer, (pid_t) syscall(SYS_gettid), seconds);
397-
# endif
398-
399-
if (timer == 0) zend_error_noreturn(E_ERROR, "Timer not created");
400-
401-
struct itimerspec its;
402-
its.it_value.tv_sec = seconds;
403-
its.it_value.tv_nsec = its.it_interval.tv_sec = its.it_interval.tv_nsec = 0;
404-
405-
if (timer_settime(timer, 0, &its, NULL) != 0)
406-
zend_strerror_noreturn(E_ERROR, errno, "Could not set timer");
407-
}
408-
/* }}} */
409-
#endif
410-
411392
void shutdown_executor(void) /* {{{ */
412393
{
413394
zend_string *key;

Zend/zend_timer.c

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/*
2+
+----------------------------------------------------------------------+
3+
| Copyright (c) The PHP Group |
4+
+----------------------------------------------------------------------+
5+
| This source file is subject to version 3.01 of the PHP license, |
6+
| that is bundled with this package in the file LICENSE, and is |
7+
| available through the world-wide-web at the following url: |
8+
| https://www.php.net/license/3_01.txt |
9+
| If you did not receive a copy of the PHP license and are unable to |
10+
| obtain it through the world-wide-web, please send a note to |
11+
| [email protected] so we can mail you a copy immediately. |
12+
+----------------------------------------------------------------------+
13+
| Author: Kévin Dunglas <[email protected]> |
14+
+----------------------------------------------------------------------+
15+
*/
16+
17+
#include "zend_timer.h"
18+
19+
#ifdef ZEND_TIMER
20+
21+
#include <stdio.h>
22+
#include <signal.h>
23+
#include <time.h>
24+
#include <unistd.h>
25+
#include <errno.h>
26+
#include <sys/syscall.h>
27+
#include <sys/types.h>
28+
29+
#include "zend.h"
30+
#include "zend_globals.h"
31+
32+
// Musl Libc defines this macro, glibc does not
33+
// According to "man 2 timer_create" this field should always be available, but it's not: https://sourceware.org/bugzilla/show_bug.cgi?id=27417
34+
# ifndef sigev_notify_thread_id
35+
# define sigev_notify_thread_id _sigev_un._tid
36+
# endif
37+
38+
ZEND_API void zend_timer_create(void) /* {{{ */
39+
{
40+
# ifdef TIMER_DEBUG
41+
fprintf(stderr, "Trying to create timer on thread %d\n", (pid_t) syscall(SYS_gettid));
42+
# endif
43+
44+
struct sigevent sev;
45+
sev.sigev_notify = SIGEV_THREAD_ID;
46+
sev.sigev_value.sival_ptr = &EG(timer);
47+
// The chosen signal must:
48+
// 1. not be used internally by libc
49+
// 2. be allowed to happen spuriously without consequences
50+
// 3. not be commonly used by applications, this excludes SIGALRM, SIGUSR1 and SIGUSR2
51+
// 4. not be used by profilers, this excludes SIGPROF
52+
// 5. not be used internally by runtimes of programs that can embed PHP, this excludes SIGURG, which is used by Go
53+
sev.sigev_signo = SIGIO;
54+
sev.sigev_notify_thread_id = (pid_t) syscall(SYS_gettid);
55+
56+
if (timer_create(CLOCK_THREAD_CPUTIME_ID, &sev, &EG(timer)) != 0) {
57+
EG(timer) = 0;
58+
zend_strerror_noreturn(E_ERROR, errno, "Could not create timer");
59+
}
60+
61+
# ifdef TIMER_DEBUG
62+
fprintf(stderr, "Timer %#jx created on thread %d\n", (uintmax_t) EG(timer), sev.sigev_notify_thread_id);
63+
# endif
64+
65+
sigaction(sev.sigev_signo, NULL, &EG(oldact));
66+
}
67+
/* }}} */
68+
69+
ZEND_API void zend_timer_settime(zend_long seconds) /* {{{ }*/
70+
{
71+
timer_t timer = EG(timer);
72+
73+
# ifdef TIMER_DEBUG
74+
fprintf(stderr, "Trying to set timer %#jx on thread %d (%ld seconds)\n", (uintmax_t) timer, (pid_t) syscall(SYS_gettid), seconds);
75+
# endif
76+
77+
if (timer == 0) zend_error_noreturn(E_ERROR, "Timer not created");
78+
79+
struct itimerspec its;
80+
its.it_value.tv_sec = seconds;
81+
its.it_value.tv_nsec = its.it_interval.tv_sec = its.it_interval.tv_nsec = 0;
82+
83+
if (timer_settime(timer, 0, &its, NULL) != 0)
84+
zend_strerror_noreturn(E_ERROR, errno, "Could not set timer");
85+
}
86+
/* }}} */
87+
88+
ZEND_API void zend_timer_delete(void) /* {{{ */
89+
{
90+
# ifdef TIMER_DEBUG
91+
fprintf(stderr, "Trying to delete timer %#jx thread %d\n", (uintmax_t) EG(timer), (pid_t) syscall(SYS_gettid));
92+
# endif
93+
94+
timer_t timer = EG(timer);
95+
if (timer == 0) zend_error_noreturn(E_ERROR, "Timer not created");
96+
97+
int err = timer_delete(timer);
98+
EG(timer) = 0;
99+
if (err != 0)
100+
zend_strerror_noreturn(E_ERROR, errno, "Could not delete timer");
101+
}
102+
/* }}}} */
103+
104+
#endif

Zend/zend_timer.h

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,34 @@
1-
#if !defined(ZEND_TIMER_H) && defined(ZTS) && defined(__linux__) && defined(HAVE_TIMER_CREATE)
1+
/*
2+
+----------------------------------------------------------------------+
3+
| Copyright (c) The PHP Group |
4+
+----------------------------------------------------------------------+
5+
| This source file is subject to version 3.01 of the PHP license, |
6+
| that is bundled with this package in the file LICENSE, and is |
7+
| available through the world-wide-web at the following url: |
8+
| https://www.php.net/license/3_01.txt |
9+
| If you did not receive a copy of the PHP license and are unable to |
10+
| obtain it through the world-wide-web, please send a note to |
11+
| [email protected] so we can mail you a copy immediately. |
12+
+----------------------------------------------------------------------+
13+
| Author: Kévin Dunglas <[email protected]> |
14+
+----------------------------------------------------------------------+
15+
*/
16+
17+
#ifndef ZEND_TIMER_H
218
#define ZEND_TIMER_H
319

20+
#ifdef __linux__
21+
#include "php_config.h"
22+
23+
# if defined(ZTS) && defined(HAVE_TIMER_CREATE)
424
#define ZEND_TIMER 1
525

6-
#include <signal.h>
7-
#include <time.h>
8-
#include <unistd.h>
9-
#include <sys/syscall.h>
10-
#include <sys/types.h>
26+
#include "zend_long.h"
1127

12-
// Musl Libc defines this macro, glibc does not
13-
// According to "man 2 timer_create" this field should always be available, but it's not: https://sourceware.org/bugzilla/show_bug.cgi?id=27417
14-
# ifndef sigev_notify_thread_id
15-
# define sigev_notify_thread_id _sigev_un._tid
16-
# endif
28+
ZEND_API void zend_timer_create(void);
29+
ZEND_API void zend_timer_settime(zend_long seconds);
30+
ZEND_API void zend_timer_delete(void);
1731

32+
# endif
33+
# endif
1834
#endif

configure.ac

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1636,7 +1636,7 @@ PHP_ADD_SOURCES(Zend, \
16361636
zend_closures.c zend_weakrefs.c zend_float.c zend_string.c zend_signal.c zend_generators.c \
16371637
zend_virtual_cwd.c zend_ast.c zend_objects.c zend_object_handlers.c zend_objects_API.c \
16381638
zend_default_classes.c zend_inheritance.c zend_smart_str.c zend_cpuinfo.c zend_gdb.c \
1639-
zend_observer.c zend_system_id.c zend_enum.c zend_fibers.c \
1639+
zend_observer.c zend_system_id.c zend_enum.c zend_fibers.c zend_timer.c \
16401640
Optimizer/zend_optimizer.c \
16411641
Optimizer/pass1.c \
16421642
Optimizer/pass3.c \

ext/pcntl/pcntl.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@
5050
# define NSIG 32
5151
#endif
5252

53+
#include "Zend/zend_timer.h"
54+
5355
ZEND_DECLARE_MODULE_GLOBALS(pcntl)
5456
static PHP_GINIT_FUNCTION(pcntl);
5557

@@ -531,6 +533,10 @@ PHP_FUNCTION(pcntl_fork)
531533
if (id == -1) {
532534
PCNTL_G(last_error) = errno;
533535
php_error_docref(NULL, E_WARNING, "Error %d", errno);
536+
} else if (id == 0) {
537+
#ifdef ZEND_TIMER
538+
zend_timer_create();
539+
#endif
534540
}
535541

536542
RETURN_LONG((zend_long) id);

0 commit comments

Comments
 (0)