示例#1
0
/*
Search @list for element with key @key.
@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 a node with key @key was found.
*/
gboolean
mono_lls_find (MonoLinkedListSet *list, MonoThreadHazardPointers *hp, uintptr_t key, HazardFreeContext context)
{
    MonoLinkedListSetNode *cur, *next;
    MonoLinkedListSetNode **prev;
    uintptr_t cur_key;

try_again:
    prev = &list->head;

    /*
     * prev is not really a hazardous pointer, but we return prev
     * in hazard pointer 2, so we set it here.  Note also that
     * prev is not a pointer to a node.  We use here the fact that
     * the first element in a node is the next pointer, so it
     * works, but it's not pretty.
     */
    mono_hazard_pointer_set (hp, 2, prev);

    cur = (MonoLinkedListSetNode *) get_hazardous_pointer_with_mask ((gpointer*)prev, hp, 1);

    while (1) {
        if (cur == NULL)
            return FALSE;
        next = (MonoLinkedListSetNode *) get_hazardous_pointer_with_mask ((gpointer*)&cur->next, hp, 0);
        cur_key = cur->key;

        /*
         * We need to make sure that we dereference prev below
         * after reading cur->next above, so we need a read
         * barrier.
         */
        mono_memory_read_barrier ();

        if (*prev != cur)
            goto try_again;

        if (!mono_lls_pointer_get_mark (next)) {
            if (cur_key >= key)
                return cur_key == key;

            prev = &cur->next;
            mono_hazard_pointer_set (hp, 2, cur);
        } else {
            next = (MonoLinkedListSetNode *) mono_lls_pointer_unmask (next);
            if (InterlockedCompareExchangePointer ((volatile gpointer*)prev, next, cur) == cur) {
                /* The hazard pointer must be cleared after the CAS. */
                mono_memory_write_barrier ();
                mono_hazard_pointer_clear (hp, 1);
                if (list->free_node_func)
                    mono_thread_hazardous_queue_free (cur, list->free_node_func);
            } else
                goto try_again;
        }
        cur = (MonoLinkedListSetNode *) mono_lls_pointer_unmask (next);
        mono_hazard_pointer_set (hp, 1, cur);
    }
}
示例#2
0
/**
 * 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;
	}
}