static void try_free_delayed_free_items (guint32 limit) { GArray *hazardous = NULL; DelayedFreeItem item; guint32 freed = 0; // Free all the items we can and re-add the ones we can't to the queue. while (mono_lock_free_array_queue_pop (&delayed_free_queue, &item)) { if (is_pointer_hazardous (item.p)) { if (!hazardous) hazardous = g_array_sized_new (FALSE, FALSE, sizeof (DelayedFreeItem), delayed_free_queue.num_used_entries); g_array_append_val (hazardous, item); continue; } item.free_func (item.p); freed++; if (limit && freed == limit) break; } if (hazardous) { for (gint i = 0; i < hazardous->len; i++) mono_lock_free_array_queue_push (&delayed_free_queue, &g_array_index (hazardous, DelayedFreeItem, i)); g_array_free (hazardous, TRUE); } }
void mono_thread_hazardous_free_or_queue (gpointer p, MonoHazardousFreeFunc free_func, gboolean free_func_might_lock, gboolean lock_free_context) { int i; if (lock_free_context) g_assert (!free_func_might_lock); if (free_func_might_lock) g_assert (!lock_free_context); /* First try to free a few entries in the delayed free table. */ for (i = 0; i < 3; ++i) try_free_delayed_free_item (lock_free_context); /* Now see if the pointer we're freeing is hazardous. If it isn't, free it. Otherwise put it in the delay list. */ if (is_pointer_hazardous (p)) { DelayedFreeItem item = { p, free_func, free_func_might_lock }; ++hazardous_pointer_count; mono_lock_free_array_queue_push (&delayed_free_queue, &item); } else { free_func (p); } }
/** * mono_thread_hazardous_queue_free: * \param p the pointer to free * \param free_func the function that can free the pointer * Queue \p p to be freed later. \p p will be freed once the hazard free queue is pumped. * * This function doesn't pump the free queue so try to accommodate a call at an appropriate time. * See \c mono_thread_hazardous_try_free_some for when it's appropriate. */ void mono_thread_hazardous_queue_free (gpointer p, MonoHazardousFreeFunc free_func) { DelayedFreeItem item = { p, free_func }; mono_atomic_inc_i32 (&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); }
static gboolean try_free_delayed_free_item (gboolean lock_free_context) { DelayedFreeItem item; gboolean popped = mono_lock_free_array_queue_pop (&delayed_free_queue, &item); if (!popped) return FALSE; if ((lock_free_context && item.might_lock) || (is_pointer_hazardous (item.p))) { mono_lock_free_array_queue_push (&delayed_free_queue, &item); return FALSE; } item.free_func (item.p); return TRUE; }
void mono_thread_hazardous_free_or_queue (gpointer p, MonoHazardousFreeFunc free_func) { int i; /* First try to free a few entries in the delayed free table. */ for (i = 0; i < 3; ++i) try_free_delayed_free_item (); /* Now see if the pointer we're freeing is hazardous. If it isn't, free it. Otherwise put it in the delay list. */ if (is_pointer_hazardous (p)) { DelayedFreeItem item = { p, free_func }; ++mono_stats.hazardous_pointer_count; mono_lock_free_array_queue_push (&delayed_free_queue, &item); } else { free_func (p); } }