diff options
author | Emiel Bruijntjes <emiel.bruijntjes@copernica.com> | 2013-09-11 08:00:28 -0700 |
---|---|---|
committer | Emiel Bruijntjes <emiel.bruijntjes@copernica.com> | 2013-09-11 08:00:28 -0700 |
commit | 68fd128d82819db1022137a45ca3224cee8ef029 (patch) | |
tree | 6f01d5456d830de9d24150ec56e5c1ee4d464faa | |
parent | f08f5850fa39c42974e12e42fa101ffe51eef594 (diff) |
The environment object that is passed to functions now always is the same environment object, added move operator= to Value class to make moving zvals faster, and added request startup and request closedown methods
-rw-r--r-- | include/extension.h | 40 | ||||
-rw-r--r-- | include/globals.h | 58 | ||||
-rw-r--r-- | include/value.h | 7 | ||||
-rw-r--r-- | src/extension.cpp | 57 | ||||
-rw-r--r-- | src/function.cpp | 5 | ||||
-rw-r--r-- | src/includes.h | 2 | ||||
-rw-r--r-- | src/value.cpp | 71 |
7 files changed, 193 insertions, 47 deletions
diff --git a/include/extension.h b/include/extension.h index b322533..ceeed78 100644 --- a/include/extension.h +++ b/include/extension.h @@ -29,6 +29,11 @@ struct _zend_module_entry; namespace Php { /** + * Optional callback types for starting and stopping the request + */ +typedef bool (*request_callback)(Environment &); + +/** * A couple of predefined native callback functions that can be registered. * These are functions that optional accept a Request and/or Parameters object, * and that either return void or a Value object. @@ -52,9 +57,10 @@ public: * Constructor that defines a number of functions right away * @param name Extension name * @param version Extension version string - * @param functions The functions that are defined + * @param callback Function that is called when request starts + * @param callback Function that is called when request ends */ - Extension(const char *name = NULL, const char *version = NULL); + Extension(const char *name = NULL, const char *version = NULL, request_callback start = NULL, request_callback stop = NULL); /** * No copy'ing and no moving @@ -109,6 +115,7 @@ public: */ virtual Environment *createEnvironment() { + // allocate the environment return new Environment(this); } @@ -121,6 +128,7 @@ public: */ virtual void deleteEnvironment(Environment *environment) { + // destruct the environment delete environment; } @@ -133,9 +141,13 @@ public: * * @return boolean */ - bool startRequest(Environment &environment) + virtual bool startRequest(Environment &environment) { - return true; + // ok if no callback was set + if (!_start) return true; + + // call the callback function + return _start(environment); } /** @@ -146,9 +158,13 @@ public: * * @return boolean */ - bool endRequest(Environment &environment) + virtual bool endRequest(Environment &environment) { - return true; + // ok if no callback is set + if (!_stop) return true; + + // call callback + return _stop(environment); } /** @@ -212,6 +228,18 @@ private: */ _zend_module_entry *_entry; + /** + * Callback that is called before each request + * @var request_callback + */ + request_callback _start; + + /** + * Callback that is called after each request + * @var request_callback + */ + request_callback _stop; + }; /** diff --git a/include/globals.h b/include/globals.h new file mode 100644 index 0000000..052bab8 --- /dev/null +++ b/include/globals.h @@ -0,0 +1,58 @@ +/** + * Globals.h + * + * Variables and structured required by the Zend engine to work + * with global variables + * + * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com> + * @copyright 2013 Copernica BV + */ + +/** + * Namespace + */ +namespace Php { + +/** + * The way how PHP C API deals with "global" variables is stupid. + * + * This is supposed to turn into a structure that is going to be + * instantiated for each parallel running request, and for which the + * PHP engine allocates a certain amount of memory, and a magic + * pointer that is passed and should be forwarded to every thinkable + * PHP function. + * + * We don't like this architecture. We have our own environment object + * that makes much more sense, and that we use. However, we need + * to assign this object somewhere, so that's what we do in this + * one and only global variable + */ +ZEND_BEGIN_MODULE_GLOBALS(phpcpp) + Php::Environment *environment; +ZEND_END_MODULE_GLOBALS(phpcpp) + +/** + * And now we're going to define a macro. This also is a ridiculous + * architecture from PHP to get access to a variable from the + * structure above. + */ +#ifdef ZTS +#define PHPCPP_G(v) TSRMG(phpcpp_globals_id, phpcpp_globals *, v) +#else +#define PHPCPP_G(v) (phpcpp_globals.v) +#endif + +/** + * We're almost there, we now need to declare an instance of the + * structure defined above (if building for a single thread) or some + * sort of impossible to understand magic pointer-to-a-pointer (for + * multi-threading builds). We make this a static variable because + * this already is bad enough. + */ +extern ZEND_DECLARE_MODULE_GLOBALS(phpcpp) + +/** + * End of namespace + */ +} + diff --git a/include/value.h b/include/value.h index e4af1b7..4854437 100644 --- a/include/value.h +++ b/include/value.h @@ -124,6 +124,13 @@ public: virtual Value &operator=(const Value &value); /** + * Move assignment + * @param value + * @return Value + */ + virtual Value &operator=(Value &&value); + + /** * Assignment operator * @param value * @return Value diff --git a/src/extension.cpp b/src/extension.cpp index 37082b2..b0d78f2 100644 --- a/src/extension.cpp +++ b/src/extension.cpp @@ -26,42 +26,13 @@ namespace Php { static Extension *extension = nullptr; /** - * The way how PHP C API deals with "global" variables is stupid. - * - * This is supposed to turn into a structure that is going to be - * instantiated for each parallel running request, and for which the - * PHP engine allocates a certain amount of memory, and a magic - * pointer that is passed and should be forwarded to every thinkable - * PHP function. - * - * We don't like this architecture. We have our own request object - * that makes much more sense, and that we use. However, we need - * to assign this object somewhere, so that's what we do in this - * one and only global variable - */ -ZEND_BEGIN_MODULE_GLOBALS(phpcpp) - Environment *environment; -ZEND_END_MODULE_GLOBALS(phpcpp) - -/** - * And now we're going to define a macro. This also is a ridiculous - * architecture from PHP to get access to a variable from the - * structure above. - */ -#ifdef ZTS -#define PHPCPP_G(v) TSRMG(phpcpp_globals_id, zend_phpcpp_globals *, v) -#else -#define PHPCPP_G(v) (phpcpp_globals.v) -#endif - -/** * We're almost there, we now need to declare an instance of the * structure defined above (if building for a single thread) or some * sort of impossible to understand magic pointer-to-a-pointer (for * multi-threading builds). We make this a static variable because * this already is bad enough. */ -static ZEND_DECLARE_MODULE_GLOBALS(phpcpp) +ZEND_DECLARE_MODULE_GLOBALS(phpcpp) /** * Function that must be defined to initialize the "globals" @@ -71,8 +42,6 @@ static ZEND_DECLARE_MODULE_GLOBALS(phpcpp) */ static void init_globals(zend_phpcpp_globals *globals) {} - - /** * Function that is called when the extension initializes * @param type Module type @@ -109,10 +78,16 @@ static int extension_shutdown(SHUTDOWN_FUNC_ARGS) static int request_startup(INIT_FUNC_ARGS) { // create the environment - PHPCPP_G(environment) = extension->createEnvironment(); + Environment *environment = extension->createEnvironment(); + + // store in global structure + PHPCPP_G(environment) = environment; + + // initialize the environment + environment->initialize(); // start the request - return BOOL2SUCCESS(extension->startRequest(*(PHPCPP_G(environment)))); + return BOOL2SUCCESS(environment->initialize() && extension->startRequest(*environment)); } /** @@ -123,11 +98,17 @@ static int request_startup(INIT_FUNC_ARGS) */ static int request_shutdown(INIT_FUNC_ARGS) { + // retrieve the environment + Environment *environment = PHPCPP_G(environment); + // end the request - bool success = extension->endRequest(*(PHPCPP_G(environment))); + bool success = extension->endRequest(*environment) && environment->finalize(); // deallocate the environment - extension->deleteEnvironment(PHPCPP_G(environment)); + extension->deleteEnvironment(environment); + + // reset global variable + PHPCPP_G(environment) = NULL; // done return BOOL2SUCCESS(success); @@ -137,8 +118,10 @@ static int request_shutdown(INIT_FUNC_ARGS) * Constructor * @param name Name of the extension * @param version Version number + * @param start Request start callback + * @param stop Request stop callback */ -Extension::Extension(const char *name, const char *version) +Extension::Extension(const char *name, const char *version, request_callback start, request_callback stop) : _start(start), _stop(stop) { // store extension variable extension = this; diff --git a/src/function.cpp b/src/function.cpp index 10b47b9..2afc1be 100644 --- a/src/function.cpp +++ b/src/function.cpp @@ -37,11 +37,8 @@ void invoke_function(INTERNAL_FUNCTION_PARAMETERS) // construct parameters Parameters params(ZEND_NUM_ARGS()); - // @todo get the appropriate request (or environment) - Environment environment(NULL); - // get the result - result = function->invoke(environment, params); + result = function->invoke(*PHPCPP_G(environment), params); } /** diff --git a/src/includes.h b/src/includes.h index cfcff2a..1a60b67 100644 --- a/src/includes.h +++ b/src/includes.h @@ -45,8 +45,10 @@ #include "../include/parameters.h" #include "../include/function.h" #include "../include/extension.h" +#include "../include/globals.h" /** * Interface files for internal use only */ #include "nativefunction.h" + diff --git a/src/value.cpp b/src/value.cpp index 7f43724..4cdac58 100644 --- a/src/value.cpp +++ b/src/value.cpp @@ -244,6 +244,77 @@ Value &Value::operator=(const Value &value) } /** + * Move operator + * @param value + * @return Value + */ +Value &Value::operator=(Value &&value) +{ + // skip self assignment + if (this == &value) return *this; + + // is the object a reference? + if (Z_ISREF_P(_val)) + { + // @todo difference if the other object is a reference or not? + + + // the current object is a reference, this means that we should + // keep the zval object, and copy the other value into it, get + // the current refcount + int refcount = Z_REFCOUNT_P(_val); + + // clean up the current zval (but keep the zval structure) + zval_dtor(_val); + + // make the copy + *_val = *value._val; + + // restore reference and refcount setting + Z_SET_ISREF_TO_P(_val, true); + Z_SET_REFCOUNT_P(_val, refcount); + + // how many references did the old variable have? + if (Z_ISREF_P(value._val) > 1) + { + // the other object already had multiple references, this + // implies that many other PHP variables are also referring + // to it, and we still need to store its contents, with one + // reference less + Z_DELREF_P(value._val); + + // and we need to run the copy constructor on the current + // value, because we're making a deep copy + zval_copy_ctor(_val); + } + else + { + // the last and only reference to the other object was + // removed, we no longer need it + FREE_ZVAL(value._val); + + // the other object is no longer valid + value._val = nullptr; + } + } + else + { + // destruct the zval (this function will decrement the reference counter, + // and only destruct if there are no other references left) + zval_ptr_dtor(&_val); + + // just copy the zval completely + _val = value._val; + + // the other object is no longer valid + value._val = nullptr; + } + + // done + return *this; +} + +/** * Assignment operator * @param value * @return Value |