Esempio n. 1
0
void *qlfqueue_dequeue(qlfqueue_t *q)
{                                      /*{{{ */
    void            *p = NULL;
    qlfqueue_node_t *head;
    qlfqueue_node_t *tail;
    qlfqueue_node_t *next_ptr;

    qassert_ret((q != NULL), NULL);
    while (1) {
        head = q->head;

        hazardous_ptr(0, head);
        if (head != q->head) { continue; }

        tail     = q->tail;
        next_ptr = head->next;

        hazardous_ptr(1, next_ptr);

        if (next_ptr == NULL) { return NULL; } /* queue is empty */
        if (head == tail) { /* tail is falling behind! */
            /* advance tail ptr... */
            (void)qthread_cas_ptr((void **)&(q->tail), (void *)tail, next_ptr);
            continue;
        }
        /* read value before CAS, otherwise another dequeue might free the next node */
        p = next_ptr->value;
        if (qthread_cas_ptr((void **)&(q->head), (void *)head, next_ptr) == head) {
            break;             /* success! */
        }
    }
    hazardous_release_node(qlfqueue_pool_free_wrapper, head);
    return p;
}                                      /*}}} */
Esempio n. 2
0
static inline qt_threadqueue_node_t *qt_internal_NEMESIS_dequeue(NEMESIS_queue *q)
{                                      /*{{{ */
    if (!q->shadow_head) {
        if (!q->head) {
            return NULL;
        }
        q->shadow_head = q->head;
        q->head        = NULL;
    }

    qt_threadqueue_node_t *const retval = (void *volatile)(q->shadow_head);

    if ((retval != NULL) && (retval != (void *)1)) {
        if (retval->next != NULL) {
            q->shadow_head = retval->next;
            retval->next   = NULL;
        } else {
            qt_threadqueue_node_t *old;
            q->shadow_head = NULL;
            old            = qthread_cas_ptr(&(q->tail), retval, NULL);
            if (old != retval) {
                while (retval->next == NULL) SPINLOCK_BODY();
                q->shadow_head = retval->next;
                retval->next   = NULL;
            }
        }
    }
    return retval;
}                                      /*}}} */
Esempio n. 3
0
qlfqueue_t *qlfqueue_create(void)
{                                      /*{{{ */
    qlfqueue_t *q;

    if (qlfqueue_node_pool == NULL) {
        switch ((uintptr_t)qthread_cas_ptr(&qlfqueue_node_pool, NULL, (void *)1)) {
            case 0: /* I won, I will allocate */
                qlfqueue_node_pool = qpool_create_aligned(sizeof(qlfqueue_node_t), 0);
                break;
            case 1:
                while (qlfqueue_node_pool == (void *)1) {
                    SPINLOCK_BODY();
                }
                break;
        }
    }
    qassert_ret((qlfqueue_node_pool != NULL), NULL);

    q = MALLOC(sizeof(struct qlfqueue_s));
    if (q != NULL) {
        q->head = (qlfqueue_node_t *)qpool_alloc(qlfqueue_node_pool);
        assert(q->head != NULL);
        if (q->head == NULL) {   /* if we're not using asserts, fail nicely */
            FREE(q, sizeof(struct qlfqueue_s));
            return NULL;
        }
        q->tail       = q->head;
        q->tail->next = NULL;
    }
    return q;
}                                      /*}}} */
Esempio n. 4
0
static int qt_lf_list_delete(marked_ptr_t        *head,
                             so_key_t             hashed_key,
                             qt_key_t             key,
                             qt_dict_key_equals_f op_equals,
                             qt_dict_cleanup_f    cleanup)
{
    while (1) {
        marked_ptr_t *lprev;
        marked_ptr_t  lcur;
        marked_ptr_t  lnext;
        if (qt_lf_list_find(head, hashed_key, key, &lprev, &lcur, &lnext, op_equals) == NULL) {
            qthread_debug(ALWAYS_OUTPUT, "### inside delete - return 0\n");
            return 0;
        }
        if (qthread_cas_ptr(&PTR_OF(lcur)->next, (void*)CONSTRUCT(0, lnext), (void*)CONSTRUCT(1, lnext)) != (void *)CONSTRUCT(0, lnext)) {
            qthread_debug(ALWAYS_OUTPUT, "### inside delete - cas failed continue\n");
            continue;
        }
        if (qthread_cas(lprev, CONSTRUCT(0, lcur), CONSTRUCT(0, lnext)) == CONSTRUCT(0, lcur)) {
            if (cleanup != NULL) {
                cleanup(PTR_OF(lcur)->key, NULL);
            }
            qpool_free(hash_entry_pool, PTR_OF(lcur));
        } else {
            qt_lf_list_find(head, hashed_key, key, NULL, NULL, NULL, op_equals);                                   // needs to set cur/prev/next
        }
        return 1;
    }
}
Esempio n. 5
0
int qlfqueue_enqueue(qlfqueue_t *q,
                     void       *elem)
{                                      /*{{{ */
    qlfqueue_node_t *tail;
    qlfqueue_node_t *next;
    qlfqueue_node_t *node;

    qassert_ret((elem != NULL), QTHREAD_BADARGS);
    qassert_ret((q != NULL), QTHREAD_BADARGS);

    node = (qlfqueue_node_t *)qpool_alloc(qlfqueue_node_pool);
    /* these asserts should be redundant */
    qassert_ret((node != NULL), QTHREAD_MALLOC_ERROR);

    memset((void *)node, 0, sizeof(qlfqueue_node_t));
    node->value = elem;

    while (1) {
        tail = q->tail;

        hazardous_ptr(0, tail);
        if (tail != q->tail) { continue; }

        next = tail->next;
        if (next != NULL) { /* tail not pointing to last node */
            (void)qthread_cas_ptr((void **)&(q->tail), (void *)tail, next);
            continue;
        }
        /* tail must be pointing to the last node */
        if (qthread_cas_ptr((void **)&(tail->next), (void *)next, node) == next) {
            break;             /* success! */
        }
    }
    (void)qthread_cas_ptr((void **)&(q->tail), (void *)tail, node);
    hazardous_ptr(0, NULL); // release the ptr (avoid hazardptr resource exhaustion)
    return QTHREAD_SUCCESS;
}                                      /*}}} */
Esempio n. 6
0
// old public method
static inline qt_hash qt_hash_create(qt_dict_key_equals_f eq,
                                     qt_dict_hash_f       hash,
                                     qt_dict_cleanup_f    cleanup)
{
    qt_hash tmp;

    if (hash_entry_pool == NULL) {
        if (qthread_cas_ptr(&hash_entry_pool, NULL, (void *)1) == NULL) {
            hash_entry_pool = qpool_create(sizeof(hash_entry));
        } else {
            while (hash_entry_pool == (void *)1) SPINLOCK_BODY();
        }
    }

    tmp = MALLOC(sizeof(qt_dictionary));
    assert(tmp);
    tmp->op_equals  = eq;
    tmp->op_hash    = hash;
    tmp->op_cleanup = cleanup;

    assert(tmp);
    if (hard_max_buckets == 0) {
        hard_max_buckets = pagesize / sizeof(marked_ptr_t);
    }
    tmp->B = calloc(hard_max_buckets, sizeof(marked_ptr_t));
    assert(tmp->B);
    tmp->size  = 2;
    tmp->count = 0;
    {
        hash_entry *dummy = qpool_alloc(hash_entry_pool);
        assert(dummy);
        memset(dummy, 0, sizeof(hash_entry));
        tmp->B[0] = CONSTRUCT(0, dummy);
    }
    return tmp;
}
Esempio n. 7
0
void *qt_hash_put_helper(qt_dictionary *h,
                         qt_key_t       key,
                         void          *value,
                         int            put_choice)
{
    uint64_t lkey = (uint64_t)(uintptr_t)(h->op_hash(key));

    HASH_KEY(lkey);
    assert(h);

    unsigned         bucket    = BASE_SPINE_BUCKET(lkey);
    hash_entry      *e         = qt_malloc(sizeof(hash_entry));   // XXX: should be from a memory pool
    spine_element_t *child_id  = &(h->base[bucket]);
    spine_element_t  child_val = h->base[bucket];
    spine_element_t *cur_id    = NULL;
    spine_t         *cur_spine = NULL;
    unsigned         depth     = 0;

    assert(e != NULL);
    e->hashed_key = lkey;
    e->key        = key;
    e->value      = value;
    e->next       = NULL;
    hash_entry *crt;
    do {
        if (child_val.e == NULL) {
            // place the entry in the hash
            if ((child_val.e = CAS(&(child_id->e), NULL, e)) == NULL) {
                // put success: no potential colliding element was present
                return value;
            }
        } else if (SPINE_PTR_TEST(child_val)) {
            INCREMENT_COUNT(child_id, child_val);
            if (cur_id) {
                DECREMENT_COUNT(cur_id);
            }
            cur_id    = child_id;
            cur_spine = SPINE_PTR(h, child_val);
            depth++;
            assert(depth <= 11); // otherwise, something has gone horribly wrong
            bucket    = SPINE_BUCKET(lkey, depth);
            child_id  = &cur_spine->elements[bucket];
            child_val = cur_spine->elements[bucket];
        } else if (child_val.e->hashed_key != lkey) {
            // upgrade to a spine
            spine_element_t newspine, cur;
            spine_t        *realspine;
            unsigned        bucket1 = SPINE_BUCKET(child_val.e->hashed_key, depth + 1);
            unsigned        bucket2 = SPINE_BUCKET(lkey, depth + 1);

            newspine.s.id                = allocate_spine(h, &realspine);
            realspine->parent            = cur_id;
            realspine->elements[bucket1] = child_val;

            if (bucket1 != bucket2) {            // both elements will be in the new spine
                newspine.s.ctr = SPINE_COUNT(2); // contains 2 elements

                realspine->elements[bucket2].e = e;

                if ((cur.e = CAS(&(child_id->e), child_val.e, newspine.e)) == child_val.e) {
                    // success!
                    if (cur_id) {
                        DECREMENT_COUNT(cur_id);
                    }
                    return value;
                } else {
                    child_val = cur;
                    deallocate_spine(h, newspine.s.id);
                }
            } else {                             // collision in the new spine (unusual; will use unnecessary CAS)
                newspine.s.ctr = SPINE_COUNT(1); // contains 1 element (oldval)

                if ((cur.e = CAS(&(child_id->e), child_val.e, newspine.e)) == child_val.e) {
                    // success
                    continue;
                } else {
                    child_val = cur;
                    deallocate_spine(h, newspine.s.id);
                }
            }
        } else {
            // use the real user-equals operation to differentiate subcases
            // it is possible that the element is there or it may not be there
            hash_entry *head;
            do {
                head    = child_id->e;
                e->next = head;
                crt     = head;
                // find the entry, if it is in the list
                while (crt) {
                    if (h->op_equals(crt->key, key)) {
                        // already exists

                        if (put_choice != PUT_IF_ABSENT) {
                            void **crt_val_adr = &(crt->value);
                            void  *crt_val     = crt->value;
                            while((qthread_cas_ptr(crt_val_adr, \
                                                   crt_val, value)) != crt_val ) {
                                crt_val = crt->value;
                            }
                        }

                        if (cur_id) { DECREMENT_COUNT(cur_id); }
                        return crt->value;
                    }
                    crt = crt->next;
                }
                // and try to insert it at the head of the list;
                // if the list changed, redu the work
            } while (qthread_cas_ptr(&(child_id->e), head, e) != head);
            // printf("IN put: (%s-%s)\n", child_id->e->key, child_id->e->value);
            // if (e->next !=NULL)
            //	printf("next key is %s and value %s\n", e->next->key, e->next->value);
            return e->value;
        }
    } while (1);
}