Improved PHP extension loading mechanism with support for module dependencies and conflicts.

This commit is contained in:
Dmitry Stogov 2005-06-17 09:36:26 +00:00
parent 61b2fcc3ce
commit c0c7a9f010
5 changed files with 149 additions and 23 deletions

2
NEWS
View File

@ -1,6 +1,8 @@
PHP NEWS
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
?? Jun 2005, PHP 5.1 Beta 2
- Improved PHP extension loading mechanism with support for module dependencies
and conflicts. (Jani, Dmitry)
- Allowed return by reference from internal functions. (Marcus, Andi, Dmitry)
- Rewrote strtotime() with support for timezones and tons of new formats.
(Derick)

View File

@ -1212,6 +1212,94 @@ ZEND_API int add_property_zval_ex(zval *arg, char *key, uint key_len, zval *valu
return SUCCESS;
}
ZEND_API int zend_startup_module(zend_module_entry *module TSRMLS_DC)
{
int name_len;
char *lcname;
if (module->module_started) {
return SUCCESS;
}
module->module_started = 1;
/* Check module dependencies */
if (module->deps) {
zend_module_dep *dep = module->deps;
while (dep->name) {
if (dep->type == MODULE_DEP_REQUIRED) {
zend_module_entry *req_mod;
name_len = strlen(dep->name);
lcname = zend_str_tolower_dup(dep->name, name_len);
if (zend_hash_find(&module_registry, lcname, name_len+1, (void**)&req_mod) == FAILURE ||
!req_mod->module_started) {
efree(lcname);
/* TODO: Check version relationship */
zend_error(E_CORE_WARNING, "Cannot load module '%s' because required module '%s' is not loaded", module->name, req_mod->name);
module->module_started = 0;
return FAILURE;
}
efree(lcname);
}
++dep;
}
}
if (module->module_startup_func) {
EG(current_module) = module;
if (module->module_startup_func(module->type, module->module_number TSRMLS_CC)==FAILURE) {
zend_error(E_CORE_ERROR,"Unable to start %s module", module->name);
EG(current_module) = NULL;
return FAILURE;
}
EG(current_module) = NULL;
}
return SUCCESS;
}
static void zend_sort_modules(void *base, size_t count, size_t siz, compare_func_t compare TSRMLS_DC)
{
Bucket **b1 = base;
Bucket **b2;
Bucket **end = b1 + count;
Bucket *tmp;
zend_module_entry *m, *r;
while (b1 < end) {
try_again:
m = (zend_module_entry*)(*b1)->pData;
if (!m->module_started && m->deps) {
zend_module_dep *dep = m->deps;
while (dep->name) {
if (dep->type == MODULE_DEP_REQUIRED || dep->type == MODULE_DEP_OPTIONAL) {
b2 = b1 + 1;
while (b2 < end) {
r = (zend_module_entry*)(*b2)->pData;
if (strcasecmp(dep->name, r->name) == 0) {
tmp = *b1;
*b1 = *b2;
*b2 = tmp;
goto try_again;
}
b2++;
}
}
dep++;
}
}
b1++;
}
}
ZEND_API int zend_startup_modules(TSRMLS_D)
{
zend_hash_sort(&module_registry, zend_sort_modules, NULL, 0 TSRMLS_CC);
zend_hash_apply(&module_registry, (apply_func_t)zend_startup_module TSRMLS_CC);
return SUCCESS;
}
ZEND_API int zend_register_module_ex(zend_module_entry *module TSRMLS_DC)
{
int name_len;
@ -1225,6 +1313,28 @@ ZEND_API int zend_register_module_ex(zend_module_entry *module TSRMLS_DC)
#if 0
zend_printf("%s: Registering module %d\n", module->name, module->module_number);
#endif
/* Check module dependencies */
if (module->deps) {
zend_module_dep *dep = module->deps;
while (dep->name) {
if (dep->type == MODULE_DEP_CONFLICTS) {
name_len = strlen(dep->name);
lcname = zend_str_tolower_dup(dep->name, name_len);
if (zend_hash_exists(&module_registry, lcname, name_len+1)) {
efree(lcname);
/* TODO: Check version relationship */
zend_error(E_CORE_WARNING, "Cannot load module '%s' because conflicting module '%s' is already loaded", module->name, dep->name);
return FAILURE;
}
efree(lcname);
}
++dep;
}
}
name_len = strlen(module->name);
lcname = zend_str_tolower_dup(module->name, name_len);
@ -1241,25 +1351,11 @@ ZEND_API int zend_register_module_ex(zend_module_entry *module TSRMLS_DC)
return FAILURE;
}
if (!module->module_started && module->module_startup_func) {
EG(current_module) = module;
if (module->module_startup_func(module->type, module->module_number TSRMLS_CC)==FAILURE) {
zend_error(E_CORE_ERROR,"Unable to start %s module", module->name);
EG(current_module) = NULL;
return FAILURE;
}
EG(current_module) = NULL;
}
module->module_started=1;
return SUCCESS;
}
ZEND_API int zend_startup_module(zend_module_entry *module)
ZEND_API int zend_register_internal_module(zend_module_entry *module TSRMLS_DC)
{
TSRMLS_FETCH();
module->module_number = zend_next_free_module();
module->type = MODULE_PERSISTENT;
return zend_register_module_ex(module TSRMLS_CC);
@ -1510,7 +1606,11 @@ ZEND_API int zend_register_module(zend_module_entry *module)
{
TSRMLS_FETCH();
return zend_register_module_ex(module TSRMLS_CC);
if (zend_register_module_ex(module TSRMLS_CC) == SUCCESS &&
zend_startup_module(module TSRMLS_CC) == SUCCESS) {
return SUCCESS;
}
return FAILURE;
}

View File

@ -173,7 +173,10 @@ ZEND_API int zend_parse_method_parameters_ex(int flags, int num_args TSRMLS_DC,
ZEND_API int zend_register_functions(zend_class_entry *scope, zend_function_entry *functions, HashTable *function_table, int type TSRMLS_DC);
ZEND_API void zend_unregister_functions(zend_function_entry *functions, int count, HashTable *function_table TSRMLS_DC);
ZEND_API int zend_register_module(zend_module_entry *module_entry);
ZEND_API int zend_register_internal_module(zend_module_entry *module_entry TSRMLS_DC);
ZEND_API int zend_register_module_ex(zend_module_entry *module TSRMLS_DC);
ZEND_API int zend_startup_module(zend_module_entry *module TSRMLS_DC);
ZEND_API int zend_startup_modules(TSRMLS_D);
ZEND_API void zend_check_magic_method_implementation(zend_class_entry *ce, zend_function *fptr, int error_type TSRMLS_DC);
ZEND_API zend_class_entry *zend_register_internal_class(zend_class_entry *class_entry TSRMLS_DC);
@ -228,8 +231,6 @@ ZEND_API zend_class_entry *zend_get_class_entry(zval *zobject TSRMLS_DC);
#define DLEXPORT
#endif
ZEND_API int zend_startup_module(zend_module_entry *module);
#define array_init(arg) _array_init((arg) ZEND_FILE_LINE_CC)
#define object_init(arg) _object_init((arg) ZEND_FILE_LINE_CC TSRMLS_CC)
#define object_init_ex(arg, ce) _object_init_ex((arg), (ce) ZEND_FILE_LINE_CC TSRMLS_CC)

View File

@ -27,7 +27,7 @@
/* The first number is the engine version and the rest is the date.
* This way engine 2 API no. is always greater than engine 1 API no..
*/
#define ZEND_EXTENSION_API_NO 220050615
#define ZEND_EXTENSION_API_NO 220050617
typedef struct _zend_extension_version_info {
int zend_extension_api_no;

View File

@ -38,15 +38,18 @@ extern struct _zend_arg_info third_arg_force_ref[4];
extern struct _zend_arg_info fourth_arg_force_ref[5];
extern struct _zend_arg_info all_args_by_ref[1];
#define ZEND_MODULE_API_NO 20050615
#define ZEND_MODULE_API_NO 20050617
#ifdef ZTS
#define USING_ZTS 1
#else
#define USING_ZTS 0
#endif
#define STANDARD_MODULE_HEADER sizeof(zend_module_entry), ZEND_MODULE_API_NO, ZEND_DEBUG, USING_ZTS, NULL
#define ZE2_STANDARD_MODULE_HEADER sizeof(zend_module_entry), ZEND_MODULE_API_NO, ZEND_DEBUG, USING_ZTS, ini_entries
#define STANDARD_MODULE_HEADER_EX sizeof(zend_module_entry), ZEND_MODULE_API_NO, ZEND_DEBUG, USING_ZTS
#define STANDARD_MODULE_HEADER \
STANDARD_MODULE_HEADER_EX, NULL, NULL
#define ZE2_STANDARD_MODULE_HEADER \
STANDARD_MODULE_HEADER_EX, ini_entries, NULL
#define STANDARD_MODULE_PROPERTIES_EX 0, 0, 0, NULL, 0
@ -60,13 +63,15 @@ extern struct _zend_arg_info all_args_by_ref[1];
struct _zend_ini_entry;
typedef struct _zend_module_entry zend_module_entry;
typedef struct _zend_module_dep zend_module_dep;
struct _zend_module_entry {
unsigned short size;
unsigned short size;
unsigned int zend_api;
unsigned char zend_debug;
unsigned char zts;
struct _zend_ini_entry *ini_entry;
struct _zend_module_dep *deps;
char *name;
struct _zend_function_entry *functions;
int (*module_startup_func)(INIT_FUNC_ARGS);
@ -83,6 +88,24 @@ struct _zend_module_entry {
int module_number;
};
#define MODULE_DEP_REQUIRED 1
#define MODULE_DEP_CONFLICTS 2
#define MODULE_DEP_OPTIONAL 3
#define ZEND_MOD_REQUIRED_EX(name, rel, ver) { name, rel, ver, MODULE_DEP_REQUIRED },
#define ZEND_MOD_CONFLICTS_EX(name, rel, ver) { name, rel, ver, MODULE_DEP_CONFLICTS },
#define ZEND_MOD_OPTIONAL_EX(name, rel, ver) { name, rel, ver, MODULE_DEP_OPTIONAL },
#define ZEND_MOD_REQUIRED(name) ZEND_MOD_REQUIRED_EX(name, NULL, NULL)
#define ZEND_MOD_CONFLICTS(name) ZEND_MOD_CONFLICTS_EX(name, NULL, NULL)
#define ZEND_MOD_OPTIONAL(name) ZEND_MOD_OPTIONAL_EX(name, NULL, NULL)
struct _zend_module_dep {
char *name; /* module name */
char *rel; /* version relationship: NULL (exists), lt|le|eq|ge|gt (to given version) */
char *version; /* version */
unsigned char type; /* dependency type */
};
extern ZEND_API HashTable module_registry;