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_try_free: * \param p the pointer to free * \param free_func the function that can free the pointer * * If \p p is not a hazardous pointer it will be immediately freed by calling \p free_func. * Otherwise it will be queued for later. * * Use this function if \p free_func can ALWAYS be called in the context where this function is being called. * * This function doesn't pump the free queue so try to accommodate a call at an appropriate time. * See mono_thread_hazardous_try_free_some for when it's appropriate. * * \returns TRUE if \p p was free or FALSE if it was queued. */ gboolean mono_thread_hazardous_try_free (gpointer p, MonoHazardousFreeFunc free_func) { if (!is_pointer_hazardous (p)) { free_func (p); return TRUE; } else { mono_thread_hazardous_queue_free (p, free_func); return FALSE; } }
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); } }