Commits

Ruslan Osmanov  committed a2b1ff0

Removed php_ev_ prefix from file names
Fix: segfault caused by situation when loop is freed, and watchers tried to access the loop
Change: organized linked list of watchers associated with a loop; stop all watchers before calling ev_loop_destroy

  • Participants
  • Parent commits 5bd526d

Comments (0)

Files changed (30)

 Problem: move the class code separate files, then simply
 ========================================================
 
-#include "php_ev_loop.c"
-#include "php_ev_watcher.c"
-#include "php_ev_io.c"
-#include "php_ev_timer.c"
+#include "loop.c"
+#include "watcher.c"
+#include "io.c"
+#include "timer.c"
 #if EV_PERIODIC_ENABLE
-#include "php_ev_periodic.c"
+#include "periodic.c"
 #endif
 #if EV_PREPARE_ENABLE
-#include "php_ev_scheduler.c"
+#include "scheduler.c"
 #endif
 #endif
 #if EV_SIGNAL_ENABLE
-#include "php_ev_signal.c"
+#include "signal.c"
 #endif
 #if EV_CHILD_ENABLE
-#include "php_ev_child.c"
+#include "child.c"
 #endif
 #if EV_STAT_ENABLE
-#include "php_ev_stat.c"
+#include "stat.c"
 #endif
 #if EV_IDLE_ENABLE
-#include "php_ev_idle.c"
+#include "idle.c"
 #endif
 #if EV_PREPARE_ENABLE
-#include "php_ev_prepare.c"
+#include "prepare.c"
 #endif
 #if EV_CHECK_ENABLE
-#include "php_ev_check.c"
+#include "check.c"
 #endif
 #if EV_EMBED_ENABLE
-#include "php_ev_embed.c"
+#include "embed.c"
 #endif
 #if EV_FORK_ENABLE
-#include "php_ev_fork.c"
+#include "fork.c"
 #endif
 #if EV_ASYNC_ENABLE
-#include "php_ev_async.c"
+#include "async.c"
 #endif
 
-Somewhere in php_ev.c, or php_ev.h
+Somewhere in ev.c, or php_ev.h
 
 ========================================================
 C++? 
