Commits

Ruslan Osmanov committed f85004f

Fix: EvWatcher:: property had been written to EvLoop::
Add: examples
Change: EvLoop made final
Refact: PHP_EV_PROP_ZVAL_* macros replaced with inline functions

Comments (0)

Files changed (5)

-Ev - PECL extension
+ev PECL extension
 
 DESCRIPTION
 ===========
 
-Ev is a PECL extension providing inteface to libev library - high performance
+ev is a PECL extension providing inteface to libev library - high performance
 full-featured event loop written in C.
 
 
 LIBEV IS EMBEDDED
 -----------------
 
-You don't need to install libev separately, since it is embedded in this
+You don't need to install libev separately, since it is embedded into this
 extension.
 
 
 PORTABILITY
 -----------
 
-Currently GNU/Linux platforms supported only.
+Currently GNU/Linux platforms supported only. But likely will work on others
+too.
 
 
+EXAMPLES
+========
+
+SIMPLE TIMERS
+-------------
+
+	<?php
+	// Create and start timer firing after 2 seconds
+	$w1 = new EvTimer(2, 0, function () {
+		echo "2 seconds elapsed\n";
+	});
+
+	// Create and launch timer firing after 2 seconds repeating each second
+	// until we manually stop it
+	$w2 = new EvTimer(2, 1, function ($w) {
+		echo "is called every second, is launched after 2 seconds\n";
+		echo "iteration = ", ev_iteration(), PHP_EOL;
+
+		// Stop the watcher after 5 iterations
+		ev_iteration() == 5 and $w->stop();
+		// Stop the watcher if further calls cause more than 10 iterations
+		ev_iteration() >= 10 and $w->stop();
+	});
+
+	// Create stopped timer. It will be inactive until we start it ourselves
+	$w_stopped = EvTimer::createStopped(10, 5, function($w) {
+		echo "Callback of a timer created as stopped\n";
+
+		// Stop the watcher after 2 iterations
+		ev_iteration() >= 2 and $w->stop();
+	});
+
+	// Loop until ev_break() is called or all of watchers stop
+	ev_run();
+
+	// Start and look if it works
+	$w_stopped->start();
+	echo "Run single iteration\n";
+	ev_run(EVRUN_ONCE);
+
+	echo "Restart the second watcher and try to handle the same events, but don't block\n";
+	$w2->again();
+	ev_run(EVRUN_NOWAIT);
+
+	$w = new EvTimer(10, 0, function() {});
+	echo "Running a blocking loop\n";
+	ev_run();
+	echo "END\n";
+	?>
+
+*Output*
+
+	2 seconds elapsed
+	is called every second, is launched after 2 seconds
+	iteration = 1
+	is called every second, is launched after 2 seconds
+	iteration = 2
+	is called every second, is launched after 2 seconds
+	iteration = 3
+	is called every second, is launched after 2 seconds
+	iteration = 4
+	is called every second, is launched after 2 seconds
+	iteration = 5
+	Run single iteration
+	Callback of a timer created as stopped
+	Restart the second watcher and try to handle the same events, but don't block
+	Running a blocking loop
+	is called every second, is launched after 2 seconds
+	iteration = 8
+	is called every second, is launched after 2 seconds
+	iteration = 9
+	is called every second, is launched after 2 seconds
+	iteration = 10
+	END
+
+PERIODIC TIMERS
+---------------
+
+*Example 1*
+
+	<?php
+	// Tick each 10.5 seconds
+	$w = new EvPeriodic(0., 10.5, NULL, function ($w, $revents) {
+		echo time(), PHP_EOL;
+	});
+	ev_run();
+	?>
+
+*Example 2*
+
+	<?php
+	// Tick each 10.5 seconds. Use reschedule callback
+
+	function reschedule_cb ($watcher, $now) {
+		return $now + (10.5. - fmod($now, 10.5));
+
+	}
+
+	$w = new EvPeriodic(0., 0., "reschedule_cb", function ($w, $revents) {
+		echo time(), PHP_EOL;
+	});
+	ev_run();
+	?>
+
+*Example 3*
+
+	<?php
+	// Tick every 10.5 seconds starting at now
+	$w = new EvPeriodic(fmod(ev_now(), 10.5), 10.5, NULL, function ($w, $revents) {
+		echo time(), PHP_EOL;
+	});
+	ev_run();
+	?>
+
+I/O EVENTS
+----------
+
+	<?php
+	// Wait until STDIN is readable
+	$w = new EvIo(STDIN, EV_READ, function ($watcher, $revents) {
+		echo "STDIN is readable\n";
+	});
+	ev_run(EVRUN_ONCE);
+	?>
+
+SIGNALS
+-------
+
+	<?php
+	// Handle SIGTERM signal
+	$w = new EvSignal(SIGTERM, function ($watcher) {
+		echo "SIGTERM received\n";
+		$watcher->stop();
+	});
+	ev_run();
+	?>
+
+STAT - FILE STATUS CHANGES
+--------------------------
+
+*Example 1*
+
+	<?php
+	// Monitor changes of /var/log/messages.
+	// Use 10 second update interval.
+	$w = new EvStat("/var/log/messages", 8, function ($w) {
+		echo "/var/log/messages changed\n";
+
+		$attr = $w->attr();
+
+		if ($attr['nlink']) {
+			printf("Current size: %ld\n", $attr['size']);
+			printf("Current atime: %ld\n", $attr['atime']);
+			printf("Current mtime: %ld\n", $attr['mtime']);
+		} else {
+			fprintf(STDERR, "`messages` file is not there!");
+			$w->stop();
+		}
+	});
+
+	ev_run();
+	?>
+
+*Example 2*
+
+	<?php
+	// Avoid missing updates by means of one second delay
+	$timer = EvTimer::createStopped(0., 1.02, function ($w) {
+		$w->stop();
+
+		$stat = $w->data;
+
+		// 1 second after the most recent change of the file
+		printf("Current size: %ld\n", $stat->attr()['size']);
+	});
+
+	$stat = new EvStat("/var/log/messages", 0., function () use ($timer) {
+		// Reset timer watcher
+		$timer->again();
+	});
+
+	$timer->data = $stat;
+
+	ev_run();
+	?>
+
+PROCESS STATUS CHANGES
+----------------------
+
+	<?php
+	$pid = pcntl_fork();
+
+	if ($pid == -1) {
+		fprintf(STDERR, "pcntl_fork failed\n");
+	} elseif ($pid) {
+		$w = new EvChild($pid, FALSE, function ($w, $revents) {
+			$w->stop();
+
+			printf("Process %d exited with status %d\n", $w->rpid, $w->rstatus);
+		});
+
+		ev_run();
+
+		// Protect against Zombies
+		pcntl_wait($status);
+	} else {
+		//Forked child
+		exit(2);
+	}
+	?>
+
 AUTHORS
 =======
 
 the world-wide-web, please send a note to license@php.net so we can mail you a
 copy immediately.
 
