gboolean mono_domain_finalize (MonoDomain *domain, guint32 timeout) { DomainFinalizationReq *req; guint32 res; HANDLE done_event; MonoInternalThread *thread = mono_thread_internal_current (); if (mono_thread_internal_current () == gc_thread) /* We are called from inside a finalizer, not much we can do here */ return FALSE; /* * No need to create another thread 'cause the finalizer thread * is still working and will take care of running the finalizers */ #ifndef HAVE_NULL_GC if (gc_disabled) return TRUE; mono_gc_collect (mono_gc_max_generation ()); done_event = CreateEvent (NULL, TRUE, FALSE, NULL); if (done_event == NULL) { return FALSE; } req = g_new0 (DomainFinalizationReq, 1); req->domain = domain; req->done_event = done_event; if (domain == mono_get_root_domain ()) finalizing_root_domain = TRUE; mono_finalizer_lock (); domains_to_finalize = g_slist_append (domains_to_finalize, req); mono_finalizer_unlock (); /* Tell the finalizer thread to finalize this appdomain */ mono_gc_finalize_notify (); if (timeout == -1) timeout = INFINITE; while (TRUE) { res = WaitForSingleObjectEx (done_event, timeout, TRUE); /* printf ("WAIT RES: %d.\n", res); */ if (res == WAIT_IO_COMPLETION) { if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0) return FALSE; } else if (res == WAIT_TIMEOUT) { /* We leak the handle here */ return FALSE; } else { break; } } CloseHandle (done_event); if (domain == mono_get_root_domain ()) { mono_thread_pool_cleanup (); mono_gc_finalize_threadpool_threads (); } return TRUE; #else /* We don't support domain finalization without a GC */ return FALSE; #endif }
gboolean mono_domain_finalize (MonoDomain *domain, guint32 timeout) { DomainFinalizationReq *req; MonoInternalThread *thread = mono_thread_internal_current (); gint res; gboolean ret; gint64 start; #if defined(__native_client__) return FALSE; #endif if (mono_thread_internal_current () == gc_thread) /* We are called from inside a finalizer, not much we can do here */ return FALSE; /* * No need to create another thread 'cause the finalizer thread * is still working and will take care of running the finalizers */ if (gc_disabled) return TRUE; /* We don't support domain finalization without a GC */ if (mono_gc_is_null ()) return FALSE; mono_gc_collect (mono_gc_max_generation ()); req = g_new0 (DomainFinalizationReq, 1); req->ref = 2; req->domain = domain; mono_coop_sem_init (&req->done, 0); if (domain == mono_get_root_domain ()) finalizing_root_domain = TRUE; mono_finalizer_lock (); domains_to_finalize = g_slist_append (domains_to_finalize, req); mono_finalizer_unlock (); /* Tell the finalizer thread to finalize this appdomain */ mono_gc_finalize_notify (); if (timeout == -1) timeout = INFINITE; if (timeout != INFINITE) start = mono_msec_ticks (); ret = TRUE; for (;;) { if (timeout == INFINITE) { res = mono_coop_sem_wait (&req->done, MONO_SEM_FLAGS_ALERTABLE); } else { gint64 elapsed = mono_msec_ticks () - start; if (elapsed >= timeout) { ret = FALSE; break; } res = mono_coop_sem_timedwait (&req->done, timeout - elapsed, MONO_SEM_FLAGS_ALERTABLE); } if (res == MONO_SEM_TIMEDWAIT_RET_SUCCESS) { break; } else if (res == MONO_SEM_TIMEDWAIT_RET_ALERTED) { if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0) { ret = FALSE; break; } } else if (res == MONO_SEM_TIMEDWAIT_RET_TIMEDOUT) { ret = FALSE; break; } else { g_error ("%s: unknown result %d", __func__, res); } } if (!ret) { /* Try removing the req from domains_to_finalize: * - if it's not found: the domain is being finalized, * so we the ref count is already decremented * - if it's found: the domain is not yet being finalized, * so we can safely decrement the ref */ gboolean found; mono_finalizer_lock (); found = g_slist_index (domains_to_finalize, req) != -1; if (found) domains_to_finalize = g_slist_remove (domains_to_finalize, req); mono_finalizer_unlock (); if (found) { /* We have to decrement it wherever we * remove it from domains_to_finalize */ if (InterlockedDecrement (&req->ref) != 1) g_error ("%s: req->ref should be 1, as we are the first one to decrement it", __func__); } goto done; } if (domain == mono_get_root_domain ()) { mono_threadpool_ms_cleanup (); mono_gc_finalize_threadpool_threads (); } done: if (InterlockedDecrement (&req->ref) == 0) { mono_coop_sem_destroy (&req->done); g_free (req); } return ret; }