static HashTable *handlers;
static WormHashTable *instance;
static WormHashTable *classes;
+static zend_llist *classes_list;
#ifdef COMPILE_DL_RPC
ZEND_GET_MODULE(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();
*/
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);
zend_worm_hash_destroy(&((*hash)->properties));
free((*hash)->name.str);
- pefree(*hash, TRUE);
+ pefree((*hash), TRUE);
}
static void rpc_string_dtor(void *pDest)
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) {
}
/* 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) ||
/* 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 */
} else {
class_hash = *class_hash_find;
}
+
+ FREE_SIGNATURE(hash_val, arg_types);
}
}
} else {
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 {
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 */
/* 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);
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);
}
}
/* 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))