|
|
|
@ -72,6 +72,11 @@ typedef union lockfree_node { |
|
|
|
|
struct gpr_stack_lockfree { |
|
|
|
|
lockfree_node *entries; |
|
|
|
|
lockfree_node head; /* An atomic entry describing curr head */ |
|
|
|
|
|
|
|
|
|
#ifndef NDEBUG |
|
|
|
|
/* Bitmap of pushed entries to check for double-push or pop */ |
|
|
|
|
gpr_atm pushed[(INVALID_ENTRY_INDEX+1)/(8*sizeof(gpr_atm))]; |
|
|
|
|
#endif |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
gpr_stack_lockfree *gpr_stack_lockfree_create(int entries) { |
|
|
|
@ -86,6 +91,9 @@ gpr_stack_lockfree *gpr_stack_lockfree_create(int entries) { |
|
|
|
|
/* Clear out all entries */ |
|
|
|
|
memset(stack->entries, 0, entries * sizeof(stack->entries[0])); |
|
|
|
|
memset(&stack->head, 0, sizeof(stack->head)); |
|
|
|
|
#ifndef NDEBUG |
|
|
|
|
memset(&stack->pushed, 0, sizeof(stack->pushed)); |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
/* Point the head at reserved dummy entry */ |
|
|
|
|
stack->head.contents.index = INVALID_ENTRY_INDEX; |
|
|
|
@ -106,6 +114,19 @@ int gpr_stack_lockfree_push(gpr_stack_lockfree *stack, int entry) { |
|
|
|
|
/* Also post-increment the aba_ctr */ |
|
|
|
|
newhead.contents.aba_ctr = stack->entries[entry].contents.aba_ctr++; |
|
|
|
|
|
|
|
|
|
#ifndef NDEBUG |
|
|
|
|
/* Check for double push */ |
|
|
|
|
{ |
|
|
|
|
int pushed_index = entry / (8*sizeof(gpr_atm)); |
|
|
|
|
int pushed_bit = entry % (8*sizeof(gpr_atm)); |
|
|
|
|
gpr_atm old_val; |
|
|
|
|
|
|
|
|
|
old_val = gpr_atm_no_barrier_fetch_add(&stack->pushed[pushed_index], |
|
|
|
|
(gpr_atm)(1UL << pushed_bit)); |
|
|
|
|
GPR_ASSERT((old_val & (1UL<<pushed_bit)) == 0); |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
do { |
|
|
|
|
/* Atomically get the existing head value for use */ |
|
|
|
|
head.atm = gpr_atm_no_barrier_load(&(stack->head.atm)); |
|
|
|
@ -119,6 +140,7 @@ int gpr_stack_lockfree_push(gpr_stack_lockfree *stack, int entry) { |
|
|
|
|
int gpr_stack_lockfree_pop(gpr_stack_lockfree *stack) { |
|
|
|
|
lockfree_node head; |
|
|
|
|
lockfree_node newhead; |
|
|
|
|
|
|
|
|
|
do { |
|
|
|
|
head.atm = gpr_atm_acq_load(&(stack->head.atm)); |
|
|
|
|
if (head.contents.index == INVALID_ENTRY_INDEX) { |
|
|
|
@ -128,5 +150,18 @@ int gpr_stack_lockfree_pop(gpr_stack_lockfree *stack) { |
|
|
|
|
gpr_atm_no_barrier_load(&(stack->entries[head.contents.index].atm)); |
|
|
|
|
|
|
|
|
|
} while (!gpr_atm_no_barrier_cas(&(stack->head.atm), head.atm, newhead.atm)); |
|
|
|
|
#ifndef NDEBUG |
|
|
|
|
/* Check for valid pop */ |
|
|
|
|
{ |
|
|
|
|
int pushed_index = head.contents.index / (8*sizeof(gpr_atm)); |
|
|
|
|
int pushed_bit = head.contents.index % (8*sizeof(gpr_atm)); |
|
|
|
|
gpr_atm old_val; |
|
|
|
|
|
|
|
|
|
old_val = gpr_atm_no_barrier_fetch_add(&stack->pushed[pushed_index], |
|
|
|
|
-(gpr_atm)(1UL << pushed_bit)); |
|
|
|
|
GPR_ASSERT((old_val & (1UL<<pushed_bit)) != 0); |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
return head.contents.index; |
|
|
|
|
} |
|
|
|
|