mscoree: Overhaul of mono runtime shutdown process.

It turns out that we can't free individual domains because that tears down
important data structures. Instead we must shut down the entire runtime, but
only if Mono doesn't shut itself down first. And we need to do it before
DLL_PROCESS_DETACH because important libraries might be gone by then.
This commit is contained in:
Vincent Povirk 2011-02-21 14:22:02 -06:00 committed by Alexandre Julliard
parent 71bfd33463
commit d6582ae8bd
4 changed files with 91 additions and 9 deletions

View File

@ -44,7 +44,7 @@ struct RuntimeHost
const struct ICorRuntimeHostVtbl *lpVtbl;
const struct ICLRRuntimeHostVtbl *lpCLRHostVtbl;
const CLRRuntimeInfo *version;
const loaded_mono *mono;
loaded_mono *mono;
struct list domains;
MonoDomain *default_domain;
CRITICAL_SECTION lock;
@ -91,6 +91,8 @@ static HRESULT RuntimeHost_AddDomain(RuntimeHost *This, MonoDomain **result)
goto end;
}
This->mono->is_started = TRUE;
list_add_tail(&This->domains, &entry->entry);
MSCOREE_LockModule();
@ -131,7 +133,6 @@ static void RuntimeHost_DeleteDomain(RuntimeHost *This, MonoDomain *domain)
{
if (entry->domain == domain)
{
This->mono->mono_jit_cleanup(domain);
list_remove(&entry->entry);
if (This->default_domain == domain)
This->default_domain = NULL;
@ -711,11 +712,13 @@ __int32 WINAPI _CorExeMain(void)
HeapFree(GetProcessHeap(), 0, argv);
unload_all_runtimes();
return exit_code;
}
HRESULT RuntimeHost_Construct(const CLRRuntimeInfo *runtime_version,
const loaded_mono *loaded_mono, RuntimeHost** result)
loaded_mono *loaded_mono, RuntimeHost** result)
{
RuntimeHost *This;
@ -786,7 +789,6 @@ HRESULT RuntimeHost_Destroy(RuntimeHost *This)
LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &This->domains, struct DomainEntry, entry)
{
This->mono->mono_jit_cleanup(cursor->domain);
list_remove(&cursor->entry);
HeapFree(GetProcessHeap(), 0, cursor);
}

View File

