예제 #1
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;
}                                      /*}}} */
예제 #2
0
// old public method; added last param to distinguish between put and put if absent
static inline hash_entry *qt_hash_put(qt_hash  h,
                                      qt_key_t key,
                                      void    *value,
                                      int      put_choice)
{
    hash_entry *node = qpool_alloc(hash_entry_pool);
    hash_entry *ret  = node;
    size_t      bucket;
    uint64_t    lkey = (uint64_t)(uintptr_t)(h->op_hash(key));

    HASH_KEY(lkey);
    bucket = lkey % h->size;

    assert(node);
    assert((lkey & MSB) == 0);
    node->hashed_key = so_regularkey(lkey);
    node->key        = key; // Also store original key!
    node->value      = value;
    node->next       = (hash_entry*)UNINITIALIZED;

    if (h->B[bucket] == UNINITIALIZED) {
        initialize_bucket(h, bucket);
    }

    if(put_choice == PUT_IF_ABSENT) {
        if (!qt_lf_list_insert(&(h->B[bucket]), node, NULL, &ret, h->op_equals)) {
            qpool_free(hash_entry_pool, node);
            return ret->value;
        }
    } else {
        qt_lf_force_list_insert(&(h->B[bucket]), node, h->op_equals);
    }

    size_t csize = h->size;
    if (qthread_incr(&h->count, 1) / csize > MAX_LOAD) {
        if (2 * csize <= hard_max_buckets) { // this caps the size of the hash
            qthread_cas(&h->size, csize, 2 * csize);
        }
    }
    return ret->value;
}
예제 #3
0
static void initialize_bucket(qt_hash h,
                              size_t  bucket)
{
    size_t       parent = GET_PARENT(bucket);
    marked_ptr_t cur;

    if (h->B[parent] == UNINITIALIZED) {
        initialize_bucket(h, parent);
    }
    hash_entry *dummy = qpool_alloc(hash_entry_pool);
    assert(dummy);
    dummy->hashed_key = so_dummykey(bucket);
    dummy->key        = NULL;
    dummy->value      = NULL;
    dummy->next       = (hash_entry*)UNINITIALIZED;
    if (!qt_lf_list_insert(&(h->B[parent]), dummy, &cur, NULL, h->op_equals)) {
        qpool_free(hash_entry_pool, dummy);
        dummy = PTR_OF(cur);
        while (h->B[bucket] != CONSTRUCT(0, dummy)) ;
    } else {
        h->B[bucket] = CONSTRUCT(0, dummy);
    }
}
예제 #4
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;
}                                      /*}}} */
예제 #5
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;
}