diff --git a/src/native/clr/host/bridge-processing.cc b/src/native/clr/host/bridge-processing.cc index a72e75d902a..c34b0b6d945 100644 --- a/src/native/clr/host/bridge-processing.cc +++ b/src/native/clr/host/bridge-processing.cc @@ -17,8 +17,8 @@ void BridgeProcessing::initialize_on_runtime_init (JNIEnv *env, jclass runtimeCl abort_unless (GCUserPeer_class != nullptr && GCUserPeer_ctor != nullptr, "Failed to load mono.android.GCUserPeer!"); } -BridgeProcessing::BridgeProcessing (MarkCrossReferencesArgs *args) noexcept - : env{ OSBridge::ensure_jnienv () }, +BridgeProcessing::BridgeProcessing (JNIEnv *jniEnv, MarkCrossReferencesArgs *args) noexcept + : env{ jniEnv }, cross_refs{ args } { if (args == nullptr) [[unlikely]] { diff --git a/src/native/clr/host/gc-bridge.cc b/src/native/clr/host/gc-bridge.cc index 6bf3a387e96..663e18dd08e 100644 --- a/src/native/clr/host/gc-bridge.cc +++ b/src/native/clr/host/gc-bridge.cc @@ -53,7 +53,6 @@ void GCBridge::mark_cross_references (MarkCrossReferencesArgs *args) noexcept abort_if_invalid_pointer_argument (args, "args"); abort_unless (args->Components != nullptr || args->ComponentCount == 0, "Components must not be null if ComponentCount is greater than 0"); abort_unless (args->CrossReferences != nullptr || args->CrossReferenceCount == 0, "CrossReferences must not be null if CrossReferenceCount is greater than 0"); - log_mark_cross_references_args_if_enabled (args); shared_args.store (args); shared_args_semaphore.release (); @@ -64,14 +63,17 @@ void GCBridge::bridge_processing () noexcept abort_unless (bridge_processing_started_callback != nullptr, "GC bridge processing started callback is not set"); abort_unless (bridge_processing_finished_callback != nullptr, "GC bridge processing finished callback is not set"); + JNIEnv *env = OSBridge::ensure_jnienv (); + while (true) { // wait until mark cross references args are set by the GC callback shared_args_semaphore.acquire (); MarkCrossReferencesArgs *args = shared_args.load (); + log_mark_cross_references_args_if_enabled (env, args); bridge_processing_started_callback (args); - BridgeProcessing bridge_processing {args}; + BridgeProcessing bridge_processing {env, args}; bridge_processing.process (); bridge_processing_finished_callback (args); @@ -79,7 +81,7 @@ void GCBridge::bridge_processing () noexcept } [[gnu::always_inline]] -void GCBridge::log_mark_cross_references_args_if_enabled (MarkCrossReferencesArgs *args) noexcept +void GCBridge::log_mark_cross_references_args_if_enabled (JNIEnv *env, MarkCrossReferencesArgs *args) noexcept { if (!Logger::gc_spew_enabled ()) [[likely]] { return; @@ -87,8 +89,6 @@ void GCBridge::log_mark_cross_references_args_if_enabled (MarkCrossReferencesArg log_info (LOG_GC, "cross references callback invoked with {} sccs and {} xrefs.", args->ComponentCount, args->CrossReferenceCount); - JNIEnv *env = OSBridge::ensure_jnienv (); - for (size_t i = 0; i < args->ComponentCount; ++i) { const StronglyConnectedComponent &scc = args->Components [i]; log_info (LOG_GC, "group {} with {} objects", i, scc.Count); diff --git a/src/native/clr/include/host/bridge-processing.hh b/src/native/clr/include/host/bridge-processing.hh index 0fdb56d931e..7d12cc47934 100644 --- a/src/native/clr/include/host/bridge-processing.hh +++ b/src/native/clr/include/host/bridge-processing.hh @@ -23,7 +23,7 @@ struct CrossReferenceTarget class BridgeProcessing { public: - BridgeProcessing (MarkCrossReferencesArgs *args) noexcept; + BridgeProcessing (JNIEnv *jniEnv, MarkCrossReferencesArgs *args) noexcept; static void initialize_on_runtime_init (JNIEnv *jniEnv, jclass runtimeClass) noexcept; void process () noexcept; private: diff --git a/src/native/clr/include/host/gc-bridge.hh b/src/native/clr/include/host/gc-bridge.hh index 80c0ac68132..86d62ccb4f3 100644 --- a/src/native/clr/include/host/gc-bridge.hh +++ b/src/native/clr/include/host/gc-bridge.hh @@ -95,7 +95,7 @@ namespace xamarin::android { static void bridge_processing () noexcept; static void mark_cross_references (MarkCrossReferencesArgs *args) noexcept; - static void log_mark_cross_references_args_if_enabled (MarkCrossReferencesArgs *args) noexcept; + static void log_mark_cross_references_args_if_enabled (JNIEnv *env, MarkCrossReferencesArgs *args) noexcept; static void log_handle_context (JNIEnv *env, HandleContext *ctx) noexcept; }; } diff --git a/src/native/clr/include/host/os-bridge.hh b/src/native/clr/include/host/os-bridge.hh index b9da49b07f9..f04067fc969 100644 --- a/src/native/clr/include/host/os-bridge.hh +++ b/src/native/clr/include/host/os-bridge.hh @@ -1,6 +1,7 @@ #pragma once #include +#include #include @@ -43,13 +44,30 @@ namespace xamarin::android { args.version = JNI_VERSION_1_6; args.name = nullptr; args.group = nullptr; - jvm->AttachCurrentThread (&env, &args); + jvm->AttachCurrentThreadAsDaemon (&env, &args); abort_unless (env != nullptr, "Unable to get a valid pointer to JNIEnv"); + + (void) pthread_once (&thread_local_env_init_key, make_key); + pthread_setspecific (thread_local_env_key, env); } return env; } + private: + static inline pthread_key_t thread_local_env_key = {}; + static inline pthread_once_t thread_local_env_init_key = PTHREAD_ONCE_INIT; + + static void make_key () noexcept + { + pthread_key_create (&thread_local_env_key, &detach_thread_from_jni); + } + + static void detach_thread_from_jni ([[maybe_unused]] void* unused) noexcept + { + jvm->DetachCurrentThread (); + } + private: static auto _monodroid_gref_inc () noexcept -> int; static auto _monodroid_gref_dec () noexcept -> int;