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; } /*}}} */
// 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; }
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); } }
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; } /*}}} */
// 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; }