#include <mono/utils/mono-threads.h>
#include <mono/utils/atomic.h>
#include <mono/utils/mono-coop-semaphore.h>
+#include <mono/utils/hazard-pointer.h>
#ifndef HOST_WIN32
#include <pthread.h>
mono_coop_sem_post (&finalizer_sem);
}
+/*
+This is the number of entries allowed in the hazard free queue before
+we explicitly cycle the finalizer thread to trigger pumping the queue.
+
+It was picked empirically by running the corlib test suite in a stress
+scenario where all hazard entries are queued.
+
+In this extreme scenario we double the number of times we cycle the finalizer
+thread compared to just GC calls.
+
+Entries are usually in the order of 100's of bytes each, so we're limiting
+floating garbage to be in the order of a dozen kb.
+*/
+static gboolean finalizer_thread_pulsed;
+#define HAZARD_QUEUE_OVERFLOW_SIZE 20
+
+static void
+hazard_free_queue_is_too_big (size_t size)
+{
+ if (size < HAZARD_QUEUE_OVERFLOW_SIZE)
+ return;
+
+ if (finalizer_thread_pulsed || InterlockedCompareExchange (&finalizer_thread_pulsed, TRUE, FALSE))
+ return;
+
+ mono_gc_finalize_notify ();
+}
+
+static void
+hazard_free_queue_pump (void)
+{
+ mono_thread_hazardous_try_free_all ();
+ finalizer_thread_pulsed = FALSE;
+}
+
#ifdef HAVE_BOEHM_GC
static void
{
gboolean wait = TRUE;
+ /* Register a hazard free queue pump callback */
+ mono_hazard_pointer_install_free_queue_size_callback (hazard_free_queue_is_too_big);
+
while (!finished) {
/* Wait to be notified that there's at least one
* finaliser to run
reference_queue_proccess_all ();
- mono_thread_hazardous_try_free_all ();
+ 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) {
static volatile int hazard_table_size = 0;
static MonoThreadHazardPointers * volatile hazard_table = NULL;
+static MonoHazardFreeQueueSizeCallback queue_size_cb;
/*
* Each entry is either 0 or 1, indicating whether that overflow small
InterlockedIncrement (&hazardous_pointer_count);
mono_lock_free_array_queue_push (&delayed_free_queue, &item);
+
+ guint32 queue_size = delayed_free_queue.num_used_entries;
+ if (queue_size && queue_size_cb)
+ queue_size_cb (queue_size);
}
+void
+mono_hazard_pointer_install_free_queue_size_callback (MonoHazardFreeQueueSizeCallback cb)
+{
+ queue_size_cb = cb;
+}
+
void
mono_thread_hazardous_try_free_all (void)
{
int mono_hazard_pointer_save_for_signal_handler (void);
void mono_hazard_pointer_restore_for_signal_handler (int small_id);
+typedef void (*MonoHazardFreeQueueSizeCallback)(size_t size);
+void mono_hazard_pointer_install_free_queue_size_callback (MonoHazardFreeQueueSizeCallback cb);
+
void mono_thread_smr_init (void);
void mono_thread_smr_cleanup (void);
#endif /*__MONO_HAZARD_POINTER_H__*/