@ -76,6 +76,8 @@ static BOOL find_mono_dll(LPCWSTR path, LPWSTR dll_path, int abi_version);
static MonoAssembly* mono_assembly_search_hook_fn(MonoAssemblyName *aname, char **assemblies_path, void *user_data);
static void mono_shutdown_callback_fn(MonoProfiler *prof);
static void set_environment(LPCWSTR bin_path)
{
WCHAR path_env[MAX_PATH];
@ -91,6 +93,10 @@ static void set_environment(LPCWSTR bin_path)
SetEnvironmentVariableW(pathW, path_env);
}
static void CDECL do_nothing(void)
{
}
static HRESULT load_mono(CLRRuntimeInfo *This, loaded_mono **result)
{
static const WCHAR bin[] = {'\\','b','i','n',0};
@ -111,6 +117,13 @@ static HRESULT load_mono(CLRRuntimeInfo *This, loaded_mono **result)
*result = &loaded_monos[This->mono_abi_version-1];
if ((*result)->is_shutdown)
{
ERR("Cannot load Mono after it has been shut down.");
*result = NULL;
return E_FAIL;
}
if (!(*result)->mono_handle)
{
strcpyW(mono_bin_path, This->mono_path);
@ -146,16 +159,17 @@ static HRESULT load_mono(CLRRuntimeInfo *This, loaded_mono **result)
LOAD_MONO_FUNCTION(mono_class_get_method_from_name);
LOAD_MONO_FUNCTION(mono_domain_assembly_open);
LOAD_MONO_FUNCTION(mono_install_assembly_preload_hook);
LOAD_MONO_FUNCTION(mono_jit_cleanup);
LOAD_MONO_FUNCTION(mono_jit_exec);
LOAD_MONO_FUNCTION(mono_jit_init);
LOAD_MONO_FUNCTION(mono_jit_set_trace_options);
LOAD_MONO_FUNCTION(mono_object_get_domain);
LOAD_MONO_FUNCTION(mono_object_new);
LOAD_MONO_FUNCTION(mono_object_unbox);
LOAD_MONO_FUNCTION(mono_profiler_install);
LOAD_MONO_FUNCTION(mono_reflection_type_from_name);
LOAD_MONO_FUNCTION(mono_runtime_invoke);
LOAD_MONO_FUNCTION(mono_runtime_object_init);
LOAD_MONO_FUNCTION(mono_runtime_quit);
LOAD_MONO_FUNCTION(mono_set_dirs);
LOAD_MONO_FUNCTION(mono_stringify_assembly_name);
@ -175,6 +189,22 @@ static HRESULT load_mono(CLRRuntimeInfo *This, loaded_mono **result)
#undef LOAD_MONO_FUNCTION
#define LOAD_OPT_VOID_MONO_FUNCTION(x) do { \
(*result)->x = (void*)GetProcAddress((*result)->mono_handle, #x); \
if (!(*result)->x) { \
(*result)->x = do_nothing; \
} \
} while (0);
LOAD_OPT_VOID_MONO_FUNCTION(mono_runtime_set_shutting_down);
LOAD_OPT_VOID_MONO_FUNCTION(mono_thread_pool_cleanup);
LOAD_OPT_VOID_MONO_FUNCTION(mono_thread_suspend_all_other_threads);
LOAD_OPT_VOID_MONO_FUNCTION(mono_threads_set_shutting_down);
#undef LOAD_OPT_VOID_MONO_FUNCTION
(*result)->mono_profiler_install((MonoProfiler*)*result, mono_shutdown_callback_fn);
(*result)->mono_set_dirs(mono_lib_path_a, mono_etc_path_a);
(*result)->mono_config_parse(NULL);
@ -200,6 +230,13 @@ fail:
return E_FAIL;
}
static void mono_shutdown_callback_fn(MonoProfiler *prof)
{
loaded_mono *mono = (loaded_mono*)prof;
mono->is_shutdown = TRUE;
}
static HRESULT CLRRuntimeInfo_GetRuntimeHost(CLRRuntimeInfo *This, RuntimeHost **result)
{
HRESULT hr = S_OK;
@ -230,11 +267,40 @@ void unload_all_runtimes(void)
{
int i;
for (i=0; i<NUM_ABI_VERSIONS; i++)
{
loaded_mono *mono = &loaded_monos[i];
if (mono->mono_handle && mono->is_started && !mono->is_shutdown)
{
/* Copied from Mono's ves_icall_System_Environment_Exit */
mono->mono_threads_set_shutting_down();
mono->mono_runtime_set_shutting_down();
mono->mono_thread_pool_cleanup();
mono->mono_thread_suspend_all_other_threads();
mono->mono_runtime_quit();
}
}
for (i=0; i<NUM_RUNTIMES; i++)
if (runtimes[i].loaded_runtime)
RuntimeHost_Destroy(runtimes[i].loaded_runtime);
}
void expect_no_runtimes(void)
{
int i;
for (i=0; i<NUM_ABI_VERSIONS; i++)
{
loaded_mono *mono = &loaded_monos[i];
if (mono->mono_handle && mono->is_started && !mono->is_shutdown)
{
ERR("Process exited with a Mono runtime loaded.\n");
return;
}
}
}
static HRESULT WINAPI CLRRuntimeInfo_QueryInterface(ICLRRuntimeInfo* iface,
REFIID riid,
void **ppvObject)

View File

@ -124,7 +124,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
DisableThreadLibraryCalls(hinstDLL);
break;
case DLL_PROCESS_DETACH:
unload_all_runtimes();
expect_no_runtimes();
break;
}
return TRUE;
@ -154,7 +154,8 @@ __int32 WINAPI _CorExeMain2(PBYTE ptrMemory, DWORD cntMemory, LPWSTR imageName,
void WINAPI CorExitProcess(int exitCode)
{
FIXME("(%x) stub\n", exitCode);
TRACE("(%x)\n", exitCode);
unload_all_runtimes();
ExitProcess(exitCode);
}

View File

@ -85,6 +85,7 @@ typedef struct _MonoImage MonoImage;
typedef struct _MonoClass MonoClass;
typedef struct _MonoObject MonoObject;
typedef struct _MonoMethod MonoMethod;
typedef struct _MonoProfiler MonoProfiler;
typedef enum {
MONO_IMAGE_OK,
@ -95,11 +96,16 @@ typedef enum {
typedef MonoAssembly* (*MonoAssemblyPreLoadFunc)(MonoAssemblyName *aname, char **assemblies_path, void *user_data);
typedef void (*MonoProfileFunc)(MonoProfiler *prof);
typedef struct loaded_mono
{
HMODULE mono_handle;
HMODULE glib_handle;
BOOL is_started;
BOOL is_shutdown;
MonoImage* (CDECL *mono_assembly_get_image)(MonoAssembly *assembly);
MonoAssembly* (CDECL *mono_assembly_open)(const char *filename, MonoImageOpenStatus *status);
MonoClass* (CDECL *mono_class_from_mono_type)(MonoType *type);
@ -109,25 +115,32 @@ typedef struct loaded_mono
MonoAssembly* (CDECL *mono_domain_assembly_open) (MonoDomain *domain, const char *name);
void (CDECL *mono_free)(void *);
void (CDECL *mono_install_assembly_preload_hook)(MonoAssemblyPreLoadFunc func, void *user_data);
void (CDECL *mono_jit_cleanup)(MonoDomain *domain);
int (CDECL *mono_jit_exec)(MonoDomain *domain, MonoAssembly *assembly, int argc, char *argv[]);
MonoDomain* (CDECL *mono_jit_init)(const char *file);
int (CDECL *mono_jit_set_trace_options)(const char* options);
MonoDomain* (CDECL *mono_object_get_domain)(MonoObject *obj);
MonoObject* (CDECL *mono_object_new)(MonoDomain *domain, MonoClass *klass);
void* (CDECL *mono_object_unbox)(MonoObject *obj);
void (CDECL *mono_profiler_install)(MonoProfiler *prof, MonoProfileFunc shutdown_callback);
MonoType* (CDECL *mono_reflection_type_from_name)(char *name, MonoImage *image);
MonoObject* (CDECL *mono_runtime_invoke)(MonoMethod *method, void *obj, void **params, MonoObject **exc);
void (CDECL *mono_runtime_object_init)(MonoObject *this_obj);
void (CDECL *mono_runtime_quit)(void);
void (CDECL *mono_runtime_set_shutting_down)(void);
void (CDECL *mono_set_dirs)(const char *assembly_dir, const char *config_dir);
char* (CDECL *mono_stringify_assembly_name)(MonoAssemblyName *aname);
void (CDECL *mono_thread_pool_cleanup)(void);
void (CDECL *mono_thread_suspend_all_other_threads)(void);
void (CDECL *mono_threads_set_shutting_down)(void);
} loaded_mono;
/* loaded runtime interfaces */
extern void unload_all_runtimes(void);
extern void expect_no_runtimes(void);
extern HRESULT RuntimeHost_Construct(const CLRRuntimeInfo *runtime_version,
const loaded_mono *loaded_mono, RuntimeHost** result);
loaded_mono *loaded_mono, RuntimeHost** result);
extern HRESULT RuntimeHost_GetInterface(RuntimeHost *This, REFCLSID clsid, REFIID riid, void **ppv);