示例#1
0
/*
Search @list for element with key @key and remove it.
@context specifies whether the function is being called from a lock-free (i.e.
signal handler or world stopped) context. It is only relevant if a node free
function was given.
The nodes next, cur and prev are returned in @hp
Returns true if @value was removed by this call.
*/
gboolean
mono_lls_remove (MonoLinkedListSet *list, MonoThreadHazardPointers *hp, MonoLinkedListSetNode *value, HazardFreeContext context)
{
    MonoLinkedListSetNode *cur, **prev, *next;
    while (1) {
        if (!mono_lls_find (list, hp, value->key, context))
            return FALSE;

        next = (MonoLinkedListSetNode *) mono_hazard_pointer_get_val (hp, 0);
        cur = (MonoLinkedListSetNode *) mono_hazard_pointer_get_val (hp, 1);
        prev = (MonoLinkedListSetNode **) mono_hazard_pointer_get_val (hp, 2);

        g_assert (cur == value);

        if (InterlockedCompareExchangePointer ((volatile gpointer*)&cur->next, mask (next, 1), next) != next)
            continue;
        /* The second CAS must happen before the first. */
        mono_memory_write_barrier ();
        if (InterlockedCompareExchangePointer ((volatile gpointer*)prev, mono_lls_pointer_unmask (next), cur) == cur) {
            /* The CAS must happen before the hazard pointer clear. */
            mono_memory_write_barrier ();
            mono_hazard_pointer_clear (hp, 1);
            if (list->free_node_func)
                mono_thread_hazardous_try_free (value, list->free_node_func);
        } else
            mono_lls_find (list, hp, value->key, context);
        return TRUE;
    }
}
示例#2
0
static void
desc_retire (Descriptor *desc)
{
	g_assert (desc->anchor.data.state == STATE_EMPTY);
	g_assert (desc->in_use);
	desc->in_use = FALSE;
	free_sb (desc->sb, desc->block_size, desc->heap->account_type);
	mono_thread_hazardous_try_free (desc, desc_enqueue_avail);
}
示例#3
0
static void
list_remove_empty_desc (MonoLockFreeAllocSizeClass *sc)
{
	int num_non_empty = 0;
	for (;;) {
		Descriptor *desc = (Descriptor*) mono_lock_free_queue_dequeue (&sc->partial);
		if (!desc)
			return;
		/*
		 * We don't need to read atomically because we're the
		 * only thread that references this descriptor.
		 */
		if (desc->anchor.data.state == STATE_EMPTY) {
			desc_retire (desc);
		} else {
			g_assert (desc->heap->sc == sc);
			mono_thread_hazardous_try_free (desc, desc_put_partial);
			if (++num_non_empty >= 2)
				return;
		}
	}
}
示例#4
0
static void
conc_table_lf_free (conc_table *table)
{
	mono_thread_hazardous_try_free (table, conc_table_free);
}
示例#5
0
static void
unregister_thread (void *arg)
{
	gpointer gc_unsafe_stackdata;
	MonoThreadInfo *info;
	int small_id;

	info = (MonoThreadInfo *) arg;
	g_assert (info);
	g_assert (mono_thread_info_is_current (info));
	g_assert (mono_thread_info_is_live (info));

	small_id = info->small_id;

	/* We only enter the GC unsafe region, as when exiting this function, the thread
	 * will be detached, and the current MonoThreadInfo* will be destroyed. */
	mono_threads_enter_gc_unsafe_region_unbalanced_with_info (info, &gc_unsafe_stackdata);

	THREADS_DEBUG ("unregistering info %p\n", info);

	mono_native_tls_set_value (thread_exited_key, GUINT_TO_POINTER (1));

	mono_threads_platform_unregister (info);

	/*
	 * TLS destruction order is not reliable so small_id might be cleaned up
	 * before us.
	 */
#ifndef HAVE_KW_THREAD
	mono_native_tls_set_value (small_id_key, GUINT_TO_POINTER (info->small_id + 1));
#endif

	/*
	First perform the callback that requires no locks.
	This callback has the potential of taking other locks, so we do it before.
	After it completes, the thread remains functional.
	*/
	if (threads_callbacks.thread_detach)
		threads_callbacks.thread_detach (info);

	mono_thread_info_suspend_lock_with_info (info);

	/*
	Now perform the callback that must be done under locks.
	This will render the thread useless and non-suspendable, so it must
	be done while holding the suspend lock to give no other thread chance
	to suspend it.
	*/
	if (threads_callbacks.thread_unregister)
		threads_callbacks.thread_unregister (info);
	mono_threads_unregister_current_thread (info);
	mono_threads_transition_detach (info);

	mono_thread_info_suspend_unlock ();

	g_byte_array_free (info->stackdata, /*free_segment=*/TRUE);

	/*now it's safe to free the thread info.*/
	mono_thread_hazardous_try_free (info, free_thread_info);
	/* Pump the HP queue */
	mono_thread_hazardous_try_free_some ();

	mono_thread_small_id_free (small_id);
}
示例#6
0
static void
list_put_partial (Descriptor *desc)
{
	g_assert (desc->anchor.data.state != STATE_FULL);
	mono_thread_hazardous_try_free (desc, desc_put_partial);
}