Commits

Ruslan Osmanov committed e8d6dca

Fix: in watcher cb handler ev_ref was needed in case if libev stopped the watcher

Comments (0)

Files changed (7)

 /* {{{ proto void ev_run([int flags = 0]) */
 PHP_FUNCTION(ev_run)
 {
-	long flags = 0;
-	zval *zloop;
+	long           flags  = 0;
+	zval          *zloop;
 	php_ev_object *ev_obj;
 
 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &flags) == FAILURE) {
 	long priority;
 	ev_watcher *watcher = PHP_EV_WATCHER_FETCH_FROM_OBJECT(obj);
 
-    if (ev_is_active(watcher)) {
-        php_error_docref(NULL TSRMLS_CC, E_ERROR,
-        		"Failed modifying active watcher");
-        return FAILURE;
+	int active = ev_is_active(watcher);
+
+    if (active) {
+        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Modifying active watcher");
     }
 
 	priority = Z_LVAL_P(value);
 	    return FAILURE;
 	}
 
+	/* TODO: stop if active */
 	php_ev_set_watcher_priority(watcher, priority TSRMLS_CC);
+	/* TODO: start if active */
 
 	return SUCCESS;
 }

tests/06_keepalive.phpt

 $timer2->keepalive(0);
 
 echo "ok 3\n";
-ev_run();
+ev_run(0);
 echo "ok 5\n";
 
 

tests/08_priority.phpt

 Check for priorities
 --FILE--
 <?php 
-error_reporting(0);
+#error_reporting(0);
 
 $t0 = new EvTimer(-1, 0, function ($w, $r) { echo "ok 4\n"; });
 $t_ = new EvTimer(-1, 0, function ($w, $r) { echo "ok 5\n"; });
 $t1 = new EvTimer(-1, 0, function ($w, $r) { echo "ok 3\n"; });
 $t1->priority = 1;
 
-$i2 = new EvIdle(function ($w, $r) { ev_iteration() == 1 ? "" : "not ", "ok 2\n"; $w->stop(); });
+$i2 = new EvIdle(function ($w, $r) { echo ev_iteration() == 1 ? "" : "not ", "ok 2\n"; $w->stop(); });
 $i2->priority = 10;
-$i3 = new EvIdle(function ($w, $r) { ev_iteration() == 3 ? "" : "not ", "ok 7\n"; $w->stop(); });
-$i1 = new EvIdle(function ($w, $r) { ev_iteration() == 2 ? "" : "not ", "ok 6\n"; $w->stop(); });
+$i3 = new EvIdle(function ($w, $r) { echo ev_iteration() == 3 ? "" : "not ", "ok 7\n"; $w->stop(); });
+$i1 = new EvIdle(function ($w, $r) { echo ev_iteration() == 2 ? "" : "not ", "ok 6\n"; $w->stop(); });
 $i1->priority = 1;
-$i_ = new EvIdle(function ($w, $r) { ev_iteration() == 4 ? "" : "not ", "ok 8\n"; $w->stop(); });
+$i_ = new EvIdle(function ($w, $r) { echo ev_iteration() == 4 ? "" : "not ", "ok 8\n"; $w->stop(); });
 $i_->priority = -1;
 
 $t0->start();
 
 	o_self = (php_ev_object *) zend_object_store_get_object(self TSRMLS_CC);
 	o_loop = (php_ev_object *) zend_object_store_get_object(loop TSRMLS_CC);
-	w      = (ev_timer *) php_ev_new_watcher(sizeof(ev_timer), self, 
+	w      = (ev_timer *) php_ev_new_watcher(sizeof(ev_timer), self,
 			PHP_EV_LOOP_OBJECT_FETCH_FROM_OBJECT(o_loop),
 			&fci, &fcc, data, priority TSRMLS_CC);
 
 
 	TSRMLS_FETCH_FROM_CTX(php_ev_watcher_thread_ctx(watcher));
 
+	/* libev might have stopped watcher */
+	if (php_ev_watcher_flags(watcher) & PHP_EV_WATCHER_FLAG_UNREFED
+			&& !ev_is_active(watcher)) {
+		PHP_EV_WATCHER_REF(watcher);
+	}
+
 	if (revents & EV_ERROR) {
 		int errorno = errno;
 		php_error_docref(NULL TSRMLS_CC, E_WARNING,
 				"Got unspecified libev error in revents, errno = %d, err = %s", errorno, strerror(errorno));
 
 		PHP_EV_EXIT_LOOP(EV_A);
-	}
-#if 0
-#if EV_STAT_ENABLE
-	/* TODO: php_ev_stat_update()*/
-	else if (revents & EV_STAT /* && php_ev_stat_update(watcher) */) {
-		PHP_EV_EXIT_LOOP(EV_A);
-	}
-#endif
-#endif 
-	else if (ZEND_FCI_INITIALIZED(*pfci)) {
+	} else if (ZEND_FCI_INITIALIZED(*pfci)) {
 		/* Setup callback args */
 		key1 = self;
 		args[0] = &key1;
 }
 /* }}} */
 
-/* {{{ proto int EvWatcher::keepalive(int value = 1) */
+/* {{{ proto int EvWatcher::keepalive([bool value = TRUE]) */
 PHP_METHOD(EvWatcher, keepalive)
 {
-	ev_watcher    *w;
-	long           n_value = 1;
+	ev_watcher *w;
+	zend_bool   n_value = 1;
 
-	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l",
-				&n_value) == FAILURE) {
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &n_value) == FAILURE) {
 		return;
 	}
 
 	w = PHP_EV_WATCHER_FETCH_FROM_THIS();
 
 	/* Returning previous state */
