3 #include "mono/metadata/loaded-images-internals.h"
4 #include "mono/metadata/image-internals.h"
5 #include "mono/metadata/metadata-internals.h"
6 #include "mono/utils/mono-logger-internals.h"
9 mono_loaded_images_init (MonoLoadedImages
*li
, MonoAssemblyLoadContext
*owner
)
12 for (int hash_idx
= 0; hash_idx
< MONO_LOADED_IMAGES_HASH_COUNT
; hash_idx
++)
13 li
->loaded_images_hashes
[hash_idx
] = g_hash_table_new (g_str_hash
, g_str_equal
);
17 mono_loaded_images_cleanup (MonoLoadedImages
*li
, gboolean shutdown
)
23 // If an assembly image is still loaded at shutdown, this could indicate managed code is still running.
24 // Reflection-only images being still loaded doesn't indicate anything as harmful, so we don't check for it.
25 g_hash_table_iter_init (&iter
, mono_loaded_images_get_hash (li
, FALSE
));
26 while (g_hash_table_iter_next (&iter
, NULL
, (void**)&image
))
27 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Assembly image '%s' [%p] still loaded at shutdown.", image
->name
, image
);
30 for (int hash_idx
= 0; hash_idx
< MONO_LOADED_IMAGES_HASH_COUNT
; hash_idx
++) {
31 g_hash_table_destroy (li
->loaded_images_hashes
[hash_idx
]);
32 li
->loaded_images_hashes
[hash_idx
] = NULL
;
37 mono_loaded_images_free (MonoLoadedImages
*li
)
39 mono_loaded_images_cleanup (li
, FALSE
);
44 mono_loaded_images_get_hash (MonoLoadedImages
*li
, gboolean refonly
)
46 g_assert (li
!= NULL
);
47 GHashTable
**loaded_images_hashes
= &li
->loaded_images_hashes
[0];
48 int idx
= refonly
? MONO_LOADED_IMAGES_HASH_PATH_REFONLY
: MONO_LOADED_IMAGES_HASH_PATH
;
49 return loaded_images_hashes
[idx
];
53 mono_loaded_images_get_by_name_hash (MonoLoadedImages
*li
, gboolean refonly
)
55 g_assert (li
!= NULL
);
56 GHashTable
**loaded_images_hashes
= &li
->loaded_images_hashes
[0];
57 int idx
= refonly
? MONO_LOADED_IMAGES_HASH_NAME_REFONLY
: MONO_LOADED_IMAGES_HASH_NAME
;
58 return loaded_images_hashes
[idx
];
61 static MonoLoadedImages
*
62 loaded_images_get_owner (MonoImage
*image
)
64 /* image->alc could be NULL if we're closing an image that wasn't
65 * registered yet (for example if two threads raced to open it and one
67 MonoAssemblyLoadContext
*alc
= mono_image_get_alc (image
);
68 return mono_alc_get_loaded_images (alc
);
72 * Atomically decrements the image refcount and removes it from the loaded
73 * images hashes if the refcount becomes zero.
75 * Returns TRUE if image unloading should proceed or FALSE otherwise.
77 * LOCKING: takes the images lock
80 mono_loaded_images_remove_image (MonoImage
*image
)
83 gboolean proceed
= FALSE
;
85 * Atomically decrement the refcount and remove ourselves from the hash tables, so
86 * register_image () can't grab an image which is being closed.
90 if (mono_atomic_dec_i32 (&image
->ref_count
) > 0)
94 li
= loaded_images_get_owner (image
);
96 /* we weren't registered; maybe lost to another image */
100 GHashTable
*loaded_images
, *loaded_images_by_name
;
103 loaded_images
= mono_loaded_images_get_hash (li
, image
->ref_only
);
104 loaded_images_by_name
= mono_loaded_images_get_by_name_hash (li
, image
->ref_only
);
107 #ifdef ENABLE_NETCORE
108 char *name_with_culture
= mono_image_get_name_with_culture_if_needed (image
);
109 if (name_with_culture
)
110 name
= name_with_culture
;
112 image2
= (MonoImage
*)g_hash_table_lookup (loaded_images
, name
);
113 if (image
== image2
) {
114 /* This is not true if we are called from mono_image_open () */
115 g_hash_table_remove (loaded_images
, name
);
117 if (image
->assembly_name
&& (g_hash_table_lookup (loaded_images_by_name
, image
->assembly_name
) == image
))
118 g_hash_table_remove (loaded_images_by_name
, (char *) image
->assembly_name
);
121 #ifdef ENABLE_NETCORE
122 g_free (name_with_culture
);
125 mono_images_unlock ();
132 mono_image_get_loaded_images_for_modules (MonoImage
*image
)
134 #ifndef ENABLE_NETCORE
135 return mono_get_global_loaded_images ();
137 g_assert_not_reached ();