Пример #1
0
int main(int argc, char* argv[]) {

    int res,pdelay;

    pdelay=0;
    if (argc==2) {
        pdelay=atoi(argv[1]);
        if (pdelay<0 || pdelay > MAX_DELAY) {
            fail("wrong delay value");
        }
    }

    report("p lock:",mcs_lock(MUTEX));

    if (fork()) {
        /* parent */
        if (pdelay) sleep(pdelay);
        report("p wait:", mcs_wait(CV,MUTEX));
        report("p unlock:",mcs_unlock(MUTEX));
        wait(NULL);
        exit(0);
    } else {
        report("ch lock:",mcs_lock(MUTEX));
        report("ch broadcast:",mcs_broadcast(CV));
        report("ch unlock:",mcs_unlock(MUTEX));
        exit(0);
    }
}
Пример #2
0
/*
 * trylock GF_cskl_nodes;
 * if GF_cskl_nodes != NULL, transfer a bunch of nodes to _lf_cskl_nodes,
 * otherwise add a few nodes to _lf_cskl_nodes.
 */
static void
csklnode_populate_lfl(
	int maxheight,
	mem_alloc m_alloc)
{
  mcs_node_t me;
  bool acquired = mcs_trylock(&GFCN_lock, &me);
  if (acquired) {
	if (GF_cskl_nodes) {
	  // transfer a bunch of nodes the global free list to the local free list
	  int n = 0;
	  while (GF_cskl_nodes && n < NUM_NODES) {
		csklnode_t *head = GF_cskl_nodes;
		GF_cskl_nodes = GF_cskl_nodes->nexts[0];
		head->nexts[0] = _lf_cskl_nodes;
		_lf_cskl_nodes = head;
		n++;
	  }
	}
	mcs_unlock(&GFCN_lock, &me);
  }
  if (!_lf_cskl_nodes) {
	csklnode_add_nodes_to_lfl(maxheight, m_alloc);
  }
}
Пример #3
0
setval_t set_remove(set_t *s, setkey_t k)
{
    ptst_t  *ptst;
    node_t  *y, *z;
    qnode_t  z_qn;
    setval_t ov = NULL;

    k = CALLER_TO_INTERNAL_KEY(k);

    ptst = critical_enter();

    z = &s->root;
    while ( (y = (k <= z->k) ? z->l : z->r) != NULL )
        z = y;

    if ( z->k == k ) 
    {
        mcs_lock(&z->lock, &z_qn);
        if ( !IS_GARBAGE(z) )
        {
            ov = GET_VALUE(z->v);

            SET_VALUE(z->v, NULL);
        }
        mcs_unlock(&z->lock, &z_qn);
    }

    if ( ov != NULL ) 
        delete_finish(ptst, z);

    critical_exit(ptst);

    return ov;
}
Пример #4
0
void mwrite(char n, int fd) {
    char mc[2];

    mc[0]='a'+n;
    mc[1]='\n';

    if (mcs_lock(mutex_id+fd)) fail("lock failed");
    write(fd,&mc,1);
    sleep(1);
    write(fd,&mc,2);
    if (mcs_unlock(mutex_id+fd)) fail("unlock failed");
}
Пример #5
0
error_t rwlock_wrlock(struct rwlock_s *rwlock)
{
	uint_t irq_state;

	mcs_lock(&rwlock->lock, &irq_state);
	//spinlock_lock(&rwlock->lock);

	if(rwlock->count == 0)
	{
		rwlock->count --;
		//spinlock_unlock(&rwlock->lock);
		mcs_unlock(&rwlock->lock, irq_state);
		return 0;
	}

	wait_on(&rwlock->wr_wait_queue, WAIT_LAST);
	//spinlock_unlock_nosched(&rwlock->lock);
	mcs_unlock(&rwlock->lock, irq_state);
	sched_sleep(current_thread);
	return 0;
}
Пример #6
0
error_t rwlock_rdlock(struct rwlock_s *rwlock)
{
	uint_t irq_state;

	//spinlock_lock(&rwlock->lock);
	mcs_lock(&rwlock->lock, &irq_state);

	/* priority is given to writers */
	if((rwlock->count >= 0) && (wait_queue_isEmpty(&rwlock->wr_wait_queue)))
	{
		rwlock->count ++;
		//spinlock_unlock(&rwlock->lock);
		mcs_unlock(&rwlock->lock, irq_state);
		return 0;
	}
  
	wait_on(&rwlock->rd_wait_queue, WAIT_LAST);
  
	//spinlock_unlock_nosched(&rwlock->lock);
	mcs_unlock(&rwlock->lock, irq_state);
	sched_sleep(current_thread);
	return 0;
}
Пример #7
0
error_t rwlock_destroy(struct rwlock_s *rwlock)
{
	register error_t err = 0;
	uint_t irq_state;

	//spinlock_lock(&rwlock->lock);
	mcs_lock(&rwlock->lock, &irq_state);

	if(rwlock->count != 0)
		err = EBUSY;

	//spinlock_unlock(&rwlock->lock);
	mcs_unlock(&rwlock->lock, irq_state);
	return err;
}
Пример #8
0
/*
 * only free non null csklnode_t*
 * pre-condition: anode is of type csklnpde_t*
 */