-	RETVAL_LONG((php_ev_watcher_flags(w) & PHP_EV_WATCHER_FLAG_KEEP_ALIVE));
+	RETVAL_BOOL((php_ev_watcher_flags(w) & PHP_EV_WATCHER_FLAG_KEEP_ALIVE));
 	n_value = n_value ? PHP_EV_WATCHER_FLAG_KEEP_ALIVE : 0;
 
 	/* Update watcher flags, if keepalive flag changed */
 #define PHP_EV_WATCHER_FLAG_KEEP_ALIVE 1
 #define PHP_EV_WATCHER_FLAG_UNREFED    2
 
-#define PHP_EV_WATCHER_UNREF(w)                                                 \
-    if (!(php_ev_watcher_flags(w) &                                             \
-                (PHP_EV_WATCHER_FLAG_KEEP_ALIVE | PHP_EV_WATCHER_FLAG_UNREFED)) \
-            && ev_is_active(w)) {                                               \
-        ev_unref(php_ev_watcher_loop(w)->loop);                                 \
-        php_ev_watcher_flags(w) |= PHP_EV_WATCHER_FLAG_UNREFED;                 \
+#define PHP_EV_WATCHER_UNREF(w)                                                            \
+    if (!(php_ev_watcher_flags(w) &                                                        \
+                (PHP_EV_WATCHER_FLAG_KEEP_ALIVE | PHP_EV_WATCHER_FLAG_UNREFED))            \
+            && ev_is_active(w)) {                                                          \
+        ev_unref(php_ev_watcher_loop(w)->loop);                                            \
+        php_ev_watcher_flags(w) |= PHP_EV_WATCHER_FLAG_UNREFED;                            \
     }
 
-#define PHP_EV_WATCHER_REF(w)                                                   \
-    if (php_ev_watcher_flags(w) & PHP_EV_WATCHER_FLAG_UNREFED) {                \
-        php_ev_watcher_flags(w) &= ~PHP_EV_WATCHER_FLAG_UNREFED;                \
-        ev_ref(php_ev_watcher_loop(w)->loop);                                   \
+#define PHP_EV_WATCHER_REF(w)                                                              \
+    if (php_ev_watcher_flags(w) & PHP_EV_WATCHER_FLAG_UNREFED) {                           \
+        php_ev_watcher_flags(w) &= ~PHP_EV_WATCHER_FLAG_UNREFED;                           \
+        ev_ref(php_ev_watcher_loop(w)->loop);                                              \
     }
 
-#define PHP_EV_WATCHER_STOP(t, w)                             \
-    do {                                                      \
-        if (php_ev_watcher_loop(w)) {                         \
-            PHP_EV_WATCHER_REF(w);                            \
-            t ## _stop(php_ev_watcher_loop_ptr(w), (t *) w);  \
-        }                                                     \
+#define PHP_EV_WATCHER_STOP(t, w)                                                          \
+    do {                                                                                   \
+        if (php_ev_watcher_loop(w)) {                                                      \
+            PHP_EV_WATCHER_REF(w);                                                         \
+            t ## _stop(php_ev_watcher_loop_ptr(w), (t *) w);                               \
+        }                                                                                  \
     } while (0)
 
-#define PHP_EV_WATCHER_START(t, w)                            \
-    do {                                                      \
-        if (php_ev_watcher_loop(w)) {                         \
-            t ## _start(php_ev_watcher_loop_ptr(w), (t *) w); \
-            PHP_EV_WATCHER_UNREF(w);                          \
-        }                                                     \
+#define PHP_EV_WATCHER_START(t, w)                                                         \
+    do {                                                                                   \
+        if (php_ev_watcher_loop(w)) {                                                      \
+            t ## _start(php_ev_watcher_loop_ptr(w), (t *) w);                              \
+            PHP_EV_WATCHER_UNREF(w);                                                       \
+        }                                                                                  \
     } while (0)
 
 /* Stop, ev_*_set() and start a watcher. Call it when need
  * to modify probably active watcher.
  * args - list of args for ev_*_set() with brackets */
-#define PHP_EV_WATCHER_RESET(t, w, args)                  \
-    do {                                                  \
-        int is_active = ev_is_active(w);                  \
-                                                          \
-        if (is_active) {                                  \
-            PHP_EV_WATCHER_STOP(t, w);                    \
-        }                                                 \
-                                                          \
-        t ## _set args;                                   \
-                                                          \
-        if (is_active) {                                  \
-            PHP_EV_WATCHER_START(t, w);                   \
-        }                                                 \
+#define PHP_EV_WATCHER_RESET(t, w, args)                                                   \
+    do {                                                                                   \
+        int is_active = ev_is_active(w);                                                   \
+                                                                                           \
+        if (is_active) {                                                                   \
+            PHP_EV_WATCHER_STOP(t, w);                                                     \
+        }                                                                                  \
+                                                                                           \
+        t ## _set args;                                                                    \
+                                                                                           \
+        if (is_active) {                                                                   \
+            PHP_EV_WATCHER_START(t, w);                                                    \
+        }                                                                                  \
     } while (0)
 
 
-#define PHP_EV_CHECK_SIGNAL_CAN_START(w)                                           \
-    do {                                                                           \
-        /* Pulled this part from EV module of Perl */                              \
-        if (signals [(w)->signum - 1].loop                                         \
-                && signals [(w)->signum - 1].loop != php_ev_watcher_loop_ptr(w)) { \
-            php_error_docref(NULL TSRMLS_CC, E_WARNING,                            \
-                    "Can't start signal watcher, signal %d already "               \
-                    "registered in another loop", w->signum);                      \
-        }                                                                          \
+#define PHP_EV_CHECK_SIGNAL_CAN_START(w)                                                   \
+    do {                                                                                   \
+        /* Pulled this part from EV module of Perl */                                      \
+        if (signals [(w)->signum - 1].loop                                                 \
+                && signals [(w)->signum - 1].loop != php_ev_watcher_loop_ptr(w)) {         \
+            php_error_docref(NULL TSRMLS_CC, E_WARNING,                                    \
+                    "Can't start signal watcher, signal %d already "                       \
+                    "registered in another loop", w->signum);                              \
+        }                                                                                  \
     } while (0)
 
-#define PHP_EV_SIGNAL_START(w)              \
-    do {                                    \
-        PHP_EV_CHECK_SIGNAL_CAN_START(w);   \
-        PHP_EV_WATCHER_START(ev_signal, w); \
+#define PHP_EV_SIGNAL_START(w)                                                             \
+    do {                                                                                   \
+        PHP_EV_CHECK_SIGNAL_CAN_START(w);                                                  \
+        PHP_EV_WATCHER_START(ev_signal, w);                                                \
     } while (0)
 
-#define PHP_EV_SIGNAL_RESET(w, seta)             \
-    do {                                         \
-        int active = ev_is_active(w);            \
-        if (active)                              \
-            PHP_EV_WATCHER_STOP(ev_signal, w);   \
-        ev_ ## signal ## _set seta;              \
-        if (active)                              \
-            PHP_EV_WATCHER_START(ev_signal, w);  \
+#define PHP_EV_SIGNAL_RESET(w, seta)                                                       \
+    do {                                                                                   \
+        int active = ev_is_active(w);                                                      \
+        if (active)                                                                        \
+            PHP_EV_WATCHER_STOP(ev_signal, w);                                             \
+        ev_ ## signal ## _set seta;                                                        \
+        if (active)                                                                        \
+            PHP_EV_WATCHER_START(ev_signal, w);                                            \
     } while (0)
 
-#define PHP_EV_WATCHER_CTOR(type, zloop) \
-	php_ev_ ## type ## _object_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU, zloop, TRUE, TRUE)
-#define PHP_EV_WATCHER_FACTORY(type, zloop) \
-	php_ev_ ## type ## _object_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU, zloop, FALSE, TRUE)
-#define PHP_EV_WATCHER_FACTORY_NS(type, zloop) \
-	php_ev_ ## type ## _object_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU, zloop, FALSE, FALSE)
+#define PHP_EV_WATCHER_CTOR(type, zloop)                                                   \
+    php_ev_ ## type ## _object_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU, zloop, TRUE, TRUE)
+#define PHP_EV_WATCHER_FACTORY(type, zloop)                                                \
+    php_ev_ ## type ## _object_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU, zloop, FALSE, TRUE)
+#define PHP_EV_WATCHER_FACTORY_NS(type, zloop)                                             \
+    php_ev_ ## type ## _object_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU, zloop, FALSE, FALSE)
 
 
 void php_ev_watcher_callback(EV_P_ ev_watcher *watcher, int revents);