+/*
+   +----------------------------------------------------------------------+
+   | PHP Version 5                                                        |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1997-2012 The PHP Group                                |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 3.01 of the PHP license,      |
+   | that is bundled with this package in the file LICENSE, and is        |
+   | available through the world-wide-web at the following url:           |
+   | http://www.php.net/license/3_01.txt                                  |
+   | If you did not receive a copy of the PHP license and are unable to   |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@php.net so we can mail you a copy immediately.               |
+   +----------------------------------------------------------------------+
+   | Author: Ruslan Osmanov <osmanov@php.net>                             |
+   +----------------------------------------------------------------------+
+*/
+#ifndef PHP_EV_COMMON_H
+#define PHP_EV_COMMON_H
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <php.h>
+#include <php_ini.h>
+#include <SAPI.h>
+#include <zend_interfaces.h>
+#include <ext/standard/info.h>
+#include <ext/standard/php_string.h>
+#include <Zend/zend_extensions.h>
+
+#ifdef ZTS
+# include "TSRM.h"
+#endif
+
+#endif /* PHP_EV_COMMON_H */
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
+/*
+   +----------------------------------------------------------------------+
+   | PHP Version 5                                                        |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1997-2012 The PHP Group                                |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 3.01 of the PHP license,      |
+   | that is bundled with this package in the file LICENSE, and is        |
+   | available through the world-wide-web at the following url:           |
+   | http://www.php.net/license/3_01.txt                                  |
+   | If you did not receive a copy of the PHP license and are unable to   |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@php.net so we can mail you a copy immediately.               |
+   +----------------------------------------------------------------------+
+   | Author: Ruslan Osmanov <osmanov@php.net>                             |
+   +----------------------------------------------------------------------+
+*/
+#ifndef PHP_EV_EMBED_H
+#define PHP_EV_EMBED_H
+
+#include "common.h"
+#include "types.h"
+
+/* EV_STANDALONE isn't needed, since we use libev/libev.m4
+ * #define EV_STANDALONE 1 */
+#undef EV_USE_POLL
+/* We compile multiple source files. So we don't need static API
+ * #define EV_API_STATIC 1 */
+#undef EV_API_STATIC
+
+#define EV_COMPAT3      0
+#define EV_FEATURES     8
+#define EV_MULTIPLICITY 1
+#define EV_USE_POLL     1
+#define EV_CHILD_ENABLE 1
+#define EV_ASYNC_ENABLE 1
+#define EV_MINPRI       -2
+#define EV_MAXPRI       2
+
+#ifdef PHP_EV_DEBUG
+# define EV_VERIFY 2
+#else
+# define EV_VERIFY 0
+#endif
+
+/* Thread context. With it we are getting rid of need 
+ * to call the heavy TSRMLS_FETCH() */
+#ifdef ZTS
+# define PHP_EV_COMMON_THREAD_CTX void ***thread_ctx
+#else
+# define PHP_EV_COMMON_THREAD_CTX
+#endif
+
+/* Override `data` member of the watcher structs.
+ * See types.h and libev/ev.h */
+#define EV_COMMON                                                         \
+    zval                        *self;      /* this struct */                        \
+    zval                        *data;      /* custom var attached by user */        \
+    php_ev_loop                 *loop;                                               \
+    zend_fcall_info             *fci;       /* fci &fcc serve $callback arg */       \
+    zend_fcall_info_cache       *fcc;                                                \
+    int                          type;      /* EV_ *constant from libev/ev.h */      \
+    int                          e_flags;                                            \
+    void                        *e_prev;    /* Linked list of ev_watcher pointers */ \
+    PHP_EV_COMMON_THREAD_CTX;                                                        \
+
+#include "libev/ev.h"
+
+#endif /* PHP_EV_EMBED_H */
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 sts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4 sts=4
+ */
+/*
+   +----------------------------------------------------------------------+
+   | PHP Version 5                                                        |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1997-2012 The PHP Group                                |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 3.01 of the PHP license,      |
+   | that is bundled with this package in the file LICENSE, and is        |
+   | available through the world-wide-web at the following url:           |
+   | http://www.php.net/license/3_01.txt                                  |
+   | If you did not receive a copy of the PHP license and are unable to   |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@php.net so we can mail you a copy immediately.               |
+   +----------------------------------------------------------------------+
+   | Author: Ruslan Osmanov <osmanov@php.net>                             |
+   +----------------------------------------------------------------------+
+*/
+
+#include "php_ev.h"
+
+#if HAVE_EV
+
+ZEND_DECLARE_MODULE_GLOBALS(ev)
+static PHP_GINIT_FUNCTION(ev);
+
+zend_class_entry *ev_loop_class_entry_ptr;
+zend_class_entry *ev_watcher_class_entry_ptr;
+zend_class_entry *ev_io_class_entry_ptr;
+
+static HashTable classes;
+static HashTable php_ev_properties;
+static HashTable php_ev_watcher_properties;
+static HashTable php_ev_io_properties;
+
+static zend_object_handlers ev_object_handlers;
+
+/* {{{ ev_module_entry */
+zend_module_entry ev_module_entry = {
+#if ZEND_MODULE_API_NO >= 20050922
+	STANDARD_MODULE_HEADER_EX, NULL,
+	NULL,
+#elif ZEND_MODULE_API_NO >= 20010901
+	STANDARD_MODULE_HEADER,
+#endif
+    "Ev",
+    ev_functions,
+    PHP_MINIT(ev),
+    PHP_MSHUTDOWN(ev),
+    NULL,                         /* PHP_RINIT(ev)     */
+    NULL,                         /* PHP_RSHUTDOWN(ev) */
+    PHP_MINFO(ev),
+    PHP_EV_VERSION,
+    PHP_MODULE_GLOBALS(ev),
+    PHP_GINIT(ev),
+    NULL,
+    NULL,
+    STANDARD_MODULE_PROPERTIES_EX
+};
+/* }}} */
+
+#ifdef COMPILE_DL_EV
+ZEND_GET_MODULE(ev)
+#endif
+
+/* {{{ Private functions */
+
+/* {{{ php_ev_prop_read_default */
+static int php_ev_prop_read_default(php_ev_object *obj, zval **retval TSRMLS_DC)
+{
+	*retval = NULL;
+	php_error_docref(NULL TSRMLS_CC, E_ERROR, "Cannot read property");
+	return FAILURE;
+}
+/* }}} */
+
+/* {{{ php_ev_prop_write_default */
+static int php_ev_prop_write_default(php_ev_object *obj, zval *newval TSRMLS_DC)
+{
+	php_error_docref(NULL TSRMLS_CC, E_ERROR, "Cannot write property");
+	return FAILURE;
+}
+/* }}} */
+
+/* {{{ php_ev_add_property */
+static void php_ev_add_property(HashTable *h, const char *name, size_t name_len, php_ev_read_t read_func, php_ev_write_t write_func TSRMLS_DC) {
+	php_ev_prop_handler p;
+
+	p.name       = (char *) name;
+	p.name_len   = name_len;
+	p.read_func  = (read_func) ? read_func : php_ev_prop_read_default;
+	p.write_func = (write_func) ? write_func: php_ev_prop_write_default;
+	zend_hash_add(h, name, name_len + 1, &p, sizeof(php_ev_prop_handler), NULL);
+}
+/* }}} */
+
+/* {{{ 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;
+	php_ev_prop_handler *hnd;
+	int             ret;
+
+	ret = FAILURE;
+	obj = (php_ev_object *) zend_objects_get_address(object TSRMLS_CC);
+
+	if (member->type != IS_STRING) {
+	    tmp_member = *member;
+	    zval_copy_ctor(&tmp_member);
+	    convert_to_string(&tmp_member);
+	    member = &tmp_member;
+	}
+
+	if (obj->prop_handler != NULL) {
+	    ret = zend_hash_find(obj->prop_handler, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, (void **) &hnd);
+	}
+
+	if (ret == SUCCESS) {
+	    ret = hnd->read_func(obj, &retval TSRMLS_CC);
+	    if (ret == SUCCESS) {
+	        /* ensure we're creating a temporary variable */
+	        Z_SET_REFCOUNT_P(retval, 0);
+	    } else {
+	        retval = EG(uninitialized_zval_ptr);
+	    }
+	} else {
+	    zend_object_handlers * std_hnd = zend_get_std_object_handlers();
+	    retval = std_hnd->read_property(object, member, type, key TSRMLS_CC);
+	}
+
+	if (member == &tmp_member) {
+	    zval_dtor(member);
+	}
+	return(retval);
+}
+/* }}} */
+
+/* {{{ php_ev_write_property */
+void php_ev_write_property(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC)
+{
+	zval             tmp_member;
+	php_ev_object   *obj;
+	php_ev_prop_handler *hnd;
+	int              ret;
+
+	if (member->type != IS_STRING) {
+	    tmp_member = *member;
+	    zval_copy_ctor(&tmp_member);
+	    convert_to_string(&tmp_member);
+	    member = &tmp_member;
+	}
+
+	ret = FAILURE;
+	obj = (php_ev_object *) zend_objects_get_address(object TSRMLS_CC);
+
+	if (obj->prop_handler != NULL) {
+	    ret = zend_hash_find((HashTable *) obj->prop_handler, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, (void **) &hnd);
+	}
+	if (ret == SUCCESS) {
+	    hnd->write_func(obj, value TSRMLS_CC);
+	    if (! PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) == 0) {
+	        Z_ADDREF_P(value);
+	        zval_ptr_dtor(&value);
+	    }
+	} else {
+	    zend_object_handlers * std_hnd = zend_get_std_object_handlers();
+	    std_hnd->write_property(object, member, value, key TSRMLS_CC);
+	}
+
+	if (member == &tmp_member) {
+	    zval_dtor(member);
+	}
+}
+/* }}} */
+
+/* {{{ php_ev_has_property */
+static int php_ev_has_property(zval *object, zval *member, int has_set_exists, const zend_literal *key TSRMLS_DC)
+{
+	php_ev_object   *obj = (php_ev_object *) zend_objects_get_address(object TSRMLS_CC);
+	int              ret = 0;
+	php_ev_prop_handler  p;
+
+	if (zend_hash_find(obj->prop_handler, Z_STRVAL_P(member), Z_STRLEN_P(member) + 1, (void **) &p) == SUCCESS) {
+	    switch (has_set_exists) {
+	        case 2:
+	            ret = 1;
+	            break;
+	        case 1: {
+	                	zval *value = php_ev_read_property(object, member, BP_VAR_IS, key TSRMLS_CC);
+	                	if (value != EG(uninitialized_zval_ptr)) {
+	                	    convert_to_boolean(value);
+	                	    ret = Z_BVAL_P(value)? 1:0;
+	                	    /* refcount is 0 */
+	                	    Z_ADDREF_P(value);
+	                	    zval_ptr_dtor(&value);
+	                	}
+	                	break;
+	                }
+	        case 0:{
+	                   zval *value = php_ev_read_property(object, member, BP_VAR_IS, key TSRMLS_CC);
+	                   if (value != EG(uninitialized_zval_ptr)) {
+	                	   ret = Z_TYPE_P(value) != IS_NULL? 1:0;
+	                	   /* refcount is 0 */
+	                	   Z_ADDREF_P(value);
+	                	   zval_ptr_dtor(&value);
+	                   }
+	                   break;
+	               }
+	        default:
+	               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid value for has_set_exists");
+	    }
+	} else {
+	    zend_object_handlers *std_hnd = zend_get_std_object_handlers();
+	    ret = std_hnd->has_property(object, member, has_set_exists, key TSRMLS_CC);
+	}
+	return ret;
+} /* }}} */
+
+/* {{{ php_ev_object_get_debug_info */
+#if PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 3
+static HashTable *php_ev_object_get_debug_info(zval *object, int *is_temp TSRMLS_DC)
+{
+	php_ev_object *obj = (php_ev_object *) zend_objects_get_address(object TSRMLS_CC); 
+	HashTable *retval, *props = obj->prop_handler;
+	HashPosition pos;
+	php_ev_prop_handler *entry;
+
+	ALLOC_HASHTABLE(retval);
+	ZEND_INIT_SYMTABLE_EX(retval, zend_hash_num_elements(props) + 1, 0);
+
+	zend_hash_internal_pointer_reset_ex(props, &pos);
+	while (zend_hash_get_current_data_ex(props, (void **) &entry, &pos) == SUCCESS) {
+	    zval member;
+	    zval *value;
+	    INIT_ZVAL(member);
+	    ZVAL_STRINGL(&member, entry->name, entry->name_len, 0);
+	    value = php_ev_read_property(object, &member, BP_VAR_IS, 0 TSRMLS_CC);
+	    if (value != EG(uninitialized_zval_ptr)) {
+	        Z_ADDREF_P(value);
+	        zend_hash_add(retval, entry->name, entry->name_len + 1, &value, sizeof(zval *) , NULL);
+	    }       
+	    zend_hash_move_forward_ex(props, &pos);
+	}               
+
+	*is_temp = 1;   
+	return retval;
+}               
+#endif    
+/* }}} */
+
+
+/* {{{ php_ev_object_free_storage 
+ * Common Ev object cleaner */
+static void php_ev_object_free_storage(void *obj_ TSRMLS_DC)
+{
+	php_ev_object *obj = (php_ev_object *) obj_;
+
+	zend_object_std_dtor(&obj->zo TSRMLS_CC);
+
+	if (obj->ptr) {
+		efree(obj->ptr);
+	}
+
+	efree(obj);
+}
+/* }}} */
+
+/* {{{ php_ev_loop_free_storage */
+static void php_ev_loop_free_storage(void *obj_ TSRMLS_DC)
+{
+	php_ev_object *obj = (php_ev_object *) obj_;
+
+	PHP_EV_ASSERT(obj->ptr);
+	php_ev_loop *ptr = (php_ev_loop *) obj->ptr;
+
+	if (ptr->loop) {
+		/* Stop all watchers associated with this loop.  But don't free their memory. 
+		 * They have special automatically called handlers for this purpose */
+		ev_watcher *w = ptr->w;
+		while (w) {
+			php_ev_stop_watcher(w TSRMLS_CC);
+			w = php_ev_watcher_prev(w);
+		}
+
+		if (ev_is_default_loop(ptr->loop)) {
+			zval **default_loop_ptr_ptr = &MyG(default_loop);
+			if (*default_loop_ptr_ptr) {
+				zval_ptr_dtor(default_loop_ptr_ptr);
+				*default_loop_ptr_ptr = NULL;
+			}
+		}
+
+		ev_loop_destroy(ptr->loop);
+		ptr->loop = NULL;
+	}
+
+	PHP_EV_FREE_FCALL_INFO(ptr->fci, ptr->fcc);
+
+	if (ptr->data) {
+		zval_ptr_dtor(&ptr->data);
+		ptr->data = NULL;
+	}
+
+	php_ev_object_free_storage(obj TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ php_ev_watcher_free_storage() 
+ * There must *not* be EvWatcher instances created by user.
+ * This is a helper for derived watcher class objects. */
+static void php_ev_watcher_free_storage(ev_watcher *ptr TSRMLS_DC)
+{
+	zval *data, *self;
+
+	/* This is done in php_ev_loop_free_storage()
+	php_ev_stop_watcher(ptr TSRMLS_CC);
+	*/
+
+	PHP_EV_FREE_FCALL_INFO(php_ev_watcher_fci(ptr), php_ev_watcher_fcc(ptr));
+	
+	data = php_ev_watcher_data(ptr);
+	self = php_ev_watcher_self(ptr);
+
+	if (data) {
+		zval_ptr_dtor(&data);
+	}
+	zval_ptr_dtor(&self);
+}
+/* }}} */
+
+/* {{{ php_ev_io_free_storage() */
+static void php_ev_io_free_storage(void *object TSRMLS_DC)
+{
+	php_ev_object *obj_ptr = (php_ev_object *) object;
+
+	PHP_EV_ASSERT(obj_ptr->ptr);
+	ev_io *ptr = (ev_io *) obj_ptr->ptr;
+
+	/* Free base class members */
+	php_ev_watcher_free_storage((ev_watcher *) ptr TSRMLS_CC);
+
+	/* Free common Ev object members and the object itself */
+	php_ev_object_free_storage(object TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ php_ev_register_object 
+ * Is called AFTER php_ev_object_new() */
+zend_object_value php_ev_register_object(zend_class_entry *ce, php_ev_object *intern TSRMLS_DC)
+{
+	zend_object_value                  retval;
+	zend_objects_free_object_storage_t func_free_storage;
+
+	if (instanceof_function(ce, ev_loop_class_entry_ptr TSRMLS_CC)) {
+		/* EvLoop */
+	 	func_free_storage = php_ev_loop_free_storage;
+	} else if (instanceof_function(ce, ev_io_class_entry_ptr TSRMLS_CC)) {
+		/* EvIo */
+	 	func_free_storage = php_ev_io_free_storage;
+	} else {
+	 	func_free_storage = php_ev_object_free_storage;
+	}
+
+	retval.handle = zend_objects_store_put(intern,
+			(zend_objects_store_dtor_t)zend_objects_destroy_object,
+			(zend_objects_free_object_storage_t)func_free_storage,
+			NULL TSRMLS_CC);
+	retval.handlers = &ev_object_handlers;
+
+	return retval;
+}
+/* }}} */
+
+/* {{{ php_ev_object_new
+ * Custom Ev object. php_ev_register_object() must be called AFTER */
+php_ev_object *php_ev_object_new(zend_class_entry *ce TSRMLS_DC)
+{
+	php_ev_object    *intern;
+	zend_class_entry *ce_parent = ce;
+
+	intern               = ecalloc(1, sizeof(php_ev_object));
+	intern->ptr          = NULL;
+	intern->prop_handler = NULL;
+
+	while (ce_parent) {
+	    if (ce_parent == ev_watcher_class_entry_ptr
+	    		|| ce_parent == ev_loop_class_entry_ptr) {
+	    	break;
+	    }
+	    ce_parent = ce_parent->parent;
+	}
+	zend_hash_find(&classes, ce_parent->name, ce_parent->name_length + 1,
+	        (void **) &intern->prop_handler);
+
+	zend_object_std_init(&intern->zo, ce TSRMLS_CC);
+	object_properties_init(&intern->zo, ce);
+
+	return intern;
+}
+/* }}} */
+
+/* {{{ php_ev_object_create
+ Custom Ev object(class instance) creator */
+zend_object_value php_ev_object_create(zend_class_entry *ce TSRMLS_DC)
+{
+	php_ev_object *intern;
+
+	intern = php_ev_object_new(ce TSRMLS_CC);
+	return php_ev_register_object(ce, intern TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ php_ev_register_classes
+ * Registers all Ev classes. Should be called in MINIT */
+static inline void php_ev_register_classes(TSRMLS_D)
+{
+	zend_class_entry *ce;
+
+	/* {{{ EvLoop */
+	PHP_EV_REGISTER_CLASS_ENTRY("EvLoop", ev_loop_class_entry_ptr, ev_loop_class_entry_functions);
+	ce = ev_loop_class_entry_ptr;
+	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);
+	zend_hash_add(&classes, ce->name, ce->name_length + 1, &php_ev_properties, sizeof(php_ev_properties), NULL);
+	/* }}} */
+
+	/* {{{ EvWatcher */
+	PHP_EV_REGISTER_CLASS_ENTRY("EvWatcher", ev_watcher_class_entry_ptr, ev_watcher_class_entry_functions);
+	ce = ev_watcher_class_entry_ptr;
+	zend_hash_init(&php_ev_watcher_properties, 0, NULL, NULL, 1);
+	PHP_EV_ADD_CLASS_PROPERTIES(&php_ev_watcher_properties, ev_watcher_property_entries);
+	PHP_EV_DECL_CLASS_PROPERTIES(ce, ev_watcher_property_entry_info);
+	zend_hash_add(&classes, ce->name, ce->name_length + 1, &php_ev_watcher_properties, sizeof(php_ev_watcher_properties), NULL);
+	/* }}} */
+
+	/* {{{ EvIo */
+	PHP_EV_REGISTER_CLASS_ENTRY_EX("EvIo", ev_io_class_entry_ptr, ev_io_class_entry_functions, ev_watcher_class_entry_ptr);
+	ce = ev_io_class_entry_ptr;
+	zend_hash_init(&php_ev_io_properties, 0, NULL, NULL, 1);
+	PHP_EV_ADD_CLASS_PROPERTIES(&php_ev_io_properties, ev_io_property_entries);
+	PHP_EV_DECL_CLASS_PROPERTIES(ce, ev_io_property_entry_info);
+	zend_hash_add(&classes, ce->name, ce->name_length + 1, &php_ev_io_properties, sizeof(php_ev_io_properties), NULL);
+	/* }}} */
+}
+/* }}} */
+
+/* Private functions }}} */
+
+
+/* {{{ PHP_GINIT_FUNCTION */ 
+static PHP_GINIT_FUNCTION(ev)
+{
+	ev_globals->default_loop = NULL;
+}
+/* }}} */
+
+
+/* {{{ PHP_MINIT_FUNCTION */
+PHP_MINIT_FUNCTION(ev)
+{
+	zend_object_handlers *std_hnd = zend_get_std_object_handlers();
+
+	memcpy(&ev_object_handlers, std_hnd, sizeof(zend_object_handlers));
+
+	ev_object_handlers.clone_obj            = NULL;
+	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;
+	ev_object_handlers.has_property         = php_ev_has_property;
+#if PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 3
+	ev_object_handlers.get_debug_info       = php_ev_object_get_debug_info;
+#endif
+
+	zend_hash_init(&classes, 0, NULL, NULL, 1);
+	php_ev_register_classes(TSRMLS_C);
+
+
+	/* {{{ EvLoop flags */
+	PHP_EV_REGISTER_LONG_CONSTANT(EVFLAG_AUTO);
+	PHP_EV_REGISTER_LONG_CONSTANT(EVFLAG_NOENV);
+	PHP_EV_REGISTER_LONG_CONSTANT(EVFLAG_FORKCHECK);
+	PHP_EV_REGISTER_LONG_CONSTANT(EVFLAG_NOINOTIFY);
+	PHP_EV_REGISTER_LONG_CONSTANT(EVFLAG_SIGNALFD);
+	PHP_EV_REGISTER_LONG_CONSTANT(EVFLAG_NOSIGMASK);
+
+	PHP_EV_REGISTER_LONG_CONSTANT(EVRUN_NOWAIT);
+	PHP_EV_REGISTER_LONG_CONSTANT(EVRUN_ONCE);
+
+	PHP_EV_REGISTER_LONG_CONSTANT(EVBREAK_CANCEL);
+	PHP_EV_REGISTER_LONG_CONSTANT(EVBREAK_ONE);
+	PHP_EV_REGISTER_LONG_CONSTANT(EVBREAK_ALL);
+	/* }}} */
+
+	PHP_EV_REGISTER_LONG_CONSTANT(EV_MINPRI);
+	PHP_EV_REGISTER_LONG_CONSTANT(EV_MAXPRI);
+
+	PHP_EV_REGISTER_LONG_CONSTANT(EV_READ);
+	PHP_EV_REGISTER_LONG_CONSTANT(EV_WRITE);
+
+	return SUCCESS;
+}
+/* }}} */
+
+
+/* {{{ PHP_MSHUTDOWN_FUNCTION */
+PHP_MSHUTDOWN_FUNCTION(ev)
+{
+	zend_hash_destroy(&php_ev_properties);
+	zend_hash_destroy(&php_ev_watcher_properties);
+	zend_hash_destroy(&php_ev_io_properties);
+	zend_hash_destroy(&classes);
+
+	return SUCCESS;
+}
+/* }}} */
+
+
+/* {{{ PHP_RINIT_FUNCTION */
+PHP_RINIT_FUNCTION(ev)
+{
+	return SUCCESS;
+}
+/* }}} */
+
+
+/* {{{ PHP_RSHUTDOWN_FUNCTION */
+PHP_RSHUTDOWN_FUNCTION(ev)
+{
+	return SUCCESS;
+}
+/* }}} */
+
+
+/* {{{ PHP_MINFO_FUNCTION */
+PHP_MINFO_FUNCTION(ev)
+{
+	php_info_print_table_start();
+	php_info_print_table_row(2, "Ev support", "enabled");
+#ifdef PHP_EV_DEBUG 
+	php_info_print_table_row(2, "Debug support", "enabled");
+#else
+	php_info_print_table_row(2, "Debug support", "disabled");
+#endif
+#ifdef PHP_EV_LIBEVENT_API
+	php_info_print_table_row(2, "Libevent compatibility API support", "enabled");
+#else
+	php_info_print_table_row(2, "Libevent compatibility API support", "disabled");
+#endif
+	php_info_print_table_row(2, "Version", PHP_EV_VERSION);
+	php_info_print_table_end();
+}
+/* }}} */
+
+
+#include "loop.c" 
+#include "io.c"
+
+#endif /* HAVE_EV */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 sts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4 sts=4
+ */

File ev_embed.h

-/*
-   +----------------------------------------------------------------------+
-   | PHP Version 5                                                        |
-   +----------------------------------------------------------------------+
-   | Copyright (c) 1997-2012 The PHP Group                                |
-   +----------------------------------------------------------------------+
-   | This source file is subject to version 3.01 of the PHP license,      |
-   | that is bundled with this package in the file LICENSE, and is        |
-   | available through the world-wide-web at the following url:           |
-   | http://www.php.net/license/3_01.txt                                  |
-   | If you did not receive a copy of the PHP license and are unable to   |
-   | obtain it through the world-wide-web, please send a note to          |
-   | license@php.net so we can mail you a copy immediately.               |
-   +----------------------------------------------------------------------+
-   | Author: Ruslan Osmanov <osmanov@php.net>                             |
-   +----------------------------------------------------------------------+
-*/
-#ifndef PHP_EV_EMBED_H
-#define PHP_EV_EMBED_H
-
-#include "php_ev_common.h"
-#include "php_ev_types.h"
-
-/* EV_STANDALONE isn't needed, since we use libev/libev.m4
- * #define EV_STANDALONE 1 */
-#undef EV_USE_POLL
-/* We compile multiple source files. So we don't need static API
- * #define EV_API_STATIC 1 */
-#undef EV_API_STATIC
-
-#define EV_COMPAT3      0
-#define EV_FEATURES     8
-#define EV_MULTIPLICITY 1
-#define EV_USE_POLL     1
-#define EV_CHILD_ENABLE 1
-#define EV_ASYNC_ENABLE 1
-#define EV_MINPRI       -2
-#define EV_MAXPRI       2
-
-#ifdef PHP_EV_DEBUG
-# define EV_VERIFY 2
-#else
-# define EV_VERIFY 0
-#endif
-
-/* Thread context. With it we are getting rid of need 
- * to call the heavy TSRMLS_FETCH() */
-#ifdef ZTS
-# define PHP_EV_EMBED_THREAD_CTX void ***thread_ctx
-#else
-# define PHP_EV_EMBED_THREAD_CTX
-#endif
-
-/* Override `data` member of the watcher structs.
- * See php_ev_types.h and libev/ev.h */
-#define EV_COMMON                                                           \
-    zval                       *self;   /* this struct */                   \
-    zval                       *data;   /* custom var attached by user */   \
-    zval                       *loop;                                       \
-    zend_fcall_info            *fci;    /* fci &fcc serve $callback arg */  \
-    zend_fcall_info_cache      *fcc;                                        \
-    int                         type;   /* EV_ *constant from libev/ev.h */ \
-    PHP_EV_EMBED_THREAD_CTX;                                                \
-
-#include "libev/ev.h"
-
-#endif /* PHP_EV_EMBED_H */
-/*
- * Local variables:
- * tab-width: 4
- * c-basic-offset: 4
- * End:
- * vim600: noet sw=4 ts=4 sts=4 fdm=marker
- * vim<600: noet sw=4 ts=4 sts=4
- */
+/*
+   +----------------------------------------------------------------------+
+   | PHP Version 5                                                        |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1997-2012 The PHP Group                                |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 3.01 of the PHP license,      |
+   | that is bundled with this package in the file LICENSE, and is        |
+   | available through the world-wide-web at the following url:           |
+   | http://www.php.net/license/3_01.txt                                  |
+   | If you did not receive a copy of the PHP license and are unable to   |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@php.net so we can mail you a copy immediately.               |
+   +----------------------------------------------------------------------+
+   | Author: Ruslan Osmanov <osmanov@php.net>                             |
+   +----------------------------------------------------------------------+
+*/
+
+#include "fe.h"
+
+/* {{{ ARGINFO */
+
+/* {{{ EvLoop */
+ZEND_BEGIN_ARG_INFO(arginfo_ev__loop_void, 0)
+ZEND_END_ARG_INFO();
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_ev_default_loop, 0, 0, 0)
+	ZEND_ARG_INFO(0, flags)
+	ZEND_ARG_INFO(0, callback)
+	ZEND_ARG_INFO(0, data)
+	ZEND_ARG_INFO(0, io_collect_interval)
+	ZEND_ARG_INFO(0, timeout_collect_interval)
+ZEND_END_ARG_INFO();
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_ev_sleep, 0, 0, 1)
+	ZEND_ARG_INFO(0, seconds)
+ZEND_END_ARG_INFO();
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_ev_run, 0, 0, 0)
+	ZEND_ARG_INFO(0, flags)
+ZEND_END_ARG_INFO();
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_ev_break, 0, 0, 0)
+	ZEND_ARG_INFO(0, how)
+ZEND_END_ARG_INFO();
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_ev_feed_signal, 0, 0, 1)
+	ZEND_ARG_INFO(0, signum)
+ZEND_END_ARG_INFO();
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_ev_feed_signal_event, 0, 0, 1)
+	ZEND_ARG_INFO(0, signum)
+ZEND_END_ARG_INFO();
+/* EvLoop }}} */
+
+/* {{{ EvWatcher */
+ZEND_BEGIN_ARG_INFO(arginfo_ev__watcher_void, 0)
+ZEND_END_ARG_INFO();
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_ev_watcher_invoke, 0, 0, 1)
+	ZEND_ARG_INFO(0, revents)
+ZEND_END_ARG_INFO();
+ZEND_BEGIN_ARG_INFO_EX(arginfo_ev_watcher_feed, 0, 0, 1)
+	ZEND_ARG_INFO(0, revents)
+ZEND_END_ARG_INFO();
+/* EvWatcher }}} */
+
+/* {{{ EvIo */
+ZEND_BEGIN_ARG_INFO_EX(arginfo_ev_io, 0, 0, 3)
+	ZEND_ARG_INFO(0, fd)
+	ZEND_ARG_INFO(0, events)
+	ZEND_ARG_INFO(0, loop)
+	ZEND_ARG_INFO(0, callback)
+	ZEND_ARG_INFO(0, data)
+	ZEND_ARG_INFO(0, priority)
+ZEND_END_ARG_INFO();
+/* EvIo }}} */
+/* ARGINFO }}} */
+
+
+/* {{{ ev_functions[] */
+const zend_function_entry ev_functions[] = {
+	{NULL, NULL, NULL}
+};
+/* }}} */
+
+/* {{{ ev_loop_class_entry_functions */
+const zend_function_entry ev_loop_class_entry_functions[] = {
+	PHP_ME(EvLoop, __construct,          arginfo_ev_default_loop,      ZEND_ACC_PUBLIC  | ZEND_ACC_CTOR)
+	PHP_ME(EvLoop, default_loop,         arginfo_ev_default_loop,      ZEND_ACC_PUBLIC  | ZEND_ACC_STATIC)
+	PHP_ME(EvLoop, loop_fork,            arginfo_ev__loop_void,        ZEND_ACC_PUBLIC)
+	PHP_ME(EvLoop, verify,               arginfo_ev__loop_void,        ZEND_ACC_PUBLIC)
+	PHP_ME(EvLoop, invoke_pending,       arginfo_ev__loop_void,        ZEND_ACC_PUBLIC)
+	PHP_ME(EvLoop, now_update,           arginfo_ev__loop_void,        ZEND_ACC_PUBLIC)
+	PHP_ME(EvLoop, suspend,              arginfo_ev__loop_void,        ZEND_ACC_PUBLIC)
+	PHP_ME(EvLoop, resume,               arginfo_ev__loop_void,        ZEND_ACC_PUBLIC)
+
+	PHP_ME(EvLoop, supported_backends,   arginfo_ev__loop_void,        ZEND_ACC_PUBLIC  | ZEND_ACC_STATIC)
+	PHP_ME(EvLoop, recommended_backends, arginfo_ev__loop_void,        ZEND_ACC_PUBLIC  | ZEND_ACC_STATIC)
+	PHP_ME(EvLoop, embeddable_backends,  arginfo_ev__loop_void,        ZEND_ACC_PUBLIC  | ZEND_ACC_STATIC)
+
+	PHP_ME(EvLoop, sleep,                arginfo_ev_sleep,             ZEND_ACC_PUBLIC  | ZEND_ACC_STATIC)
+	PHP_ME(EvLoop, time,                 arginfo_ev__loop_void,        ZEND_ACC_PUBLIC  | ZEND_ACC_STATIC)
+	PHP_ME(EvLoop, now,                  arginfo_ev__loop_void,        ZEND_ACC_PUBLIC)
+
+	PHP_ME(EvLoop, run,                  arginfo_ev_run,               ZEND_ACC_PUBLIC)
+	PHP_ME(EvLoop, break,                arginfo_ev_break,             ZEND_ACC_PUBLIC)
+	PHP_ME(EvLoop, feed_signal,          arginfo_ev_feed_signal,       ZEND_ACC_PUBLIC  | ZEND_ACC_STATIC)
+	PHP_ME(EvLoop, feed_signal_event,    arginfo_ev_feed_signal_event, ZEND_ACC_PUBLIC  | ZEND_ACC_STATIC)
+
+	{ NULL, NULL, NULL }
+};
+/* }}} */
+
+/* {{{ ev_watcher_class_entry_functions */
+const zend_function_entry ev_watcher_class_entry_functions[] = {
+	PHP_ABSTRACT_ME(EvWatcher, __construct, NULL)
+
+	PHP_ME(EvWatcher, start,   arginfo_ev__watcher_void,  ZEND_ACC_PUBLIC)
+	PHP_ME(EvWatcher, stop,    arginfo_ev__watcher_void,  ZEND_ACC_PUBLIC)
+	PHP_ME(EvWatcher, clear,   arginfo_ev__watcher_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__watcher_void,  ZEND_ACC_PUBLIC)
+
+	{ NULL, NULL, NULL }
+};
+/* }}} */
+
+/* {{{ ev_io_class_entry_functions */
+const zend_function_entry ev_io_class_entry_functions[] = {
+	PHP_ME(EvIo, __construct, arginfo_ev_io, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
+	{ NULL, NULL, NULL }
+};
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: fdm=marker
+ * vim: noet sts=4 sw=4 ts=4
+ */
+/*
+   +----------------------------------------------------------------------+
+   | PHP Version 5                                                        |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1997-2011 The PHP Group                                |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 3.01 of the PHP license,      |
+   | that is bundled with this package in the file LICENSE, and is        |
+   | available through the world-wide-web at the following url:           |
+   | http://www.php.net/license/3_01.txt                                  |
+   | If you did not receive a copy of the PHP license and are unable to   |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@php.net so we can mail you a copy immediately.               |
+   +----------------------------------------------------------------------+
+   | Author: Ruslan Osmanov <osmanov@php.net>                             |
+   +----------------------------------------------------------------------+
+*/
+#ifndef PHP_EV_FE_H
+#define PHP_EV_FE_H
+
+#include "embed.h"
+
+/* {{{ EvLoop */
+PHP_METHOD(EvLoop, __construct);
+PHP_METHOD(EvLoop, default_loop);
+PHP_METHOD(EvLoop, loop_fork);
+PHP_METHOD(EvLoop, verify);
+PHP_METHOD(EvLoop, invoke_pending);
+PHP_METHOD(EvLoop, now_update);
+PHP_METHOD(EvLoop, suspend);
+PHP_METHOD(EvLoop, resume);
+PHP_METHOD(EvLoop, supported_backends);
+PHP_METHOD(EvLoop, recommended_backends);
+PHP_METHOD(EvLoop, embeddable_backends);
+PHP_METHOD(EvLoop, sleep);
+PHP_METHOD(EvLoop, time);
+PHP_METHOD(EvLoop, now);
+PHP_METHOD(EvLoop, run);
+PHP_METHOD(EvLoop, break);
+PHP_METHOD(EvLoop, feed_signal);
+PHP_METHOD(EvLoop, feed_signal_event);
+/* }}} */
+
+/* {{{ EvWatcher */
+/* PHP_METHOD(EvWatcher, __construct); */
+PHP_METHOD(EvWatcher, start);
+PHP_METHOD(EvWatcher, stop);
+PHP_METHOD(EvWatcher, clear);
+PHP_METHOD(EvWatcher, invoke);
+PHP_METHOD(EvWatcher, feed);
+PHP_METHOD(EvWatcher, getLoop);
+/* }}} */
+
+/* {{{ EvIo */
+PHP_METHOD(EvIo, __construct);
+/* }}} */
+
+#endif /* PHP_EV_FE_H */
+
+/* 
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * vim600: fdm=marker
+ * vim: noet sts=4 sw=4 ts=4
+ */
+/*
+   +----------------------------------------------------------------------+
+   | PHP Version 5                                                        |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1997-2012 The PHP Group                                |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 3.01 of the PHP license,      |
+   | that is bundled with this package in the file LICENSE, and is        |
+   | available through the world-wide-web at the following url:           |
+   | http://www.php.net/license/3_01.txt                                  |
+   | If you did not receive a copy of the PHP license and are unable to   |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@php.net so we can mail you a copy immediately.               |
+   +----------------------------------------------------------------------+
+   | Author: Ruslan Osmanov <osmanov@php.net>                             |
+   +----------------------------------------------------------------------+
+*/
+
+
+/* {{{ proto EvIo::__construct(resource fd, int events, EvLoop loop, callback callback[, mixed data = NULL[, int priority = 0]]) */
+PHP_METHOD(EvIo, __construct)
+{
+	zval          *self;
+	zval          *z_stream;
+	php_ev_object *o_self;
+	php_ev_object *o_loop;
+	ev_io         *io_watcher;
+
+	zval                  *loop;
+	zval                  *data      = NULL;
+	php_stream            *fd_stream;
+	zend_fcall_info        fci       = empty_fcall_info;
+	zend_fcall_info_cache  fcc       = empty_fcall_info_cache;
+	long                   priority  = 0;
+	long                   events;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rlOf|z!l",
+				&z_stream, &events, &loop, ev_loop_class_entry_ptr, &fci, &fcc,
+				&data, &priority) == FAILURE) {
+		return;
+	}
+
+	if (events & ~(EV_READ | EV_WRITE)) {
+		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid events mask");
+		return;
+	}
+
+	self    = getThis();
+	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);
+	io_watcher = (ev_io *)php_ev_new_watcher(sizeof(ev_io), self,
+			PHP_EV_LOOP_OBJECT_FETCH_FROM_OBJECT(o_loop),
+			&fci, &fcc, data, priority TSRMLS_CC);
+
+	io_watcher->type = EV_IO;
+	
+	php_stream_from_zval_no_verify(fd_stream, &z_stream);
+	if (fd_stream == NULL) {
+		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed obtaining fd");
+		return;
+	}
+	ev_io_set(io_watcher, Z_LVAL_P(z_stream), events);
+
+	o_self->ptr = (void *)io_watcher;
+}
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 sts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4 sts=4
+ */
+/*
+   +----------------------------------------------------------------------+
+   | PHP Version 5                                                        |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1997-2012 The PHP Group                                |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 3.01 of the PHP license,      |
+   | that is bundled with this package in the file LICENSE, and is        |
+   | available through the world-wide-web at the following url:           |
+   | http://www.php.net/license/3_01.txt                                  |
+   | If you did not receive a copy of the PHP license and are unable to   |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@php.net so we can mail you a copy immediately.               |
+   +----------------------------------------------------------------------+
+   | Author: Ruslan Osmanov <osmanov@php.net>                             |
+   +----------------------------------------------------------------------+
+*/
+
+/* {{{ php_ev_loop_object_ctor
+ * Creates an instance of EvLoop class and puts it in retval
+ * in_ctor: whether called from constructor of a loop class 
+ * default_loop: whether to return/create the default loop */
+static void php_ev_loop_object_ctor(INTERNAL_FUNCTION_PARAMETERS, const zend_bool in_ctor, const zend_bool is_default_loop)
+{
+	php_ev_object          *ev_obj;
+	ev_loop                *loop;
+	zval                  **default_loop_ptr_ptr     = NULL;
+	zval                   *self                     = getThis();
+
+	long                    flags                    = EVFLAG_AUTO;
+	double                  io_collect_interval      = 0.;
+	double                  timeout_collect_interval = 0.;
+	zval                   *data                     = NULL;
+	zend_fcall_info         fci                      = empty_fcall_info;
+	zend_fcall_info_cache   fcc                      = empty_fcall_info_cache;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lf!z!dd",
+				&flags, &fci, &fcc, &data, 
+				&io_collect_interval, &timeout_collect_interval) == FAILURE) {
+		return;
+	}
+
+	default_loop_ptr_ptr = &MyG(default_loop);
+
+	if (!in_ctor) {
+		/* Factory method mode */
+		if (is_default_loop) {
+			if (!*default_loop_ptr_ptr) {
+				loop = ev_default_loop(flags);
+			} else {
+				php_error_docref(NULL TSRMLS_CC, E_WARNING,
+						"Returning previously created default loop");
+				RETURN_ZVAL(*default_loop_ptr_ptr, /* copy */ 1, /* dtor*/ 0);
+				return;
+			}
+		} else {
+			loop = ev_loop_new(flags);
+		}
+
+		if (!loop) {
+			php_error_docref(NULL TSRMLS_CC, E_ERROR,
+					"Failed to instanciate default loop, "
+					"bad $LIBEV_FLAGS in environment?");
+			return;
+		}
+
+		/* Assign return value */
+		Z_TYPE_P(return_value) = IS_OBJECT;
+		object_init_ex(return_value, ev_loop_class_entry_ptr);
+		Z_SET_REFCOUNT_P(return_value, 1);
+		Z_UNSET_ISREF_P(return_value);
+
+		ev_obj = (php_ev_object *) zend_object_store_get_object(return_value TSRMLS_CC);
+
+		/* Save return_value in MyG(default_loop) */
+		if (!*default_loop_ptr_ptr) {
+			MAKE_STD_ZVAL(*default_loop_ptr_ptr);
+			REPLACE_ZVAL_VALUE(default_loop_ptr_ptr, return_value, 1);
+		}
+	} else {
+		/* Create custom event loop(OOP API) */
+		loop = ev_loop_new(flags);
+		if (!loop) {
+			php_error_docref(NULL TSRMLS_CC, E_ERROR,
+					"Failed to instanciate loop, bad backend, "
+					"or bad $LIBEV_FLAGS in environment?");
+			return;
+		}
+
+		ev_obj = (php_ev_object *) zend_object_store_get_object(self TSRMLS_CC);
+	}
+
+	php_ev_loop *ptr = (php_ev_loop *) emalloc(sizeof(php_ev_loop));
+	memset(ptr, 0, sizeof(php_ev_loop));
+	ptr->loop = loop;
+
+	PHP_EV_COPY_FCALL_INFO(ptr->fci, ptr->fcc, &fci, &fcc);
+
+	if (data) {
+		Z_ADDREF_P(data);
+	}
+	ptr->data                     = data;
+	ptr->io_collect_interval      = io_collect_interval;
+	ptr->timeout_collect_interval = timeout_collect_interval;
+	ev_obj->ptr                   = (void *) ptr;
+
+	ev_set_userdata(loop, (void *) return_value); 
+}
+/* }}} */
+
+/* {{{ proto EvLoop EvLoop::default_loop([int flags = EVLAG_AUTO[, callback callback = NULL[, mixed data = NULL[, double io_collect_interval = 0.[, double timeout_collect_interval = 0.]]]]])
+*/
+PHP_METHOD(EvLoop, default_loop)
+{
+	php_ev_loop_object_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU,
+			/* in ctor */FALSE, /* is_default_loop */TRUE);
+}
+/* }}} */
+
+/* {{{ proto EvLoop EvLoop::__construct([int flags = EVLAG_AUTO[, callback callback = NULL[, mixed data = NULL[, double io_collect_interval = 0.[, double timeout_collect_interval = 0.]]]]]) */
+PHP_METHOD(EvLoop, __construct) 
+{
+	php_ev_loop_object_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU,
+			/* in ctor */TRUE, /* is_default_loop */FALSE);
+}
+/* }}} */
+
+
+#define PHP_EV_LOOP_METHOD_VOID(name)                  \
+    PHP_METHOD(EvLoop, name)                           \
+    {                                                  \
+        PHP_EV_LOOP_FETCH_FROM_THIS;                   \
+                                                       \
+        if (zend_parse_parameters_none() == FAILURE) { \
+            return;                                    \
+        }                                              \
+                                                       \
+        ev_##name(EV_A);                               \
+    }
+
+#define PHP_EV_LOOP_METHOD_INT_VOID(name)              \
+    PHP_METHOD(EvLoop, name)                           \
+    {                                                  \
+        if (zend_parse_parameters_none() == FAILURE) { \
+            return;                                    \
+        }                                              \
+                                                       \
+        RETURN_LONG((long)ev_##name());                \
+    }
+
+#define PHP_EV_LOOP_METHOD_DOUBLE_VOID(name)           \
+    PHP_METHOD(EvLoop, name)                           \
+    {                                                  \
+        if (zend_parse_parameters_none() == FAILURE) { \
+            return;                                    \
+        }                                              \
+                                                       \
+        RETURN_DOUBLE((double)ev_##name());            \
+    }
+
+PHP_EV_LOOP_METHOD_VOID(loop_fork)
+PHP_EV_LOOP_METHOD_VOID(verify)
+PHP_EV_LOOP_METHOD_VOID(invoke_pending)
+PHP_EV_LOOP_METHOD_VOID(now_update)
+PHP_EV_LOOP_METHOD_VOID(suspend)
+PHP_EV_LOOP_METHOD_VOID(resume)
+
+PHP_EV_LOOP_METHOD_INT_VOID(supported_backends)
+PHP_EV_LOOP_METHOD_INT_VOID(recommended_backends)
+PHP_EV_LOOP_METHOD_INT_VOID(embeddable_backends)
+
+/* {{{ proto void sleep(double seconds) */
+PHP_METHOD(EvLoop, sleep) 
+{
+	double seconds;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &seconds) == FAILURE) {
+		return;
+	}
+
+	ev_sleep(seconds);
+}
+/* }}} */
+
+PHP_EV_LOOP_METHOD_DOUBLE_VOID(time)
+
+/* {{{ proto double EvLoop::now(void) */
+PHP_METHOD(EvLoop, now)
+{
+	PHP_EV_LOOP_FETCH_FROM_THIS;
+
+	if (zend_parse_parameters_none() == FAILURE) {
+		return;
+	}
+
+	RETURN_DOUBLE((double)ev_now(EV_A));
+}
+/* }}} */
+
+/* {{{ proto void EvLoop::run([int flags = 0]) */
+PHP_METHOD(EvLoop, run)
+{
+	PHP_EV_LOOP_FETCH_FROM_THIS;
+
+	long flags = 0;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &flags) == FAILURE) {
+		return;
+	}
+
+	ev_run(EV_A_ flags);
+}
+/* }}} */
+
+/* {{{ proto void EvLoop::break([int how = 0]) */
+PHP_METHOD(EvLoop, break)
+{
+	PHP_EV_LOOP_FETCH_FROM_THIS;
+
+	long how = 0;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &how) == FAILURE) {
+		return;
+	}
+
+	ev_break(EV_A_ how);
+}
+/* }}} */
+
+/* {{{ proto void EvLoop::feed_signal(int signum) */
+PHP_METHOD(EvLoop, feed_signal)
+{
+	long signum;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &signum) == FAILURE) {
+		return;
+	}
+
+	ev_feed_signal(signum);
+}
+/* }}} */
+
+/* {{{ proto void EvLoop::feed_signal_event(int signum) */
+PHP_METHOD(EvLoop, feed_signal_event)
+{
+	long			signum;
+	php_ev_object	*ev_obj;
+	zval			**default_loop_ptr_ptr = &MyG(default_loop);
+	
+	if (!*default_loop_ptr_ptr) {
+		php_error_docref(NULL TSRMLS_CC, E_ERROR,
+				"The default loop is not initialized");
+		return;
+	}
+
+	/* Fetch the default loop */
+	ev_obj = (php_ev_object *) zend_object_store_get_object(*default_loop_ptr_ptr TSRMLS_CC);
+	EV_P = PHP_EV_LOOP_FETCH_FROM_OBJECT(ev_obj);
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &signum) == FAILURE) {
+		return;
+	}
+
+	ev_feed_signal_event(EV_A_ signum);
+}
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 sts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4 sts=4
+ */
+/*
+   +----------------------------------------------------------------------+
+   | PHP Version 5                                                        |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1997-2012 The PHP Group                                |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 3.01 of the PHP license,      |
+   | that is bundled with this package in the file LICENSE, and is        |
+   | available through the world-wide-web at the following url:           |
+   | http://www.php.net/license/3_01.txt                                  |
+   | If you did not receive a copy of the PHP license and are unable to   |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@php.net so we can mail you a copy immediately.               |
+   +----------------------------------------------------------------------+
+   | Author: Ruslan Osmanov <osmanov@php.net>                             |
+   +----------------------------------------------------------------------+
+*/
+
+#ifndef PHP_EV_MACROS_H
+# define PHP_EV_MACROS_H
+
+#ifndef TRUE
+# define TRUE 1
+#endif
+
+#ifndef FALSE
+# define FALSE 0
+#endif
+
+#ifdef PHP_EV_DEBUG
+# define PHP_EV_ASSERT(x) assert(x)
+#else
+# define PHP_EV_ASSERT(x)
+#endif
+
+#ifdef ZTS
+# define MyG(v)                     TSRMG(ev_globals_id, zend_ev_globals *, v)
+# define TSRMLS_FETCH_FROM_CTX(ctx) void ***tsrm_ls = (void ***) ctx
+# define TSRMLS_SET_CTX(ctx)        ctx = (void ***) tsrm_ls
+#else
+# define MyG(v)                     (ev_globals.v)
+# define TSRMLS_FETCH_FROM_CTX(ctx)
+# define TSRMLS_SET_CTX(ctx)
+#endif
+
+
+#define PHP_EV_REGISTER_LONG_CONSTANT(name) \
+	REGISTER_LONG_CONSTANT(#name, name, CONST_CS | CONST_PERSISTENT)
+
+#define PHP_EV_REGISTER_CLASS_LONG_CONSTANT(name, zconst)     \
+    zconst = pemalloc(sizeof(zval), 1);                       \
+    INIT_PZVAL(zconst);                                       \
+    ZVAL_LONG(zconst, name);                                  \
+    zend_hash_add(&ce->constants_table, #name, sizeof(#name), \
+            (void*)&zconst, sizeof(zval*), NULL);
+
+#define PHP_EV_REGISTER_CLASS_ENTRY(name, ce, ce_functions) \
+{                                                           \
+    zend_class_entry tmp_ce;                                \
+    INIT_CLASS_ENTRY(tmp_ce, name, ce_functions);           \
+    ce = zend_register_internal_class(&tmp_ce TSRMLS_CC);   \
+    ce->create_object = php_ev_object_create;               \
+}
+
+#define PHP_EV_REGISTER_CLASS_ENTRY_EX(name, ce, ce_functions, parent_ce)       \
+{                                                                               \
+    zend_class_entry tmp_ce;                                                    \
+    INIT_CLASS_ENTRY_EX(tmp_ce, name, sizeof(name) - 1, ce_functions);          \
+    ce = zend_register_internal_class_ex(&tmp_ce, parent_ce, NULL TSRMLS_CC);   \
+    ce->create_object = parent_ce->create_object; /*php_ev_object_create; */    \
+}
+
+#define PHP_EV_ADD_CLASS_PROPERTIES(a, b)                                                      \
+{                                                                                              \
+    int i = 0;                                                                                 \
+    while (b[i].name != NULL) {                                                                \
+        php_ev_add_property((a), (b)[i].name, (b)[i].name_length,                              \
+                (php_ev_read_t)(b)[i].read_func, (php_ev_write_t)(b)[i].write_func TSRMLS_CC); \
+        i++;                                                                                   \
+    }                                                                                          \
+}
+
+#define PHP_EV_DECL_CLASS_PROPERTIES(a, b)                                                           \
+{                                                                                                    \
+    int i = 0;                                                                                       \
+    while (b[i].name != NULL) {                                                                      \
+        zend_declare_property_null((a), (b)[i].name, (b)[i].name_length, ZEND_ACC_PUBLIC TSRMLS_CC); \
+        i++;                                                                                         \
+    }                                                                                                \
+}
+
+#define PHP_EV_CONSTRUCT_CHECK(ev_obj)                                        \
+    if (!ev_obj->ptr) {                                                       \
+        php_error_docref(NULL TSRMLS_CC, E_ERROR, "Loop is not initialized"); \
+        return;                                                               \
+    }
+
+#if PHP_VERSION_ID >= 50300
+# define PHP_EV_FCI_ADDREF(pfci)          \
+{                                         \
+    if (pfci->object_ptr) {               \
+        Z_ADDREF_P(pfci->object_ptr);     \
+    }                                     \
+}
+# define PHP_EV_FCI_DELREF(pfci)          \
+{                                         \
+    if (pfci->object_ptr) {               \
+        zval_ptr_dtor(&pfci->object_ptr); \
+    }                                     \
+}
+#else
+# define PHP_EV_FCI_ADDREF(pfci)
+# define PHP_EV_FCI_DELREF(pfci)
+#endif
+
+#define PHP_EV_COPY_FCALL_INFO(pfci_dst, pfcc_dst, pfci, pfcc)                                        \
+{                                                                                                     \
+    if (ZEND_FCI_INITIALIZED(*pfci)) {                                                                \
+        pfci_dst = (zend_fcall_info *) safe_emalloc(1, sizeof(zend_fcall_info), 0);                   \
+        pfcc_dst = (zend_fcall_info_cache *) safe_emalloc(1, sizeof(zend_fcall_info_cache), 0);       \
+                                                                                                      \
+        memcpy(pfci_dst, pfci, sizeof(zend_fcall_info));                                              \
+        memcpy(pfcc_dst, pfcc, sizeof(zend_fcall_info_cache));                                        \
+                                                                                                      \
+        /* Prevent auto-destruction of the zvals within */                                            \
+        Z_ADDREF_P(pfci_dst->function_name);                                                          \
+        PHP_EV_FCI_ADDREF(pfci_dst);                                                                  \
+    } else {                                                                                          \
+        pfci_dst = NULL;                                                                              \
+        pfcc_dst = NULL;                                                                              \
+    }                                                                                                 \
+}
+
+#define PHP_EV_FREE_FCALL_INFO(pfci, pfcc)       \
+{                                                \
+    if (pfci && pfcc) {                          \
+        efree(pfcc);                             \
+                                                 \
+        if (ZEND_FCI_INITIALIZED(*pfci)) {       \
+            zval_ptr_dtor(&pfci->function_name); \
+            PHP_EV_FCI_DELREF(pfci);             \
+        }                                        \
+        efree(pfci);                             \
+    }                                            \
+}
+
+#define PHP_EV_LOOP_OBJECT_FETCH_FROM_OBJECT(obj) (obj ? (php_ev_loop *) obj->ptr : NULL)
+#define PHP_EV_WATCHER_FETCH_FROM_OBJECT(o)       ((ev_watcher *) o->ptr)
+
+#define PHP_EV_LOOP_FETCH_FROM_OBJECT(obj) (obj ? PHP_EV_LOOP_OBJECT_FETCH_FROM_OBJECT(obj)->loop : NULL)
+#define PHP_EV_LOOP_FETCH_FROM_THIS                                                             \
+    php_ev_object *ev_obj = (php_ev_object *)zend_object_store_get_object(getThis() TSRMLS_CC); \
+    PHP_EV_CONSTRUCT_CHECK(ev_obj);                                                             \
+    EV_P = PHP_EV_LOOP_FETCH_FROM_OBJECT(ev_obj) /* no ';' */
+
+#define PHP_EV_CHECK_PENDING_WATCHER(w)              \
+{                                                    \
+    if (ev_is_pending(w)) {                          \
+        php_error_docref(NULL TSRMLS_CC, E_ERROR,    \
+                "Failed modifying pending watcher"); \
+        return;                                      \
+    }                                                \
+}
+
+#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)
+
+#endif /* PHP_EV_MACROS_H*/
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * vim600: fdm=marker
+ * vim: noet sts=4 sw=4 ts=4
+ */
+/*
+   +----------------------------------------------------------------------+
+   | PHP Version 5                                                        |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1997-2012 The PHP Group                                |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 3.01 of the PHP license,      |
+   | that is bundled with this package in the file LICENSE, and is        |
+   | available through the world-wide-web at the following url:           |
+   | http://www.php.net/license/3_01.txt                                  |
+   | If you did not receive a copy of the PHP license and are unable to   |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@php.net so we can mail you a copy immediately.               |
+   +----------------------------------------------------------------------+
+   | Author: Ruslan Osmanov <osmanov@php.net>                             |
+   +----------------------------------------------------------------------+
+*/
+
+#include "embed.h"
+#include "priv.h"
+#include "watcher.h"
+
+
+/* {{{ EvLoop property handlers */
+
+/* {{{ ev_loop_prop_data_read  */
+static int ev_loop_prop_data_read(php_ev_object *obj, zval **retval TSRMLS_DC)
+{
+	PHP_EV_ASSERT(obj->ptr);
+
+	zval *data = PHP_EV_LOOP_OBJECT_FETCH_FROM_OBJECT(obj)->data;
+
+	PHP_EV_PROP_ZVAL_READ(data);
+
+	return SUCCESS;
+}
+/* }}} */
+
+/* {{{ ev_loop_prop_data_write  */
+static int ev_loop_prop_data_write(php_ev_object *obj, zval *value TSRMLS_DC)
+{
+	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);
+
+	return SUCCESS;
+}
+/* }}} */
+
+/* {{{ ev_loop_prop_backend_read */
+static int ev_loop_prop_backend_read(php_ev_object *obj, zval **retval TSRMLS_DC)
+{
+	PHP_EV_ASSERT(obj->ptr);
+	
+	MAKE_STD_ZVAL(*retval);
+	ZVAL_LONG(*retval, ev_backend(PHP_EV_LOOP_FETCH_FROM_OBJECT(obj)));
+
+	return SUCCESS;
+}
+/* }}} */
+
+/* {{{ ev_loop_prop_is_default_loop_read */
+static int ev_loop_prop_is_default_loop_read(php_ev_object *obj, zval **retval TSRMLS_DC)
+{
+	PHP_EV_ASSERT(obj->ptr);
+	
+	MAKE_STD_ZVAL(*retval);
+	ZVAL_BOOL(*retval, ev_is_default_loop(PHP_EV_LOOP_FETCH_FROM_OBJECT(obj)));
+
+	return SUCCESS;
+}
+/* }}} */
+
+/* {{{ ev_loop_prop_iteration_loop_read */
+static int ev_loop_prop_iteration_loop_read(php_ev_object *obj, zval **retval TSRMLS_DC)
+{
+	PHP_EV_ASSERT(obj->ptr);
+	
+	MAKE_STD_ZVAL(*retval);
+	ZVAL_LONG(*retval, ev_iteration(PHP_EV_LOOP_FETCH_FROM_OBJECT(obj)));
+
+	return SUCCESS;
+}
+/* }}} */
+
+/* {{{ ev_loop_prop_pending_loop_read */
+static int ev_loop_prop_pending_loop_read(php_ev_object *obj, zval **retval TSRMLS_DC)
+{
+	PHP_EV_ASSERT(obj->ptr);
+	
+	MAKE_STD_ZVAL(*retval);
+	ZVAL_LONG(*retval, ev_pending_count(PHP_EV_LOOP_FETCH_FROM_OBJECT(obj)));
+
+	return SUCCESS;
+}
+/* }}} */
+
+/* }}} */
+
+/* {{{ EvWatcher property handlers */
+
+/* {{{ ev_watcher_prop_is_active_read */
+static int ev_watcher_prop_is_active_read(php_ev_object *obj, zval **retval TSRMLS_DC)
+{
+	PHP_EV_ASSERT(obj->ptr);
+	
+	MAKE_STD_ZVAL(*retval);
+	ZVAL_BOOL(*retval, ev_is_active(PHP_EV_WATCHER_FETCH_FROM_OBJECT(obj)));
+
+	return SUCCESS;
+}
+/* }}} */
+
+/* {{{ ev_watcher_prop_data_read  */
+static int ev_watcher_prop_data_read(php_ev_object *obj, zval **retval TSRMLS_DC)
+{
+	PHP_EV_ASSERT(obj->ptr);
+
+	zval *data = PHP_EV_WATCHER_FETCH_FROM_OBJECT(obj)->data;
+
+	PHP_EV_PROP_ZVAL_READ(data);
+
+	return SUCCESS;
+}
+/* }}} */
+
+/* {{{ ev_watcher_prop_data_write */
+static int ev_watcher_prop_data_write(php_ev_object *obj, zval *value TSRMLS_DC)
+{
+	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);
+
+	return SUCCESS;
+}
+/* }}} */
+
+/* {{{ ev_watcher_prop_is_pending_read */
+static int ev_watcher_prop_is_pending_read(php_ev_object *obj, zval **retval TSRMLS_DC)
+{
+	PHP_EV_ASSERT(obj->ptr);
+	
+	MAKE_STD_ZVAL(*retval);
+	ZVAL_BOOL(*retval, ev_is_pending(PHP_EV_WATCHER_FETCH_FROM_OBJECT(obj)));
+
+	return SUCCESS;
+}
+/* }}} */
+
+/* {{{ ev_watcher_prop_priority_read */
+static int ev_watcher_prop_priority_read(php_ev_object *obj, zval **retval TSRMLS_DC)
+{
+	PHP_EV_ASSERT(obj->ptr);
+	
+	MAKE_STD_ZVAL(*retval);
+	ZVAL_LONG(*retval, ev_priority(PHP_EV_WATCHER_FETCH_FROM_OBJECT(obj)));
+
+	return SUCCESS;
+}
+/* }}} */
+
+/* {{{ ev_watcher_prop_priority_write */
+static int ev_watcher_prop_priority_write(php_ev_object *obj, zval *value TSRMLS_DC)
+{
+	PHP_EV_ASSERT(obj->ptr);
+
+	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;
+    }
+
+	priority = Z_LVAL_P(value);
+	if (priority < INT_MIN) {
+		php_error_docref(NULL TSRMLS_CC, E_WARNING,
+				"Priority value must be bigger than INT_MIN");
+	    return FAILURE;
+	}
+	if (priority > INT_MAX) {
+		php_error_docref(NULL TSRMLS_CC, E_WARNING,
+				"Priority value must not exceed INT_MAX");
+	    return FAILURE;
+	}
+
+	php_ev_set_watcher_priority(watcher, priority TSRMLS_CC);
+
+	return SUCCESS;
+}
+/* }}} */
+
+/* }}} */
+
+
+/* {{{ ev_loop_property_entries[] */
+const php_ev_property_entry ev_loop_property_entries[] = {
+	{"data",            sizeof("data")            - 1, ev_loop_prop_data_read,            ev_loop_prop_data_write},
+	{"backend",         sizeof("backend")         - 1, ev_loop_prop_backend_read,         NULL},
+	{"is_default_loop", sizeof("is_default_loop") - 1, ev_loop_prop_is_default_loop_read, NULL},
+	{"iteration",       sizeof("iteration")       - 1, ev_loop_prop_iteration_loop_read,  NULL},
+	{"pending",         sizeof("pending")         - 1, ev_loop_prop_pending_loop_read,    NULL},
+    {NULL, 0, NULL, NULL}
+};
+/* }}} */
+
+/* {{{ ev_loop_property_entry_info[] */
+const zend_property_info ev_loop_property_entry_info[] = {
+	{ZEND_ACC_PUBLIC, "data",            sizeof("data") - 1,            -1, 0, NULL, 0, NULL},
+	{ZEND_ACC_PUBLIC, "backend",         sizeof("backend") - 1,         -1, 0, NULL, 0, NULL},
+	{ZEND_ACC_PUBLIC, "is_default_loop", sizeof("is_default_loop") - 1, -1, 0, NULL, 0, NULL},
+	{ZEND_ACC_PUBLIC, "iteration",       sizeof("iteration") - 1,       -1, 0, NULL, 0, NULL},
+	{ZEND_ACC_PUBLIC, "pending",         sizeof("pending") - 1,         -1, 0, NULL, 0, NULL},
+	{0,                NULL,             0,                             -1, 0, NULL, 0, NULL}
+};
+/* }}} */
+
+/* {{{ ev_watcher_property_entries[] */
+const php_ev_property_entry ev_watcher_property_entries[] = {
+	{"is_active",  sizeof("is_active")  - 1, ev_watcher_prop_is_active_read,  NULL},
+	{"data",       sizeof("data")       - 1, ev_watcher_prop_data_read,       ev_watcher_prop_data_write},
+	{"is_pending", sizeof("is_pending") - 1, ev_watcher_prop_is_pending_read, NULL},
+	{"priority",   sizeof("priority")   - 1, ev_watcher_prop_priority_read,   ev_watcher_prop_priority_write},
+	{NULL, 0, NULL, NULL}
+};
+/* }}} */
+
+/* {{{ ev_watcher_property_entry_info[] */
+const zend_property_info ev_watcher_property_entry_info[] = {
+	{ZEND_ACC_PUBLIC, "is_active",  sizeof("is_active")  - 1, -1, 0, NULL, 0, NULL},
+	{ZEND_ACC_PUBLIC, "data",       sizeof("data")       - 1, -1, 0, NULL, 0, NULL},
+	{ZEND_ACC_PUBLIC, "is_pending", sizeof("is_pending") - 1, -1, 0, NULL, 0, NULL},
+	{ZEND_ACC_PUBLIC, "priority",   sizeof("priority")   - 1, -1, 0, NULL, 0, NULL},
+	{ZEND_ACC_PUBLIC, "loop",       sizeof("loop")       - 1, -1, 0, NULL, 0, NULL},
+	{0, NULL, 0, -1, 0, NULL, 0, NULL}
+};
+/* }}} */
+
+/* {{{ ev_io_property_entries[] */
+const php_ev_property_entry ev_io_property_entries[] = {
+    {NULL, 0, NULL, NULL}
+};
+/* }}} */
+
+/* {{{ ev_io_property_entry_info[] */
+const zend_property_info ev_io_property_entry_info[] = {
+	{0, NULL, 0, -1, 0, NULL, 0, NULL},
+};
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: fdm=marker
+ * vim: noet sts=4 sw=4 ts=4
+ */

