summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEmiel Bruijntjes <emiel.bruijntjes@copernica.com>2013-08-30 07:47:55 -0700
committerEmiel Bruijntjes <emiel.bruijntjes@copernica.com>2013-08-30 07:47:55 -0700
commitc2343400688366e567f67e89a50d573786f98bec (patch)
treeca130b093bb72748f3c3f53e25968320ed828f7c /src
parent49faa66adb7870d9e20596d2ae7c41c9638045e3 (diff)
Further work in progress (that breaks everything)
Diffstat (limited to 'src')
-rw-r--r--src/extension.cpp176
-rw-r--r--src/functions.cpp54
-rw-r--r--src/functions.h85
-rw-r--r--src/hiddenpointer.h159
-rw-r--r--src/includes.h4
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"