//---------------------------------------------------------------- fifocell * fifoget (fifo * ff) { fifocell * volatile head; fifocell * next; short done = 0; do { LWARX (&ff->head); head = ff->head; /* read the head cell */ next = head->link; /* read the next cell */ /* WARNING: the next pointer still needs to be checked before reading its value */ if (head == ff->tail) { /* is queue empty or tail falling behind? */ if (head->link == fifo_end(ff) && STWCX (&ff->head, (void *)head, (void *)head)) /* is queue really 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 */ CASLNE (&ff->tail, (void *)head, fifo_end(ff)); } 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 = STWCX (&ff->head, (void *)head, next); } } while (!done); msAtomicDec (&ff->count); if (head == &ff->dummy) { fifoput(ff,head); head = fifoget(ff); } return (fifocell *)head; }
//---------------------------------------------------------------- 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 fifoinit (fifo* ff) { ff->count.value = 0; ff->oc = ff->ic = 0; ff->dummy.link = fifo_end(ff); ff->head = ff->tail = &ff->dummy; }
//---------------------------------------------------------------- void fifoput (fifo * ff, fifocell * cl) { fifocell * volatile tail; cl->link = fifo_end(ff); /* set the cell next pointer to the end marker */ while (1) { 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 */ CASLNE (&ff->tail, (void *)tail, fifo_end(ff)); } } CASLNE (&ff->tail, (void *)tail, fifo_end(ff)); msAtomicInc (&ff->count); }
//---------------------------------------------------------------- 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); }
static void test2() { fifo_t *f1 = fifo_new(1024 * 4); int i; void *p; for (i = 0; i < 1023; i++) { p = fifo_alloc(f1, 13); assert(p); *(int *)p = i; fifo_put(f1, p, 13); p = fifo_get(f1, 13); assert(p); assert(*(int *)p == i); fifo_end(f1, p, 13); } assert(fifo_empty(f1)); }
static void test3() { fifo_t *f1 = fifo_new(1024 * 4); int i; void *p; for (i = 0; i < 1023; i++) { p = fifo_alloc(f1, 13); assert(p); *(int *)p = i; fifo_put(f1, p, 13); p = fifo_extend(f1, p, 13, 13 * 2); assert(p); fifo_put(f1, p, 26); printf("%u %u\n", f1->pt, f1->gt); p = fifo_get(f1, 26); assert(p); assert(*(int *)p == i); fifo_end(f1, p, 26); } assert(fifo_empty(f1)); }