File php_ev.c

-/*
-   +----------------------------------------------------------------------+
-   | PHP Version 5                                                        |
-   +----------------------------------------------------------------------+
-   | Copyright (c) 1997-2012 The PHP Group                                |
-   +----------------------------------------------------------------------+
-   | This source file is subject to version 3.01 of the PHP license,      |
-   | that is bundled with this package in the file LICENSE, and is        |
-   | available through the world-wide-web at the following url:           |
-   | http://www.php.net/license/3_01.txt                                  |
-   | If you did not receive a copy of the PHP license and are unable to   |
-   | obtain it through the world-wide-web, please send a note to          |
-   | license@php.net so we can mail you a copy immediately.               |
-   +----------------------------------------------------------------------+
-   | Author: Ruslan Osmanov <osmanov@php.net>                             |
-   +----------------------------------------------------------------------+
-*/
-
-#include "php_ev.h"
-
-#if HAVE_EV
-
-ZEND_DECLARE_MODULE_GLOBALS(ev)
-static PHP_GINIT_FUNCTION(ev);
-
-zend_class_entry *ev_loop_class_entry_ptr;
-zend_class_entry *ev_watcher_class_entry_ptr;
-zend_class_entry *ev_io_class_entry_ptr;
-
-static HashTable classes;
-static HashTable php_ev_properties;
-static HashTable php_ev_watcher_properties;
-static HashTable php_ev_io_properties;
-
-static zend_object_handlers ev_object_handlers;
-
-/* {{{ ev_module_entry */
-zend_module_entry ev_module_entry = {
-#if ZEND_MODULE_API_NO >= 20050922
-	STANDARD_MODULE_HEADER_EX, NULL,
-	NULL,
-#elif ZEND_MODULE_API_NO >= 20010901
-	STANDARD_MODULE_HEADER,
-#endif
-	"Ev",
-	ev_functions,
-	PHP_MINIT(ev),
-	PHP_MSHUTDOWN(ev),
-	PHP_RINIT(ev),     /* Replace with NULL if there is nothing to do at request start */
-	PHP_RSHUTDOWN(ev), /* Replace with NULL if there is nothing to do at request end   */
-	PHP_MINFO(ev),
-	PHP_EV_VERSION, 
-	PHP_MODULE_GLOBALS(ev),
-	PHP_GINIT(ev),
-	NULL,
-	NULL,
-	STANDARD_MODULE_PROPERTIES_EX
-};
-/* }}} */
-
-#ifdef COMPILE_DL_EV
-ZEND_GET_MODULE(ev)
-#endif
-
-/* {{{ Private functions */
-
-/* {{{ php_ev_prop_read_default */
-static int php_ev_prop_read_default(php_ev_object *obj, zval **retval TSRMLS_DC)
-{
-	*retval = NULL;
-	php_error_docref(NULL TSRMLS_CC, E_ERROR, "Cannot read property");
-	return FAILURE;
-}
-/* }}} */
-
-/* {{{ php_ev_prop_write_default */
-static int php_ev_prop_write_default(php_ev_object *obj, zval *newval TSRMLS_DC)
-{
-	php_error_docref(NULL TSRMLS_CC, E_ERROR, "Cannot write property");
-	return FAILURE;
-}
-/* }}} */
-
-/* {{{ php_ev_add_property */
-static void php_ev_add_property(HashTable *h, const char *name, size_t name_len, php_ev_read_t read_func, php_ev_write_t write_func TSRMLS_DC) {
-	ev_prop_handler p;
-
-	p.name       = (char *) name;
-	p.name_len   = name_len;
-	p.read_func  = (read_func) ? read_func : php_ev_prop_read_default;
-	p.write_func = (write_func) ? write_func: php_ev_prop_write_default;
-	zend_hash_add(h, name, name_len + 1, &p, sizeof(ev_prop_handler), NULL);
-}
-/* }}} */
-
-/* {{{ 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;
-	ev_prop_handler		*hnd;
-	int					ret;
-
-	ret = FAILURE;
-	obj = (php_ev_object *)zend_objects_get_address(object TSRMLS_CC);
-
-	if (member->type != IS_STRING) {
-	    tmp_member = *member;
-	    zval_copy_ctor(&tmp_member);
-	    convert_to_string(&tmp_member);
-	    member = &tmp_member;
-	}
-
-	if (obj->prop_handler != NULL) {
-	    ret = zend_hash_find(obj->prop_handler, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, (void **) &hnd);
-	}
-
-	if (ret == SUCCESS) {
-	    ret = hnd->read_func(obj, &retval TSRMLS_CC);
-	    if (ret == SUCCESS) {
-	        /* ensure we're creating a temporary variable */
-	        Z_SET_REFCOUNT_P(retval, 0);
-	    } else {
-	        retval = EG(uninitialized_zval_ptr);
-	    }
-	} else {
-	    zend_object_handlers * std_hnd = zend_get_std_object_handlers();
-	    retval = std_hnd->read_property(object, member, type, key TSRMLS_CC);
-	}
-
-	if (member == &tmp_member) {
-	    zval_dtor(member);
-	}
-	return(retval);
-}
-/* }}} */
-
-/* {{{ php_ev_write_property */
-void php_ev_write_property(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC)
-{
-	zval				tmp_member;
-	php_ev_object		*obj;
-	ev_prop_handler		*hnd;
-	int					ret;
-
-	if (member->type != IS_STRING) {
-	    tmp_member = *member;
-	    zval_copy_ctor(&tmp_member);
-	    convert_to_string(&tmp_member);
-	    member = &tmp_member;
-	}
-
-	ret = FAILURE;
-	obj = (php_ev_object *)zend_objects_get_address(object TSRMLS_CC);
-
-	if (obj->prop_handler != NULL) {
-	    ret = zend_hash_find((HashTable *)obj->prop_handler, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, (void **) &hnd);
-	}
-	if (ret == SUCCESS) {
-	    hnd->write_func(obj, value TSRMLS_CC);
-	    if (! PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) == 0) {
-	        Z_ADDREF_P(value);
-	        zval_ptr_dtor(&value);
-	    }
-	} else {
-	    zend_object_handlers * std_hnd = zend_get_std_object_handlers();
-	    std_hnd->write_property(object, member, value, key TSRMLS_CC);
-	}
-
-	if (member == &tmp_member) {
-	    zval_dtor(member);
-	}
-}
-/* }}} */
-
-/* {{{ php_ev_has_property */
-static int php_ev_has_property(zval *object, zval *member, int has_set_exists, const zend_literal *key TSRMLS_DC)
-{
-	php_ev_object *obj = (php_ev_object *)zend_objects_get_address(object TSRMLS_CC);
-	ev_prop_handler p;
-	int ret = 0;
-
-	if (zend_hash_find(obj->prop_handler, Z_STRVAL_P(member), Z_STRLEN_P(member) + 1, (void **)&p) == SUCCESS) {
-	    switch (has_set_exists) {
-	        case 2:
-	            ret = 1;
-	            break;
-	        case 1: {
-	                	zval *value = php_ev_read_property(object, member, BP_VAR_IS, key TSRMLS_CC);
-	                	if (value != EG(uninitialized_zval_ptr)) {
-	                	    convert_to_boolean(value);
-	                	    ret = Z_BVAL_P(value)? 1:0;
-	                	    /* refcount is 0 */
-	                	    Z_ADDREF_P(value);
-	                	    zval_ptr_dtor(&value);
-	                	}
-	                	break;
-	                }
-	        case 0:{
-	                   zval *value = php_ev_read_property(object, member, BP_VAR_IS, key TSRMLS_CC);
-	                   if (value != EG(uninitialized_zval_ptr)) {
-	                	   ret = Z_TYPE_P(value) != IS_NULL? 1:0;
-	                	   /* refcount is 0 */
-	                	   Z_ADDREF_P(value);
-	                	   zval_ptr_dtor(&value);
-	                   }
-	                   break;
-	               }
-	        default:
-	               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid value for has_set_exists");
-	    }
-	} else {
-	    zend_object_handlers *std_hnd = zend_get_std_object_handlers();
-	    ret = std_hnd->has_property(object, member, has_set_exists, key TSRMLS_CC);
-	}
-	return ret;
-} /* }}} */
-
-/* {{{ php_ev_object_get_debug_info */
-#if PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 3
-static HashTable *php_ev_object_get_debug_info(zval *object, int *is_temp TSRMLS_DC)
-{
-	php_ev_object *obj = (php_ev_object *)zend_objects_get_address(object TSRMLS_CC); 
-	HashTable *retval, *props = obj->prop_handler;
-	HashPosition pos;
-	ev_prop_handler *entry;
-
-	ALLOC_HASHTABLE(retval);
-	ZEND_INIT_SYMTABLE_EX(retval, zend_hash_num_elements(props) + 1, 0);
-
-	zend_hash_internal_pointer_reset_ex(props, &pos);
-	while (zend_hash_get_current_data_ex(props, (void **)&entry, &pos) == SUCCESS) {
-	    zval member;
-	    zval *value;
-	    INIT_ZVAL(member);
-	    ZVAL_STRINGL(&member, entry->name, entry->name_len, 0);
-	    value = php_ev_read_property(object, &member, BP_VAR_IS, 0 TSRMLS_CC);
-	    if (value != EG(uninitialized_zval_ptr)) {
-	        Z_ADDREF_P(value);
-	        zend_hash_add(retval, entry->name, entry->name_len + 1, &value, sizeof(zval *), NULL);
-	    }       
-	    zend_hash_move_forward_ex(props, &pos);
-	}               
-
-	*is_temp = 1;   
-	return retval;
-}               
-#endif    
-/* }}} */
-
-
-/* {{{ php_ev_object_free_storage 
- * Common Ev object cleaner */
-static void php_ev_object_free_storage(void *object TSRMLS_DC)
-{
-	php_ev_object *intern = (php_ev_object *) object;
-
-	zend_object_std_dtor(&intern->zo TSRMLS_CC);
-
-	if (intern->ptr) {
-		efree(intern->ptr);
-	}
-
-	efree(intern);
-}
-/* }}} */
-
-/* {{{ php_ev_loop_free_storage*/
-static void php_ev_loop_free_storage(void *object TSRMLS_DC)
-{
-	php_printf("php_ev_loop_free_storage\n");
-	php_ev_object *obj_ptr = (php_ev_object *) object;
-
-	PHP_EV_ASSERT(obj_ptr->ptr);
-	php_ev_object_loop *ptr = (php_ev_object_loop *) obj_ptr->ptr;
-
-	if (ptr->fci && ptr->fcc) {
-		PHP_EV_FREE_FCALL_INFO(ptr->fci, ptr->fcc);
-	}
-
-	if (ptr->loop) {
-		if (ev_is_default_loop(ptr->loop)) {
-			zval **default_loop_ptr_ptr = &MyG(default_loop);
-			if (*default_loop_ptr_ptr) {
-				zval_ptr_dtor(default_loop_ptr_ptr);
-				default_loop_ptr_ptr = NULL;
-			}
-		}
-		ev_loop_destroy(ptr->loop);
-		ptr->loop = NULL;
-	}
-
-	if (ptr->data) {
-		zval_ptr_dtor(&ptr->data);
-		ptr->data = NULL;
-	}
-
-	php_ev_object_free_storage(object TSRMLS_CC);
-}
-/* }}} */
-
-/* {{{ php_ev_watcher_free_storage() 
- * There must *not* be EvWatcher instances created by user.
- * This is a helper for derived watcher class objects. */
-static void php_ev_watcher_free_storage(ev_watcher *ptr TSRMLS_DC)
-{
-	php_printf("php_ev_watcher_free_storage\n");
-	zval *data, *self;
-
-	php_ev_stop_watcher(ptr TSRMLS_CC);
-
-	PHP_EV_FREE_FCALL_INFO(php_ev_watcher_fci(ptr), php_ev_watcher_fcc(ptr));
-	
-	data = php_ev_watcher_data(ptr);
-	self = php_ev_watcher_self(ptr);
-
-	if (data) {
-		zval_ptr_dtor(&data);
-	}
-	zval_ptr_dtor(&self);
-}
-/* }}} */
-
-/* {{{ php_ev_io_free_storage() */
-static void php_ev_io_free_storage(void *object TSRMLS_DC)
-{
-	php_printf("php_ev_io_free_storage\n");
-	php_ev_object *obj_ptr = (php_ev_object *) object;
-
-	PHP_EV_ASSERT(obj_ptr->ptr);
-	ev_io *ptr = (ev_io *)obj_ptr->ptr;
-
-	/* Free base class members */
-	php_ev_watcher_free_storage((ev_watcher *)ptr TSRMLS_CC);
-
-	/* Free common Ev object members and the object itself */
-	php_ev_object_free_storage(object TSRMLS_CC);
-}
-/* }}} */
-
-/* {{{ php_ev_register_object 
- * Is called AFTER php_ev_object_new() */
-zend_object_value php_ev_register_object(zend_class_entry *ce, php_ev_object *intern TSRMLS_DC)
-{
-	zend_object_value                  retval;
-	zend_objects_free_object_storage_t func_free_storage;
-
-	if (instanceof_function(ce, ev_loop_class_entry_ptr TSRMLS_CC)) {
-		/* EvLoop */
-	 	func_free_storage = php_ev_loop_free_storage;
-	} else if (instanceof_function(ce, ev_io_class_entry_ptr TSRMLS_CC)) {
-		/* EvIo */
-	 	func_free_storage = php_ev_io_free_storage;
-	} else {
-	 	func_free_storage = php_ev_object_free_storage;
-	}
-
-	retval.handle = zend_objects_store_put(intern,
-			(zend_objects_store_dtor_t)zend_objects_destroy_object,
-			(zend_objects_free_object_storage_t)func_free_storage,
-			NULL TSRMLS_CC);
-	retval.handlers = &ev_object_handlers;
-
-	return retval;
-}
-/* }}} */
-
-/* {{{ php_ev_object_new
- * Custom Ev object. php_ev_register_object() must be called AFTER */
-php_ev_object *php_ev_object_new(zend_class_entry *ce TSRMLS_DC)
-{
-	php_ev_object    *intern;
-	zend_class_entry *ce_parent = ce;
-
-	intern               = ecalloc(1, sizeof(php_ev_object));
-	intern->ptr          = NULL;
-	intern->prop_handler = NULL;
-
-	while (ce_parent) {
-	    if (ce_parent == ev_watcher_class_entry_ptr
-	    		|| ce_parent == ev_loop_class_entry_ptr) {
-	    	break;