diff options
-rw-r--r-- | bridges/source/jni_uno/java/com/sun/star/bridges/jni_uno/JNI_proxy.java | 24 | ||||
-rw-r--r-- | bridges/source/jni_uno/jni_base.h | 3 | ||||
-rw-r--r-- | bridges/source/jni_uno/jni_bridge.cxx | 123 | ||||
-rw-r--r-- | bridges/source/jni_uno/jni_bridge.h | 11 | ||||
-rw-r--r-- | bridges/source/jni_uno/jni_info.cxx | 3 | ||||
-rw-r--r-- | bridges/source/jni_uno/jni_java2uno.cxx | 16 | ||||
-rw-r--r-- | bridges/source/jni_uno/jni_uno2java.cxx | 10 | ||||
-rw-r--r-- | cppuhelper/source/component_context.cxx | 16 | ||||
-rw-r--r-- | jurt/com/sun/star/lib/uno/bridges/java_remote/ProxyFactory.java | 15 | ||||
-rw-r--r-- | jurt/com/sun/star/lib/uno/bridges/java_remote/java_remote_bridge.java | 12 | ||||
-rw-r--r-- | jurt/com/sun/star/lib/util/AsynchronousFinalizer.java | 71 |
11 files changed, 217 insertions, 87 deletions
diff --git a/bridges/source/jni_uno/java/com/sun/star/bridges/jni_uno/JNI_proxy.java b/bridges/source/jni_uno/java/com/sun/star/bridges/jni_uno/JNI_proxy.java index 732d30b925b5..12817e57eeda 100644 --- a/bridges/source/jni_uno/java/com/sun/star/bridges/jni_uno/JNI_proxy.java +++ b/bridges/source/jni_uno/java/com/sun/star/bridges/jni_uno/JNI_proxy.java @@ -63,7 +63,7 @@ public final class JNI_proxy implements java.lang.reflect.InvocationHandler private final Type m_type; private final String m_oid; private final Class m_class; - + private final AsynchronousFinalizer m_finalizer; public static String get_stack_trace( Throwable throwable ) throws Throwable @@ -98,16 +98,19 @@ public final class JNI_proxy implements java.lang.reflect.InvocationHandler @Override protected void finalize() { - AsynchronousFinalizer.add(new AsynchronousFinalizer.Job() { - public void run() throws Throwable { - JNI_proxy.this.finalize( m_bridge_handle ); - } - }); + if (m_finalizer != null) { + m_finalizer.add(new AsynchronousFinalizer.Job() { + public void run() throws Throwable { + JNI_proxy.this.finalize( m_bridge_handle ); + } + }); + } } private JNI_proxy( long bridge_handle, IEnvironment java_env, - long receiver_handle, long td_handle, Type type, String oid ) + long receiver_handle, long td_handle, Type type, String oid, + AsynchronousFinalizer finalizer) { m_bridge_handle = bridge_handle; m_java_env = java_env; @@ -116,16 +119,19 @@ public final class JNI_proxy implements java.lang.reflect.InvocationHandler m_type = type; m_oid = oid; m_class = m_type.getZClass(); + m_finalizer = finalizer; } public static Object create( long bridge_handle, IEnvironment java_env, long receiver_handle, long td_handle, Type type, String oid, - java.lang.reflect.Constructor proxy_ctor ) + java.lang.reflect.Constructor proxy_ctor, + AsynchronousFinalizer finalizer) throws Throwable { JNI_proxy handler = new JNI_proxy( - bridge_handle, java_env, receiver_handle, td_handle, type, oid ); + bridge_handle, java_env, receiver_handle, td_handle, type, oid, + finalizer); Object proxy = proxy_ctor.newInstance( new Object [] { handler } ); return java_env.registerInterface( proxy, new String [] { oid }, type ); } diff --git a/bridges/source/jni_uno/jni_base.h b/bridges/source/jni_uno/jni_base.h index 5e29c12674b0..25dee559c98a 100644 --- a/bridges/source/jni_uno/jni_base.h +++ b/bridges/source/jni_uno/jni_base.h @@ -125,7 +125,8 @@ class JNI_guarded_context public: inline explicit JNI_guarded_context( - JNI_info const * jni_info, ::jvmaccess::UnoVirtualMachine * vm_access ) + JNI_info const * jni_info, + rtl::Reference<jvmaccess::UnoVirtualMachine> const & vm_access) : AttachGuard( vm_access->getVirtualMachine() ), JNI_context( jni_info, AttachGuard::getEnvironment(), diff --git a/bridges/source/jni_uno/jni_bridge.cxx b/bridges/source/jni_uno/jni_bridge.cxx index da3a33be415d..809eb3b96c90 100644 --- a/bridges/source/jni_uno/jni_bridge.cxx +++ b/bridges/source/jni_uno/jni_bridge.cxx @@ -84,8 +84,8 @@ void SAL_CALL Mapping_map_to_uno( static_cast< Mapping const * >( mapping )->m_bridge; JNI_guarded_context jni( bridge->m_jni_info, - reinterpret_cast< ::jvmaccess::UnoVirtualMachine * >( - bridge->m_java_env->pContext ) ); + (static_cast<jni_uno::Context *>(bridge->m_java_env->pContext) + ->machine)); JNI_interface_type_info const * info = static_cast< JNI_interface_type_info const * >( @@ -135,8 +135,9 @@ void SAL_CALL Mapping_map_to_java( static_cast< Mapping const * >( mapping )->m_bridge; JNI_guarded_context jni( bridge->m_jni_info, - reinterpret_cast< ::jvmaccess::UnoVirtualMachine * >( - bridge->m_java_env->pContext ) ); + (static_cast<jni_uno::Context *>( + bridge->m_java_env->pContext) + ->machine)); jni->DeleteGlobalRef( *ppJavaI ); *ppJavaI = 0; } @@ -147,8 +148,8 @@ void SAL_CALL Mapping_map_to_java( static_cast< Mapping const * >( mapping )->m_bridge; JNI_guarded_context jni( bridge->m_jni_info, - reinterpret_cast< ::jvmaccess::UnoVirtualMachine * >( - bridge->m_java_env->pContext ) ); + (static_cast<jni_uno::Context *>(bridge->m_java_env->pContext) + ->machine)); JNI_interface_type_info const * info = static_cast< JNI_interface_type_info const * >( @@ -233,8 +234,7 @@ Bridge::Bridge( { // bootstrapping bridge jni_info m_jni_info = JNI_info::get_jni_info( - reinterpret_cast< ::jvmaccess::UnoVirtualMachine * >( - m_java_env->pContext ) ); + static_cast<jni_uno::Context *>(m_java_env->pContext)->machine); assert(m_java_env != 0); assert(m_uno_env != 0); @@ -409,21 +409,51 @@ OUString JNI_context::get_stack_trace( jobject jo_exc ) const using namespace ::jni_uno; -extern "C" -{ -namespace -{ - +extern "C" { -void SAL_CALL java_env_disposing( uno_Environment * java_env ) - SAL_THROW_EXTERN_C() -{ - ::jvmaccess::UnoVirtualMachine * machine = - reinterpret_cast< ::jvmaccess::UnoVirtualMachine * >( - java_env->pContext ); - java_env->pContext = 0; - machine->release(); +void SAL_CALL java_env_dispose(uno_Environment * env) { + jni_uno::Context * context = static_cast<jni_uno::Context *>(env->pContext); + jobject async; + { + osl::MutexGuard g(context->mutex); + async = context->asynchronousFinalizer; + context->asynchronousFinalizer = nullptr; + } + if (async != nullptr) { + try { + jvmaccess::VirtualMachine::AttachGuard g( + context->machine->getVirtualMachine()); + JNIEnv * jniEnv = g.getEnvironment(); + jclass cl = jniEnv->FindClass( + "com/sun/star/lib/util/AsynchronousFinalizer"); + if (cl == nullptr) { + jniEnv->ExceptionClear(); + SAL_WARN("bridges", "exception in FindClass"); + } else { + jmethodID id = jniEnv->GetMethodID(cl, "drain", "()V"); + if (id == nullptr) { + jniEnv->ExceptionClear(); + SAL_WARN("bridges", "exception in GetMethodID"); + } else { + jniEnv->CallObjectMethod(async, id); + if (jniEnv->ExceptionOccurred()) { + jniEnv->ExceptionClear(); + SAL_WARN("bridges", "exception in CallObjectMethod"); + } + } + } + jniEnv->DeleteGlobalRef(async); + } catch (jvmaccess::VirtualMachine::AttachGuard::CreationException &) { + SAL_WARN( + "bridges", + "jvmaccess::VirtualMachine::AttachGuard::CreationException"); + } + } } + +void SAL_CALL java_env_disposing(uno_Environment * env) { + java_env_dispose(env); + delete static_cast<jni_uno::Context *>(env->pContext); } #ifdef DISABLE_DYNLOADING @@ -434,14 +464,53 @@ void SAL_CALL java_env_disposing( uno_Environment * java_env ) SAL_DLLPUBLIC_EXPORT void SAL_CALL uno_initEnvironment( uno_Environment * java_env ) SAL_THROW_EXTERN_C() { + java_env->pContext = new jni_uno::Context( + static_cast<jvmaccess::UnoVirtualMachine *>(java_env->pContext)); + java_env->dispose = java_env_dispose; java_env->environmentDisposing = java_env_disposing; java_env->pExtEnv = 0; // no extended support - assert(java_env->pContext != 0); - - ::jvmaccess::UnoVirtualMachine * machine = - reinterpret_cast< ::jvmaccess::UnoVirtualMachine * >( - java_env->pContext ); - machine->acquire(); + try { + jvmaccess::VirtualMachine::AttachGuard g( + static_cast<jni_uno::Context *>(java_env->pContext)->machine + ->getVirtualMachine()); + JNIEnv * jniEnv = g.getEnvironment(); + jclass cl = jniEnv->FindClass( + "com/sun/star/lib/util/AsynchronousFinalizer"); + if (cl == nullptr) { + jniEnv->ExceptionClear(); + SAL_WARN("bridges", "exception in FindClass"); + //TODO: report failure + } else { + jmethodID id = jniEnv->GetMethodID(cl, "<init>", "()V"); + if (id == nullptr) { + jniEnv->ExceptionClear(); + SAL_WARN("bridges", "exception in GetMethodID"); + //TODO: report failure + } else { + jobject o = jniEnv->NewObject(cl, id); + if (o == nullptr) { + jniEnv->ExceptionClear(); + SAL_WARN("bridges", "exception in NewObject"); + //TODO: report failure + } else { + o = jniEnv->NewGlobalRef(o); + if (o == nullptr) { + jniEnv->ExceptionClear(); + SAL_WARN("bridges", "exception in NewGlobalRef"); + //TODO: report failure + } else { + (static_cast<jni_uno::Context *>(java_env->pContext)-> + asynchronousFinalizer) + = o; + } + } + } + } + } catch (jvmaccess::VirtualMachine::AttachGuard::CreationException &) { + SAL_WARN( + "bridges", + "jvmaccess::VirtualMachine::AttachGuard::CreationException"); + } } #ifdef DISABLE_DYNLOADING diff --git a/bridges/source/jni_uno/jni_bridge.h b/bridges/source/jni_uno/jni_bridge.h index e1a2aadecbb6..7c5bf379a301 100644 --- a/bridges/source/jni_uno/jni_bridge.h +++ b/bridges/source/jni_uno/jni_bridge.h @@ -36,6 +36,17 @@ namespace jni_uno { +struct Context: boost::noncopyable { + explicit Context( + rtl::Reference<jvmaccess::UnoVirtualMachine> const & theMachine): + machine(theMachine), asynchronousFinalizer(nullptr) + {} + + rtl::Reference<jvmaccess::UnoVirtualMachine> machine; + osl::Mutex mutex; + jobject asynchronousFinalizer; +}; + //==== holds environments and mappings ========================================= struct Bridge; struct Mapping : public uno_Mapping diff --git a/bridges/source/jni_uno/jni_info.cxx b/bridges/source/jni_uno/jni_info.cxx index 038d971dc271..aa910f12d5b2 100644 --- a/bridges/source/jni_uno/jni_info.cxx +++ b/bridges/source/jni_uno/jni_info.cxx @@ -724,7 +724,8 @@ JNI_info::JNI_info( m_method_JNI_proxy_create = jni->GetStaticMethodID( (jclass) jo_JNI_proxy.get(), "create", "(JLcom/sun/star/uno/IEnvironment;JJLcom/sun/star/uno/Type;Ljava/lang" - "/String;Ljava/lang/reflect/Constructor;)Ljava/lang/Object;" ); + "/String;Ljava/lang/reflect/Constructor;" + "Lcom/sun/star/lib/util/AsynchronousFinalizer;)Ljava/lang/Object;" ); jni.ensure_no_exception(); assert( 0 != m_method_JNI_proxy_create ); // field JNI_proxy.m_receiver_handle diff --git a/bridges/source/jni_uno/jni_java2uno.cxx b/bridges/source/jni_uno/jni_java2uno.cxx index 9aaa02f13994..086399e26dd0 100644 --- a/bridges/source/jni_uno/jni_java2uno.cxx +++ b/bridges/source/jni_uno/jni_java2uno.cxx @@ -58,7 +58,7 @@ jobject Bridge::map_to_java( oid.pData, (typelib_InterfaceTypeDescription *)info->m_td.get() ); // create java and register java proxy - jvalue args2[ 7 ]; + jvalue args2[ 8 ]; acquire(); args2[ 0 ].j = reinterpret_cast< sal_Int64 >( this ); (*pUnoI->acquire)( pUnoI ); @@ -69,6 +69,12 @@ jobject Bridge::map_to_java( args2[ 4 ].l = info->m_type; args2[ 5 ].l = jo_oid.get(); args2[ 6 ].l = info->m_proxy_ctor; + jni_uno::Context * context = static_cast<jni_uno::Context *>( + m_java_env->pContext); + { + osl::MutexGuard g(context->mutex); + args2[ 7 ].l = context->asynchronousFinalizer; + } jo_iface = jni->CallStaticObjectMethodA( m_jni_info->m_class_JNI_proxy, m_jni_info->m_method_JNI_proxy_create, args2 ); @@ -373,8 +379,8 @@ JNICALL Java_com_sun_star_bridges_jni_1uno_JNI_1proxy_dispatch_1call( JNI_context jni( jni_info, jni_env, static_cast< jobject >( - reinterpret_cast< ::jvmaccess::UnoVirtualMachine * >( - bridge->m_java_env->pContext )->getClassLoader() ) ); + static_cast<Context *>(bridge->m_java_env->pContext)->machine + ->getClassLoader())); OUString method_name; @@ -620,8 +626,8 @@ JNICALL Java_com_sun_star_bridges_jni_1uno_JNI_1proxy_finalize__J( JNI_context jni( jni_info, jni_env, static_cast< jobject >( - reinterpret_cast< ::jvmaccess::UnoVirtualMachine * >( - bridge->m_java_env->pContext )->getClassLoader() ) ); + static_cast<Context *>(bridge->m_java_env->pContext)->machine + ->getClassLoader())); uno_Interface * pUnoI = reinterpret_cast< uno_Interface * >( jni->GetLongField( diff --git a/bridges/source/jni_uno/jni_uno2java.cxx b/bridges/source/jni_uno/jni_uno2java.cxx index d84acf3a931c..c50be5de9a37 100644 --- a/bridges/source/jni_uno/jni_uno2java.cxx +++ b/bridges/source/jni_uno/jni_uno2java.cxx @@ -128,8 +128,7 @@ void Bridge::call_java( assert( function_pos_offset == 0 || function_pos_offset == 1 ); JNI_guarded_context jni( - m_jni_info, reinterpret_cast< ::jvmaccess::UnoVirtualMachine * >( - m_java_env->pContext ) ); + m_jni_info, static_cast<Context *>(m_java_env->pContext)->machine); // assure fully initialized iface_td: ::com::sun::star::uno::TypeDescription iface_holder; @@ -529,8 +528,7 @@ void SAL_CALL UNO_proxy_free( uno_ExtEnvironment * env, void * proxy ) { JNI_guarded_context jni( bridge->m_jni_info, - reinterpret_cast< ::jvmaccess::UnoVirtualMachine * >( - bridge->m_java_env->pContext ) ); + static_cast<Context *>(bridge->m_java_env->pContext)->machine); jni->DeleteGlobalRef( that->m_javaI ); jni->DeleteGlobalRef( that->m_jo_oid ); @@ -674,8 +672,8 @@ void SAL_CALL UNO_proxy_dispatch( JNI_info const * jni_info = bridge->m_jni_info; JNI_guarded_context jni( jni_info, - reinterpret_cast< ::jvmaccess::UnoVirtualMachine * >( - bridge->m_java_env->pContext ) ); + (static_cast<Context *>(bridge->m_java_env->pContext) + ->machine)); JNI_interface_type_info const * info = static_cast< JNI_interface_type_info const * >( diff --git a/cppuhelper/source/component_context.cxx b/cppuhelper/source/component_context.cxx index 16642e9133fb..53b5eb000468 100644 --- a/cppuhelper/source/component_context.cxx +++ b/cppuhelper/source/component_context.cxx @@ -731,6 +731,22 @@ void ComponentContext::disposing() for ( ; iPos != iEnd; ++iPos ) delete iPos->second; m_map.clear(); + + // Hack to terminate any JNI bridge's AsynchronousFinalizer thread (as JNI + // proxies get finalized with arbitrary delay, so the bridge typically does + // not dispose itself early enough before the process exits): + uno_Environment ** envs; + sal_Int32 envCount; + uno_getRegisteredEnvironments( + &envs, &envCount, &rtl_allocateMemory, OUString("java").pData); + assert(envCount >= 0); + assert(envCount == 0 || envs != nullptr); + for (sal_Int32 i = 0; i != envCount; ++i) { + assert(envs[i] != nullptr); + assert(envs[i]->dispose != nullptr); + (*envs[i]->dispose)(envs[i]); + } + rtl_freeMemory(envs); } ComponentContext::ComponentContext( diff --git a/jurt/com/sun/star/lib/uno/bridges/java_remote/ProxyFactory.java b/jurt/com/sun/star/lib/uno/bridges/java_remote/ProxyFactory.java index edcceca44757..e249062fa07e 100644 --- a/jurt/com/sun/star/lib/uno/bridges/java_remote/ProxyFactory.java +++ b/jurt/com/sun/star/lib/uno/bridges/java_remote/ProxyFactory.java @@ -57,6 +57,10 @@ final class ProxyFactory { } } + public void dispose() throws InterruptedException { + asynchronousFinalizer.drain(); + } + public static XBridge getBridge(Object obj) { if (Proxy.isProxyClass(obj.getClass())) { InvocationHandler h = Proxy.getInvocationHandler(obj); @@ -126,13 +130,10 @@ final class ProxyFactory { @Override protected void finalize() { - AsynchronousFinalizer.add(new AsynchronousFinalizer.Job() { + decrementDebugCount(); + asynchronousFinalizer.add(new AsynchronousFinalizer.Job() { public void run() throws Throwable { - try { - request("release", null); - } finally { - decrementDebugCount(); - } + request("release", null); } }); } @@ -187,4 +188,6 @@ final class ProxyFactory { private final RequestHandler requestHandler; private final XBridge bridge; + private final AsynchronousFinalizer asynchronousFinalizer = + new AsynchronousFinalizer(); } diff --git a/jurt/com/sun/star/lib/uno/bridges/java_remote/java_remote_bridge.java b/jurt/com/sun/star/lib/uno/bridges/java_remote/java_remote_bridge.java index 722f825e6ba5..48784283a99a 100644 --- a/jurt/com/sun/star/lib/uno/bridges/java_remote/java_remote_bridge.java +++ b/jurt/com/sun/star/lib/uno/bridges/java_remote/java_remote_bridge.java @@ -499,7 +499,12 @@ public class java_remote_bridge try { _messageDispatcher.terminate(); - _xConnection.close(); + try { + _xConnection.close(); + } catch (com.sun.star.io.IOException e) { + System.err.println( + getClass().getName() + ".dispose - IOException:" + e); + } if (Thread.currentThread() != _messageDispatcher && _messageDispatcher.isAlive()) @@ -519,6 +524,8 @@ public class java_remote_bridge // assert _java_environment instanceof java_environment; ((java_environment) _java_environment).revokeAllProxies(); + proxyFactory.dispose(); + if (DEBUG) { if (_life_count != 0) { System.err.println(getClass().getName() @@ -535,9 +542,6 @@ public class java_remote_bridge } catch (InterruptedException e) { System.err.println(getClass().getName() + ".dispose - InterruptedException:" + e); - } catch (com.sun.star.io.IOException e) { - System.err.println(getClass().getName() + ".dispose - IOException:" - + e); } } diff --git a/jurt/com/sun/star/lib/util/AsynchronousFinalizer.java b/jurt/com/sun/star/lib/util/AsynchronousFinalizer.java index 4dcd69a97e1f..71743b25241b 100644 --- a/jurt/com/sun/star/lib/util/AsynchronousFinalizer.java +++ b/jurt/com/sun/star/lib/util/AsynchronousFinalizer.java @@ -35,6 +35,37 @@ import java.util.LinkedList; * long-running finalize methods, this class could be removed again.</p> */ public final class AsynchronousFinalizer { + public AsynchronousFinalizer() { + thread = new Thread("AsynchronousFinalizer") { + @Override + public void run() { + for (;;) { + Job j; + synchronized (queue) { + for (;;) { + if (done) { + return; + } + if (!queue.isEmpty()) { + break; + } + try { + queue.wait(); + } catch (InterruptedException e) { + return; + } + } + j = queue.remove(0); + } + try { + j.run(); + } catch (Throwable e) {} + } + } + }; + thread.start(); + } + /** * Add a job to be executed asynchronously. * @@ -43,7 +74,7 @@ public final class AsynchronousFinalizer { * * @param job represents the body of some finalize method; must not be null. */ - public static void add(Job job) { + public void add(Job job) { synchronized (queue) { boolean first = queue.isEmpty(); queue.add(job); @@ -53,6 +84,14 @@ public final class AsynchronousFinalizer { } } + public void drain() throws InterruptedException { + synchronized (queue) { + done = true; + queue.notify(); + } + thread.join(); + } + /** * An interface to represent bodies of finalize methods. * @@ -65,31 +104,7 @@ public final class AsynchronousFinalizer { void run() throws Throwable; } - private static final LinkedList<Job> queue = new LinkedList<Job>(); - - static { - Thread t = new Thread("AsynchronousFinalizer") { - @Override - public void run() { - for (;;) { - Job j; - synchronized (queue) { - while (queue.isEmpty()) { - try { - queue.wait(); - } catch (InterruptedException e) {} - } - j = queue.remove(0); - } - try { - j.run(); - } catch (Throwable e) {} - } - } - }; - t.setDaemon(true); - t.start(); - } - - private AsynchronousFinalizer() {} + private final LinkedList<Job> queue = new LinkedList<Job>(); + private final Thread thread; + private boolean done = false; } |