+
 vim: tw=80 ft=markdown
 
 /* {{{ php_ev_read_property */
 static zval *php_ev_read_property(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC)
 {
-	zval            tmp_member;
-	zval            *retval;
-	php_ev_object   *obj;
+	zval                 tmp_member;
+	zval                *retval;
+	php_ev_object       *obj;
 	php_ev_prop_handler *hnd;
-	int             ret;
+	int                  ret;
 
 	ret = FAILURE;
 	obj = (php_ev_object *) zend_objects_get_address(object TSRMLS_CC);
 	/* {{{ EvLoop */
 	PHP_EV_REGISTER_CLASS_ENTRY("EvLoop", ev_loop_class_entry_ptr, ev_loop_class_entry_functions);
 	ce = ev_loop_class_entry_ptr;
+	ce->ce_flags |= ZEND_ACC_FINAL_CLASS;
 	zend_hash_init(&php_ev_properties, 0, NULL, NULL, 1);
 	PHP_EV_ADD_CLASS_PROPERTIES(&php_ev_properties, ev_loop_property_entries);
 	PHP_EV_DECL_CLASS_PROPERTIES(ce, ev_loop_property_entry_info);
 
 	memcpy(&ev_object_handlers, std_hnd, sizeof(zend_object_handlers));
 
-	ev_object_handlers.clone_obj            = NULL;
+	ev_object_handlers.clone_obj            = NULL; /* TODO: add __clone() handler */
 	ev_object_handlers.read_property        = php_ev_read_property;
 	ev_object_handlers.write_property       = php_ev_write_property;
 	ev_object_handlers.get_property_ptr_ptr = std_hnd->get_property_ptr_ptr;
 
 /* {{{ EvWatcher */
 
+
 ZEND_BEGIN_ARG_INFO_EX(arginfo_ev_watcher_invoke, 0, 0, 1)
 	ZEND_ARG_INFO(0, revents)
 ZEND_END_ARG_INFO();
 const zend_function_entry ev_watcher_class_entry_functions[] = {
 	PHP_ABSTRACT_ME(EvWatcher, __construct, NULL)
 
-	PHP_ME(EvWatcher, start,        arginfo_ev__void,                ZEND_ACC_PUBLIC)
-	PHP_ME(EvWatcher, stop,         arginfo_ev__void,                ZEND_ACC_PUBLIC)
-	PHP_ME(EvWatcher, clear,        arginfo_ev__void,                ZEND_ACC_PUBLIC)
-	PHP_ME(EvWatcher, invoke,       arginfo_ev_watcher_invoke,       ZEND_ACC_PUBLIC)
-	PHP_ME(EvWatcher, feed,         arginfo_ev_watcher_feed,         ZEND_ACC_PUBLIC)
-	PHP_ME(EvWatcher, getLoop,      arginfo_ev__void,                ZEND_ACC_PUBLIC)
-	PHP_ME(EvWatcher, keepalive,    arginfo_ev_watcher_keepalive,    ZEND_ACC_PUBLIC)
-	PHP_ME(EvWatcher, setCallback,  arginfo_ev_watcher_set_callback, ZEND_ACC_PUBLIC)
+	PHP_ME(EvWatcher, start,       arginfo_ev__void,                ZEND_ACC_PUBLIC)
+	PHP_ME(EvWatcher, stop,        arginfo_ev__void,                ZEND_ACC_PUBLIC)
+	PHP_ME(EvWatcher, clear,       arginfo_ev__void,                ZEND_ACC_PUBLIC)
+	PHP_ME(EvWatcher, invoke,      arginfo_ev_watcher_invoke,       ZEND_ACC_PUBLIC)
+	PHP_ME(EvWatcher, feed,        arginfo_ev_watcher_feed,         ZEND_ACC_PUBLIC)
+	PHP_ME(EvWatcher, getLoop,     arginfo_ev__void,                ZEND_ACC_PUBLIC)
+	PHP_ME(EvWatcher, keepalive,   arginfo_ev_watcher_keepalive,    ZEND_ACC_PUBLIC)
+	PHP_ME(EvWatcher, setCallback, arginfo_ev_watcher_set_callback, ZEND_ACC_PUBLIC)
 
 	{ NULL, NULL, NULL }
 };
 
 #define PHP_EV_EXIT_LOOP(__loop) ev_break((__loop), EVBREAK_ALL)
 
-
-#define PHP_EV_PROP_ZVAL_READ(data)          \
-    do {                                     \
-        if (!data) {                         \
-            ALLOC_INIT_ZVAL(*retval);        \
-            return SUCCESS;                  \
-        }                                    \
-                                             \
-        MAKE_STD_ZVAL(*retval);              \
-        REPLACE_ZVAL_VALUE(retval, data, 1); \
-    } while (0)
-
-#define PHP_EV_PROP_ZVAL_WRITE(ppz)                                     \
-    do {                                                                \
-        /* Make a copy of the zval, avoid direct binding to the address \
-         * of value, since it breaks refcount in php_ev_read_property() \
-         * causing further leaks and memory access violations */        \
-        if (!*ppz) {                                                    \
-            MAKE_STD_ZVAL(*ppz);                                        \
-        }                                                               \
-        REPLACE_ZVAL_VALUE(ppz, value, 1);                              \
-    } while (0)
-
 #define PHP_EV_CHECK_REPEAT(repeat)                                                 \
     if (repeat < 0.) {                                                              \
         php_error_docref(NULL TSRMLS_CC, E_ERROR, # repeat " value must be >= 0."); \
    +----------------------------------------------------------------------+
 */
 
-#if 0
-#include "embed.h"
-#include "priv.h"
-#endif
 #include "php_ev.h"
 #include "watcher.h"
 
+static inline void php_ev_prop_write_zval(zval **ppz, const zval *value)
+{
+	if (!*ppz) {
+		MAKE_STD_ZVAL(*ppz);
+	}
+
+    /* Make a copy of the zval, avoid direct binding to the address
+     * of value, since it breaks refcount in php_ev_read_property()
+     * causing further leaks and memory access violations */
+	REPLACE_ZVAL_VALUE(ppz, value, 1);
+}
+
+static inline void php_ev_prop_read_zval(const zval *pz, zval **retval)
+{
+	if (!pz) {
+		ALLOC_INIT_ZVAL(*retval);
+		return;
+	}
+
+    MAKE_STD_ZVAL(*retval);
+    REPLACE_ZVAL_VALUE(retval, pz, 1);
+}
+
 
 /* {{{ EvLoop property handlers */
 
 
 	zval *data = PHP_EV_LOOP_OBJECT_FETCH_FROM_OBJECT(obj)->data;
 
-	PHP_EV_PROP_ZVAL_READ(data);
+	php_ev_prop_read_zval(data, retval);
 
 	return SUCCESS;
 }
 {
 	PHP_EV_ASSERT(obj->ptr);
 
-	zval **data_ptr_ptr = &(PHP_EV_LOOP_OBJECT_FETCH_FROM_OBJECT(obj))->data;
-
-	PHP_EV_PROP_ZVAL_WRITE(data_ptr_ptr);
+	php_ev_prop_write_zval(&(PHP_EV_LOOP_OBJECT_FETCH_FROM_OBJECT(obj))->data, value);
 
 	return SUCCESS;
 }
 
 	zval *data = PHP_EV_WATCHER_FETCH_FROM_OBJECT(obj)->data;
 
-	PHP_EV_PROP_ZVAL_READ(data);
+	php_ev_prop_read_zval(data, retval);
 
 	return SUCCESS;
 }
 {
 	PHP_EV_ASSERT(obj->ptr);
 
-	zval **data_ptr_ptr = &(PHP_EV_LOOP_OBJECT_FETCH_FROM_OBJECT(obj))->data;
-
-	PHP_EV_PROP_ZVAL_WRITE(data_ptr_ptr);
+	php_ev_prop_write_zval(&(PHP_EV_WATCHER_FETCH_FROM_OBJECT(obj))->data, value);
 
 	return SUCCESS;
 }
 
 	php_ev_embed *embed_ptr = (php_ev_embed *) PHP_EV_WATCHER_FETCH_FROM_OBJECT(obj);
 
-	PHP_EV_PROP_ZVAL_READ(embed_ptr->other);
+	php_ev_prop_read_zval(embed_ptr->other, retval);
 
 	return SUCCESS;
 }
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.