static void delete_by_rotation(ptst_t *ptst, node_t *f, int dir, qnode_t *pqn[], int lock_idx) { node_t *g, *h, *s = FOLLOW(f, dir); if ( s->v != NULL ) { UNLOCK(f, pqn[lock_idx+0]); UNLOCK(s, pqn[lock_idx+1]); return; } if ( s->l == NULL ) _remove(ptst, f, dir, RIGHT, pqn+lock_idx); else if ( s->r == NULL ) _remove(ptst, f, dir, LEFT, pqn+lock_idx); else { g = rotate(ptst, f, dir, LEFT, &h, pqn+lock_idx); lock_idx ^= 2; if ( h->l == NULL ) { assert(h->v == NULL); _remove(ptst, g, RIGHT, RIGHT, pqn+lock_idx); } else { delete_by_rotation(ptst, g, RIGHT, pqn, lock_idx); LOCK(f, pqn[0]); if ( (g != FOLLOW(f, dir)) || IS_BLUE(f) ) { UNLOCK(f, pqn[0]); } else { LOCK(g, pqn[1]); /* * XXX Check that there is a node H to be rotated up. * This is missing from the original paper, and must surely * be a bug (we lost all locks at previous delete_by_rotation, * so we can't know the existence of G's children). */ if ( g->r != NULL ) { g = rotate(ptst, f, dir, RIGHT, &h, pqn); UNLOCK(g, pqn[2]); UNLOCK(h, pqn[3]); } else { UNLOCK(f, pqn[0]); UNLOCK(g, pqn[1]); } } } } }
static void _remove(ptst_t *ptst, node_t *a, int dir1, int dir2, qnode_t **pqn) { node_t *b = FOLLOW(a, dir1), *c = FOLLOW(b, dir2); assert(FOLLOW(b, FLIP(dir2)) == NULL); assert(!IS_BLUE(a)); assert(!IS_BLUE(b)); UPDATE(a, dir1, c); UPDATE(b, FLIP(dir2), c); b->p = a; MK_BLUE(b); gc_free(ptst, b, gc_id); UNLOCK(a, pqn[0]); UNLOCK(b, pqn[1]); }
static node_t *strong_search(node_t *n, setkey_t k, qnode_t *qn) { node_t *b = n; node_t *a = FOLLOW(b, k); retry: while ( (a != NULL) && (a->k != k) ) { b = a; a = FOLLOW(a, k); } if ( a == NULL ) { LOCK(b, qn); if ( IS_GARBAGE(b) ) { UNLOCK(b, qn); a = b->p; goto retry; } else if ( (a = FOLLOW(b, k)) != NULL ) { UNLOCK(b, qn); goto retry; } a = b; } else { LOCK(a, qn); if ( IS_GARBAGE(a) ) { UNLOCK(a, qn); a = a->p; goto retry; } else if ( IS_REDUNDANT(a) ) { UNLOCK(a, qn); a = a->r; goto retry; } } return a; }
setval_t set_remove(set_t *s, setkey_t k) { node_t *f, *w; qnode_t qn[4], *pqn[] = { qn+0, qn+1, qn+2, qn+3, qn+0, qn+1 }; int dir; setval_t v = NULL; ptst_t *ptst; k = CALLER_TO_INTERNAL_KEY(k); ptst = critical_enter(); f = find(&s->root, k, pqn[0], &dir); if ( (w = FOLLOW(f, dir)) != NULL ) { LOCK(w, pqn[1]); v = w->v; w->v = NULL; assert(!IS_BLUE(w)); delete_by_rotation(ptst, f, dir, pqn, 0); } else { UNLOCK(f, pqn[0]); } critical_exit(ptst); return v; }
static node_t *rotate(ptst_t *ptst, node_t *a, int dir1, int dir2, node_t **pc, qnode_t *pqn[]) { node_t *b = FOLLOW(a, dir1), *c = FOLLOW(b, dir2); node_t *bp = gc_alloc(ptst, gc_id), *cp = gc_alloc(ptst, gc_id); qnode_t c_qn; LOCK(c, &c_qn); memcpy(bp, b, sizeof(*b)); memcpy(cp, c, sizeof(*c)); mcs_init(&bp->lock); mcs_init(&cp->lock); LOCK(bp, pqn[3]); LOCK(cp, pqn[2]); assert(!IS_BLUE(a)); assert(!IS_BLUE(b)); assert(!IS_BLUE(c)); UPDATE(cp, FLIP(dir2), bp); UPDATE(bp, dir2, FOLLOW(c, FLIP(dir2))); UPDATE(a, dir1, cp); b->p = a; MK_BLUE(b); c->p = cp; MK_BLUE(c); gc_free(ptst, b, gc_id); gc_free(ptst, c, gc_id); UNLOCK(a, pqn[0]); UNLOCK(b, pqn[1]); UNLOCK(c, &c_qn); *pc = bp; return cp; }
setval_t set_update(set_t *s, setkey_t k, setval_t v, int overwrite) { node_t *f, *w; qnode_t f_qn, w_qn; int dir; setval_t ov = NULL; ptst_t *ptst; k = CALLER_TO_INTERNAL_KEY(k); ptst = critical_enter(); retry: f = find(&s->root, k, &f_qn, &dir); if ( (w = FOLLOW(f, dir)) != NULL ) { /* Protected by parent lock. */ assert(!IS_BLUE(w)); ov = w->v; if ( overwrite || (ov == NULL) ) w->v = v; } else { w = gc_alloc(ptst, gc_id); w->l = NULL; w->r = NULL; w->v = v; w->k = k; mcs_init(&w->lock); UPDATE(f, dir, w); } UNLOCK(f, &f_qn); critical_exit(ptst); return ov; }
static node_t *find(node_t *n, setkey_t k, qnode_t *qn, int *pdir) { int dir; node_t *f, *s; s = n; do { f = s; retry: if ( k < f->k ) { dir = LEFT; s = f->l; } else { dir = RIGHT; s = f->r; } } while ( (s != NULL) && (s->k != k) ); LOCK(f, qn); if ( IS_BLUE(f) ) { UNLOCK(f, qn); f = f->p; goto retry; } if ( s != FOLLOW(f, dir) ) { UNLOCK(f, qn); goto retry; } *pdir = dir; return f; }
static node_t *weak_search(node_t *n, setkey_t k) { while ( (n != NULL) && (n->k != k) ) n = FOLLOW(n, k); return n; }
static inline lispobj cdr(lispobj conscell) { return FOLLOW(conscell,LIST_POINTER,cons).cdr; }