1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 5 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2021 The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Author: Ruslan Osmanov <osmanov@php.net> |
16 +----------------------------------------------------------------------+
17 */
18
19 #include "php_ev.h"
20
21 /* Defined in ev.c */
22 extern zend_class_entry *ev_loop_class_entry_ptr;
23
24 /* {{{ php_ev_watcher_callback() */
php_ev_watcher_callback(EV_P_ ev_watcher * watcher,int revents)25 void php_ev_watcher_callback(EV_P_ ev_watcher *watcher, int revents)
26 {
27 zval **args[2];
28 zval *key2;
29 zval *retval_ptr;
30 zval *self = php_ev_watcher_self(watcher);
31 zend_fcall_info *pfci = php_ev_watcher_fci(watcher);
32
33 TSRMLS_FETCH_FROM_CTX(php_ev_watcher_thread_ctx(watcher));
34
35 /* libev might have stopped watcher */
36 if (php_ev_watcher_flags(watcher) & PHP_EV_WATCHER_FLAG_UNREFED
37 && !ev_is_active(watcher)) {
38 PHP_EV_WATCHER_REF(watcher);
39 }
40
41 if (UNEXPECTED(revents & EV_ERROR)) {
42 int errorno = errno;
43 php_error_docref(NULL TSRMLS_CC, E_WARNING,
44 "Got unspecified libev error in revents, errno = %d, err = %s", errorno, strerror(errorno));
45
46 PHP_EV_EXIT_LOOP(EV_A);
47 } else if (EXPECTED(ZEND_FCI_INITIALIZED(*pfci))) {
48 ev_loop *loop = php_ev_watcher_loop(watcher)->loop;
49
50 /* Setup callback args */
51 args[0] = &self;
52 Z_ADDREF_P(self);
53
54 MAKE_STD_ZVAL(key2);
55 args[1] = &key2;
56 ZVAL_LONG(key2, revents);
57
58 /* Prepare callback */
59 zend_uint fcc_param_count = php_ev_watcher_fcc(watcher)->function_handler ?
60 php_ev_watcher_fcc(watcher)->function_handler->common.num_args : 0;
61 pfci->params = args;
62 pfci->retval_ptr_ptr = &retval_ptr;
63 pfci->param_count = MIN(2, fcc_param_count);
64 pfci->no_separation = 1;
65
66 if (EXPECTED(zend_call_function(pfci, php_ev_watcher_fcc(watcher) TSRMLS_CC) == SUCCESS
67 && retval_ptr)) {
68 zval_ptr_dtor(&retval_ptr);
69 } else {
70 php_error_docref(NULL TSRMLS_CC, E_WARNING,
71 "An error occurred while invoking the callback");
72 }
73
74 if (EG(exception)) {
75 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Stopping event loop because of uncaught exception in the callback");
76 PHP_EV_ASSERT(loop);
77 ev_break(loop, EVBREAK_ONE);
78 }
79
80 zval_ptr_dtor(&self);
81 zval_ptr_dtor(&key2);
82 }
83 }
84 /* }}} */
85
86 /* {{{ php_ev_set_watcher()
87 * Configure preallocated watcher of the specified type, initialize common watcher fields
88 */
php_ev_set_watcher(ev_watcher * w,size_t size,zval * self,php_ev_loop * o_loop,const zend_fcall_info * pfci,const zend_fcall_info_cache * pfcc,zval * data,int priority TSRMLS_DC)89 void php_ev_set_watcher(ev_watcher *w, size_t size, zval *self, php_ev_loop *o_loop, const zend_fcall_info *pfci, const zend_fcall_info_cache *pfcc, zval *data, int priority TSRMLS_DC)
90 {
91 /* Re-link the doubly linked list */
92
93 ev_watcher *w_next = o_loop->w;
94 o_loop->w = w;
95
96 if (w_next) {
97 php_ev_watcher_next(w) = (void *) w_next;
98 php_ev_watcher_prev(w_next) = (void *) w;
99 }
100
101 ev_init((ev_watcher *) w, (ZEND_FCI_INITIALIZED(*pfci) ? php_ev_watcher_callback : 0));
102
103 if (data) {
104 Z_ADDREF_P(data);
105 }
106
107 #if 0
108 Z_ADDREF_P(self);
109 #endif
110
111 php_ev_watcher_self(w) = self;
112 php_ev_watcher_data(w) = data;
113 php_ev_watcher_loop(w) = o_loop;
114 php_ev_watcher_flags(w) = PHP_EV_WATCHER_FLAG_KEEP_ALIVE /*| PHP_EV_WATCHER_FLAG_SELF_UNREFED*/;
115
116 PHP_EV_COPY_FCALL_INFO(php_ev_watcher_fci(w), php_ev_watcher_fcc(w), pfci, pfcc);
117
118 php_ev_set_watcher_priority(w, priority);
119
120 TSRMLS_SET_CTX(php_ev_watcher_thread_ctx(w));
121 }
122 /* }}} */
123
124 /* {{{ php_ev_new_watcher()
125 * Create watcher of the specified type, initialize common watcher fields
126 */
php_ev_new_watcher(size_t size,zval * self,php_ev_loop * o_loop,const zend_fcall_info * pfci,const zend_fcall_info_cache * pfcc,zval * data,int priority TSRMLS_DC)127 void *php_ev_new_watcher(size_t size, zval *self, php_ev_loop *o_loop, const zend_fcall_info *pfci, const zend_fcall_info_cache *pfcc, zval *data, int priority TSRMLS_DC)
128 {
129 void *w = ecalloc(1, size);
130
131 php_ev_set_watcher((ev_watcher *) w, size, self, o_loop, pfci, pfcc, data, priority TSRMLS_CC);
132
133 return w;
134 }
135 /* }}} */
136
137 /* {{{ php_ev_start_watcher() */
php_ev_start_watcher(ev_watcher * watcher TSRMLS_DC)138 void php_ev_start_watcher(ev_watcher *watcher TSRMLS_DC)
139 {
140 switch (watcher->type) {
141 case EV_IO:
142 PHP_EV_WATCHER_START(ev_io, watcher);
143 break;
144 case EV_TIMER:
145 PHP_EV_WATCHER_START(ev_timer, watcher);
146 break;
147 #if EV_PERIODIC_ENABLE
148 case EV_PERIODIC:
149 PHP_EV_WATCHER_START(ev_periodic, watcher);
150 break;
151 #endif
152 #if EV_SIGNAL_ENABLE
153 case EV_SIGNAL:
154 PHP_EV_SIGNAL_START((ev_signal *) watcher);
155 break;
156 #endif
157 #if EV_CHILD_ENABLE
158 case EV_CHILD:
159 PHP_EV_WATCHER_START(ev_child, watcher);
160 break;
161 #endif
162 #if EV_STAT_ENABLE
163 case EV_STAT:
164 PHP_EV_WATCHER_START(ev_stat, watcher);
165 break;
166 #endif
167 #if EV_IDLE_ENABLE
168 case EV_IDLE:
169 PHP_EV_WATCHER_START(ev_idle, watcher);
170 break;
171 #endif
172 #if EV_PREPARE_ENABLE
173 case EV_PREPARE:
174 PHP_EV_WATCHER_START(ev_prepare, watcher);
175 break;
176 #endif
177 #if EV_CHECK_ENABLE
178 case EV_CHECK:
179 PHP_EV_WATCHER_START(ev_check, watcher);
180 break;
181 #endif
182 #if EV_EMBED_ENABLE
183 case EV_EMBED:
184 PHP_EV_WATCHER_START(ev_embed, watcher);
185 break;
186 #endif
187 #if EV_FORK_ENABLE
188 case EV_FORK:
189 PHP_EV_WATCHER_START(ev_fork, watcher);
190 break;
191 #endif
192 #if EV_ASYNC_ENABLE
193 case EV_ASYNC:
194 PHP_EV_WATCHER_START(ev_async, watcher);
195 break;
196 #endif
197 default:
198 break;
199 }
200 }
201 /* }}} */
202
203 /* {{{ php_ev_stop_watcher() */
php_ev_stop_watcher(ev_watcher * watcher TSRMLS_DC)204 void php_ev_stop_watcher(ev_watcher *watcher TSRMLS_DC)
205 {
206 switch (php_ev_watcher_type(watcher)) {
207 case EV_IO:
208 PHP_EV_WATCHER_STOP(ev_io, watcher);
209 break;
210 case EV_TIMER:
211 PHP_EV_WATCHER_STOP(ev_timer, watcher);
212 break;
213 #if EV_PERIODIC_ENABLE
214 case EV_PERIODIC:
215 PHP_EV_WATCHER_STOP(ev_periodic, watcher);
216 break;
217 #endif
218 #if EV_SIGNAL_ENABLE
219 case EV_SIGNAL:
220 PHP_EV_SIGNAL_STOP((ev_signal *) watcher);
221 break;
222 #endif
223 #if EV_CHILD_ENABLE
224 case EV_CHILD:
225 PHP_EV_WATCHER_STOP(ev_child, watcher);
226 break;
227 #endif
228 #if EV_STAT_ENABLE
229 case EV_STAT:
230 PHP_EV_WATCHER_STOP(ev_stat, watcher);
231 break;
232 #endif
233 #if EV_IDLE_ENABLE
234 case EV_IDLE:
235 PHP_EV_WATCHER_STOP(ev_idle, watcher);
236 break;
237 #endif
238 #if EV_PREPARE_ENABLE
239 case EV_PREPARE:
240 PHP_EV_WATCHER_STOP(ev_prepare, watcher);
241 break;
242 #endif
243 #if EV_CHECK_ENABLE
244 case EV_CHECK:
245 PHP_EV_WATCHER_STOP(ev_check, watcher);
246 break;
247 #endif
248 #if EV_EMBED_ENABLE
249 case EV_EMBED:
250 PHP_EV_WATCHER_STOP(ev_embed, watcher);
251 break;
252 #endif
253 #if EV_FORK_ENABLE
254 case EV_FORK:
255 PHP_EV_WATCHER_STOP(ev_fork, watcher);
256 break;
257 #endif
258 #if EV_ASYNC_ENABLE
259 case EV_ASYNC:
260 PHP_EV_WATCHER_STOP(ev_async, watcher);
261 break;
262 #endif
263 default:
264 break;
265 }
266 }
267 /* }}} */
268
269
270 /* {{{ Methods */
271
272 /* {{{ proto void EvWatcher::start(void) */
PHP_METHOD(EvWatcher,start)273 PHP_METHOD(EvWatcher, start)
274 {
275 php_ev_object *o_self;
276
277 if (zend_parse_parameters_none() == FAILURE) {
278 return;
279 }
280
281 o_self = (php_ev_object *) zend_object_store_get_object(getThis() TSRMLS_CC);
282
283 php_ev_start_watcher(PHP_EV_WATCHER_FETCH_FROM_OBJECT(o_self) TSRMLS_CC);
284 }
285 /* }}} */
286
287 /* {{{ proto void EvWatcher::stop(void) */
PHP_METHOD(EvWatcher,stop)288 PHP_METHOD(EvWatcher, stop)
289 {
290 php_ev_object *o_self;
291
292 if (zend_parse_parameters_none() == FAILURE) {
293 return;
294 }
295
296 o_self = (php_ev_object *) zend_object_store_get_object(getThis() TSRMLS_CC);
297
298 php_ev_stop_watcher(PHP_EV_WATCHER_FETCH_FROM_OBJECT(o_self) TSRMLS_CC);
299 }
300 /* }}} */
301
302 /* {{{ proto int EvWatcher::clear(void) */
PHP_METHOD(EvWatcher,clear)303 PHP_METHOD(EvWatcher, clear)
304 {
305 php_ev_object *o_self;
306 ev_watcher *w;
307
308 if (zend_parse_parameters_none() == FAILURE) {
309 return;
310 }
311
312 o_self = (php_ev_object *) zend_object_store_get_object(getThis() TSRMLS_CC);
313 w = PHP_EV_WATCHER_FETCH_FROM_OBJECT(o_self);
314
315 RETURN_LONG((long)ev_clear_pending(php_ev_watcher_loop_ptr(w), w));
316 }
317 /* }}} */
318
319 /* {{{ proto void EvWatcher::invoke(int revents) */
PHP_METHOD(EvWatcher,invoke)320 PHP_METHOD(EvWatcher, invoke)
321 {
322 php_ev_object *o_self;
323 ev_watcher *w;
324 long revents;
325
326 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l",
327 &revents) == FAILURE) {
328 return;
329 }
330
331 o_self = (php_ev_object *) zend_object_store_get_object(getThis() TSRMLS_CC);
332 w = PHP_EV_WATCHER_FETCH_FROM_OBJECT(o_self);
333
334 ev_invoke(php_ev_watcher_loop_ptr(w), w, (int)revents);
335 }
336 /* }}} */
337
338 /* {{{ proto void EvWatcher::feed(int revents) */
PHP_METHOD(EvWatcher,feed)339 PHP_METHOD(EvWatcher, feed)
340 {
341 php_ev_object *o_self;
342 ev_watcher *w;
343 long revents;
344
345 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l",
346 &revents) == FAILURE) {
347 return;
348 }
349
350 o_self = (php_ev_object *) zend_object_store_get_object(getThis() TSRMLS_CC);
351 w = PHP_EV_WATCHER_FETCH_FROM_OBJECT(o_self);
352
353 ev_feed_event(php_ev_watcher_loop_ptr(w), w, (int)revents);
354 }
355 /* }}} */
356
357 /* {{{ proto EvLoop EvWatcher::getLoop(void) */
PHP_METHOD(EvWatcher,getLoop)358 PHP_METHOD(EvWatcher, getLoop)
359 {
360 php_ev_object *o_self;
361 php_ev_loop *o_loop;
362 ev_watcher *w;
363
364 if (zend_parse_parameters_none() == FAILURE) {
365 return;
366 }
367
368 o_self = (php_ev_object *) zend_object_store_get_object(getThis() TSRMLS_CC);
369 w = PHP_EV_WATCHER_FETCH_FROM_OBJECT(o_self);
370 o_loop = php_ev_watcher_loop(w);
371
372 zval *zloop = (zval *) ev_userdata(o_loop->loop);
373
374 if (!zloop) {
375 RETURN_NULL();
376 }
377 RETVAL_ZVAL(zloop, 1, 0);
378 }
379 /* }}} */
380
381 /* {{{ proto int EvWatcher::keepalive([bool value = TRUE]) */
PHP_METHOD(EvWatcher,keepalive)382 PHP_METHOD(EvWatcher, keepalive)
383 {
384 ev_watcher *w;
385 zend_bool n_value = TRUE;
386
387 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &n_value) == FAILURE) {
388 return;
389 }
390
391 w = PHP_EV_WATCHER_FETCH_FROM_THIS();
392
393 /* Returning previous state */
394 RETVAL_BOOL((php_ev_watcher_flags(w) & PHP_EV_WATCHER_FLAG_KEEP_ALIVE));
395 n_value = n_value != FALSE ? PHP_EV_WATCHER_FLAG_KEEP_ALIVE : 0;
396
397 /* Update watcher flags, if keepalive flag changed */
398 if ((n_value ^ php_ev_watcher_flags(w)) & PHP_EV_WATCHER_FLAG_KEEP_ALIVE) {
399 php_ev_watcher_flags(w) = (php_ev_watcher_flags(w) & ~PHP_EV_WATCHER_FLAG_KEEP_ALIVE) | n_value;
400 PHP_EV_WATCHER_REF(w);
401 PHP_EV_WATCHER_UNREF(w);
402 }
403 }
404 /* }}} */
405
406 /* {{{ proto void EvWatcher::setCallback(callable callback) */
PHP_METHOD(EvWatcher,setCallback)407 PHP_METHOD(EvWatcher, setCallback)
408 {
409 ev_watcher *w;
410 zend_fcall_info fci;
411 zend_fcall_info_cache fcc;
412
413 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "f",
414 &fci, &fcc) == FAILURE) {
415 return;
416 }
417
418 w = PHP_EV_WATCHER_FETCH_FROM_THIS();
419
420 PHP_EV_FREE_FCALL_INFO(w->fci, w->fcc);
421 PHP_EV_COPY_FCALL_INFO(w->fci, w->fcc, &fci, &fcc);
422 }
423 /* }}} */
424
425 /* Methods }}} */
426
427
428 /*
429 * Local variables:
430 * tab-width: 4
431 * c-basic-offset: 4
432 * End:
433 * vim600: noet sw=4 ts=4 sts=4 fdm=marker
434 * vim<600: noet sw=4 ts=4 sts=4
435 */
436