typedef struct DomainFinalizationReq {
MonoDomain *domain;
+#ifdef TARGET_WIN32
HANDLE done_event;
+#else
+ gboolean done;
+ MonoCoopCond cond;
+ MonoCoopMutex mutex;
+#endif
} DomainFinalizationReq;
static gboolean gc_disabled = FALSE;
gboolean log_finalizers = FALSE;
gboolean mono_do_not_finalize = FALSE;
+ volatile gboolean suspend_finalizers = FALSE;
gchar **mono_do_not_finalize_class_names = NULL;
#define mono_finalizer_lock() mono_coop_mutex_lock (&finalizer_mutex)
return result;
}
+typedef struct {
+ MonoCoopCond *cond;
+ MonoCoopMutex *mutex;
+} BreakCoopAlertableWaitUD;
+
+static inline void
+break_coop_alertable_wait (gpointer user_data)
+{
+ BreakCoopAlertableWaitUD *ud = (BreakCoopAlertableWaitUD*)user_data;
+
+ mono_coop_mutex_lock (ud->mutex);
+ mono_coop_cond_signal (ud->cond);
+ mono_coop_mutex_unlock (ud->mutex);
+}
+
+/*
+ * coop_cond_timedwait_alertable:
+ *
+ * Wait on COND/MUTEX. If ALERTABLE is non-null, the wait can be interrupted.
+ * In that case, *ALERTABLE will be set to TRUE, and 0 is returned.
+ */
+static inline gint
+coop_cond_timedwait_alertable (MonoCoopCond *cond, MonoCoopMutex *mutex, guint32 timeout_ms, gboolean *alertable)
+{
+ int res;
+
+ if (alertable) {
+ BreakCoopAlertableWaitUD ud;
+
+ *alertable = FALSE;
+ ud.cond = cond;
+ ud.mutex = mutex;
+ mono_thread_info_install_interrupt (break_coop_alertable_wait, &ud, alertable);
+ if (*alertable)
+ return 0;
+ }
+ res = mono_coop_cond_timedwait (cond, mutex, timeout_ms);
+ if (alertable) {
+ mono_thread_info_uninstall_interrupt (alertable);
+ if (*alertable)
+ return 0;
+ }
+ return res;
+}
+
static gboolean
add_thread_to_finalize (MonoInternalThread *thread, MonoError *error)
{
return is_ok (error);
}
- static volatile gboolean suspend_finalizers = FALSE;
/*
* actually, we might want to queue the finalize requests in a separate thread,
* but we need to be careful about the execution domain of the thread...
mono_domain_finalize (MonoDomain *domain, guint32 timeout)
{
DomainFinalizationReq *req;
- guint32 res;
- HANDLE done_event;
MonoInternalThread *thread = mono_thread_internal_current ();
#if defined(__native_client__)
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;
+
+#ifdef TARGET_WIN32
+ req->done_event = CreateEvent (NULL, TRUE, FALSE, NULL);
+ if (req->done_event == NULL) {
+ g_free (req);
+ return FALSE;
+ }
+#else
+ mono_coop_cond_init (&req->cond);
+ mono_coop_mutex_init (&req->mutex);
+#endif
if (domain == mono_get_root_domain ())
finalizing_root_domain = TRUE;
if (timeout == -1)
timeout = INFINITE;
+#if TARGET_WIN32
while (TRUE) {
- res = guarded_wait (done_event, timeout, TRUE);
+ guint32 res = guarded_wait (req->done_event, timeout, TRUE);
/* printf ("WAIT RES: %d.\n", res); */
if (res == WAIT_IO_COMPLETION) {
}
}
- CloseHandle (done_event);
+ CloseHandle (req->done_event);
+#else
+ mono_coop_mutex_lock (&req->mutex);
+ while (!req->done) {
+ gboolean alerted;
+ int res = coop_cond_timedwait_alertable (&req->cond, &req->mutex, timeout, &alerted);
+ if (alerted) {
+ if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0) {
+ mono_coop_mutex_unlock (&req->mutex);
+ return FALSE;
+ }
+ } else if (res == ETIMEDOUT) {
+ /* We leak the cond/mutex here */
+ mono_coop_mutex_unlock (&req->mutex);
+ return FALSE;
+ } else {
+ break;
+ }
+ }
+ mono_coop_mutex_unlock (&req->mutex);
+
+ /* When we reach here, the other thread has already exited the critical section, so this is safe to free */
+ mono_coop_cond_destroy (&req->cond);
+ mono_coop_mutex_destroy (&req->mutex);
+ g_free (req);
+#endif
if (domain == mono_get_root_domain ()) {
mono_threadpool_ms_cleanup ();
g_ptr_array_free (objs, TRUE);
}
#elif defined(HAVE_SGEN_GC)
- mono_gc_finalize_domain (domain, &suspend_finalizers);
+ mono_gc_finalize_domain (domain);
mono_gc_invoke_finalizers ();
#endif
reference_queue_clear_for_domain (domain);
/* printf ("DONE.\n"); */
+#if TARGET_WIN32
SetEvent (req->done_event);
/* The event is closed in mono_domain_finalize if we get here */
g_free (req);
+#else
+ mono_coop_mutex_lock (&req->mutex);
+ req->done = TRUE;
+ mono_coop_cond_signal (&req->cond);
+ mono_coop_mutex_unlock (&req->mutex);
+#endif
}
static guint32
hazard_free_queue_pump ();
/* Avoid posting the pending done event until there are pending finalizers */
- if (mono_coop_sem_timedwait (&finalizer_sem, 0, MONO_SEM_FLAGS_NONE) == 0) {
+ if (mono_coop_sem_timedwait (&finalizer_sem, 0, MONO_SEM_FLAGS_NONE) == MONO_SEM_TIMEDWAIT_RET_SUCCESS) {
/* Don't wait again at the start of the loop */
wait = FALSE;
} else {
/* Set a flag which the finalizer thread can check */
suspend_finalizers = TRUE;
+ mono_gc_suspend_finalizers ();
/* Try to abort the thread, in the hope that it is running managed code */
mono_thread_internal_abort (gc_thread);