Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[mono] More domain cleanups #50479

Merged
merged 8 commits into from
Apr 6, 2021
351 changes: 4 additions & 347 deletions src/mono/mono/metadata/appdomain.c

Large diffs are not rendered by default.

20 changes: 10 additions & 10 deletions src/mono/mono/metadata/appdomain.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,13 @@ mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *co
MONO_API MonoDomain *
mono_domain_get (void);

MONO_API MonoDomain *
MONO_API MONO_RT_EXTERNAL_ONLY MonoDomain *
mono_domain_get_by_id (int32_t domainid);

MONO_API int32_t
MONO_API MONO_RT_EXTERNAL_ONLY int32_t
mono_domain_get_id (MonoDomain *domain);

MONO_API const char *
MONO_API MONO_RT_EXTERNAL_ONLY const char *
mono_domain_get_friendly_name (MonoDomain *domain);

MONO_API MONO_RT_EXTERNAL_ONLY mono_bool
Expand All @@ -91,16 +91,16 @@ mono_domain_set_internal (MonoDomain *domain);
MONO_API MONO_RT_EXTERNAL_ONLY void
mono_domain_unload (MonoDomain *domain);

MONO_API void
MONO_API MONO_RT_EXTERNAL_ONLY void
mono_domain_try_unload (MonoDomain *domain, MonoObject **exc);

MONO_API mono_bool
MONO_API MONO_RT_EXTERNAL_ONLY mono_bool
mono_domain_is_unloading (MonoDomain *domain);

MONO_API MONO_RT_EXTERNAL_ONLY MonoDomain *
mono_domain_from_appdomain (MonoAppDomain *appdomain);

MONO_API void
MONO_API MONO_RT_EXTERNAL_ONLY void
mono_domain_foreach (MonoDomainFunc func, void* user_data);

MONO_API MONO_RT_EXTERNAL_ONLY MonoAssembly *
Expand All @@ -112,7 +112,7 @@ mono_domain_ensure_entry_assembly (MonoDomain *domain, MonoAssembly *assembly);
MONO_API MONO_RT_EXTERNAL_ONLY mono_bool
mono_domain_finalize (MonoDomain *domain, uint32_t timeout);

MONO_API void
MONO_API MONO_RT_EXTERNAL_ONLY void
mono_domain_free (MonoDomain *domain, mono_bool force);

MONO_API mono_bool
Expand All @@ -130,13 +130,13 @@ mono_context_init (MonoDomain *domain);
MONO_API MONO_RT_EXTERNAL_ONLY void
mono_context_set (MonoAppContext *new_context);

MONO_API MonoAppContext *
MONO_API MONO_RT_EXTERNAL_ONLY MonoAppContext *
mono_context_get (void);

MONO_API int32_t
MONO_API MONO_RT_EXTERNAL_ONLY int32_t
mono_context_get_id (MonoAppContext *context);

MONO_API int32_t
MONO_API MONO_RT_EXTERNAL_ONLY int32_t
mono_context_get_domain_id (MonoAppContext *context);

MONO_API MonoJitInfo *
Expand Down
221 changes: 215 additions & 6 deletions src/mono/mono/metadata/assembly-load-context.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,25 @@
#include "mono/utils/mono-compiler.h"

#include "mono/metadata/assembly.h"
#include "mono/metadata/assembly-internals.h"
#include "mono/metadata/domain-internals.h"
#include "mono/metadata/exception-internals.h"
#include "mono/metadata/icall-decl.h"
#include "mono/metadata/loader-internals.h"
#include "mono/metadata/loaded-images-internals.h"
#include "mono/metadata/mono-private-unstable.h"
#include "mono/metadata/mono-debug.h"
#include "mono/utils/mono-error-internals.h"
#include "mono/utils/mono-logger-internals.h"

GENERATE_GET_CLASS_WITH_CACHE (assembly_load_context, "System.Runtime.Loader", "AssemblyLoadContext");
static GENERATE_GET_CLASS_WITH_CACHE (assembly, "System.Reflection", "Assembly");

static GSList *alcs;
static MonoAssemblyLoadContext *default_alc;
static MonoCoopMutex alc_list_lock; /* Used when accessing 'alcs' */
/* Protected by alc_list_lock */
static GSList *loaded_assemblies;

static inline void
alcs_lock (void)
Expand Down Expand Up @@ -92,17 +97,18 @@ mono_alc_cleanup_assemblies (MonoAssemblyLoadContext *alc)
// The minimum refcount on assemblies is 2: one for the domain and one for the ALC.
// The domain refcount might be less than optimal on netcore, but its removal is too likely to cause issues for now.
GSList *tmp;
MonoDomain *domain = mono_get_root_domain ();

