16
16
17
17
#ifdef ZEND_MAX_EXECUTION_TIMERS
18
18
19
+ # ifdef __APPLE__
20
+
21
+ #include <dispatch/dispatch.h>
22
+ # ifdef ZTS
23
+ #include <pthread.h>
24
+ # endif
25
+
26
+ #include "zend.h"
27
+ #include "zend_globals.h"
28
+
29
+ // macOS doesn't support timer_create(), fallback to Grand Central Dispatch
30
+
31
+ static inline void zend_max_execution_timer_handler (void * arg )
32
+ {
33
+ pthread_t * tid = (pthread_t * ) arg ;
34
+ pthread_kill (* tid , ZEND_MAX_EXECUTION_TIMERS_SIGNAL );
35
+ }
36
+
37
+ static inline void zend_max_execution_timer_cancel (void * arg )
38
+ {
39
+ pthread_t * tid = (pthread_t * ) arg ;
40
+ free (tid );
41
+ }
42
+
43
+ ZEND_API void zend_max_execution_timer_init (void ) /* {{{ */
44
+ {
45
+ pid_t pid = getpid ();
46
+
47
+ if (EG (pid ) == pid ) {
48
+ return ;
49
+ }
50
+
51
+ dispatch_queue_global_t queue = dispatch_get_global_queue (QOS_CLASS_UTILITY , 0 );
52
+ EG (max_execution_timer_timer ) = dispatch_source_create (DISPATCH_SOURCE_TYPE_TIMER , 0 , 0 , queue );
53
+ if (EG (max_execution_timer_timer ) == NULL ) {
54
+ zend_strerror_noreturn (E_ERROR , errno , "Could not create dispatch source" );
55
+ }
56
+
57
+ EG (pid ) = pid ;
58
+ EG (max_execution_timer_suspended ) = 1 ;
59
+
60
+ # ifdef ZTS
61
+ pthread_t lpid = pthread_self ();
62
+ pthread_t * tid = malloc (sizeof (pthread_t ));
63
+ memcpy (tid , & lpid , sizeof (pthread_t ));
64
+ dispatch_set_context (EG (max_execution_timer_timer ), tid );
65
+ # endif
66
+
67
+ dispatch_source_set_event_handler_f (EG (max_execution_timer_timer ), zend_max_execution_timer_handler );
68
+ dispatch_source_set_cancel_handler_f (EG (max_execution_timer_timer ), zend_max_execution_timer_cancel );
69
+ } /* }}} */
70
+
71
+ void zend_max_execution_timer_settime (zend_long seconds ) /* {{{ */
72
+ {
73
+ if (seconds == 0 ) {
74
+ if (!EG (max_execution_timer_suspended )) {
75
+ dispatch_suspend (EG (max_execution_timer_timer ));
76
+ EG (max_execution_timer_suspended ) = 1 ;
77
+ }
78
+
79
+ return ;
80
+ }
81
+
82
+ dispatch_source_set_timer (
83
+ EG (max_execution_timer_timer ),
84
+ dispatch_time (DISPATCH_TIME_NOW , seconds * NSEC_PER_SEC ),
85
+ seconds * NSEC_PER_SEC ,
86
+ 0
87
+ );
88
+ if (EG (max_execution_timer_suspended )) {
89
+ dispatch_resume (EG (max_execution_timer_timer ));
90
+ EG (max_execution_timer_suspended ) = 0 ;
91
+ }
92
+ } /* }}} */
93
+
94
+ void zend_max_execution_timer_shutdown (void ) /* {{{ */
95
+ {
96
+ /* Don't try to delete a timer created before a call to fork() */
97
+ if (EG (pid ) != getpid ()) {
98
+ return ;
99
+ }
100
+
101
+ EG (pid ) = 0 ;
102
+
103
+ dispatch_source_cancel (EG (max_execution_timer_timer ));
104
+ //dispatch_release(EG(max_execution_timer_timer));
105
+ } /* }}} */
106
+
107
+ # else
108
+
19
109
#include <stdio.h>
20
110
#include <signal.h>
21
111
#include <time.h>
22
112
#include <unistd.h>
23
113
#include <errno.h>
24
114
#include <sys/syscall.h>
25
115
#include <sys/types.h>
26
- # ifdef __FreeBSD__
27
- # include <pthread_np.h>
28
- # endif
116
+ # ifdef __FreeBSD__
117
+ # include <pthread_np.h>
118
+ # endif
29
119
30
120
#include "zend.h"
31
121
#include "zend_globals.h"
32
122
33
123
// Musl Libc defines this macro, glibc does not
34
124
// 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
35
- # ifndef sigev_notify_thread_id
36
- # define sigev_notify_thread_id _sigev_un._tid
37
- # endif
125
+ # ifndef sigev_notify_thread_id
126
+ # define sigev_notify_thread_id _sigev_un._tid
127
+ # endif
38
128
39
129
// FreeBSD doesn't support CLOCK_BOOTTIME
40
- # ifdef __FreeBSD__
41
- # define ZEND_MAX_EXECUTION_TIMERS_CLOCK CLOCK_MONOTONIC
42
- # else
43
- # define ZEND_MAX_EXECUTION_TIMERS_CLOCK CLOCK_BOOTTIME
44
- # endif
130
+ # ifdef __FreeBSD__
131
+ # define ZEND_MAX_EXECUTION_TIMERS_CLOCK CLOCK_MONOTONIC
132
+ # else
133
+ # define ZEND_MAX_EXECUTION_TIMERS_CLOCK CLOCK_BOOTTIME
134
+ # endif
45
135
46
136
ZEND_API void zend_max_execution_timer_init (void ) /* {{{ */
47
137
{
@@ -54,12 +144,12 @@ ZEND_API void zend_max_execution_timer_init(void) /* {{{ */
54
144
struct sigevent sev ;
55
145
sev .sigev_notify = SIGEV_THREAD_ID ;
56
146
sev .sigev_value .sival_ptr = & EG (max_execution_timer_timer );
57
- sev .sigev_signo = SIGRTMIN ;
58
- # ifdef __FreeBSD__
147
+ sev .sigev_signo = ZEND_MAX_EXECUTION_TIMERS_SIGNAL ;
148
+ # ifdef __FreeBSD__
59
149
sev .sigev_notify_thread_id = pthread_getthreadid_np ();
60
- # else
150
+ # else
61
151
sev .sigev_notify_thread_id = (pid_t ) syscall (SYS_gettid );
62
- # endif
152
+ # endif
63
153
64
154
// Measure wall time instead of CPU time as originally planned now that it is possible https://github.com/php/php-src/pull/6504#issuecomment-1370303727
65
155
if (timer_create (ZEND_MAX_EXECUTION_TIMERS_CLOCK , & sev , & EG (max_execution_timer_timer )) != 0 ) {
@@ -68,9 +158,9 @@ ZEND_API void zend_max_execution_timer_init(void) /* {{{ */
68
158
69
159
EG (pid ) = getpid ();
70
160
71
- # ifdef MAX_EXECUTION_TIMERS_DEBUG
161
+ # ifdef MAX_EXECUTION_TIMERS_DEBUG
72
162
fprintf (stderr , "Timer %#jx created on thread %d\n" , (uintmax_t ) EG (max_execution_timer_timer ), sev .sigev_notify_thread_id );
73
- # endif
163
+ # endif
74
164
75
165
sigaction (sev .sigev_signo , NULL , & EG (oldact ));
76
166
}
@@ -89,9 +179,9 @@ void zend_max_execution_timer_settime(zend_long seconds) /* {{{ }*/
89
179
its .it_value .tv_sec = seconds ;
90
180
its .it_value .tv_nsec = its .it_interval .tv_sec = its .it_interval .tv_nsec = 0 ;
91
181
92
- # ifdef MAX_EXECUTION_TIMERS_DEBUG
182
+ # ifdef MAX_EXECUTION_TIMERS_DEBUG
93
183
fprintf (stderr , "Setting timer %#jx on thread %d (%ld seconds)...\n" , (uintmax_t ) timer , (pid_t ) syscall (SYS_gettid ), seconds );
94
- # endif
184
+ # endif
95
185
96
186
if (timer_settime (timer , 0 , & its , NULL ) != 0 ) {
97
187
zend_strerror_noreturn (E_ERROR , errno , "Could not set timer" );
@@ -110,9 +200,9 @@ void zend_max_execution_timer_shutdown(void) /* {{{ */
110
200
111
201
timer_t timer = EG (max_execution_timer_timer );
112
202
113
- # ifdef MAX_EXECUTION_TIMERS_DEBUG
203
+ # ifdef MAX_EXECUTION_TIMERS_DEBUG
114
204
fprintf (stderr , "Deleting timer %#jx on thread %d...\n" , (uintmax_t ) timer , (pid_t ) syscall (SYS_gettid ));
115
- # endif
205
+ # endif
116
206
117
207
int err = timer_delete (timer );
118
208
if (err != 0 ) {
@@ -121,4 +211,5 @@ void zend_max_execution_timer_shutdown(void) /* {{{ */
121
211
}
122
212
/* }}}} */
123
213
214
+ # endif
124
215
#endif
0 commit comments