#include <config.h>
#include <glib.h>
#include <string.h>
-#include <errno.h>
#include <mono/metadata/gc-internal.h>
#include <mono/metadata/mono-gc.h>
#include <mono/metadata/threadpool.h>
#include <mono/metadata/threadpool-internals.h>
#include <mono/metadata/threads-types.h>
-#include <mono/metadata/sgen-conf.h>
+#include <mono/sgen/sgen-conf.h>
#include <mono/utils/mono-logger-internal.h>
#include <mono/metadata/gc-internal.h>
#include <mono/metadata/marshal.h> /* for mono_delegate_free_ftnptr () */
#include <mono/utils/mono-semaphore.h>
#include <mono/utils/mono-memory-model.h>
#include <mono/utils/mono-counters.h>
+#include <mono/utils/mono-time.h>
#include <mono/utils/dtrace.h>
#include <mono/utils/mono-threads.h>
#include <mono/utils/atomic.h>
HANDLE done_event;
} DomainFinalizationReq;
-#ifdef PLATFORM_WINCE /* FIXME: add accessors to gc.dll API */
-extern void (*__imp_GC_finalizer_notifier)(void);
-#define GC_finalizer_notifier __imp_GC_finalizer_notifier
-extern int __imp_GC_finalize_on_demand;
-#define GC_finalize_on_demand __imp_GC_finalize_on_demand
-#endif
-
static gboolean gc_disabled = FALSE;
static gboolean finalizing_root_domain = FALSE;
static GSList *domains_to_finalize= NULL;
static MonoMList *threads_to_finalize = NULL;
+static gboolean finalizer_thread_exited;
+/* Uses finalizer_mutex */
+static mono_cond_t exited_cond;
+
static MonoInternalThread *gc_thread;
static void object_register_finalizer (MonoObject *obj, void (*callback)(void *, void*));
static void reference_queue_proccess_all (void);
static void mono_reference_queue_cleanup (void);
static void reference_queue_clear_for_domain (MonoDomain *domain);
-#ifndef HAVE_NULL_GC
static HANDLE pending_done_event;
-static HANDLE shutdown_event;
-#endif
-
-GCStats gc_stats;
static guint32
guarded_wait (HANDLE handle, guint32 timeout, gboolean alertable)
finalizer = mono_class_get_finalizer (o->vtable->klass);
-#ifndef DISABLE_COM
/* If object has a CCW but has no finalizer, it was only
* registered for finalization in order to free the CCW.
* Else it needs the regular finalizer run.
mono_domain_set_internal (caller_domain);
return;
}
-#endif
/*
* To avoid the locking plus the other overhead of mono_runtime_invoke (),
* is still working and will take care of running the finalizers
*/
-#ifndef HAVE_NULL_GC
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 ());
done_event = CreateEvent (NULL, TRUE, FALSE, NULL);
}
return TRUE;
-#else
- /* We don't support domain finalization without a GC */
- return FALSE;
-#endif
}
void
void
ves_icall_System_GC_WaitForPendingFinalizers (void)
{
-#ifndef HAVE_NULL_GC
+ if (mono_gc_is_null ())
+ return;
+
if (!mono_gc_pending_finalizers ())
return;
/* g_print ("Waiting for pending finalizers....\n"); */
guarded_wait (pending_done_event, INFINITE, TRUE);
/* g_print ("Done pending....\n"); */
-#endif
}
void
return -1;
}
-static void*
+static MonoGCDescriptor
make_root_descr_all_refs (int numbits, gboolean pinned)
{
#ifdef HAVE_SGEN_GC
if (pinned)
- return NULL;
+ return MONO_GC_DESCRIPTOR_NULL;
#endif
return mono_gc_make_root_descr_all_refs (numbits);
}
}
MonoBoolean
-GCHandle_CheckCurrentDomain (guint32 gchandle)
+mono_gc_GCHandle_CheckCurrentDomain (guint32 gchandle)
{
return mono_gchandle_is_in_domain (gchandle, mono_domain_get ());
}
-#ifndef HAVE_NULL_GC
-
#ifdef MONO_HAS_SEMAPHORES
static MonoSemType finalizer_sem;
#endif
g_message ( "%s: prodding finalizer", __func__);
#endif
+ if (mono_gc_is_null ())
+ return;
+
#ifdef MONO_HAS_SEMAPHORES
MONO_SEM_POST (&finalizer_sem);
#else
g_assert (mono_domain_get () == mono_get_root_domain ());
mono_gc_set_skip_thread (TRUE);
+ MONO_PREPARE_BLOCKING
if (wait) {
/* An alertable wait is required so this thread can be suspended on windows */
#endif
}
wait = TRUE;
+ MONO_FINISH_BLOCKING
mono_gc_set_skip_thread (FALSE);
mono_threads_perform_thread_dump ();
mono_console_handle_async_ops ();
-#ifndef DISABLE_ATTACH
mono_attach_maybe_start ();
-#endif
if (domains_to_finalize) {
mono_finalizer_lock ();
#endif
}
- SetEvent (shutdown_event);
+ mono_finalizer_lock ();
+ finalizer_thread_exited = TRUE;
+ mono_cond_signal (&exited_cond);
+ mono_finalizer_unlock ();
+
return 0;
}
}
finalizer_event = CreateEvent (NULL, FALSE, FALSE, NULL);
+ g_assert (finalizer_event);
pending_done_event = CreateEvent (NULL, TRUE, FALSE, NULL);
- shutdown_event = CreateEvent (NULL, TRUE, FALSE, NULL);
- if (finalizer_event == NULL || pending_done_event == NULL || shutdown_event == NULL) {
- g_assert_not_reached ();
- }
+ g_assert (pending_done_event);
+ mono_cond_init (&exited_cond, 0);
#ifdef MONO_HAS_SEMAPHORES
MONO_SEM_INIT (&finalizer_sem, 0);
#endif
g_message ("%s: cleaning up finalizer", __func__);
#endif
+ if (mono_gc_is_null ())
+ return;
+
if (!gc_disabled) {
- ResetEvent (shutdown_event);
finished = TRUE;
if (mono_thread_internal_current () != gc_thread) {
gboolean timed_out = FALSE;
+ guint32 start_ticks = mono_msec_ticks ();
+ guint32 end_ticks = start_ticks + 2000;
mono_gc_finalize_notify ();
/* Finishing the finalizer thread, so wait a little bit... */
/* MS seems to wait for about 2 seconds */
- if (guarded_wait (shutdown_event, 2000, FALSE) == WAIT_TIMEOUT) {
+ while (!finalizer_thread_exited) {
+ guint32 current_ticks = mono_msec_ticks ();
+ guint32 timeout;
+
+ if (current_ticks >= end_ticks)
+ break;
+ else
+ timeout = end_ticks - current_ticks;
+ MONO_PREPARE_BLOCKING;
+ mono_finalizer_lock ();
+ if (!finalizer_thread_exited)
+ mono_cond_timedwait_ms (&exited_cond, &finalizer_mutex, timeout);
+ mono_finalizer_unlock ();
+ MONO_FINISH_BLOCKING;
+ }
+
+ if (!finalizer_thread_exited) {
int ret;
/* Set a flag which the finalizer thread can check */
}
}
gc_thread = NULL;
-#ifdef HAVE_BOEHM_GC
- GC_finalizer_notifier = NULL;
-#endif
+ mono_gc_base_cleanup ();
}
mono_reference_queue_cleanup ();
- mono_mutex_destroy (&handle_section);
mono_mutex_destroy (&allocator_section);
mono_mutex_destroy (&finalizer_mutex);
mono_mutex_destroy (&reference_queue_mutex);
}
-#else
-
-/* Null GC dummy functions */
+/**
+ * mono_gc_mutex_cleanup:
+ *
+ * Destroy the mutexes that may still be used after the main cleanup routine.
+ */
void
-mono_gc_finalize_notify (void)
-{
-}
-
-void mono_gc_init (void)
-{
- mono_mutex_init_recursive (&handle_section);
-}
-
-void mono_gc_cleanup (void)
+mono_gc_mutex_cleanup (void)
{
+ mono_mutex_destroy (&handle_section);
}
-#endif
-
gboolean
mono_gc_is_finalizer_internal_thread (MonoInternalThread *thread)
{
}
#endif
-/**
- * mono_gc_parse_environment_string_extract_number:
- *
- * @str: points to the first digit of the number
- * @out: pointer to the variable that will receive the value
- *
- * Tries to extract a number from the passed string, taking in to account m, k
- * and g suffixes
- *
- * Returns true if passing was successful
- */
-gboolean
-mono_gc_parse_environment_string_extract_number (const char *str, size_t *out)
-{
- char *endptr;
- int len = strlen (str), shift = 0;
- size_t val;
- gboolean is_suffix = FALSE;
- char suffix;
-
- if (!len)
- return FALSE;
-
- suffix = str [len - 1];
-
- switch (suffix) {
- case 'g':
- case 'G':
- shift += 10;
- case 'm':
- case 'M':
- shift += 10;
- case 'k':
- case 'K':
- shift += 10;
- is_suffix = TRUE;
- break;
- default:
- if (!isdigit (suffix))
- return FALSE;
- break;
- }
-
- errno = 0;
- val = strtol (str, &endptr, 10);
-
- if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
- || (errno != 0 && val == 0) || (endptr == str))
- return FALSE;
-
- if (is_suffix) {
- size_t unshifted;
-
- if (val < 0) /* negative numbers cannot be suffixed */
- return FALSE;
- if (*(endptr + 1)) /* Invalid string. */
- return FALSE;
-
- unshifted = (size_t)val;
- val <<= shift;
- if (val < 0) /* overflow */
- return FALSE;
- if (((size_t)val >> shift) != unshifted) /* value too large */
- return FALSE;
- }
-
- *out = val;
- return TRUE;
-}
-
#ifndef HAVE_SGEN_GC
void*
mono_gc_alloc_mature (MonoVTable *vtable)