// Remove the assemblies from domain_assemblies
mono_domain_assemblies_lock (domain);
// Remove the assemblies from loaded_assemblies
for (tmp = alc->loaded_assemblies; tmp; tmp = tmp->next) {
MonoAssembly *assembly = (MonoAssembly *)tmp->data;
domain->domain_assemblies = g_slist_remove (domain->domain_assemblies, assembly);

alcs_lock ();
loaded_assemblies = g_slist_remove (loaded_assemblies, assembly);
alcs_unlock ();

mono_assembly_decref (assembly);
mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Unloading ALC [%p], removing assembly %s[%p] from domain_assemblies, ref_count=%d\n", alc, assembly->aname.name, assembly, assembly->ref_count);
mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Unloading ALC [%p], removing assembly %s[%p] from loaded_assemblies, ref_count=%d\n", alc, assembly->aname.name, assembly, assembly->ref_count);
}
mono_domain_assemblies_unlock (domain);

// Release the GC roots
for (tmp = alc->loaded_assemblies; tmp; tmp = tmp->next) {
Expand Down Expand Up @@ -262,6 +268,135 @@ ves_icall_System_Runtime_Loader_AssemblyLoadContext_GetLoadContextForAssembly (M
return (gpointer)alc->gchandle;
}

static gboolean
add_assembly_to_array (MonoArrayHandle dest, int dest_idx, MonoAssembly* assm, MonoError *error)
{
HANDLE_FUNCTION_ENTER ();
error_init (error);
MonoReflectionAssemblyHandle assm_obj = mono_assembly_get_object_handle (assm, error);
goto_if_nok (error, leave);
MONO_HANDLE_ARRAY_SETREF (dest, dest_idx, assm_obj);
leave:
HANDLE_FUNCTION_RETURN_VAL (is_ok (error));
}

MonoArrayHandle
ves_icall_System_Runtime_Loader_AssemblyLoadContext_InternalGetLoadedAssemblies (MonoError *error)
{
GPtrArray *assemblies = mono_alc_get_all_loaded_assemblies ();

MonoArrayHandle res = mono_array_new_handle (mono_class_get_assembly_class (), assemblies->len, error);
goto_if_nok (error, leave);
for (int i = 0; i < assemblies->len; ++i) {
if (!add_assembly_to_array (res, i, (MonoAssembly *)g_ptr_array_index (assemblies, i), error))
goto leave;
}

leave:
g_ptr_array_free (assemblies, TRUE);
return res;
}

static
MonoAssembly *
mono_alc_load_file (MonoAssemblyLoadContext *alc, MonoStringHandle fname, MonoAssembly *executing_assembly, MonoAssemblyContextKind asmctx, MonoError *error)
{
MonoAssembly *ass = NULL;
HANDLE_FUNCTION_ENTER ();
char *filename = NULL;
if (MONO_HANDLE_IS_NULL (fname)) {
mono_error_set_argument_null (error, "assemblyFile", "");
goto leave;
}

filename = mono_string_handle_to_utf8 (fname, error);
goto_if_nok (error, leave);

if (!g_path_is_absolute (filename)) {
mono_error_set_argument (error, "assemblyFile", "Absolute path information is required.");
goto leave;
}

MonoImageOpenStatus status;
MonoAssemblyOpenRequest req;
mono_assembly_request_prepare_open (&req, asmctx, alc);
req.requesting_assembly = executing_assembly;
ass = mono_assembly_request_open (filename, &req, &status);
if (!ass) {
if (status == MONO_IMAGE_IMAGE_INVALID)
mono_error_set_bad_image_by_name (error, filename, "Invalid Image: %s", filename);
else
mono_error_set_simple_file_not_found (error, filename);
}

leave:
g_free (filename);
HANDLE_FUNCTION_RETURN_VAL (ass);
}

MonoReflectionAssemblyHandle
ves_icall_System_Runtime_Loader_AssemblyLoadContext_InternalLoadFile (gpointer alc_ptr, MonoStringHandle fname, MonoStackCrawlMark *stack_mark, MonoError *error)
{
MonoReflectionAssemblyHandle result = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
MonoAssemblyLoadContext *alc = (MonoAssemblyLoadContext *)alc_ptr;

MonoAssembly *executing_assembly;
executing_assembly = mono_runtime_get_caller_from_stack_mark (stack_mark);
MonoAssembly *ass = mono_alc_load_file (alc, fname, executing_assembly, mono_alc_is_default (alc) ? MONO_ASMCTX_LOADFROM : MONO_ASMCTX_INDIVIDUAL, error);
goto_if_nok (error, leave);

result = mono_assembly_get_object_handle (ass, error);

leave:
return result;
}

static MonoAssembly*
mono_alc_load_raw_bytes (MonoAssemblyLoadContext *alc, guint8 *assembly_data, guint32 raw_assembly_len, guint8 *raw_symbol_data, guint32 raw_symbol_len, MonoError *error)
{
MonoAssembly *ass = NULL;
MonoImageOpenStatus status;
MonoImage *image = mono_image_open_from_data_internal (alc, (char*)assembly_data, raw_assembly_len, TRUE, NULL, FALSE, NULL, NULL);

if (!image) {
mono_error_set_bad_image_by_name (error, "In memory assembly", "0x%p", assembly_data);
return ass;
}

if (raw_symbol_data)
mono_debug_open_image_from_memory (image, raw_symbol_data, raw_symbol_len);

MonoAssemblyLoadRequest req;
mono_assembly_request_prepare_load (&req, MONO_ASMCTX_INDIVIDUAL, alc);
ass = mono_assembly_request_load_from (image, "", &req, &status);

if (!ass) {
mono_image_close (image);
mono_error_set_bad_image_by_name (error, "In Memory assembly", "0x%p", assembly_data);
return ass;
}

/* Clear the reference added by mono_image_open_from_data_internal above */
mono_image_close (image);

return ass;
}

MonoReflectionAssemblyHandle
ves_icall_System_Runtime_Loader_AssemblyLoadContext_InternalLoadFromStream (gpointer native_alc, gpointer raw_assembly_ptr, gint32 raw_assembly_len, gpointer raw_symbols_ptr, gint32 raw_symbols_len, MonoError *error)
{
MonoAssemblyLoadContext *alc = (MonoAssemblyLoadContext *)native_alc;
MonoReflectionAssemblyHandle result = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
MonoAssembly *assm = NULL;
assm = mono_alc_load_raw_bytes (alc, (guint8 *)raw_assembly_ptr, raw_assembly_len, (guint8 *)raw_symbols_ptr, raw_symbols_len, error);
goto_if_nok (error, leave);

result = mono_assembly_get_object_handle (assm, error);

leave:
return result;
}

gboolean
mono_alc_is_default (MonoAssemblyLoadContext *alc)
{
Expand Down Expand Up @@ -420,3 +555,77 @@ mono_alc_invoke_resolve_using_resolve_satellite_nofail (MonoAssemblyLoadContext

return result;
}

void
mono_alc_add_assembly (MonoAssemblyLoadContext *alc, MonoAssembly *ass)
{
GSList *tmp;

g_assert (ass);

if (!ass->aname.name)
return;

mono_alc_assemblies_lock (alc);
for (tmp = alc->loaded_assemblies; tmp; tmp = tmp->next) {
if (tmp->data == ass) {
mono_alc_assemblies_unlock (alc);
return;
}
}

mono_assembly_addref (ass);
// Prepending here will break the test suite with frequent InvalidCastExceptions, so we have to append
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fact prepending here doesn't work still annoys me. I wish I'd left more info about why, since it's not obvious months later what the actual problem was.

alc->loaded_assemblies = g_slist_append (alc->loaded_assemblies, ass);
mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Assembly %s[%p] added to ALC (%p), ref_count=%d", ass->aname.name, ass, (gpointer)alc, ass->ref_count);
mono_alc_assemblies_unlock (alc);

alcs_lock ();
loaded_assemblies = g_slist_append (loaded_assemblies, ass);
alcs_unlock ();
}

MonoAssembly*
mono_alc_find_assembly (MonoAssemblyLoadContext *alc, MonoAssemblyName *aname)
{
GSList *tmp;
MonoAssembly *ass;

const MonoAssemblyNameEqFlags eq_flags = MONO_ANAME_EQ_IGNORE_PUBKEY | MONO_ANAME_EQ_IGNORE_VERSION | MONO_ANAME_EQ_IGNORE_CASE;

mono_alc_assemblies_lock (alc);
for (tmp = alc->loaded_assemblies; tmp; tmp = tmp->next) {
ass = (MonoAssembly *)tmp->data;
g_assert (ass != NULL);
// FIXME: Can dynamic assemblies match here for netcore?
if (assembly_is_dynamic (ass) || !mono_assembly_names_equal_flags (aname, &ass->aname, eq_flags))
continue;

mono_alc_assemblies_unlock (alc);
return ass;
}
mono_alc_assemblies_unlock (alc);
return NULL;
}

/*
* mono_alc_get_all_loaded_assemblies:
*
* Return a list of loaded assemblies in all appdomains.
*/
GPtrArray*
mono_alc_get_all_loaded_assemblies (void)
{
GSList *tmp;
GPtrArray *assemblies;
MonoAssembly *ass;

assemblies = g_ptr_array_new ();
alcs_lock ();
for (tmp = loaded_assemblies; tmp; tmp = tmp->next) {
ass = (MonoAssembly *)tmp->data;
g_ptr_array_add (assemblies, ass);
}
alcs_unlock ();
return assemblies;
}
9 changes: 8 additions & 1 deletion src/mono/mono/metadata/class-internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -1536,6 +1536,13 @@ m_field_get_offset (MonoClassField *field)
* the lifetime of the image/class/method.
*/

static inline MonoMemoryManager*
mono_mem_manager_get_ambient (void)
{
// FIXME: All callers should get a MemoryManager from their callers or context
return (MonoMemoryManager *)mono_alc_get_default ()->memory_manager;
}

static inline MonoMemoryManager*
m_image_get_mem_manager (MonoImage *image)
{
Expand Down Expand Up @@ -1582,7 +1589,7 @@ static inline MonoMemoryManager*
m_method_get_mem_manager (MonoMethod *method)
{
// FIXME:
return mono_domain_memory_manager (mono_get_root_domain ());
return (MonoMemoryManager *)mono_alc_get_default ()->memory_manager;
}

static inline void *
Expand Down
Loading