data_type dequeue() { pointer_t tail, head, next; data_type val=NULL; while(true){ head = this->head_; tail = this->tail_; next = (head.ptr)->next; if (head != this->head_) continue; if(head.ptr == tail.ptr){ if (next.ptr == NULL){ return 1; } pointer_t new_pt(next.ptr, tail.tag+1); CAS2(&(this->tail_), tail, new_pt); } else{ val = next.ptr->value; pointer_t new_pt(next.ptr, head.tag+1); if(CAS2(&(this->head_), head, new_pt)){ break; } } } delete head.ptr; return val; }
//---------------------------------------------------------------- fifocell * fifoget(fifo * ff) { fifocell * volatile head; fifocell * next; unsigned long ic, oc; short done = 0; do { oc = ff->oc; /* read the head modification count */ ic = ff->ic; /* read the tail modification count */ head = ff->head; /* read the head cell */ next = head->link; /* read the next cell */ if (oc == ff->oc) { /* ensures that next is a valid pointer */ /* to avoid failure when reading next value */ if (head == ff->tail) { /* is queue empty or tail falling behind? */ if (next == fifo_end(ff)) /* is queue empty? */ return 0; /* queue is empty; return NULL */ /* tail is pointing to head in a non empty queue, */ /* try to set tail to the next cell */ CAS2 (&ff->tail, head, ic, next, ic+1); } else if (next != fifo_end(ff)) { /* if we are not competing on the dummy cell */ /* and we try to set head to the next cell */ done = CAS2 (&ff->head, head, oc, next, oc+1); } } } while (!done); msAtomicDec (&ff->count); if (head == &ff->dummy) { fifoput(ff,head); head = fifoget(ff); } return (fifocell *)head; }
//---------------------------------------------------------------- void fifoput (fifo * ff, fifocell * cl) { long ic; fifocell * volatile tail; cl->link = fifo_end(ff); /* set the cell next pointer to the end marker */ while (1) { ic = ff->ic; /* read the tail modification count */ tail = ff->tail; /* read the tail cell */ /* try to link the cell to the tail cell */ if (CAS (&tail->link, fifo_end(ff), cl)) break; else /* tail was not pointing to the last cell, try to set tail to the next cell */ CAS2 (&ff->tail, tail, ic, tail->link, ic+1); } /* enqeue is done, try to set tail to the enqueued cell */ CAS2 (&ff->tail, tail, ic, cl, ic+1); msAtomicInc (&ff->count); }
/* on intel architecture, the ABA problem is catched using oc (out count) and a CAS2 */ lifocell* lfpop (lifo * lf) { volatile long oc; lifocell * volatile top; do { oc = lf->oc; top = lf->top; if (!top) return 0; } while (!CAS2 (&lf->top, top, oc, top->link, oc+1)); msAtomicDec (&lf->count); return top; }
void enqueue(data_type val) { pointer_t tail, next; node_t* nd = new node_t(); nd->value = val; //printf("%lld\n", val); while(true){ tail = this->tail_; next = tail.ptr->next; if (tail == this->tail_) { if(next.ptr == NULL) { pointer_t new_pt(nd, next.tag+1); if(CAS2(&(this->tail_.ptr->next), next, new_pt)){ break; // Enqueue done! } }else { pointer_t new_pt(next.ptr, tail.tag+1); CAS2(&(this->tail_), tail, new_pt); } } } pointer_t new_pt(nd, tail.tag+1); CAS2(&(this->tail_), tail, new_pt); }