// File: /workspace/github_c_makefile_star2_O0/darkautism[P]lfqueue/lfq.c
// Function: lfq_dequeue_tid
void * lfq_dequeue_tid(struct lfq_ctx *ctx, int tid ) {
	//int cn_runtimes = 0;
	volatile struct lfq_node *old_head, *new_head;
#if 1  // HP[tid] stuff is necessary for deallocation.  (but it's still not safe).
	do {
	retry:  // continue jumps to the bottom of the loop, and would attempt a CAS with uninitialized new_head
		old_head = ctx->head;
		ctx->HP[tid] = old_head;  // seq-cst store.  (better: use xchg instead of mov + mfence on x86)
		mb();

		if (old_head != ctx->head)  // another thread freed it before seeing our HP[tid] store
			goto retry;
		new_head = old_head->next;   // FIXME: crash with old_head=NULL during deallocation (tid=5)?  (main thread=25486, this=25489)
		if (new_head==0 /* || new_head != old_head->next*/ ){  // redoing the same load isn't useful
			ctx->HP[tid] = 0;
			return 0;  // never remove the last node
		}
#ifdef DEBUG
		assert(new_head != (void*)-1 && "read an already-freed node");
#endif
	} while( ! CAS(&ctx->head, old_head, new_head) );
#else  // without HP[] stuff
	do {
		old_head = ctx->head;
		//ctx->HP[tid] = old_head;
		new_head = old_head->next;
		//if (old_head != ctx->head) continue;
		if (!new_head) {
			// ctx->HP[tid] = 0;
			return 0;  // never remove the last node
		}
#ifdef DEBUG
		assert(new_head != (void*)-1 && "read an already-freed node");
#endif
	} while( !CAS(&ctx->head, old_head, new_head) );
#endif
//	mb();  // CAS is already a memory barrier, at least on x86.

	// we've atomically advanced head, and we're the thread that won the race to claim a node
	// We return the data from the *new* head.
	// The list starts off with a dummy node, so the current head is always a node that's already been read.

	ctx->HP[tid] = 0;
	void *ret = new_head->data;
	new_head->can_free = true;
//	ATOMIC_SUB( &ctx->count, 1 );

	//old_head->next = (void*)-1;  // done in safe-free in the actual free() path.  poison the pointer to detect use-after-free

	// we need to avoid freeing until other readers are definitely not going to load its ->next in the CAS loop
	safe_free(ctx, (struct lfq_node *)old_head);

	//free(old_head);
	return ret;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x30, %rsp
movq %rdi, -0x10(%rbp)
movl %esi, -0x14(%rbp)
jmp 0x15f1
movq -0x10(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x20(%rbp)
movq -0x20(%rbp), %rdx
movq -0x10(%rbp), %rax
movq 0x10(%rax), %rax
movslq -0x14(%rbp), %rcx
movq %rdx, (%rax,%rcx,8)
mfence
movq -0x20(%rbp), %rax
movq -0x10(%rbp), %rcx
movq (%rcx), %rcx
cmpq %rcx, %rax
je 0x1625
jmp 0x15f1
movq -0x20(%rbp), %rax
movq 0x8(%rax), %rax
movq %rax, -0x28(%rbp)
cmpq $0x0, -0x28(%rbp)
jne 0x1656
movq -0x10(%rbp), %rax
movq 0x10(%rax), %rax
movslq -0x14(%rbp), %rcx
movq $0x0, (%rax,%rcx,8)
movq $0x0, -0x8(%rbp)
jmp 0x16b8
jmp 0x1658
movq -0x10(%rbp), %rcx
movq -0x20(%rbp), %rax
movq -0x28(%rbp), %rdx
lock
cmpxchgq %rdx, (%rcx)
movq %rax, %rcx
sete %al
xorb $-0x1, %al
testb $0x1, %al
jne 0x15ef
movq -0x10(%rbp), %rax
movq 0x10(%rax), %rax
movslq -0x14(%rbp), %rcx
movq $0x0, (%rax,%rcx,8)
movq -0x28(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x30(%rbp)
movq -0x28(%rbp), %rax
movl $0x1, 0x10(%rax)
movq -0x10(%rbp), %rdi
movq -0x20(%rbp), %rsi
callq 0x13f0
movq -0x30(%rbp), %rax
movq %rax, -0x8(%rbp)
movq -0x8(%rbp), %rax
addq $0x30, %rsp
popq %rbp
retq
nopw %cs:(%rax,%rax)