From: Harald Radi Date: Tue, 19 Mar 2002 23:28:52 +0000 (+0000) Subject: pass function signature in zend_parse_parameters style X-Git-Tag: php-4.3.0dev-ZendEngine2-Preview1~1205 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=2adf5bea7c00fcf5184a5377ad075dde494305fd;p=php pass function signature in zend_parse_parameters style lookup cache works now per signature (not only method name) reviewed resource management # have to learn now .. --- diff --git a/ext/rpc/com/com.c b/ext/rpc/com/com.c index 0ccccfe3b8..522be7dcd1 100644 --- a/ext/rpc/com/com.c +++ b/ext/rpc/com/com.c @@ -1,7 +1,7 @@ #include "com.h" /* protos */ -static int com_hash(char *, zend_uint, char **, zend_uint *, int, zval ***, int); +static int com_hash(char *, zend_uint, char **, zend_uint *, int, char *, int); static int com_ctor(char *, zend_uint, void **, int , zval ***); static int com_dtor(void **); static int com_call(char *, zend_uint, void **, zval **, int, zval ***); @@ -17,7 +17,7 @@ static int com_get_properties(HashTable **, void **); /* register rpc callback function */ RPC_REGISTER_HANDLERS_START(com) POOL, -HASH_AS_INT, +HASH_AS_INT_WITH_SIGNATURE, com_hash, com_ctor, com_dtor, @@ -51,7 +51,7 @@ RPC_INIT_FUNCTION(com) /* rpc handler functions */ -static int com_hash(char *name, zend_uint name_len, char **hash, zend_uint *hash_len, int num_args, zval **args[], int type) +static int com_hash(char *name, zend_uint name_len, char **hash, zend_uint *hash_len, int num_args, char *arg_types, int type) { *hash = strdup(name); *hash_len = name_len; diff --git a/ext/rpc/handler.h b/ext/rpc/handler.h index bc3e9b34d2..3b108d5754 100644 --- a/ext/rpc/handler.h +++ b/ext/rpc/handler.h @@ -56,7 +56,7 @@ typedef struct _rpc_object_handlers { const zend_bool pool_instances; const zend_uint hash_type; - int (*rpc_hash)(char *name, zend_uint name_len, char **hash, zend_uint *hash_len, int num_args, zval **args[], int type); + int (*rpc_hash)(char *name, zend_uint name_len, char **hash, zend_uint *hash_len, int num_args, char *arg_types, int type); int (*rpc_ctor)(char *class_name, zend_uint class_name_len, void **data, int num_args, zval **args[]); int (*rpc_dtor)(void **data); int (*rpc_call)(char *method_name, zend_uint method_name_len, void **data, zval **return_value, int num_args, zval **args[]); diff --git a/ext/rpc/rpc.c b/ext/rpc/rpc.c index 2652ff6ce3..7c63ab7a3c 100644 --- a/ext/rpc/rpc.c +++ b/ext/rpc/rpc.c @@ -85,6 +85,7 @@ zend_module_entry rpc_module_entry = { static HashTable *handlers; static WormHashTable *instance; static WormHashTable *classes; +static zend_llist *classes_list; #ifdef COMPILE_DL_RPC ZEND_GET_MODULE(rpc); @@ -108,11 +109,13 @@ ZEND_MINIT_FUNCTION(rpc) handlers = (HashTable *) pemalloc(sizeof(HashTable), TRUE); instance = (WormHashTable *) pemalloc(sizeof(WormHashTable), TRUE); classes = (WormHashTable *) pemalloc(sizeof(WormHashTable), TRUE); + classes_list = (zend_llist *) pemalloc(sizeof(zend_llist), TRUE); 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); - + zend_worm_hash_init(classes, 0, NULL, NULL, TRUE); + zend_llist_init(classes_list, sizeof(rpc_class_hash **), rpc_class_dtor, TRUE); + FOREACH_HANDLER { HANDLER.rpc_handler_init(); @@ -145,10 +148,11 @@ ZEND_MINIT_FUNCTION(rpc) */ ZEND_MSHUTDOWN_FUNCTION(rpc) { + /* destroy instances first */ zend_worm_hash_destroy(instance); zend_worm_hash_destroy(classes); - /* destroy instances first ! */ + zend_llist_destroy(classes_list); zend_hash_destroy(handlers); pefree(handlers, TRUE); @@ -197,7 +201,7 @@ static void rpc_class_dtor(void *pDest) zend_worm_hash_destroy(&((*hash)->properties)); free((*hash)->name.str); - pefree(*hash, TRUE); + pefree((*hash), TRUE); } static void rpc_string_dtor(void *pDest) @@ -436,7 +440,9 @@ ZEND_FUNCTION(rpc_load) rpc_class_hash *class_hash; rpc_class_hash **class_hash_find = NULL; rpc_internal **intern; - int retval; + rpc_string hash_val; + int retval, append = 0; + char *arg_types; /* check if we were called as a constructor or as a function */ if (!object) { @@ -463,7 +469,7 @@ ZEND_FUNCTION(rpc_load) } /* fetch further parameters */ - GET_ARGS_EX(num_args, args, args_free, 2); + GET_ARGS_EX(num_args, args, args_free, 1); /* if classname != integer */ if ((zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, 1 TSRMLS_CC, "l", &((*intern)->class_name_len)) != SUCCESS) || @@ -481,26 +487,31 @@ ZEND_FUNCTION(rpc_load) /* hash classname if hashing function exists */ if ((*(*intern)->handlers)->rpc_hash) { + GET_CTOR_SIGNATURE(intern, hash_val, num_args, arg_types); + /* check if already hashed */ - if (zend_worm_hash_find(classes, (*intern)->class_name, (*intern)->class_name_len + 1, (void **) &class_hash_find) != SUCCESS) { + if (zend_worm_hash_find(classes, hash_val.str, hash_val.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), num_args, args, CLASS) != SUCCESS) { + &(class_hash->name.len), num_args, arg_types, CLASS) != SUCCESS) { /* TODO: exception */ } - /* register with non-hashed key */ - zend_worm_hash_add(classes, (*intern)->class_name, (*intern)->class_name_len + 1, &class_hash, sizeof(rpc_class_hash *), NULL); + /* register with non-hashed key + * also track all instaces in a llist for destruction later on, because there might be duplicate entries in + * the hashtable and we can't determine if a pointer references to an already freed element + */ + zend_worm_hash_add(classes, hash_val.str, hash_val.len + 1, &class_hash, sizeof(rpc_class_hash *), (void **) &class_hash_find); + tsrm_mutex_lock(classes->mx_writer); + zend_llist_add_element(classes_list, class_hash_find); + tsrm_mutex_unlock(classes->mx_writer); if (class_hash->name.str) { /* register string hashcode */ @@ -512,6 +523,8 @@ ZEND_FUNCTION(rpc_load) } else { class_hash = *class_hash_find; } + + FREE_SIGNATURE(hash_val, arg_types); } } } else { @@ -526,10 +539,6 @@ 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 { @@ -564,7 +573,7 @@ ZEND_FUNCTION(rpc_call) zval *object = getThis(); zval ***args, ***args_free; zend_uint num_args = ZEND_NUM_ARGS(); - char *hash = NULL; + char *hash = NULL, *arg_types; int hash_len, retval, strip = 0; /* check if we were called as a method or as a function */ @@ -592,7 +601,7 @@ ZEND_FUNCTION(rpc_call) /* scope for internal data */ { - rpc_string *method_hash, **method_hash_find; + rpc_string hash_val, *method_hash, **method_hash_find; GET_INTERNAL(intern); method_hash = (rpc_string *) pemalloc(sizeof(rpc_string), TRUE); @@ -602,28 +611,27 @@ ZEND_FUNCTION(rpc_call) 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 */ + /* string passed */ + GET_METHOD_SIGNATURE(intern, method_hash, hash_val, num_args, arg_types); /* check if already hashed */ - if (zend_worm_hash_find(&((*intern)->hash->methods), hash, hash_len + 1, (void **) &method_hash_find) != SUCCESS) { + if (zend_worm_hash_find(&((*intern)->hash->methods), hash_val.str, hash_val.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) { + num_args, arg_types, 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); + zend_worm_hash_add(&((*intern)->hash->methods), hash_val.str, hash_val.len + 1, &method_hash, sizeof(rpc_string *), NULL); } else { pefree(method_hash, TRUE); method_hash = *method_hash_find; } + + FREE_SIGNATURE(hash_val, arg_types); } } diff --git a/ext/rpc/rpc.h b/ext/rpc/rpc.h index 81f8af314a..ce2b0e59d6 100644 --- a/ext/rpc/rpc.h +++ b/ext/rpc/rpc.h @@ -48,6 +48,69 @@ /* TODO: exception */ \ } +#define GET_CTOR_SIGNATURE(intern, hash_val, num_args, arg_types) \ + GET_SIGNATURE(intern, (*intern)->class_name, (*intern)->class_name_len, hash_val, num_args, arg_types) + +#define GET_METHOD_SIGNATURE(intern, method, hash_val, num_args, arg_types) \ + GET_SIGNATURE(intern, method->str, method->len, hash_val, num_args, arg_types) + +#define GET_SIGNATURE(intern, name, name_len, hash_val, num_args, arg_types) \ + hash_val.len = name_len; \ + \ + if ((*(*intern)->handlers)->hash_type & HASH_WITH_SIGNATURE) { \ + zend_uint _signature_counter; \ + \ + arg_types = (char *) emalloc(sizeof(char) * (num_args + 1)); \ + hash_val.len += num_args + 1; \ + \ + for (_signature_counter = 0; _signature_counter < num_args; _signature_counter++) { \ + switch (Z_TYPE_PP(args[_signature_counter])) { \ + case IS_NULL: \ + arg_types[_signature_counter] = 'n'; \ + break; \ + case IS_LONG: \ + arg_types[_signature_counter] = 'l'; \ + break; \ + case IS_DOUBLE: \ + arg_types[_signature_counter] = 'd'; \ + break; \ + case IS_STRING: \ + arg_types[_signature_counter] = 's'; \ + break; \ + case IS_ARRAY: \ + arg_types[_signature_counter] = 'a'; \ + break; \ + case IS_OBJECT: \ + arg_types[_signature_counter] = 'o'; \ + break; \ + case IS_BOOL: \ + arg_types[_signature_counter] = 'b'; \ + break; \ + case IS_RESOURCE: \ + arg_types[_signature_counter] = 'r'; \ + break; \ + default: \ + arg_types[_signature_counter] = 'u'; \ + } \ + } \ + \ + arg_types[_signature_counter] = '\0'; \ + } else { \ + arg_types = (char *) emalloc(sizeof(char)); \ + arg_types[0] = '\0'; \ + } \ + \ + hash_val.str = (char *) emalloc(sizeof(char) * (hash_val.len + 2)); \ + memcpy(hash_val.str, arg_types, num_args + 1); \ + memcpy(&hash_val.str[hash_val.len - name_len], \ + name, name_len + 1); + +#define FREE_SIGNATURE(hash_val, arg_types) \ + efree(arg_types); \ + efree(hash_val.str); + + + #define RPC_REFCOUNT(intern) ((*intern)->refcount) #define RPC_ADDREF(intern) (++RPC_REFCOUNT(intern)) #define RPC_DELREF(intern) (--RPC_REFCOUNT(intern)) diff --git a/ext/rpc/tests/test1.php b/ext/rpc/tests/test1.php index e989f53168..aee876aedb 100644 --- a/ext/rpc/tests/test1.php +++ b/ext/rpc/tests/test1.php @@ -1,11 +1,26 @@ call("blah"); $rpc->call("heh"); +$rpc->call("blah"); +com_call($rpc, 1, "1"); +com_call($rpc, 1, "1"); +$rpc->call("blah"); +$rpc->call("blah"); +$rpc->call("blah"); +$rpc2->call("hehe"); +$rpc2->call("hehe"); +$rpc2->call("hehe"); +$rpc2->call("hehe"); +$rpc2->call("hehe"); +com_call($rpc, "call", 1); +com_call($rpc, 1, "1"); com_call($rpc, "call", 1); +com_call($rpc2, "call", 1); +com_call($rpc2, "call", 1); //$rpc->addref(); //$clone = $rpc->__clone(); @@ -18,7 +33,7 @@ com_call($rpc, "call", 1); //delete $rpc; //delete $clone; -$heh = com_load(1, 1); +$heh = com_load("heh", 1); $heh->knorp(); /*delete $heh;*/ ?> \ No newline at end of file