Apply changes from https://github.com/dotnet/runtime/commit/eb1756e97d23df13bc6fe798e...
[mono-project.git] / mono / metadata / loaded-images.c
blobc0fa0d5e6aa3acf4e6341798486a031e315c3010
1 #include "config.h"
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"
8 void
9 mono_loaded_images_init (MonoLoadedImages *li, MonoAssemblyLoadContext *owner)
11 li->owner = 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);
16 void
17 mono_loaded_images_cleanup (MonoLoadedImages *li, gboolean shutdown)
19 if (shutdown) {
20 GHashTableIter iter;
21 MonoImage *image;
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;
36 void
37 mono_loaded_images_free (MonoLoadedImages *li)
39 mono_loaded_images_cleanup (li, FALSE);
40 g_free (li);
43 GHashTable *
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];
52 GHashTable *
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
66 * of them lost) */
67 MonoAssemblyLoadContext *alc = mono_image_get_alc (image);
68 return mono_alc_get_loaded_images (alc);
71 /**
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
79 gboolean
80 mono_loaded_images_remove_image (MonoImage *image)
82 char *name = NULL;
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.
88 mono_images_lock ();
90 if (mono_atomic_dec_i32 (&image->ref_count) > 0)
91 goto done;
93 MonoLoadedImages *li;
94 li = loaded_images_get_owner (image);
95 if (!li) {
96 /* we weren't registered; maybe lost to another image */
97 proceed = TRUE;
98 goto done;
100 GHashTable *loaded_images, *loaded_images_by_name;
101 MonoImage *image2;
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);
106 name = image->name;
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;
111 #endif
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);
120 proceed = TRUE;
121 #ifdef ENABLE_NETCORE
122 g_free (name_with_culture);
123 #endif
124 done:
125 mono_images_unlock ();
127 return proceed;
131 MonoLoadedImages*
132 mono_image_get_loaded_images_for_modules (MonoImage *image)
134 #ifndef ENABLE_NETCORE
135 return mono_get_global_loaded_images ();
136 #else
137 g_assert_not_reached ();
138 #endif