1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
#include "config.h"
#include "mono/metadata/loaded-images-internals.h"
#include "mono/metadata/image-internals.h"
#include "mono/metadata/metadata-internals.h"
#include "mono/utils/mono-logger-internals.h"
void
mono_loaded_images_init (MonoLoadedImages *li, MonoAssemblyLoadContext *owner)
{
li->owner = owner;
for (int hash_idx = 0; hash_idx < MONO_LOADED_IMAGES_HASH_COUNT; hash_idx++)
li->loaded_images_hashes [hash_idx] = g_hash_table_new (g_str_hash, g_str_equal);
}
void
mono_loaded_images_cleanup (MonoLoadedImages *li, gboolean shutdown)
{
if (shutdown) {
GHashTableIter iter;
MonoImage *image;
// If an assembly image is still loaded at shutdown, this could indicate managed code is still running.
// Reflection-only images being still loaded doesn't indicate anything as harmful, so we don't check for it.
g_hash_table_iter_init (&iter, mono_loaded_images_get_hash (li, FALSE));
while (g_hash_table_iter_next (&iter, NULL, (void**)&image))
mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly image '%s' [%p] still loaded at shutdown.", image->name, image);
}
for (int hash_idx = 0; hash_idx < MONO_LOADED_IMAGES_HASH_COUNT; hash_idx++) {
g_hash_table_destroy (li->loaded_images_hashes [hash_idx]);
li->loaded_images_hashes [hash_idx] = NULL;
}
}
void
mono_loaded_images_free (MonoLoadedImages *li)
{
mono_loaded_images_cleanup (li, FALSE);
g_free (li);
}
GHashTable *
mono_loaded_images_get_hash (MonoLoadedImages *li, gboolean refonly)
{
g_assert (li != NULL);
GHashTable **loaded_images_hashes = &li->loaded_images_hashes[0];
int idx = refonly ? MONO_LOADED_IMAGES_HASH_PATH_REFONLY : MONO_LOADED_IMAGES_HASH_PATH;
return loaded_images_hashes [idx];
}
GHashTable *
mono_loaded_images_get_by_name_hash (MonoLoadedImages *li, gboolean refonly)
{
g_assert (li != NULL);
GHashTable **loaded_images_hashes = &li->loaded_images_hashes[0];
int idx = refonly ? MONO_LOADED_IMAGES_HASH_NAME_REFONLY : MONO_LOADED_IMAGES_HASH_NAME;
return loaded_images_hashes [idx];
}
static MonoLoadedImages *
loaded_images_get_owner (MonoImage *image)
{
/* image->alc could be NULL if we're closing an image that wasn't
* registered yet (for example if two threads raced to open it and one
* of them lost) */
MonoAssemblyLoadContext *alc = mono_image_get_alc (image);
return mono_alc_get_loaded_images (alc);
}
/**
* Atomically decrements the image refcount and removes it from the loaded
* images hashes if the refcount becomes zero.
*
* Returns TRUE if image unloading should proceed or FALSE otherwise.
*
* LOCKING: takes the images lock
*/
gboolean
mono_loaded_images_remove_image (MonoImage *image)
{
char *name = NULL;
gboolean proceed = FALSE;
/*
* Atomically decrement the refcount and remove ourselves from the hash tables, so
* register_image () can't grab an image which is being closed.
*/
mono_images_lock ();
if (mono_atomic_dec_i32 (&image->ref_count) > 0)
goto done;
MonoLoadedImages *li;
li = loaded_images_get_owner (image);
if (!li) {
/* we weren't registered; maybe lost to another image */
proceed = TRUE;
goto done;
}
GHashTable *loaded_images, *loaded_images_by_name;
MonoImage *image2;
loaded_images = mono_loaded_images_get_hash (li, image->ref_only);
loaded_images_by_name = mono_loaded_images_get_by_name_hash (li, image->ref_only);
name = image->name;
image2 = (MonoImage *)g_hash_table_lookup (loaded_images, name);
if (image == image2) {
/* This is not true if we are called from mono_image_open () */
g_hash_table_remove (loaded_images, name);
}
if (image->assembly_name && (g_hash_table_lookup (loaded_images_by_name, image->assembly_name) == image))
g_hash_table_remove (loaded_images_by_name, (char *) image->assembly_name);
proceed = TRUE;
done:
mono_images_unlock ();
return proceed;
}
MonoLoadedImages*
mono_image_get_loaded_images_for_modules (MonoImage *image)
{
return mono_get_global_loaded_images ();
}
|