void
cskl_free(void* anode)
{
  if (!anode) return;
  // add node to the front of the global free csklnode list.
  mcs_node_t me;
  csklnode_t *node = (csklnode_t*)anode;
  for (int i = 0; i < node->height; i++) {
	node->nexts[i] = NULL;
  }
  mcs_lock(&GFCN_lock, &me);
  node->nexts[0] = GF_cskl_nodes;
  GF_cskl_nodes = node;
  mcs_unlock(&GFCN_lock, &me);
}
Пример #9
0
static void inline
unlock_preds
(csklnode_t *preds[],
	mcs_node_t mcs_nodes[],
	int highestLocked)
{
  // unlock each of my predecessors, as necessary
  csklnode_t *prevPred = NULL;
  for (int layer = 0; layer <= highestLocked; layer++) {
	csklnode_t *pred = preds[layer];
	if (pred != prevPred) {
	  mcs_unlock(&pred->lock, &mcs_nodes[layer]);
	}
	prevPred = pred;
  }
}
Пример #10
0
error_t rwlock_tryrdlock(struct rwlock_s *rwlock)
{
	register error_t err = 0;
	uint_t irq_state;

	//spinlock_lock(&rwlock->lock);
	mcs_lock(&rwlock->lock, &irq_state);

	if((rwlock->count >= 0) && (wait_queue_isEmpty(&rwlock->wr_wait_queue)))
		rwlock->count ++;
	else
		err = EBUSY;

	//spinlock_unlock(&rwlock->lock);
	mcs_unlock(&rwlock->lock, irq_state);
	return err;
}
Пример #11
0
error_t rwlock_unlock(struct rwlock_s *rwlock)
{
	register error_t err = 0;
	uint_t irq_state;

	//spinlock_lock(&rwlock->lock);
	mcs_lock(&rwlock->lock, &irq_state);

	if(rwlock->count == 0)
	{
		printk(ERROR, "ERROR: Unexpected rwlock_unlock\n");
		err = EPERM;
		goto fail_eperm;
	}
  
	if(rwlock->count > 1)  /* caller is a reader and no waiting writers */
	{
		rwlock->count --; 
		goto unlock_end;
	}

	/* We are the last reader or a writer */
	rwlock->count = 0;

	if((wakeup_one(&rwlock->wr_wait_queue, WAIT_FIRST)))
	{
		rwlock->count --;
		goto unlock_end;
	}

	/* No pending writer was found */
	rwlock->count += wakeup_all(&rwlock->rd_wait_queue);
  
fail_eperm:
unlock_end:
	//spinlock_unlock(&rwlock->lock);
	mcs_unlock(&rwlock->lock, irq_state);
	return err;
}
Пример #12
0
/*
 * TODO: this function is not used anywhere and leaks memory.
 */
