diff options
author | Emiel Bruijntjes <emiel.bruijntjes@copernica.com> | 2013-08-30 07:47:55 -0700 |
---|---|---|
committer | Emiel Bruijntjes <emiel.bruijntjes@copernica.com> | 2013-08-30 07:47:55 -0700 |
commit | c2343400688366e567f67e89a50d573786f98bec (patch) | |
tree | ca130b093bb72748f3c3f53e25968320ed828f7c /src | |
parent | 49faa66adb7870d9e20596d2ae7c41c9638045e3 (diff) |
Further work in progress (that breaks everything)
Diffstat (limited to 'src')
-rw-r--r-- | src/extension.cpp | 176 | ||||
-rw-r--r-- | src/functions.cpp | 54 | ||||
-rw-r--r-- | src/functions.h | 85 | ||||
-rw-r--r-- | src/hiddenpointer.h | 159 | ||||
-rw-r--r-- | src/includes.h | 4 |
5 files changed, 327 insertions, 151 deletions
diff --git a/src/extension.cpp b/src/extension.cpp index c995f0b..ee22794 100644 --- a/src/extension.cpp +++ b/src/extension.cpp @@ -12,35 +12,79 @@ namespace PhpCpp { /** - * Pointer to the one and only extension - * @var Extension + * If this extension is compiled for a PHP version with multi + * threading support, we need an additional header file */ -static Extension *extension; +#ifdef ZTS +#include "TSRM.h" +#endif /** - * Constructor - * @param name Name of the extension - * @param version Version number + * 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 */ -Extension::Extension(const char *name, const char *version, const std::initializer_list<Function> &functions) : _name(name), _version(version) -{ - // allocate functions - _functions = new Functions(functions); - - // store pointer to the one and only extension - extension = this; -} +ZEND_BEGIN_MODULE_GLOBALS(phpcpp) + Request *request; +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 REQUEST_G(v) TSRMG(phpcpp_globals_id, zend_phpcpp_globals *, v) +#else +#define REQUEST_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) + +/** + * Function that must be defined to initialize the "globals" + * We do not have to initialize anything, but PHP needs to call this + * method (crazy) + * @param globals + */ +static void php_phpcpp_init_globals(zend_phpcpp_globals *globals) {} + +/** + * The extension is a sort of singleton, so we keep one pointer to it here + * @var Extension + */ +static Extension *extension = nullptr; + /** - * Destructor + * Helper method to get back the current extension object + * @return Extension */ -Extension::~Extension() +static Extension *get_extension() { - // deallocate functions - delete _functions; - - // deallocate entry - if (_entry) delete _entry; + // retrieve the extension or module name (because PHP of course does + // not pass such extremely useful information as they've no clue how + // to make a decent API + zend_module_entry *module = EG(current_module); + + // the pointer to the extension is hidden in front of the name + return HiddenPointer<Extension>(module->name); } /** @@ -51,8 +95,14 @@ Extension::~Extension() */ static int extension_startup(INIT_FUNC_ARGS) { + + + + // initialize and allocate the "global" variables +// ZEND_INIT_MODULE_GLOBALS(hello, php_phpcpp_init_globals, NULL); + // initialize the extension - return BOOL2SUCCESS(extension->initialize()); + return BOOL2SUCCESS(get_extension()->initialize()); } /** @@ -63,10 +113,8 @@ static int extension_startup(INIT_FUNC_ARGS) */ static int extension_shutdown(SHUTDOWN_FUNC_ARGS) { - std::cout << "extension_shutdown" << std::endl; - // finalize the extension - return BOOL2SUCCESS(extension->finalize()); + return BOOL2SUCCESS(get_extension()->finalize()); } /** @@ -78,7 +126,7 @@ static int extension_shutdown(SHUTDOWN_FUNC_ARGS) static int request_startup(INIT_FUNC_ARGS) { // create the request - return BOOL2SUCCESS(extension->startRequest()); + return BOOL2SUCCESS(get_extension()->startRequest()); } /** @@ -90,49 +138,49 @@ static int request_startup(INIT_FUNC_ARGS) static int request_shutdown(INIT_FUNC_ARGS) { // end the request - return BOOL2SUCCESS(extension->endRequest()); + return BOOL2SUCCESS(get_extension()->endRequest()); } + /** - * Retrieve a pointer to the entry - * @return zend_module_entry + * Constructor + * @param name Name of the extension + * @param version Version number */ -zend_module_entry *Extension::entry() +Extension::Extension(const char *name, const char *version, const Functions &functions) { - // already initialized? - if (_entry) return _entry; - - // allocate now - _entry = new zend_module_entry; - - // assign all members - _entry->size = sizeof(zend_module_entry); // size of the data - _entry->zend_api = ZEND_MODULE_API_NO; // api number - _entry->zend_debug = ZEND_DEBUG; // debug mode enabled? - _entry->zts = USING_ZTS; // is thread safety enabled? - _entry->ini_entry = NULL; // the php.ini record - _entry->deps = NULL; // dependencies on other modules - _entry->name = _name; // extension name - _entry->functions = _functions->internal(); // functions supported by this module - _entry->module_startup_func = extension_startup; // startup function for the whole extension - _entry->module_shutdown_func = extension_shutdown; // shutdown function for the whole extension - _entry->request_startup_func = request_startup; // startup function per request - _entry->request_shutdown_func = request_shutdown; // shutdown function per request - _entry->info_func = NULL; // information for retrieving info - _entry->version = _version; // version string - _entry->globals_size = 0; // size of the global variables - _entry->globals_ptr = NULL; // pointer to the globals - _entry->globals_ctor = NULL; // constructor for global variables - _entry->globals_dtor = NULL; // destructor for global variables - _entry->post_deactivate_func = NULL; // unknown function - _entry->module_started = 0; // module is not yet started - _entry->type = 0; // temporary or persistent module, will be filled by Zend engine - _entry->handle = NULL; // dlopen() handle, will be filled by Zend engine - _entry->module_number = 0; // module number will be filled in by Zend engine - _entry->build_id = ZEND_MODULE_BUILD_ID; // check if extension and zend engine are compatible - - // done - return _entry; + // assign all members (apart from the globals) + _entry.size = sizeof(zend_module_entry); // size of the data + _entry.zend_api = ZEND_MODULE_API_NO; // api number + _entry.zend_debug = ZEND_DEBUG; // debug mode enabled? + _entry.zts = USING_ZTS; // is thread safety enabled? + _entry.ini_entry = NULL; // the php.ini record + _entry.deps = NULL; // dependencies on other modules + _entry.name = HiddenPointer<Extension>(this, name); // extension name, with a hidden pointer to the extension object + _entry.functions = functions.internal(); // functions supported by this module + _entry.module_startup_func = extension_startup; // startup function for the whole extension + _entry.module_shutdown_func = extension_shutdown; // shutdown function for the whole extension + _entry.request_startup_func = request_startup; // startup function per request + _entry.request_shutdown_func = request_shutdown; // shutdown function per request + _entry.info_func = NULL; // information for retrieving info + _entry.version = version; // version string + _entry.globals_size = 0; // size of the global variables + _entry.globals_ptr = NULL; // pointer to the globals + _entry.globals_ctor = NULL; // constructor for global variables + _entry.globals_dtor = NULL; // destructor for global variables + _entry.post_deactivate_func = NULL; // unknown function + _entry.module_started = 0; // module is not yet started + _entry.type = 0; // temporary or persistent module, will be filled by Zend engine + _entry.handle = NULL; // dlopen() handle, will be filled by Zend engine + _entry.module_number = 0; // module number will be filled in by Zend engine + _entry.build_id = ZEND_MODULE_BUILD_ID; // check if extension and zend engine are compatible + + // things that only need to be initialized +#ifdef ZTS + _entry.globals_id_ptr = NULL; +#else + _entry.globals_ptr = NULL; +#endif } /** diff --git a/src/functions.cpp b/src/functions.cpp new file mode 100644 index 0000000..f9e0ffb --- /dev/null +++ b/src/functions.cpp @@ -0,0 +1,54 @@ +/** + * Functions.cpp + * + * Implementation for the functions class + * + * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com> + * @copyright 2013 Copernica BV + */ +#include "includes.h" + +/** + * Set up namespace + */ +namespace PhpCpp { + +/** + * Constructor + * @param functions The functions to parse + */ +Functions::Functions(const std::initializer_list<Function> &functions) : _functions(functions) +{ + // allocate the function entries + _entries = new zend_function_entry[functions.size() + 1]; + + // keep iterator counter + int i = 0; + + // loop through the functions + for (auto it = begin(functions); it != functions.end(); it++) + { + // let the callable fill the array + it->internal()->fill(&_entries[i++]); + } + + // last entry should be set to all zeros + zend_function_entry *last = &_entries[i]; + + // all should be set to zero + memset(last, 0, sizeof(zend_function_entry)); +} + +/** + * Destructor + */ +Functions::~Functions() +{ + delete[] _entries; +} + +/** + * End of namespace + */ +} + diff --git a/src/functions.h b/src/functions.h deleted file mode 100644 index bc08b8a..0000000 --- a/src/functions.h +++ /dev/null @@ -1,85 +0,0 @@ -/** - * Functions.h - * - * Internal helper class that parses the functions initializer list, and - * that converts it into a zend_function_entry array. - * - * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com> - * @copyright 2013 Copernica BV - */ - -/** - * Set up namespace - */ -namespace PhpCpp { - -/** - * Class definition - */ -class Functions -{ -public: - /** - * Constructor - * @param functions The functions to parse - */ - Functions(const std::initializer_list<Function> &functions) : _functions(functions) - { - // allocate the function entries - _entries = new zend_function_entry[functions.size() + 1]; - - // keep iterator counter - int i = 0; - - // loop through the functions - for (auto it = begin(functions); it != functions.end(); it++) - { - // let the callable fill the array - it->internal()->fill(&_entries[i++]); - } - - // last entry should be set to all zeros - zend_function_entry *last = &_entries[i]; - - // all should be set to zero - memset(last, 0, sizeof(zend_function_entry)); - } - - /** - * Destructor - */ - virtual ~Functions() - { - delete[] _entries; - } - - /** - * Retrieve the internal data - * @return zend_function_entry* - */ - zend_function_entry *internal() - { - return _entries; - } - - -private: - /** - * The internal entries - * @var zend_function_entry* - */ - zend_function_entry *_entries; - - /** - * Vector of functions (we need this because the function objects must - * remain in memory) - * @var vector - */ - std::vector<Function> _functions; -}; - -/** - * End of namespace - */ -} - diff --git a/src/hiddenpointer.h b/src/hiddenpointer.h new file mode 100644 index 0000000..616dfee --- /dev/null +++ b/src/hiddenpointer.h @@ -0,0 +1,159 @@ +/** + * HiddenPointer.h + * + * Helper class that we use to hide a pointer in a string. We do this + * by creating a string buffer that is a littlebit bigger, and put + * the hidden pointer in front of the name + * + * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com> + * @copyright 2013 Copernica BV + */ + +/** + * Set up namespace + */ +namespace PhpCpp { + +/** + * Class definition + */ +template <typename Type> +class HiddenPointer +{ +public: + /** + * Constructor to hide the pointer in a buffer + * @param pointer The hidden pointer + * @param text The visible text + * @param size Optional text size + */ + HiddenPointer(Type *pointer, const char *text, int size=-1) + { + // calculate size + if (size < 0) size = strlen(text); + + // reserve enough room for the text and the pointer + _data.reserve(size + sizeof(Type *)); + + // store the pointer + _data.assign(std::string((const char *)&pointer, sizeof(Type *))); + + // append the text + _data.append(text, size); + + // store pointers + _pointer = pointer; + _text = _data.c_str() + sizeof(Type *); + } + + /** + * Constructor to retrieve the object given a buffer + * @param text The visible text + * @param size Size of the text + */ + HiddenPointer(const char *text, int size=-1) + { + // calculate size + if (size < 0) size = strlen(text); + + // the pointer is stored right in front of the name + _pointer = *((Type **)(text - sizeof(Type *))); + _text = text; + } + + /** + * Copy constructor + * @param that + */ + HiddenPointer(const HiddenPointer<Type> &that) : _pointer(that._pointer), _text(that._text), _data(that._data) + { + // if data is filled, the text is located inside the data + if (_data.size() > 0) _text = _data.c_str() + sizeof(Type *); + } + + /** + * Destructor + */ + virtual ~HiddenPointer() {} + + /** + * Assignment operator + * @param that + * @return HiddenPointer + */ + HiddenPointer<Type> operator=(const HiddenPointer &that) + { + // skip self assignment + if (&that == this) return *this; + + // copy members + _pointer = that._pointer; + _text = that._text; + _data = that._data; + + // if data is filled, the text is located inside the data + if (_data.size() > 0) _text = _data.c_str() + sizeof(Type *); + } + + /** + * Retrieve the pointer + * @return Type* + */ + Type *pointer() + { + return _pointer; + } + + /** + * Retrieve the text + * @return const char * + */ + const char *text() + { + return _text; + } + + /** + * Cast to the pointer + * @return Type* + */ + operator Type* () + { + return _pointer; + } + + /** + * Cast to text + * @return const char * + */ + operator const char * () + { + return _text; + } + +private: + /** + * The actual pointer + * @var Type* + */ + Type *_pointer; + + /** + * The original text + * @var text + */ + const char *_text; + + /** + * Optional data buffer + * @var string + */ + std::string _data; + +}; + +/** + * End of namespace + */ +} + diff --git a/src/includes.h b/src/includes.h index 58f14c2..28d8b51 100644 --- a/src/includes.h +++ b/src/includes.h @@ -38,6 +38,7 @@ #include "../include/member.h" #include "../include/arguments.h" #include "../include/function.h" +#include "../include/functions.h" #include "../include/extension.h" /** @@ -45,5 +46,4 @@ */ #include "callable.h" #include "arginfo.h" -#include "functions.h" - +#include "hiddenpointer.h" |