Reentrancy fixes

This commit is contained in:
Sam Ruby 2000-07-09 04:16:31 +00:00
parent 5c13954eed
commit 629bc67086
6 changed files with 242 additions and 114 deletions

View file

@ -68,12 +68,33 @@ static char *javahome = 0;
static char *javalib = 0;
static int iniUpdated = 0;
static JavaVM *jvm = 0;
static JNIEnv *jenv = 0;
static jclass php_reflect;
static void *dl_handle = 0;
typedef struct {
JavaVM *jvm;
JNIEnv *jenv;
jobject php_reflect;
jclass reflect_class;
} php_java_globals;
#ifdef ZTS
#define JG(v) (java_globals->v)
#define JG_FETCH() php_java_globals *java_globals = ts_resource(java_globals_id)
#define JG_D php_java_globals *java_globals
#define JG_DC , JG_D
#define JG_C dir_globals
#define JG_CC , JG_C
int java_globals_id;
#else
#define JG(v) (java_globals.v)
#define JG_FETCH()
#define JG_D
#define JG_DC
#define JG_C
#define JG_CC
php_java_globals javadir_globals;
#endif
static zend_class_entry java_class_entry;
static PHP_INI_MH(OnIniUpdate) {
@ -106,15 +127,17 @@ PHP_INI_END()
* Destroy a Java Virtual Machine.
*/
void jvm_destroy() {
if (php_reflect) (*jenv)->DeleteGlobalRef(jenv, php_reflect);
if (jvm) {
(*jvm)->DetachCurrentThread(jvm);
(*jvm)->DestroyJavaVM(jvm);
jvm = 0;
JG_FETCH();
if (JG(php_reflect)) (*JG(jenv))->DeleteGlobalRef(JG(jenv), JG(php_reflect));
if (JG(jvm)) {
(*JG(jvm))->DetachCurrentThread(JG(jvm));
(*JG(jvm))->DestroyJavaVM(JG(jvm));
JG(jvm) = 0;
}
if (dl_handle) DL_UNLOAD(dl_handle);
php_reflect = 0;
jenv = 0;
JG(php_reflect) = 0;
JG(jenv) = 0;
}
/*
@ -134,9 +157,10 @@ static void addJVMOption(JavaVMInitArgs *vm_args, char *name, char *value) {
#endif
static int jvm_create() {
JG_FETCH();
int rc;
jclass local_php_reflect;
jobject local_php_reflect;
jthrowable error;
jint (JNICALL *JNI_CreateVM)(const void*,const void*,void*);
@ -217,21 +241,22 @@ static int jvm_create() {
#endif
rc = (*JNI_CreateVM)(&jvm, &jenv, &vm_args);
rc = (*JNI_CreateVM)(&JG(jvm), &JG(jenv), &vm_args);
if (rc) {
php_error(E_ERROR, "Unable to create Java Virtual Machine");
return rc;
}
local_php_reflect = (*jenv)->FindClass(jenv, "net/php/reflect");
error = (*jenv)->ExceptionOccurred(jenv);
JG(reflect_class) = (*JG(jenv))->FindClass(JG(jenv), "net/php/reflect");
error = (*JG(jenv))->ExceptionOccurred(JG(jenv));
if (error) {
jclass errClass;
jmethodID toString;
jobject errString;
const char *errAsUTF;
jboolean isCopy;
JNIEnv *jenv = JG(jenv);
(*jenv)->ExceptionClear(jenv);
errClass = (*jenv)->GetObjectClass(jenv, error);
toString = (*jenv)->GetMethodID(jenv, errClass, "toString",
@ -244,13 +269,17 @@ static int jvm_create() {
return -1;
}
php_reflect = (*jenv)->NewGlobalRef(jenv, local_php_reflect);
local_php_reflect = (*JG(jenv))->AllocObject(JG(jenv), JG(reflect_class));
JG(php_reflect) = (*JG(jenv))->NewGlobalRef(JG(jenv), local_php_reflect);
return rc;
}
/***************************************************************************/
static jobjectArray _java_makeArray(int argc, pval** argv) {
JG_FETCH();
JNIEnv *jenv = JG(jenv);
jclass objectClass = (*jenv)->FindClass(jenv, "java/lang/Object");
jobjectArray result = (*jenv)->NewObjectArray(jenv, argc, objectClass, 0);
jobject arg;
@ -273,23 +302,23 @@ static jobjectArray _java_makeArray(int argc, pval** argv) {
break;
case IS_BOOL:
makeArg = (*jenv)->GetStaticMethodID(jenv, php_reflect, "MakeArg",
makeArg = (*jenv)->GetMethodID(jenv, JG(reflect_class), "MakeArg",
"(Z)Ljava/lang/Object;");
arg = (*jenv)->CallStaticObjectMethod(jenv, php_reflect, makeArg,
arg = (*jenv)->CallObjectMethod(jenv, JG(php_reflect), makeArg,
(jboolean)(argv[i]->value.lval));
break;
case IS_LONG:
makeArg = (*jenv)->GetStaticMethodID(jenv, php_reflect, "MakeArg",
makeArg = (*jenv)->GetMethodID(jenv, JG(reflect_class), "MakeArg",
"(J)Ljava/lang/Object;");
arg = (*jenv)->CallStaticObjectMethod(jenv, php_reflect, makeArg,
arg = (*jenv)->CallObjectMethod(jenv, JG(php_reflect), makeArg,
(jlong)(argv[i]->value.lval));
break;
case IS_DOUBLE:
makeArg = (*jenv)->GetStaticMethodID(jenv, php_reflect, "MakeArg",
makeArg = (*jenv)->GetMethodID(jenv, JG(reflect_class), "MakeArg",
"(D)Ljava/lang/Object;");
arg = (*jenv)->CallStaticObjectMethod(jenv, php_reflect, makeArg,
arg = (*jenv)->CallObjectMethod(jenv, JG(php_reflect), makeArg,
(jdouble)(argv[i]->value.dval));
break;
@ -323,6 +352,9 @@ static int checkError(pval *value) {
void java_call_function_handler
(INTERNAL_FUNCTION_PARAMETERS, zend_property_reference *property_reference)
{
JG_FETCH();
JNIEnv *jenv;
pval *object = property_reference->object;
zend_overloaded_element *function_name = (zend_overloaded_element *)
property_reference->elements_list->tail->data;
@ -333,9 +365,10 @@ void java_call_function_handler
pval **arguments = (pval **) emalloc(sizeof(pval *)*arg_count);
getParametersArray(ht, arg_count, arguments);
if (iniUpdated && jenv) jvm_destroy();
if (!jenv) jvm_create();
if (!jenv) return;
if (iniUpdated && JG(jenv)) jvm_destroy();
if (!JG(jenv)) jvm_create();
if (!JG(jenv)) return;
jenv = JG(jenv);
if (!strcmp("java",function_name->element.value.str.val)) {
@ -343,12 +376,12 @@ void java_call_function_handler
First argument is the class name. Any additional arguments will
be treated as constructor parameters. */
jmethodID co = (*jenv)->GetStaticMethodID(jenv, php_reflect, "CreateObject",
jmethodID co = (*jenv)->GetMethodID(jenv, JG(reflect_class), "CreateObject",
"(Ljava/lang/String;[Ljava/lang/Object;J)V");
jstring className=(*jenv)->NewStringUTF(jenv, arguments[0]->value.str.val);
(pval*)(long)result = object;
(*jenv)->CallStaticVoidMethod(jenv, php_reflect, co,
(*jenv)->CallVoidMethod(jenv, JG(php_reflect), co,
className, _java_makeArray(arg_count-1, arguments+1), result);
(*jenv)->DeleteLocalRef(jenv, className);
@ -362,14 +395,14 @@ void java_call_function_handler
/* invoke a method on the given object */
jmethodID invoke = (*jenv)->GetStaticMethodID(jenv, php_reflect, "Invoke",
jmethodID invoke = (*jenv)->GetMethodID(jenv, JG(reflect_class), "Invoke",
"(Ljava/lang/Object;Ljava/lang/String;[Ljava/lang/Object;J)V");
zend_hash_index_find(object->value.obj.properties, 0, (void**) &handle);
obj = zend_list_find((*handle)->value.lval, &type);
method = (*jenv)->NewStringUTF(jenv, function_name->element.value.str.val);
(pval*)(long)result = return_value;
(*jenv)->CallStaticVoidMethod(jenv, php_reflect, invoke,
(*jenv)->CallVoidMethod(jenv, JG(php_reflect), invoke,
obj, method, _java_makeArray(arg_count, arguments), result);
(*jenv)->DeleteLocalRef(jenv, method);
@ -386,30 +419,38 @@ void java_call_function_handler
PHP_FUNCTION(java_last_exception_get)
{
JG_FETCH();
jlong result = 0;
jmethodID lastEx;
if (ZEND_NUM_ARGS()!=0) WRONG_PARAM_COUNT;
(pval*)(long)result = return_value;
lastEx = (*jenv)->GetStaticMethodID(jenv, php_reflect, "lastException",
"(J)V");
lastEx = (*JG(jenv))->GetMethodID(JG(jenv), JG(reflect_class),
"lastException", "(J)V");
(*jenv)->CallStaticVoidMethod(jenv, php_reflect, lastEx, result);
(*JG(jenv))->CallVoidMethod(JG(jenv), JG(php_reflect), lastEx, result);
}
/***************************************************************************/
PHP_FUNCTION(java_last_exception_clear)
{
JG_FETCH();
jlong result = 0;
jmethodID clearEx;
if (ZEND_NUM_ARGS()!=0) WRONG_PARAM_COUNT;
(pval*)(long)result = return_value;
clearEx = (*jenv)->GetStaticMethodID(jenv, php_reflect, "clearException",
"()V");
clearEx = (*JG(jenv))->GetMethodID(JG(jenv), JG(reflect_class),
"clearException", "()V");
(*jenv)->CallStaticVoidMethod(jenv, php_reflect, clearEx);
(*JG(jenv))->CallVoidMethod(JG(jenv), JG(php_reflect), clearEx);
}
/***************************************************************************/
@ -417,6 +458,9 @@ PHP_FUNCTION(java_last_exception_clear)
static pval _java_getset_property
(zend_property_reference *property_reference, jobjectArray value)
{
JG_FETCH();
JNIEnv *jenv = JG(jenv);
pval presult;
jlong result = 0;
pval **pobject;
@ -441,10 +485,10 @@ static pval _java_getset_property
"Attempt to access a Java property on a non-Java object");
} else {
/* invoke the method */
jmethodID gsp = (*jenv)->GetStaticMethodID(jenv, php_reflect, "GetSetProp",
jmethodID gsp = (*jenv)->GetMethodID(jenv, JG(reflect_class), "GetSetProp",
"(Ljava/lang/Object;Ljava/lang/String;[Ljava/lang/Object;J)V");
(*jenv)->CallStaticVoidMethod
(jenv, php_reflect, gsp, obj, propName, value, result);
(*jenv)->CallVoidMethod
(jenv, JG(php_reflect), gsp, obj, propName, value, result);
}
(*jenv)->DeleteLocalRef(jenv, propName);
@ -472,9 +516,16 @@ int java_set_property_handler
/***************************************************************************/
static void _php_java_destructor(void *jobject) {
if (jenv) (*jenv)->DeleteGlobalRef(jenv, jobject);
JG_FETCH();
if (JG(jenv)) (*JG(jenv))->DeleteGlobalRef(JG(jenv), jobject);
}
#ifdef ZTS
static void alloc_java_globals_ctor(php_java_globals *java_globals) {
memset(java_globals, 0, sizeof(php_java_globals));
}
#endif
PHP_MINIT_FUNCTION(java) {
INIT_OVERLOADED_CLASS_ENTRY(java_class_entry, "java", NULL,
java_call_function_handler,
@ -494,13 +545,19 @@ PHP_MINIT_FUNCTION(java) {
libpath=PG(extension_dir);
}
#ifdef ZTS
java_globals_id = ts_allocate_id(sizeof(php_java_globals),
(ts_allocate_ctor)alloc_java_globals_ctor, NULL);
#endif
return SUCCESS;
}
PHP_MSHUTDOWN_FUNCTION(java) {
JG_FETCH();
UNREGISTER_INI_ENTRIES();
if (jvm) jvm_destroy();
if (JG(jvm)) jvm_destroy();
return SUCCESS;
}
@ -620,8 +677,16 @@ JNIEXPORT void JNICALL Java_net_php_reflect_setException
JNIEXPORT void JNICALL Java_net_php_reflect_setEnv
(JNIEnv *newJenv, jclass self)
{
JG_FETCH();
jobject local_php_reflect;
iniUpdated=0;
jenv=newJenv;
if (!self) self = (*jenv)->FindClass(jenv, "net/php/reflect");
php_reflect = (*jenv)->NewGlobalRef(jenv, self);
JG(jenv)=newJenv;
if (!self) self = (*JG(jenv))->FindClass(JG(jenv), "net/php/reflect");
JG(reflect_class) = self;
if (JG(php_reflect)) (*JG(jenv))->DeleteGlobalRef(JG(jenv), JG(php_reflect));
local_php_reflect = (*JG(jenv))->AllocObject(JG(jenv), JG(reflect_class));
JG(php_reflect) = (*JG(jenv))->NewGlobalRef(JG(jenv), local_php_reflect);
}