//---------------------------------------------------------------- fifocell* fifoflush (fifo* ff) { fifocell* next, *cur; fifocell* first; first = fifoget(ff); if (first==0) return 0; cur = first; while ((next = fifoget(ff))) { cur->link = next; cur = next; } cur->link = 0; return first; }
//---------------------------------------------------------------- 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; }
// We dequeue in two stages. First we get the element, and then we // "cleanup" to free the element we got. void* wsfifoget(wsfifo* ff) { void* ptr = fifoget(& ff->ff); if (! ptr) { // Doesn't need to be while. //sleep(1); printf("."); pthread_mutex_lock(& ff->mut); ptr = fifoget(& ff->ff); // If there is STILL nothing while we have the lock then we need to block. if (!ptr) { pthread_cond_wait(& ff->cond, & ff->mut); ptr = fifoget(& ff->ff); // Now we better get something. } // Do this before we unlock? pthread_mutex_unlock(& ff->mut); } //printf(" got val off queue #%d, %p : %p %p %d %d\n", // index, queue_table[index], ptr, (void**)ptr+1, *((int*)((void**)ptr+1)), *((char*)((void**)ptr+1))); ff->last_cell = ptr; return ((void**)ptr)+1; }