123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110 |
- #include "LockFreeFIFO.h"
- #include "foundation/align.h"
- #include "foundation/atomics.h"
- #if 1
- static int CAS2(FIFO_POINTER *fifo, queue_node_t *tail, size_t icount, queue_node_t *next, size_t icount2)
- {
- NALIGN(8) FIFO_POINTER compare = { tail, icount };
- NALIGN(8) FIFO_POINTER exchange = { next, icount2 };
- return nx_atomic_cmpxchg2(*(int64_t *)&compare, *(int64_t *)&exchange, (volatile int64_t *)fifo);
-
- }
- #else
- inline char CAS2 (volatile void * addr, volatile void * v1, volatile long v2, void * n1, long n2)
- {
- register char c;
- __asm {
- push ebx
- push ecx
- push edx
- push esi
- mov esi, addr
- mov eax, v1
- mov ebx, n1
- mov ecx, n2
- mov edx, v2
- LOCK cmpxchg8b qword ptr [esi]
- sete c
- pop esi
- pop edx
- pop ecx
- pop ebx
- }
- return c;
- }
- #endif
- static int CAS(queue_node_t **fifo, queue_node_t *compare, queue_node_t *exchange)
- {
- return nx_atomic_cmpxchg_pointer(compare, exchange, (void* volatile *)fifo);
- }
- #define ENDFIFO(ff) ((queue_node_t*)0)
- void fifo_init(fifo_t *fifo)
- {
- fifo->dummy.Next = ENDFIFO(fifo);
- fifo->head.fifo_node_t = fifo->tail.fifo_node_t = &fifo->dummy;
- fifo->head.count = fifo->tail.count = 0;
- fifo->count = 0;
- }
- void fifo_push(fifo_t *fifo, queue_node_t *cl)
- {
- queue_node_t * volatile tail;
- size_t icount;
- cl->Next = ENDFIFO(fifo);
- for (;;)
- {
- icount = fifo->tail.count;
- tail = fifo->tail.fifo_node_t;
- if (CAS(&tail->Next, ENDFIFO(fifo), cl))
- {
- break;
- }
- else
- {
- CAS2(&fifo->tail, tail, icount, tail->Next, icount+1);
- }
- }
- CAS2 (&fifo->tail, tail, icount, cl, icount+1);
- nx_atomic_inc(&fifo->count);
- }
- queue_node_t *fifo_pop(fifo_t *fifo)
- {
- queue_node_t * volatile head;
- for (;;)
- {
- size_t ocount = fifo->head.count;
- size_t icount = fifo->tail.count;
- head = fifo->head.fifo_node_t;
- queue_node_t *next = head->Next;
- if (ocount == fifo->head.count)
- {
- if (head == fifo->tail.fifo_node_t)
- {
- if (next == ENDFIFO(fifo))
- {
- return 0;
- }
-
- CAS2(&fifo->tail, head, icount, next, icount+1);
- }
- else if (next != ENDFIFO(fifo))
- {
- if (CAS2(&fifo->head, head, ocount, next, ocount+1))
- {
- break;
- }
- }
- }
- }
- nx_atomic_dec(&fifo->count);
- if (head == &fifo->dummy)
- {
- fifo_push(fifo,head);
- head = fifo_pop(fifo);
- }
- return head;
- }
|