bool
cskl_delete(cskiplist_t *cskl, void *value)
{
  int max_height = cskl->max_height;
  bool node_is_marked = false;
  csklnode_t     *node   = NULL;

  for (;;) {
	csklnode_t     *preds[max_height];
	csklnode_t     *succs[max_height];
	mcs_node_t  mcs_nodes[max_height];
	int         height = -1;

	//--------------------------------------------------------------------------
	// Look for a node matching v
	//--------------------------------------------------------------------------
	int layer = cskiplist_find_helper(cskl->compare, cskl, value,
		preds, succs, cskiplist_find_full);

	//--------------------------------------------------------------------------
	// A matching node is available to remove. We may have marked it earlier as
	// we began its removal.
	//--------------------------------------------------------------------------
	if (node_is_marked ||
		(layer != NO_LAYER &&
			cskiplist_node_is_removable(succs[layer], layer))) {

	  //------------------------------------------------------------------------
	  // if I haven't already marked this node for deletion, do so.
	  //------------------------------------------------------------------------
	  if (!node_is_marked) {
		node = succs[layer];
		height = node->height;
		mcs_lock(&node->lock, &mcs_nodes[layer]);
		if (node->marked) {
		  mcs_unlock(&node->lock, &mcs_nodes[layer]);
		  return false;
		}
		node->marked = true;
		node_is_marked = true;
	  }
	  //------------------------------------------------------------------------
	  // Post-condition: Node is marked and locked.
	  //------------------------------------------------------------------------

	  //------------------------------------------------------------------------
	  // Acquire a lock on node's predecessor at each layer.
	  //
	  // valid condition:
	  //   no predecessor is marked
	  //   each of my predecessors still points to the successor I recorded (me)
	  //
	  // If the valid condition is not satisfied, unlock all of my predecessors
	  // and retry.
	  //------------------------------------------------------------------------
	  int highestLocked = -1;
	  csklnode_t *pred, *succ;
	  csklnode_t *prevPred = NULL;
	  bool valid = true;
	  for (int layer = 0; valid && (layer < height); layer++) {
		pred = preds[layer];
		succ = succs[layer];
		if (pred != prevPred) {
		  mcs_lock(&pred->lock, &mcs_nodes[layer]);
		  highestLocked = layer;
		  prevPred = pred;
		}
		valid = !pred->marked && pred->nexts[layer] == succ;
	  }

	  if (!valid) {
		unlock_preds(preds, mcs_nodes, highestLocked);
		continue;
	  }
	  //-----------------------------------------------------------------------
	  // Post-condition: All predecessors are locked for delete.
	  //-----------------------------------------------------------------------

	  //-----------------------------------------------------------------------
	  // Complete the deletion: Splice out node at each layer and release lock
	  // on node's predecessor at each layer.
	  //-----------------------------------------------------------------------
	  for (int layer = height - 1; layer >= 0; layer--) {
		// Splice out node at layer.
		preds[layer]->nexts[layer] = node->nexts[layer];
	  }

	  // Unlock self.
	  mcs_unlock(&node->lock, &mcs_nodes[layer]);

	  unlock_preds(preds, mcs_nodes, highestLocked);
	  return true;
	} else {
	  return false;
	}
  }
}
Пример #13
0
static void fix_unbalance_up(ptst_t *ptst, node_t *x)
{
    qnode_t x_qn, g_qn, p_qn, w_qn, gg_qn;
    node_t *g, *p, *w, *gg;
    int done = 0;

    do {
        assert(IS_UNBALANCED(x->v));
        if ( IS_GARBAGE(x) ) return;

        p  = x->p;
        g  = p->p;
        gg = g->p;

        mcs_lock(&gg->lock, &gg_qn);
        if ( !ADJACENT(gg, g) || IS_UNBALANCED(gg->v) || IS_GARBAGE(gg) ) 
            goto unlock_gg;

        mcs_lock(&g->lock, &g_qn);
        if ( !ADJACENT(g, p) || IS_UNBALANCED(g->v) ) goto unlock_ggg;

        mcs_lock(&p->lock, &p_qn);
        if ( !ADJACENT(p, x) || IS_UNBALANCED(p->v) ) goto unlock_pggg;

        mcs_lock(&x->lock, &x_qn);
        
        assert(IS_RED(x->v));
        assert(IS_UNBALANCED(x->v));

        if ( IS_BLACK(p->v) )
        {
            /* Case 1. Nothing to do. */
            x->v = MK_BALANCED(x->v);
            done = 1;
            goto unlock_xpggg;
        }

        if ( IS_ROOT(x) )
        {
            /* Case 2. */
            x->v = MK_BLACK(MK_BALANCED(x->v));
            done = 1;
            goto unlock_xpggg;
        }

        if ( IS_ROOT(p) )
        {
            /* Case 2. */
            p->v = MK_BLACK(p->v);
            x->v = MK_BALANCED(x->v);
            done = 1;
            goto unlock_xpggg;
        }

        if ( g->l == p ) w = g->r; else w = g->l;
        mcs_lock(&w->lock, &w_qn);

        if ( IS_RED(w->v) )
        {
            /* Case 5. */
            /* In all other cases, doesn't change colour or subtrees. */
            if ( IS_UNBALANCED(w->v) ) goto unlock_wxpggg;
            g->v = MK_UNBALANCED(MK_RED(g->v));
            p->v = MK_BLACK(p->v);
            w->v = MK_BLACK(w->v);
            x->v = MK_BALANCED(x->v);
            done = 2;
            goto unlock_wxpggg;
        }

        /* Cases 3 & 4. Both of these need the great-grandfather locked. */
        if ( p == g->l )
        {
            if ( x == p->l )
            {
                /* Case 3. Single rotation. */
                x->v = MK_BALANCED(x->v);
                p->v = MK_BLACK(p->v);
                g->v = MK_RED(g->v);
                right_rotate(ptst, g);
            }
            else
            {
                /* Case 4. Double rotation. */
                x->v = MK_BALANCED(MK_BLACK(x->v));
                g->v = MK_RED(g->v);
                left_rotate(ptst, p);
                right_rotate(ptst, g);                
            }
        }
        else /* SYMMETRIC CASE */
        {
            if ( x == p->r )
            {
                /* Case 3. Single rotation. */
                x->v = MK_BALANCED(x->v);
                p->v = MK_BLACK(p->v);
                g->v = MK_RED(g->v);
                left_rotate(ptst, g);
            }
            else
            {
                /* Case 4. Double rotation. */
                x->v = MK_BALANCED(MK_BLACK(x->v));
                g->v = MK_RED(g->v);
                right_rotate(ptst, p);
                left_rotate(ptst, g);                
            }
        }

        done = 1;

    unlock_wxpggg:
        mcs_unlock(&w->lock, &w_qn);
    unlock_xpggg:
        mcs_unlock(&x->lock, &x_qn);
    unlock_pggg:
        mcs_unlock(&p->lock, &p_qn);
    unlock_ggg:
        mcs_unlock(&g->lock, &g_qn);
    unlock_gg:
        mcs_unlock(&gg->lock, &gg_qn);
        
        if ( done == 2 )
        {
            x = g;
            done = 0;
        }
    }
    while ( !done );
}
Пример #14
0
static void fix_unbalance_down(ptst_t *ptst, node_t *x)
{
    /* WN == W_NEAR, WF == W_FAR (W_FAR is further, in key space, from X). */
    qnode_t x_qn, w_qn, p_qn, g_qn, wn_qn, wf_qn;
    node_t *w, *p, *g, *wn, *wf;
    int done = 0;

    do {
        if ( !IS_UNBALANCED(x->v) || IS_GARBAGE(x) ) return;

        p = x->p;
        g = p->p;

        mcs_lock(&g->lock, &g_qn);
        if ( !ADJACENT(g, p) || IS_UNBALANCED(g->v) || IS_GARBAGE(g) )
            goto unlock_g;

        mcs_lock(&p->lock, &p_qn);
        if ( !ADJACENT(p, x) || IS_UNBALANCED(p->v) ) goto unlock_pg;

        mcs_lock(&x->lock, &x_qn);

        if ( !IS_BLACK(x->v) || !IS_UNBALANCED(x->v) )
        {
            done = 1;
            goto unlock_xpg;
        }

        if ( IS_ROOT(x) )
        {
            x->v = MK_BALANCED(x->v);
            done = 1;
            goto unlock_xpg;
        }

        w = (x == p->l) ? p->r : p->l;
        mcs_lock(&w->lock, &w_qn);
        if ( IS_UNBALANCED(w->v) )
        {
            if ( IS_BLACK(w->v) )
            {
                /* Funky relaxed rules to the rescue. */
                x->v = MK_BALANCED(x->v);
                w->v = MK_BALANCED(w->v);
                if ( IS_BLACK(p->v) )
                {
                    p->v = MK_UNBALANCED(p->v);
                    done = 2;
                }
                else
                {
                    p->v = MK_BLACK(p->v);
                    done = 1;
                }
            }
            goto unlock_wxpg;
        }

        assert(!IS_LEAF(w));
        
        if ( x == p->l )
        {
            wn = w->l;
            wf = w->r;
        }
        else
        {
            wn = w->r;
            wf = w->l;
        }

        mcs_lock(&wn->lock, &wn_qn);
        /* Hanke has an extra relaxed transform here. It's not needed. */
        if ( IS_UNBALANCED(wn->v) ) goto unlock_wnwxpg;

        mcs_lock(&wf->lock, &wf_qn);
        if ( IS_UNBALANCED(wf->v) ) goto unlock_wfwnwxpg;

        if ( IS_RED(w->v) )
        {
            /* Case 1. Rotate at parent. */
            assert(IS_BLACK(p->v) && IS_BLACK(wn->v) && IS_BLACK(wf->v));
            w->v = MK_BLACK(w->v);
            p->v = MK_RED(p->v);
            if ( x == p->l ) left_rotate(ptst, p); else right_rotate(ptst, p);
            goto unlock_wfwnwxpg;
        }

        if ( IS_BLACK(wn->v) && IS_BLACK(wf->v) )
        {
            if ( IS_RED(p->v) )
            {
                /* Case 2. Simple recolouring. */
                p->v = MK_BLACK(p->v);
                done = 1;
            }
            else
            {
                /* Case 5. Simple recolouring. */
                p->v = MK_UNBALANCED(p->v);
                done = 2;
            }
            w->v = MK_RED(w->v);
            x->v = MK_BALANCED(x->v);
            goto unlock_wfwnwxpg;
        }

        if ( x == p->l )
        {
            if ( IS_RED(wf->v) )
            {
                /* Case 3. Single rotation. */
                wf->v = MK_BLACK(wf->v);
                w->v = SET_COLOUR(w->v, GET_COLOUR(p->v));
                p->v = MK_BLACK(p->v);
                x->v = MK_BALANCED(x->v);
                left_rotate(ptst, p);
            }
            else
            {
                /* Case 4. Double rotation. */
                assert(IS_RED(wn->v));
                wn->v = SET_COLOUR(wn->v, GET_COLOUR(p->v));
                p->v = MK_BLACK(p->v);
                x->v = MK_BALANCED(x->v);
                right_rotate(ptst, w);
                left_rotate(ptst, p);
            }
        }
        else /* SYMMETRIC CASE: X == P->R  */
        {
            if ( IS_RED(wf->v) )
            {
                /* Case 3. Single rotation. */
                wf->v = MK_BLACK(wf->v);
                w->v = SET_COLOUR(w->v, GET_COLOUR(p->v));
                p->v = MK_BLACK(p->v);
                x->v = MK_BALANCED(x->v);
                right_rotate(ptst, p);
            }
            else
            {
                /* Case 4. Double rotation. */
                assert(IS_RED(wn->v));
                wn->v = SET_COLOUR(wn->v, GET_COLOUR(p->v));
                p->v = MK_BLACK(p->v);
                x->v = MK_BALANCED(x->v);
                left_rotate(ptst, w);
                right_rotate(ptst, p);
            }
        }

        done = 1;

    unlock_wfwnwxpg:
        mcs_unlock(&wf->lock, &wf_qn);
    unlock_wnwxpg:
        mcs_unlock(&wn->lock, &wn_qn);
    unlock_wxpg:
        mcs_unlock(&w->lock, &w_qn);
    unlock_xpg:
        mcs_unlock(&x->lock, &x_qn);
    unlock_pg:
        mcs_unlock(&p->lock, &p_qn);
    unlock_g:
        mcs_unlock(&g->lock, &g_qn);
        
        if ( done == 2 )
        {
            x = p;
            done = 0;
        }
    }
    while ( !done );
}
Пример #15
0
int main(int argc, char* argv[]){

	int res,turns,i;
	int pp[2];
	char * text;

	if (argc!=2){
		fail("one argument needed");
	}

	turns=atoi(argv[1]);
	if (turns<0 || turns > MAX_DELAY){
		fail("wrong number of turns");
	}
	pipe(pp);

	setsid();
	mutex= getpid();
	cv1= mutex<<1;
	cv2= (mutex<<1)+1;
	if (fork()){
		/* parent */
		int r;
		char buf[10];

		for (i=0;i< turns; i++){
			mcs_wait(cv1,mutex);

			r= read(pp[0],buf,2);
			if (r!=2){
				if (r!=1){
					fprintf(stderr,"FAIL: pipe read failed.\n");
					kill(0, SIGTERM);
				}
				mcs_wait(cv1,mutex);
				r= read(pp[0],buf,2);
				if (r!=1){
					fprintf(stderr,"FAIL: unexpected number of bytes in pipe.\n");
					kill(0, SIGTERM);
				}
			}
			write(1,"TI",2);
			sleep(1);
			write(1,"C\n",2);
			mcs_broadcast(cv2);
		}
		mcs_unlock(mutex);
	} else {
		fork();

		mcs_lock(mutex);
		mcs_broadcast(cv1);
		write(pp[1],"0",1);
		for (i=0;i< turns; i++){
			mcs_wait(cv2,mutex);
			write(1,"TA",2);
			sleep(1);
			write(1,"C\n",2);
			mcs_broadcast(cv1);
			write(pp[1],"0",1);
		}
		mcs_unlock(mutex);
	}

	wait(NULL);
	exit(0);
}
Пример #16
0
static void delete_finish(ptst_t *ptst, node_t *x)
{
    qnode_t g_qn, p_qn, w_qn, x_qn;
    node_t *g, *p, *w;
    int done = 0;

    do {
        if ( IS_GARBAGE(x) ) return;

        p = x->p;
        g = p->p;

        mcs_lock(&g->lock, &g_qn);
        if ( !ADJACENT(g, p) || IS_UNBALANCED(g->v) || IS_GARBAGE(g) ) 
            goto unlock_g;
        
        mcs_lock(&p->lock, &p_qn);
        /* Removing unbalanced red nodes is okay. */
        if ( !ADJACENT(p, x) || (IS_UNBALANCED(p->v) && IS_BLACK(p->v)) )
            goto unlock_pg;

        mcs_lock(&x->lock, &x_qn);
        if ( IS_UNBALANCED(x->v) ) goto unlock_xpg;        
        if ( GET_VALUE(x->v) != NULL )
        {
            done = 1;
            goto unlock_xpg;
        }

        if ( p->l == x ) w = p->r; else w = p->l;
        assert(w != x);
        mcs_lock(&w->lock, &w_qn);
        if ( IS_UNBALANCED(w->v) ) goto unlock_wxpg;

        if ( g->l == p ) g->l = w; else g->r = w; 
        MK_GARBAGE(p); gc_free(ptst, p, gc_id);
        MK_GARBAGE(x); gc_free(ptst, x, gc_id);
        w->p = g;
        if ( IS_BLACK(p->v) && IS_BLACK(w->v) )
        {
            w->v = MK_UNBALANCED(w->v);
            done = 2;
        }
        else
        {
            w->v = MK_BLACK(w->v);
            done = 1;
        }

    unlock_wxpg:
        mcs_unlock(&w->lock, &w_qn);
    unlock_xpg:
        mcs_unlock(&x->lock, &x_qn);
    unlock_pg:
        mcs_unlock(&p->lock, &p_qn);
    unlock_g:
        mcs_unlock(&g->lock, &g_qn);
    }
    while ( !done );

    if ( done == 2 ) fix_unbalance_down(ptst, w);
}
Пример #17
0
setval_t set_update(set_t *s, setkey_t k, setval_t v, int overwrite)
{
    ptst_t  *ptst;
    qnode_t  y_qn, z_qn;
    node_t  *y, *z, *new_internal, *new_leaf;
    int      fix_up = 0;
    setval_t ov = NULL;

    k = CALLER_TO_INTERNAL_KEY(k);

    ptst = critical_enter();

 retry:
    z = &s->root;
    while ( (y = (k <= z->k) ? z->l : z->r) != NULL )
        z = y;
    
    y = z->p;
    mcs_lock(&y->lock, &y_qn);
    if ( (((k <= y->k) ? y->l : y->r) != z) || IS_GARBAGE(y) )
    {
        mcs_unlock(&y->lock, &y_qn);
        goto retry;
    }

    mcs_lock(&z->lock, &z_qn);
    assert(!IS_GARBAGE(z) && IS_LEAF(z));

    if ( z->k == k )
    {
        ov = GET_VALUE(z->v);
        if ( overwrite || (ov == NULL) )
            SET_VALUE(z->v, v);
    }
    else
    {
        new_leaf     = gc_alloc(ptst, gc_id);
        new_internal = gc_alloc(ptst, gc_id);
        new_leaf->k = k;
        new_leaf->v = MK_BLACK(v);
        new_leaf->l = NULL;
        new_leaf->r = NULL;

        new_leaf->p = new_internal;
        mcs_init(&new_leaf->lock);
        if ( z->k < k )
        {
            new_internal->k = z->k;
            new_internal->l = z;
            new_internal->r = new_leaf;
        }
        else
        {
            new_internal->k = k;
            new_internal->l = new_leaf;
            new_internal->r = z;
        }
        new_internal->p = y;
        mcs_init(&new_internal->lock);

        if ( IS_UNBALANCED(z->v) )
        {
            z->v = MK_BALANCED(z->v);
            new_internal->v = MK_BLACK(INTERNAL_VALUE);
        }
        else if ( IS_RED(y->v) )
        {
            new_internal->v = MK_UNBALANCED(MK_RED(INTERNAL_VALUE));
            fix_up = 1;
        }
        else
        {
            new_internal->v = MK_RED(INTERNAL_VALUE);
        }

        WMB();

        z->p = new_internal;
        if ( y->l == z ) y->l = new_internal; else y->r = new_internal;
    }

    mcs_unlock(&y->lock, &y_qn);
    mcs_unlock(&z->lock, &z_qn);

    if ( fix_up ) 
        fix_unbalance_up(ptst, new_internal);

 out:
    critical_exit(ptst);

    return ov;
}