diff options
Diffstat (limited to 'ext/rpc/rpc.c')
-rw-r--r-- | ext/rpc/rpc.c | 284 |
1 files changed, 169 insertions, 115 deletions
diff --git a/ext/rpc/rpc.c b/ext/rpc/rpc.c index a871f4284e..2652ff6ce3 100644 --- a/ext/rpc/rpc.c +++ b/ext/rpc/rpc.c @@ -12,8 +12,6 @@ ZEND_DECLARE_MODULE_GLOBALS(rpc) -static int rpc_global_startup(void); -static int rpc_global_shutdown(void); static void rpc_globals_ctor(zend_rpc_globals * TSRMLS_DC); static void rpc_instance_dtor(void *); static void rpc_class_dtor(void *); @@ -35,7 +33,6 @@ static int rpc_has_property(zval *, zval *, int TSRMLS_DC); static void rpc_unset_property(zval *, zval * TSRMLS_DC); static HashTable* rpc_get_properties(zval * TSRMLS_DC); static union _zend_function* rpc_get_method(zval *, char *, int TSRMLS_DC); -static int rpc_call(char *, INTERNAL_FUNCTION_PARAMETERS); static union _zend_function* rpc_get_constructor(zval * TSRMLS_DC); static int rpc_get_classname(zval *, char **, zend_uint *, int TSRMLS_DC); static int rpc_compare(zval *, zval * TSRMLS_DC); @@ -56,7 +53,7 @@ static zend_object_handlers rpc_handlers = { rpc_unset_property, rpc_get_properties, rpc_get_method, - rpc_call, + NULL, rpc_get_constructor, rpc_get_classname, rpc_compare @@ -89,8 +86,6 @@ static HashTable *handlers; static WormHashTable *instance; static WormHashTable *classes; -static unsigned long thread_count = 0; - #ifdef COMPILE_DL_RPC ZEND_GET_MODULE(rpc); #endif @@ -102,10 +97,13 @@ PHP_INI_BEGIN() PHP_INI_END() /* }}} */ -/* still not sure if MINIT is really only once per server and not once per thread - * so i keep the init stuff here here +static void rpc_globals_ctor(zend_rpc_globals *rpc_globals TSRMLS_DC) +{ +} + +/* {{{ ZEND_MINIT_FUNCTION */ -static int rpc_global_startup(void) +ZEND_MINIT_FUNCTION(rpc) { handlers = (HashTable *) pemalloc(sizeof(HashTable), TRUE); instance = (WormHashTable *) pemalloc(sizeof(WormHashTable), TRUE); @@ -114,7 +112,7 @@ static int rpc_global_startup(void) zend_hash_init(handlers, 0, NULL, NULL, TRUE); zend_worm_hash_init(instance, 0, NULL, rpc_instance_dtor, TRUE); zend_worm_hash_init(classes, 0, NULL, rpc_class_dtor, TRUE); - + FOREACH_HANDLER { HANDLER.rpc_handler_init(); @@ -130,39 +128,7 @@ static int rpc_global_startup(void) /* load all available rpc handler into a hash */ zend_hash_add(handlers, HANDLER.name, strlen(HANDLER.name) + 1, &(HANDLER.handlers), sizeof(rpc_object_handlers *), NULL); - } - return SUCCESS; -} - -/* same as above for shutdown */ -static int rpc_global_shutdown(void) -{ - zend_hash_destroy(handlers); - zend_worm_hash_destroy(instance); - zend_worm_hash_destroy(classes); - - pefree(handlers, TRUE); - pefree(instance, TRUE); - pefree(classes, TRUE); - - return SUCCESS; -} - -static void rpc_globals_ctor(zend_rpc_globals *rpc_globals TSRMLS_DC) -{ -} - -/* {{{ ZEND_MINIT_FUNCTION - */ -ZEND_MINIT_FUNCTION(rpc) -{ - /* GINIT */ - if (thread_count++ == 0) { - rpc_global_startup(); - } - - FOREACH_HANDLER { /* register classes and functions */ zend_register_internal_class(HANDLER.ce TSRMLS_CC); zend_register_functions(HANDLER.functions, NULL, MODULE_PERSISTENT TSRMLS_CC); @@ -179,10 +145,15 @@ ZEND_MINIT_FUNCTION(rpc) */ ZEND_MSHUTDOWN_FUNCTION(rpc) { - /* GSHUTDOWN */ - if (--thread_count == 0) { - rpc_global_shutdown(); - } + zend_worm_hash_destroy(instance); + zend_worm_hash_destroy(classes); + + /* destroy instances first ! */ + zend_hash_destroy(handlers); + + pefree(handlers, TRUE); + pefree(instance, TRUE); + pefree(classes, TRUE); UNREGISTER_INI_ENTRIES(); return SUCCESS; @@ -206,8 +177,12 @@ static void rpc_instance_dtor(void *pDest) rpc_internal **intern; intern = (rpc_internal **) pDest; + + (*(*intern)->handlers)->rpc_dtor(&((*intern)->data)); - /* TODO: destruct custom data */ + tsrm_mutex_free((*intern)->function_table.mx_reader); + tsrm_mutex_free((*intern)->function_table.mx_writer); + tsrm_mutex_free((*intern)->mx_handler); pefree(*intern, TRUE); } @@ -254,9 +229,13 @@ static zend_object_value rpc_create_object(zend_class_entry *class_type TSRMLS_D intern->clonecount = 1; intern->data = NULL; intern->pool_instances = 0; + intern->function_table.hash = intern->ce->function_table; + intern->function_table.reader = 0; + intern->function_table.mx_reader = tsrm_mutex_alloc(); + intern->function_table.mx_writer = tsrm_mutex_alloc(); intern->mx_handler = tsrm_mutex_alloc(); - if (zend_hash_find(handlers, class_type->name, class_type->name_length + 1, (void **) &(intern->handlers)) == FAILURE) { + if (zend_hash_find(handlers, class_type->name, class_type->name_length + 1, (void **) &(intern->handlers)) != SUCCESS) { /* TODO: exception */ } @@ -390,39 +369,46 @@ static union _zend_function* rpc_get_method(zval *object, char *method, int meth zend_function *function; GET_INTERNAL(intern); - if (zend_hash_find(&((*intern)->ce->function_table), method, method_len + 1, &function) == FAILURE) { - function = (zend_function *) emalloc(sizeof(zend_function)); - function->type = ZEND_OVERLOADED_FUNCTION; - function->common.arg_types = NULL; - function->common.function_name = method; - function->common.scope = NULL; - } + if (zend_worm_hash_find(&((*intern)->function_table), method, method_len + 1, &function) != SUCCESS) { + zend_internal_function *zif; - return function; -} + zif = (zend_internal_function *) emalloc(sizeof(zend_internal_function)); + zif->arg_types = NULL; + zif->function_name = method; + zif->handler = ZEND_FN(rpc_call); + zif->scope = NULL; + zif->type = ZEND_INTERNAL_FUNCTION; -static int rpc_call(char *method, INTERNAL_FUNCTION_PARAMETERS) -{ -// zval *object = getThis(); -// GET_INTERNAL(intern); + /* add new method to the method table */ + zend_worm_hash_add(&((*intern)->function_table), method, method_len + 1, zif, sizeof(zend_function), &function); + efree(zif); + } - return SUCCESS; + return function; } static union _zend_function* rpc_get_constructor(zval *object TSRMLS_DC) { - zend_internal_function *rpc_ctor; + zend_function *rpc_ctor; GET_INTERNAL(intern); - rpc_ctor = (zend_internal_function *) emalloc(sizeof(zend_internal_function)); + if (zend_worm_hash_find(&((*intern)->function_table), (*intern)->ce->name, (*intern)->ce->name_length + 1, &rpc_ctor) != SUCCESS) { + zend_internal_function *zif; + + zif = (zend_internal_function *) emalloc(sizeof(zend_internal_function)); - rpc_ctor->type = ZEND_INTERNAL_FUNCTION; - rpc_ctor->function_name = (*intern)->ce->name; - rpc_ctor->scope = (*intern)->ce; - rpc_ctor->arg_types = NULL; - rpc_ctor->handler = ZEND_FN(rpc_load); + zif->type = ZEND_INTERNAL_FUNCTION; + zif->function_name = (*intern)->ce->name; + zif->scope = (*intern)->ce; + zif->arg_types = NULL; + zif->handler = ZEND_FN(rpc_load); - return (zend_function *) rpc_ctor; + /* add new constructor to the method table */ + zend_worm_hash_add(&((*intern)->function_table), (*intern)->ce->name, (*intern)->ce->name_length + 1, zif, sizeof(zend_function), &rpc_ctor); + efree(zif); + } + + return rpc_ctor; } static int rpc_get_classname(zval *object, char **class_name, zend_uint *class_name_len, int parent TSRMLS_DC) @@ -445,11 +431,12 @@ static int rpc_compare(zval *object1, zval *object2 TSRMLS_DC) ZEND_FUNCTION(rpc_load) { zval *object = getThis(); - zval ***args; + zval ***args, ***args_free; zend_uint num_args = ZEND_NUM_ARGS(); rpc_class_hash *class_hash; rpc_class_hash **class_hash_find = NULL; rpc_internal **intern; + int retval; /* check if we were called as a constructor or as a function */ if (!object) { @@ -457,67 +444,58 @@ ZEND_FUNCTION(rpc_load) * and then we have to set up a zval containing the object */ - char *key; - int key_len; - - /* the name of the rpc layer is prepended to '_load' so lets strip everything after - * the first '_' away from the function name - */ - zend_class_entry **ce; - key = estrdup(get_active_function_name(TSRMLS_C)); - key_len = strchr(key, '_') - key; - key[key_len] = '\0'; - - /* get the class entry for the requested rpc layer */ - if (zend_hash_find(CG(class_table), key, key_len + 1, (void **) &ce) == FAILURE) { - /* TODO: exception here */ - } + /* get class entry */ + GET_CLASS(ce); /* set up a new zval container */ - ALLOC_ZVAL(object); - INIT_PZVAL(object); + object = return_value; Z_TYPE_P(object) = IS_OBJECT; /* create a new object */ object->value.obj = rpc_create_object(*ce TSRMLS_CC); - /* return the newly created object */ - return_value = object; - /* now everything is set up the same way as if we were called as a constructor */ } - if (GET_INTERNAL_EX(intern, object) == FAILURE) { + if (GET_INTERNAL_EX(intern, object) != SUCCESS) { /* TODO: exception */ } + /* fetch further parameters */ + GET_ARGS_EX(num_args, args, args_free, 2); + /* if classname != integer */ - if ((zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, 2 TSRMLS_CC, "l", &((*intern)->class_name_len)) == FAILURE) || + if ((zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, 1 TSRMLS_CC, "l", &((*intern)->class_name_len)) != SUCCESS) || /* or we have no hash function */ !((*(*intern)->handlers)->rpc_hash) || /* or integer hashing is not allowed */ - ((*(*intern)->handlers)->hash_type != HASH_AS_INT)) { + !((*(*intern)->handlers)->hash_type & HASH_AS_INT)) { /* else check for string - classname */ - if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, 2 TSRMLS_CC, "s", &((*intern)->class_name), &((*intern)->class_name_len)) == FAILURE) { + if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, 1 TSRMLS_CC, "s", &((*intern)->class_name), &((*intern)->class_name_len)) != SUCCESS) { /* none of the two possibilities */ + /* TODO: exception */ php_error(E_WARNING, "wrong arguments for %s()", get_active_function_name(TSRMLS_C)); } else { /* hash classname if hashing function exists */ if ((*(*intern)->handlers)->rpc_hash) { /* check if already hashed */ - if (zend_worm_hash_find(classes, (*intern)->class_name, (*intern)->class_name_len + 1, (void **) &class_hash_find) == FAILURE) { + if (zend_worm_hash_find(classes, (*intern)->class_name, (*intern)->class_name_len + 1, (void **) &class_hash_find) != SUCCESS) { class_hash = pemalloc(sizeof(rpc_class_hash), TRUE); /* set up the cache */ zend_worm_hash_init(&(class_hash->methods), 0, NULL, rpc_string_dtor, TRUE); zend_worm_hash_init(&(class_hash->properties), 0, NULL, rpc_string_dtor, TRUE); + if ((*(*intern)->handlers)->hash_type & HASH_WITH_SIGNATURE) { + /* TODO: add signature to hash key */ + } + /* do hashing */ - if ((*(*intern)->handlers)->rpc_hash((*intern)->class_name, (*intern)->class_name_len, - &(class_hash->name.str), &(class_hash->name.len), CLASS) == FAILURE) { + if ((*(*intern)->handlers)->rpc_hash((*intern)->class_name, (*intern)->class_name_len, &(class_hash->name.str), + &(class_hash->name.len), num_args, args, CLASS) != SUCCESS) { /* TODO: exception */ } @@ -527,7 +505,7 @@ ZEND_FUNCTION(rpc_load) if (class_hash->name.str) { /* register string hashcode */ zend_worm_hash_add(classes, class_hash->name.str, class_hash->name.len + 1, &class_hash, sizeof(rpc_class_hash *), NULL); - } else if (!class_hash->name.str && ((*(*intern)->handlers)->hash_type == HASH_AS_INT)) { + } else if (!class_hash->name.str && ((*(*intern)->handlers)->hash_type & HASH_AS_INT)) { /* register int hashcode */ zend_worm_hash_index_update(classes, class_hash->name.len, &class_hash, sizeof(rpc_class_hash *), NULL); } @@ -538,7 +516,7 @@ ZEND_FUNCTION(rpc_load) } } else { /* integer classname (hashcode) */ - if (zend_worm_hash_index_find(classes, (*intern)->class_name_len, (void**) &class_hash_find) == FAILURE) { + if (zend_worm_hash_index_find(classes, (*intern)->class_name_len, (void**) &class_hash_find) != SUCCESS) { class_hash = pemalloc(sizeof(rpc_class_hash), TRUE); /* set up the cache */ @@ -548,23 +526,16 @@ ZEND_FUNCTION(rpc_load) zend_worm_hash_init(&(class_hash->methods), 0, NULL, rpc_string_dtor, TRUE); zend_worm_hash_init(&(class_hash->properties), 0, NULL, rpc_string_dtor, TRUE); + if ((*(*intern)->handlers)->hash_type & HASH_WITH_SIGNATURE) { + /* TODO: add signature to hash key */ + } + /* register int hashcode, we don't know more */ zend_worm_hash_index_update(classes, class_hash->name.len, &class_hash, sizeof(rpc_class_hash *), NULL); } else { class_hash = *class_hash_find; } } - - /* fetch further parameters */ - args = (zval ***) emalloc(sizeof(zval **) * num_args); - - if (zend_get_parameters_array_ex(num_args, args) == FAILURE) { - /* TODO: exception */ - } - - /* strip away the first two parameters */ - num_args -= 2; - args = (num_args > 0) ? &args[2] : NULL; /* if hash function available */ if ((*(*intern)->handlers)->rpc_hash) { @@ -572,21 +543,104 @@ ZEND_FUNCTION(rpc_load) (*intern)->hash = class_hash; /* call the rpc ctor */ - (*(*intern)->handlers)->rpc_ctor(class_hash->name.str, class_hash->name.len, &((*intern)->data), num_args, args); + retval = (*(*intern)->handlers)->rpc_ctor(class_hash->name.str, class_hash->name.len, &((*intern)->data), num_args, args); } else { /* disable caching from now on */ (*intern)->hash = NULL; /* call the rpc ctor */ - (*(*intern)->handlers)->rpc_ctor((*intern)->class_name, (*intern)->class_name_len, &((*intern)->data), num_args, args); + retval = (*(*intern)->handlers)->rpc_ctor((*intern)->class_name, (*intern)->class_name_len, &((*intern)->data), num_args, args); } - /* efree hash_find stuff ? */ + efree(args_free); + + if (retval != SUCCESS) { + /* TODO: exception */ + } } ZEND_FUNCTION(rpc_call) { - /* FIXME */ + zval *object = getThis(); + zval ***args, ***args_free; + zend_uint num_args = ZEND_NUM_ARGS(); + char *hash = NULL; + int hash_len, retval, strip = 0; + + /* check if we were called as a method or as a function */ + if (!object) { + /* we were called as a function so we have to figure out which rpc layer was requested */ + + /* get class entry */ + GET_CLASS(ce); + + if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, 2 TSRMLS_CC, "Ol", &object, *ce, &hash_len) != SUCCESS) { + if (zend_parse_parameters_ex(0, 2 TSRMLS_CC, "Os", &object, *ce, &hash, &hash_len) != SUCCESS) { + /* none of the two possibilities */ + /* TODO: exception */ + php_error(E_WARNING, "wrong arguments for %s()", get_active_function_name(TSRMLS_C)); + } + } + + strip = 2; + } else { + hash = get_active_function_name(TSRMLS_C); + hash_len = strlen(hash); + } + + GET_ARGS_EX(num_args, args, args_free, strip); + + /* scope for internal data */ + { + rpc_string *method_hash, **method_hash_find; + GET_INTERNAL(intern); + + method_hash = (rpc_string *) pemalloc(sizeof(rpc_string), TRUE); + method_hash->str = hash; + method_hash->len = hash_len; + + if ((*intern)->hash) { + /* cache method table lookups */ + + if ((*(*intern)->handlers)->hash_type & HASH_WITH_SIGNATURE) { + /* TODO: add signature to hash key */ + } + + if (!hash && !((*(*intern)->handlers)->hash_type & HASH_AS_INT)) { + /* TODO: exception */ + } else if(hash) { + /* string method */ + + /* check if already hashed */ + if (zend_worm_hash_find(&((*intern)->hash->methods), hash, hash_len + 1, (void **) &method_hash_find) != SUCCESS) { + if ((*(*intern)->handlers)->rpc_hash(hash, hash_len, &(method_hash->str), &(method_hash->len), + num_args, args, METHOD) != SUCCESS) { + /* TODO: exception */ + } + + /* register with non-hashed key */ + zend_worm_hash_add(&((*intern)->hash->methods), hash, hash_len + 1, &method_hash, sizeof(rpc_string *), NULL); + } else { + pefree(method_hash, TRUE); + method_hash = *method_hash_find; + } + } + } + + /* actually this should not be neccesary, but who knows :) + * considering possible thread implementations in future php versions + * and srm it is better to do concurrency checks + */ + tsrm_mutex_lock((*intern)->mx_handler); + retval = (*(*intern)->handlers)->rpc_call(method_hash->str, method_hash->len, &((*intern)->data), &return_value, num_args, args); + tsrm_mutex_unlock((*intern)->mx_handler); + } + + efree(args_free); + + if (retval != SUCCESS) { + /* TODO: exception here */ + } } ZEND_FUNCTION(rpc_set) |