From: "Vincent Povirk" Subject: [2/3] mscoree: Overhaul of mono runtime shutdown process. Message-Id: <33F6268AA99B6C448F07F03B2B6497D38CE500@taz.CodeWeavers.local> Date: Wed, 23 Feb 2011 15:48:13 -0600 From 012c369b0b8483df32b6a8c859587ddee54eda44 Mon Sep 17 00:00:00 2001 From: Vincent Povirk Date: Mon, 21 Feb 2011 14:22:02 -0600 Subject: [PATCH 2/3] 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. --- dlls/mscoree/corruntimehost.c | 10 +++-- dlls/mscoree/metahost.c | 68 +++++++++++++++++++++++++++++++++++++++- dlls/mscoree/mscoree_main.c | 5 ++- dlls/mscoree/mscoree_private.h | 17 +++++++++- 4 files changed, 91 insertions(+), 9 deletions(-) diff --git a/dlls/mscoree/corruntimehost.c b/dlls/mscoree/corruntimehost.c index 3c26340..0254753 100644 --- a/dlls/mscoree/corruntimehost.c +++ b/dlls/mscoree/corruntimehost.c @@ -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); } diff --git a/dlls/mscoree/metahost.c b/dlls/mscoree/metahost.c index 2cafcb8..01d70b0 100644 --- a/dlls/mscoree/metahost.c +++ b/dlls/mscoree/metahost.c @@ -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 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; imono_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; imono_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) diff --git a/dlls/mscoree/mscoree_main.c b/dlls/mscoree/mscoree_main.c index a3e1cec..6901f7a 100644 --- a/dlls/mscoree/mscoree_main.c +++ b/dlls/mscoree/mscoree_main.c @@ -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); } diff --git a/dlls/mscoree/mscoree_private.h b/dlls/mscoree/mscoree_private.h index 222b3ca..16ae5d3 100644 --- a/dlls/mscoree/mscoree_private.h +++ b/dlls/mscoree/mscoree_private.h @@ -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); -- 1.7.1