/* {{{ pthreads_get_method will attempt to apply pthreads specific modifiers */ zend_function * pthreads_get_method(PTHREADS_GET_METHOD_PASSTHRU_D) { zend_class_entry *scope; zend_function *call; zend_function *callable; char *lcname; int access = 0; PTHREAD thread = PTHREADS_FETCH_FROM(*pobject); if (thread) { switch((access=pthreads_modifiers_get(thread->modifiers, method TSRMLS_CC))){ case ZEND_ACC_PRIVATE: case ZEND_ACC_PROTECTED: scope = Z_OBJCE_PP(pobject); lcname = (char*) calloc(1, methodl+1); zend_str_tolower_copy(lcname, method, methodl); if (zend_hash_find(&scope->function_table, lcname, methodl+1, (void**)&call)==SUCCESS) { callable = (zend_function*) emalloc(sizeof(zend_function)); callable->type = ZEND_OVERLOADED_FUNCTION; callable->common.function_name = call->common.function_name; callable->common.fn_flags = ZEND_ACC_PUBLIC; callable->common.scope = scope; callable->common.arg_info = call->common.arg_info; callable->common.num_args = call->common.num_args; callable->common.required_num_args = call->common.required_num_args; #if PHP_VERSION_ID < 50400 callable->common.pass_rest_by_reference = call->common.pass_rest_by_reference; callable->common.return_reference = call->common.return_reference; #endif free(lcname); return callable; } free(lcname); /* TODO : if not found ? switch to default ? or return some error ? */ default: call = zend_handlers->get_method(PTHREADS_GET_METHOD_PASSTHRU_C); } } else call = zend_handlers->get_method(PTHREADS_GET_METHOD_PASSTHRU_C); return call; } /* }}} */
/* {{{ pthreads_call_method */ int pthreads_call_method(PTHREADS_CALL_METHOD_PASSTHRU_D) { zval ***argv = NULL, zmethod, *zresult; zend_function *call = NULL; zend_fcall_info info; zend_fcall_info_cache cache; zend_class_entry *scope; int called = -1, argc = ZEND_NUM_ARGS(), access = ZEND_ACC_PUBLIC, mlength = 0; char *lcname; zend_bool unprotect; if (getThis()) { PTHREAD thread = PTHREADS_FETCH; if (thread) { switch((access=pthreads_modifiers_get(thread->modifiers, method TSRMLS_CC))){ case ZEND_ACC_PRIVATE: case ZEND_ACC_PROTECTED: { scope = Z_OBJCE_P(getThis()); /* * Stop invalid private method calls */ if (access == ZEND_ACC_PRIVATE && !PTHREADS_IN_THREAD(thread)) { zend_error_noreturn( E_ERROR, "pthreads detected an attempt to call private method %s::%s from outside the threading context", scope->name, method ); return FAILURE; } /* * Get arguments from stack */ if (ZEND_NUM_ARGS()) { argv = safe_emalloc(sizeof(zval **), argc, 0); if (argv) { zend_get_parameters_array_ex(argc, argv); } } mlength = strlen(method); lcname = calloc(1, mlength+1); zend_str_tolower_copy(lcname, method, mlength); if (zend_hash_find(&scope->function_table, lcname, mlength+1, (void**)&call)==SUCCESS) { if (call) { /* * Make protected method call */ { if (access != ZEND_ACC_PROTECTED || pthreads_modifiers_protect(thread->modifiers, method, &unprotect TSRMLS_CC)) { ZVAL_STRINGL(&zmethod, method, strlen(method), 0); info.size = sizeof(info); info.object_ptr = getThis(); info.function_name = &zmethod; info.retval_ptr_ptr = &zresult; info.no_separation = 1; info.symbol_table = NULL; info.param_count = argc; info.params = argv; cache.initialized = 1; cache.function_handler = call; cache.calling_scope = EG(called_scope); cache.called_scope = scope; cache.object_ptr = getThis(); if ((called=zend_call_function(&info, &cache TSRMLS_CC))!=SUCCESS) { zend_error_noreturn( E_ERROR, "pthreads has experienced an internal error while calling %s method %s::%s and cannot continue", (access == ZEND_ACC_PROTECTED) ? "protected" : "private", scope->name, method ); } else { #if PHP_VERSION_ID > 50399 { zend_op_array *ops = (zend_op_array*) call; if (ops) { if (ops->run_time_cache) { efree(ops->run_time_cache); ops->run_time_cache = NULL; } } } #endif if (!return_value_used) { zval_ptr_dtor(&zresult); } else { ZVAL_ZVAL(return_value, zresult, 1, 1); } } if (access == ZEND_ACC_PROTECTED) { pthreads_modifiers_unprotect(thread->modifiers, method, unprotect TSRMLS_CC); } } else { zend_error_noreturn( E_ERROR, "pthreads has experienced an internal error while calling %s method %s::%s and cannot continue", (access == ZEND_ACC_PROTECTED) ? "protected" : "private", scope->name, method ); called = FAILURE; } } } else { zend_error_noreturn( E_ERROR, "pthreads has experienced an internal error while finding %s method %s::%s and cannot continue", (access == ZEND_ACC_PROTECTED) ? "protected" : "private", scope->name, method ); called = FAILURE; } } /* * Free unstacked arguments */ if (argc) { efree(argv); } free(lcname); return called; } break; } } } switch (called) { case -1: return zend_handlers->call_method(PTHREADS_CALL_METHOD_PASSTHRU_C); default: return called; } } /* }}} */