/* * Logically remove an element by setting a mark bit to 1 * before removing it physically. */ sval_t parse_delete(intset_l_t *set, skey_t key) { node_l_t *pred, *curr; sval_t result = 0; int done = 0; do { PARSE_TRY(); pred = set->head; curr = pred->next; while (likely(curr->key < key)) { pred = curr; curr = curr->next; } UPDATE_TRY(); GL_LOCK(set->lock); /* when GL_[UN]LOCK is defined the [UN]LOCK is not ;-) */ LOCK(ND_GET_LOCK(pred)); LOCK(ND_GET_LOCK(curr)); if (parse_validate(pred, curr)) { if (key == curr->key) { result = curr->val; node_l_t* c_nxt = curr->next; curr->marked = 1; pred->next = c_nxt; #if GC == 1 ssmem_free(alloc, (void*) curr); #endif } done = 1; } GL_UNLOCK(set->lock); UNLOCK(ND_GET_LOCK(curr)); UNLOCK(ND_GET_LOCK(pred)); } while (!done); return result; }
int parse_insert(intset_l_t *set, skey_t key, sval_t val) { node_l_t *curr, *pred, *newnode; int result = -1; do { PARSE_TRY(); pred = set->head; curr = pred->next; while (likely(curr->key < key)) { pred = curr; curr = curr->next; } UPDATE_TRY(); GL_LOCK(set->lock); /* when GL_[UN]LOCK is defined the [UN]LOCK is not ;-) */ LOCK(ND_GET_LOCK(pred)); LOCK(ND_GET_LOCK(curr)); if (parse_validate(pred, curr)) { result = (curr->key != key); if (result) { newnode = new_node_l(key, val, curr, 0); #ifdef __tile__ MEM_BARRIER; #endif pred->next = newnode; } } GL_UNLOCK(set->lock); UNLOCK(ND_GET_LOCK(curr)); UNLOCK(ND_GET_LOCK(pred)); } while (result < 0); return result; }
sval_t lockc_find(intset_l_t *set, skey_t key) { PARSE_TRY(); node_l_t *curr, *next; sval_t res = 0; GL_LOCK(set->lock); /* when GL_[UN]LOCK is defined the [UN]LOCK is not ;-) */ LOCK(ND_GET_LOCK(set->head)); curr = set->head; LOCK(ND_GET_LOCK(curr->next)); next = curr->next; while (next->key < key) { UNLOCK(ND_GET_LOCK(curr)); curr = next; LOCK(ND_GET_LOCK(next->next)); next = curr->next; } if (key == next->key) { res = next->val; } GL_UNLOCK(set->lock); UNLOCK(ND_GET_LOCK(curr)); UNLOCK(ND_GET_LOCK(next)); return res; }
sl_node_t* get_lock(sl_node_t* pred, skey_t key, int lvl) { sl_node_t* succ = pred->next[lvl]; while (succ->key < key) { pred = succ; succ = succ->next[lvl]; } LOCK(ND_GET_LOCK(pred)); succ = pred->next[lvl]; while (succ->key < key) { UNLOCK(ND_GET_LOCK(pred)); pred = succ; LOCK(ND_GET_LOCK(pred)); succ = pred->next[lvl]; } return pred; }
/* * Function unlock_levels is an helper function for the insert and delete * functions. */ inline void unlock_levels(sl_intset_t* set, sl_node_t **nodes, int highestlevel) { #if defined(LL_GLOBAL_LOCK) GL_UNLOCK(set->lock); #else int i; sl_node_t *old = NULL; for (i = 0; i <= highestlevel; i++) { if (old != nodes[i]) { UNLOCK(ND_GET_LOCK(nodes[i])); } old = nodes[i]; } #endif }
node_l_t* new_node_l(skey_t key, sval_t val, node_l_t* next, int initializing) { volatile node_l_t *node; #if GC == 1 if (initializing) /* for initialization AND the coupling algorithm */ { node = (volatile node_l_t *) ssalloc(sizeof(node_l_t)); } else { node = (volatile node_l_t *) ssmem_alloc(alloc, sizeof(node_l_t)); } #else node = (volatile node_l_t *) ssalloc(sizeof(node_l_t)); #endif if (node == NULL) { perror("malloc @ new_node"); exit(1); } node->key = key; node->val = val; node->next = next; node->marked = 0; INIT_LOCK(ND_GET_LOCK(node)); #if defined(__tile__) /* on tilera you may have store reordering causing the pointer to a new node to become visible, before the contents of the node are visible */ MEM_BARRIER; #endif /* __tile__ */ return (node_l_t*) node; }
int lockc_insert(intset_l_t *set, skey_t key, sval_t val) { PARSE_TRY(); UPDATE_TRY(); node_l_t *curr, *next, *newnode; int found; GL_LOCK(set->lock); /* when GL_[UN]LOCK is defined the [UN]LOCK is not ;-) */ LOCK(ND_GET_LOCK(set->head)); curr = set->head; LOCK(ND_GET_LOCK(curr->next)); next = curr->next; while (next->key < key) { UNLOCK(ND_GET_LOCK(curr)); curr = next; LOCK(ND_GET_LOCK(next->next)); next = curr->next; } found = (key == next->key); if (!found) { newnode = new_node_l(key, val, next, 1); #ifdef __tile__ MEM_BARRIER; #endif curr->next = newnode; } GL_UNLOCK(set->lock); UNLOCK(ND_GET_LOCK(curr)); UNLOCK(ND_GET_LOCK(next)); return !found; }
/* * Function optimistic_delete is similar to the method remove of the paper. * Here we avoid the fast search parameter as the comparison is faster in C * than calling the Java compareTo method of the Comparable interface * (cf. p132 of SIROCCO'07 proceedings). */ sval_t optimistic_delete(sl_intset_t *set, skey_t key) { sl_node_t *succs[HERLIHY_MAX_MAX_LEVEL], *preds[HERLIHY_MAX_MAX_LEVEL]; sl_node_t *node_todel, *prev_pred; sl_node_t *pred, *succ; int is_marked, toplevel, highest_locked, i, valid, found; unsigned int backoff; node_todel = NULL; is_marked = 0; toplevel = -1; backoff = 1; PARSE_START_TS(2); while(1) { UPDATE_TRY(); found = optimistic_search(set, key, preds, succs, 1); PARSE_END_TS(2, lat_parsing_rem); /* If not marked and ok to delete, then mark it */ if (is_marked || (found != -1 && ok_to_delete(succs[found], found))) { GL_LOCK(set->lock); /* when GL_[UN]LOCK is defined the [UN]LOCK is not ;-) */ if (!is_marked) { node_todel = succs[found]; LOCK(ND_GET_LOCK(node_todel)); toplevel = node_todel->toplevel; /* Unless it has been marked meanwhile */ if (node_todel->marked) { GL_UNLOCK(set->lock); UNLOCK(ND_GET_LOCK(node_todel)); PARSE_END_INC(lat_parsing_rem); return 0; } node_todel->marked = 1; is_marked = 1; } /* Physical deletion */ highest_locked = -1; prev_pred = NULL; valid = 1; for (i = 0; valid && (i < toplevel); i++) { pred = preds[i]; succ = succs[i]; if (pred != prev_pred) { LOCK(ND_GET_LOCK(pred)); highest_locked = i; prev_pred = pred; } valid = (!pred->marked && ((volatile sl_node_t*) pred->next[i] == (volatile sl_node_t*) succ)); } if (!valid) { unlock_levels(set, preds, highest_locked); if (backoff > 5000) { nop_rep(backoff & MAX_BACKOFF); } backoff <<= 1; continue; } for (i = (toplevel-1); i >= 0; i--) { preds[i]->next[i] = node_todel->next[i]; } sval_t val = node_todel->val; #if GC == 1 ssmem_free(alloc, (void*) node_todel); #endif UNLOCK(ND_GET_LOCK(node_todel)); unlock_levels(set, preds, highest_locked); PARSE_END_INC(lat_parsing_rem); return val; } else { PARSE_END_INC(lat_parsing_rem); return 0; } } }
/* * Function optimistic_insert stands for the add method of the original paper. * Unlocking and freeing the memory are done at the right places. */ int optimistic_insert(sl_intset_t *set, skey_t key, sval_t val) { sl_node_t *succs[HERLIHY_MAX_MAX_LEVEL], *preds[HERLIHY_MAX_MAX_LEVEL]; sl_node_t *node_found, *prev_pred, *new_node; sl_node_t *pred, *succ; int toplevel, highest_locked, i, valid, found; unsigned int backoff; toplevel = get_rand_level(); backoff = 1; PARSE_START_TS(1); while (1) { UPDATE_TRY(); found = optimistic_search(set, key, preds, succs, 1); PARSE_END_TS(1, lat_parsing_put); if (found != -1) { node_found = succs[found]; if (!node_found->marked) { while (!node_found->fullylinked) { PAUSE; } PARSE_END_INC(lat_parsing_put); return 0; } continue; } GL_LOCK(set->lock); /* when GL_[UN]LOCK is defined the [UN]LOCK is not ;-) */ highest_locked = -1; prev_pred = NULL; valid = 1; for (i = 0; valid && (i < toplevel); i++) { pred = preds[i]; succ = succs[i]; if (pred != prev_pred) { LOCK(ND_GET_LOCK(pred)); highest_locked = i; prev_pred = pred; } valid = (!pred->marked && !succ->marked && ((volatile sl_node_t*) pred->next[i] == (volatile sl_node_t*) succ)); } if (!valid) { /* Unlock the predecessors before leaving */ unlock_levels(set, preds, highest_locked); /* unlocks the global-lock in the GL case */ if (backoff > 5000) { nop_rep(backoff & MAX_BACKOFF); } backoff <<= 1; continue; } new_node = sl_new_simple_node(key, val, toplevel, 0); for (i = 0; i < toplevel; i++) { new_node->next[i] = succs[i]; } #if defined(__tile__) MEM_BARRIER; #endif for (i = 0; i < toplevel; i++) { preds[i]->next[i] = new_node; } new_node->fullylinked = 1; unlock_levels(set, preds, highest_locked); PARSE_END_INC(lat_parsing_put); return 1; } }
sval_t alistarh_deleteMin(sl_intset_t *set) { skey_t key; sval_t result; sl_node_t *next, *node; sl_node_t *update[HERLIHY_MAX_MAX_LEVEL]; sl_node_t *succ, *pred; int i, level, continue_flag; retry: if (unlikely(rand_range(100) <= cleaner_percentage)) { //become cleaner result = 0; PARSE_START_TS(4); node = last_dummy_entry->next[0]; while(node->next[0]!=NULL && result==0) { if (unlikely(node->key > node->next[0]->key)) { node = node->next[0]; continue; } succ = NULL; pred = set->head; key = node->key; continue_flag = 0; for (level = levelmax - 1; level >= 0; level--) { succ = pred->next[level]; while (succ->key < key) { pred = succ; succ = succ->next[level]; } update[level] = pred; } PARSE_END_TS(3, lat_parsing_deleteMin++); GL_LOCK(set->lock); succ = pred; int is_garbage; do { succ = succ->next[0]; if (succ->key > key) { GL_UNLOCK(set->lock); continue_flag = 1; break; } LOCK(ND_GET_LOCK(succ)); is_garbage = (succ->key > succ->next[0]->key); if (is_garbage || succ->key != key) { UNLOCK(ND_GET_LOCK(succ)); } else { break; } } while(true); if (continue_flag) { node = node->next[0]; continue; } for (level = succ->toplevel - 1; level >= 0; level--) { pred = get_lock(update[level], key, level); pred->next[level] = succ->next[level]; succ->next[level] = pred; // pointer reversal! :-) UNLOCK(ND_GET_LOCK(pred)); } result = node->val; UNLOCK(ND_GET_LOCK(succ)); GL_UNLOCK(set->lock); #if GC == 1 ssmem_free(alloc, (void*) succ); #endif } PARSE_END_TS(4, lat_parsing_cleaner++); return result; } else //spray & mark as deleted { UPDATE_TRY(); PARSE_START_TS(3); result = 0; node = set->head; next = NULL; for(level = starting_height; level>=0; level-=ALISTARH_LEVELS_TO_DESCEND) { i = (int)rand_range(max_jump_length); for (; i>0; i--) { next = node->next[level]; if (next==NULL || next->next[0]==NULL) break; node = next; } } if (unlikely(node == set->head)) goto retry; if (unlikely(node->val == KEY_MIN+1)) goto retry; if (unlikely(node->key > node->next[0]->key)) goto retry; succ = NULL; pred = set->head; key = node->key; for (level = levelmax - 1; level >= 0; level--) { succ = pred->next[level]; while (succ->key < key) { pred = succ; succ = succ->next[level]; } update[level] = pred; } PARSE_END_TS(3, lat_parsing_deleteMin++); GL_LOCK(set->lock); succ = pred; int is_garbage; do { succ = succ->next[0]; if (succ->key > key) { GL_UNLOCK(set->lock); goto retry; } LOCK(ND_GET_LOCK(succ)); is_garbage = (succ->key > succ->next[0]->key); if (is_garbage || succ->key != key) { UNLOCK(ND_GET_LOCK(succ)); } else { break; } } while(true); for (level = succ->toplevel - 1; level >= 0; level--) { pred = get_lock(update[level], key, level); pred->next[level] = succ->next[level]; succ->next[level] = pred; // pointer reversal! :-) UNLOCK(ND_GET_LOCK(pred)); } result = node->val; UNLOCK(ND_GET_LOCK(succ)); GL_UNLOCK(set->lock); #if GC == 1 ssmem_free(alloc, (void*) succ); #endif return result; } }
sval_t optimistic_delete(sl_intset_t *set, skey_t key) { PARSE_TRY(); UPDATE_TRY(); PARSE_START_TS(2); sl_node_t* update[HERLIHY_MAX_MAX_LEVEL]; sl_node_t* succ = NULL; sl_node_t* pred = set->head; int lvl; for (lvl = levelmax - 1; lvl >= 0; lvl--) { succ = pred->next[lvl]; while (succ->key < key) { pred = succ; succ = succ->next[lvl]; } update[lvl] = pred; } PARSE_END_TS(2, lat_parsing_rem++); GL_LOCK(set->lock); succ = pred; int is_garbage; do { succ = succ->next[0]; if (succ->key > key) { GL_UNLOCK(set->lock); return false; } LOCK(ND_GET_LOCK(succ)); is_garbage = (succ->key > succ->next[0]->key); if (is_garbage || succ->key != key) { UNLOCK(ND_GET_LOCK(succ)); } else { break; } } while(true); for (lvl = succ->toplevel - 1; lvl >= 0; lvl--) { pred = get_lock(update[lvl], key, lvl); pred->next[lvl] = succ->next[lvl]; succ->next[lvl] = pred; /* pointer reversal! :-) */ UNLOCK(ND_GET_LOCK(pred)); } UNLOCK(ND_GET_LOCK(succ)); GL_UNLOCK(set->lock); #if GC == 1 ssmem_free(alloc, (void*) succ); #endif return succ->val; }
int optimistic_insert(sl_intset_t *set, skey_t key, sval_t val) { PARSE_TRY(); UPDATE_TRY(); PARSE_START_TS(1); sl_node_t* update[HERLIHY_MAX_MAX_LEVEL]; sl_node_t* succ; sl_node_t* pred = set->head; int lvl; for (lvl = levelmax - 1; lvl >= 0; lvl--) { succ = pred->next[lvl]; while (succ->key < key) { pred = succ; succ = succ->next[lvl]; } if (unlikely(succ->key == key)) /* at any search level */ { return false; } update[lvl] = pred; } PARSE_END_TS(1, lat_parsing_put++); int rand_lvl = get_rand_level(); /* do the rand_lvl outside the CS */ GL_LOCK(set->lock); pred = get_lock(pred, key, 0); if (unlikely(pred->next[0]->key == key)) { UNLOCK(ND_GET_LOCK(pred)); GL_UNLOCK(set->lock); return false; } sl_node_t* n = sl_new_simple_node(key, val, rand_lvl, 0); LOCK(ND_GET_LOCK(n)); n->next[0] = pred->next[0]; /* we already hold the lock for lvl 0 */ #ifdef __tile__ MEM_BARRIER; #endif pred->next[0] = n; UNLOCK(ND_GET_LOCK(pred)); for (lvl = 1; lvl < n->toplevel; lvl++) { pred = get_lock(update[lvl], key, lvl); n->next[lvl] = pred->next[lvl]; #ifdef __tile__ MEM_BARRIER; #endif pred->next[lvl] = n; UNLOCK(ND_GET_LOCK(pred)); } UNLOCK(ND_GET_LOCK(n)); GL_UNLOCK(set->lock); return 1; }