From a8f3d4c47b342ef1ce9c951239a1618a0912484c Mon Sep 17 00:00:00 2001 From: Emiel Bruijntjes Date: Sun, 12 Apr 2015 12:11:13 +0200 Subject: Php::dl() function now gets an extra "persistent" parameter to load extensions persistently --- Examples/DlUnrestricted/dlunrestricted.cpp | 5 +- include/call.h | 6 +-- zend/eval.cpp | 9 +++- zend/module.cpp | 30 ++++++++++++ zend/module.h | 78 +++++++++++++++++++++++++++++- 5 files changed, 120 insertions(+), 8 deletions(-) create mode 100644 zend/module.cpp diff --git a/Examples/DlUnrestricted/dlunrestricted.cpp b/Examples/DlUnrestricted/dlunrestricted.cpp index bdc7cae..a7ec7ed 100644 --- a/Examples/DlUnrestricted/dlunrestricted.cpp +++ b/Examples/DlUnrestricted/dlunrestricted.cpp @@ -29,8 +29,11 @@ Php::Value dl_unrestricted(Php::Parameters ¶ms) // get extension name std::string pathname = params[0]; + // should it be opened persistently? + bool persistent = params.size() > 1 ? params[1].boolValue() : false; + // load the extension - return Php::dl(pathname); + return Php::dl(pathname, persistent); } /** diff --git a/include/call.h b/include/call.h index 36574ce..094c7d2 100644 --- a/include/call.h +++ b/include/call.h @@ -27,9 +27,9 @@ extern PHPCPP_EXPORT bool define(const std::string &name, const Value &value extern PHPCPP_EXPORT bool defined(const char *constant); extern PHPCPP_EXPORT bool defined(const char *constant, size_t size); extern PHPCPP_EXPORT bool defined(const std::string &constant); -extern PHPCPP_EXPORT bool dl(const char *filename); -inline PHPCPP_EXPORT bool dl(const std::string &filename) { return dl(filename.c_str()); } -inline PHPCPP_EXPORT bool dl(const Value &filename) { return dl(filename.rawValue()); } +extern PHPCPP_EXPORT bool dl(const char *filename, bool persistent = false); +inline PHPCPP_EXPORT bool dl(const std::string &filename, bool persistent = false) { return dl(filename.c_str(), persistent); } +inline PHPCPP_EXPORT bool dl(const Value &filename, bool persistent = false) { return dl(filename.rawValue(), persistent); } extern PHPCPP_EXPORT Value eval(const char *phpCode); inline PHPCPP_EXPORT Value eval(const std::string &phpCode) { return eval(phpCode.c_str()); } extern PHPCPP_EXPORT Value include(const char *filename); diff --git a/zend/eval.cpp b/zend/eval.cpp index 7ab4957..6d043b1 100644 --- a/zend/eval.cpp +++ b/zend/eval.cpp @@ -93,12 +93,17 @@ Value require_once(const char *filename) /** * Implementation of the dl() function - activate a different PHP extension + * + * If you open an extension persistently, the static variables inside it are + * kept open for as long as apache runs. + * * @param filename + * @param persistent */ -bool dl(const char *filename) +bool dl(const char *filename, bool persistent) { // create the module - Module module(filename); + Module module(filename, persistent); // start the module return module.start(); diff --git a/zend/module.cpp b/zend/module.cpp new file mode 100644 index 0000000..46d03d8 --- /dev/null +++ b/zend/module.cpp @@ -0,0 +1,30 @@ +/** + * Module.cpp + * + * Module implementation file + * + * @author Emiel Bruijntjes + * @copyright 2015 Copernica BV + */ + +/** + * Dependencies + */ +#include "includes.h" + +/** + * Set up namespace + */ +namespace Php { + +/** + * The persistent handles + * @var Module::Persistent + */ +Module::Persistent Module::_persistent; + +/** + * End of namespace + */ +} + diff --git a/zend/module.h b/zend/module.h index 4fa6bce..40cd6f7 100644 --- a/zend/module.h +++ b/zend/module.h @@ -43,7 +43,7 @@ private: * @var zend_module_entry */ zend_module_entry *_entry = nullptr; - + #ifdef ZTS /** * When in thread safety mode, we also keep track of the TSRM_LS var @@ -52,12 +52,82 @@ private: void ***tsrm_ls; #endif + /** + * Internal helper class with persistent modules + */ + class Persistent + { + private: + /** + * The set of handles + * @var std::set + */ + std::set _handles; + + public: + /** + * Constructor + */ + Persistent() {} + + /** + * Destructor + */ + virtual ~Persistent() + { + // remove all handles + while (!_handles.empty()) + { + // get first handle + auto iter = _handles.begin(); + + // remove the handle + DL_UNLOAD(*iter); + + // remove from set + _handles.erase(iter); + } + } + + /** + * Check whether a handle is already persistently opened + * @param handle + * @return bool + */ + bool contains(void *handle) const + { + return _handles.find(handle) != _handles.end(); + } + + /** + * Add a library persistently + * @param module + */ + void add(const char *module) + { + // insert the handle + _handles.insert(DL_LOAD(module)); + } + }; + + /** + * All persistent modules + * @var Persistent + */ + static Persistent _persistent; + public: /** * Constructor + * + * A module can be loaded persistently. This means that the variables in + * the module will keep in scope for as long as Apache runs, even though + * the extension is not active in other page views + * * @param module Name of the module + * @param persistent Should it be loaded persistently */ - Module(const char *module) + Module(const char *module, bool persistent) { #ifdef ZTS // fetch multi-threading thing @@ -76,6 +146,10 @@ public: // handle should be valid if (!_handle) return; + // if we have to open it persistently, we open it for a second time so that + // the refcounter always stays 1 or higher + if (persistent && !_persistent.contains(_handle)) _persistent.add(module); + // we have to call the get_module() function Symbol get_module(_handle, "get_module"); -- cgit v1.2.3