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