|
|
|
@ -71,6 +71,9 @@ struct grpc_completion_queue { |
|
|
|
|
gpr_refcount pending_events; |
|
|
|
|
/** Once owning_refs drops to zero, we will destroy the cq */ |
|
|
|
|
gpr_refcount owning_refs; |
|
|
|
|
/** counter of how many things have ever been queued on this completion queue
|
|
|
|
|
useful for avoiding locks to check the queue */ |
|
|
|
|
gpr_atm things_queued_ever; |
|
|
|
|
/** 0 initially, 1 once we've begun shutting down */ |
|
|
|
|
int shutdown; |
|
|
|
|
int shutdown_called; |
|
|
|
@ -125,15 +128,6 @@ void grpc_cq_global_shutdown(void) { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
struct grpc_cq_alarm { |
|
|
|
|
grpc_timer alarm; |
|
|
|
|
grpc_cq_completion completion; |
|
|
|
|
/** completion queue where events about this alarm will be posted */ |
|
|
|
|
grpc_completion_queue *cq; |
|
|
|
|
/** user supplied tag */ |
|
|
|
|
void *tag; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
grpc_completion_queue *grpc_completion_queue_create(void *reserved) { |
|
|
|
|
grpc_completion_queue *cc; |
|
|
|
|
GPR_ASSERT(!reserved); |
|
|
|
@ -170,6 +164,7 @@ grpc_completion_queue *grpc_completion_queue_create(void *reserved) { |
|
|
|
|
cc->is_server_cq = 0; |
|
|
|
|
cc->is_non_listening_server_cq = 0; |
|
|
|
|
cc->num_pluckers = 0; |
|
|
|
|
gpr_atm_no_barrier_store(&cc->things_queued_ever, 0); |
|
|
|
|
#ifndef NDEBUG |
|
|
|
|
cc->outstanding_tag_count = 0; |
|
|
|
|
#endif |
|
|
|
@ -280,6 +275,7 @@ void grpc_cq_end_op(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc, |
|
|
|
|
GPR_ASSERT(found); |
|
|
|
|
#endif |
|
|
|
|
shutdown = gpr_unref(&cc->pending_events); |
|
|
|
|
gpr_atm_no_barrier_fetch_add(&cc->things_queued_ever, 1); |
|
|
|
|
if (!shutdown) { |
|
|
|
|
cc->completed_tail->next = |
|
|
|
|
((uintptr_t)storage) | (1u & (uintptr_t)cc->completed_tail->next); |
|
|
|
@ -318,6 +314,7 @@ void grpc_cq_end_op(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
typedef struct { |
|
|
|
|
gpr_atm last_seen_things_queued_ever; |
|
|
|
|
grpc_completion_queue *cq; |
|
|
|
|
gpr_timespec deadline; |
|
|
|
|
grpc_cq_completion *stolen_completion; |
|
|
|
@ -328,17 +325,23 @@ static bool cq_is_next_finished(grpc_exec_ctx *exec_ctx, void *arg) { |
|
|
|
|
cq_is_finished_arg *a = arg; |
|
|
|
|
grpc_completion_queue *cq = a->cq; |
|
|
|
|
GPR_ASSERT(a->stolen_completion == NULL); |
|
|
|
|
gpr_mu_lock(cq->mu); |
|
|
|
|
if (cq->completed_tail != &cq->completed_head) { |
|
|
|
|
a->stolen_completion = (grpc_cq_completion *)cq->completed_head.next; |
|
|
|
|
cq->completed_head.next = a->stolen_completion->next & ~(uintptr_t)1; |
|
|
|
|
if (a->stolen_completion == cq->completed_tail) { |
|
|
|
|
cq->completed_tail = &cq->completed_head; |
|
|
|
|
gpr_atm current_last_seen_things_queued_ever = |
|
|
|
|
gpr_atm_no_barrier_load(&cq->things_queued_ever); |
|
|
|
|
if (current_last_seen_things_queued_ever != a->last_seen_things_queued_ever) { |
|
|
|
|
gpr_mu_lock(cq->mu); |
|
|
|
|
a->last_seen_things_queued_ever = |
|
|
|
|
gpr_atm_no_barrier_load(&cq->things_queued_ever); |
|
|
|
|
if (cq->completed_tail != &cq->completed_head) { |
|
|
|
|
a->stolen_completion = (grpc_cq_completion *)cq->completed_head.next; |
|
|
|
|
cq->completed_head.next = a->stolen_completion->next & ~(uintptr_t)1; |
|
|
|
|
if (a->stolen_completion == cq->completed_tail) { |
|
|
|
|
cq->completed_tail = &cq->completed_head; |
|
|
|
|
} |
|
|
|
|
gpr_mu_unlock(cq->mu); |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
gpr_mu_unlock(cq->mu); |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
gpr_mu_unlock(cq->mu); |
|
|
|
|
return gpr_time_cmp(a->deadline, gpr_now(a->deadline.clock_type)) < 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -386,12 +389,13 @@ grpc_event grpc_completion_queue_next(grpc_completion_queue *cc, |
|
|
|
|
|
|
|
|
|
deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC); |
|
|
|
|
|
|
|
|
|
cq_is_finished_arg is_finished_arg = {cc, deadline, NULL, NULL}; |
|
|
|
|
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT_WITH_FINISH_CHECK( |
|
|
|
|
cq_is_next_finished, &is_finished_arg); |
|
|
|
|
|
|
|
|
|
GRPC_CQ_INTERNAL_REF(cc, "next"); |
|
|
|
|
gpr_mu_lock(cc->mu); |
|
|
|
|
cq_is_finished_arg is_finished_arg = { |
|
|
|
|
gpr_atm_no_barrier_load(&cc->things_queued_ever), cc, deadline, NULL, |
|
|
|
|
NULL}; |
|
|
|
|
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT_WITH_FINISH_CHECK( |
|
|
|
|
cq_is_next_finished, &is_finished_arg); |
|
|
|
|
for (;;) { |
|
|
|
|
if (is_finished_arg.stolen_completion != NULL) { |
|
|
|
|
gpr_mu_unlock(cc->mu); |
|
|
|
@ -496,23 +500,29 @@ static bool cq_is_pluck_finished(grpc_exec_ctx *exec_ctx, void *arg) { |
|
|
|
|
cq_is_finished_arg *a = arg; |
|
|
|
|
grpc_completion_queue *cq = a->cq; |
|
|
|
|
GPR_ASSERT(a->stolen_completion == NULL); |
|
|
|
|
gpr_mu_lock(cq->mu); |
|
|
|
|
grpc_cq_completion *c; |
|
|
|
|
grpc_cq_completion *prev = &cq->completed_head; |
|
|
|
|
while ((c = (grpc_cq_completion *)(prev->next & ~(uintptr_t)1)) != |
|
|
|
|
&cq->completed_head) { |
|
|
|
|
if (c->tag == a->tag) { |
|
|
|
|
prev->next = (prev->next & (uintptr_t)1) | (c->next & ~(uintptr_t)1); |
|
|
|
|
if (c == cq->completed_tail) { |
|
|
|
|
cq->completed_tail = prev; |
|
|
|
|
gpr_atm current_last_seen_things_queued_ever = |
|
|
|
|
gpr_atm_no_barrier_load(&cq->things_queued_ever); |
|
|
|
|
if (current_last_seen_things_queued_ever != a->last_seen_things_queued_ever) { |
|
|
|
|
gpr_mu_lock(cq->mu); |
|
|
|
|
a->last_seen_things_queued_ever = |
|
|
|
|
gpr_atm_no_barrier_load(&cq->things_queued_ever); |
|
|
|
|
grpc_cq_completion *c; |
|
|
|
|
grpc_cq_completion *prev = &cq->completed_head; |
|
|
|
|
while ((c = (grpc_cq_completion *)(prev->next & ~(uintptr_t)1)) != |
|
|
|
|
&cq->completed_head) { |
|
|
|
|
if (c->tag == a->tag) { |
|
|
|
|
prev->next = (prev->next & (uintptr_t)1) | (c->next & ~(uintptr_t)1); |
|
|
|
|
if (c == cq->completed_tail) { |
|
|
|
|
cq->completed_tail = prev; |
|
|
|
|
} |
|
|
|
|
gpr_mu_unlock(cq->mu); |
|
|
|
|
a->stolen_completion = c; |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
gpr_mu_unlock(cq->mu); |
|
|
|
|
a->stolen_completion = c; |
|
|
|
|
return true; |
|
|
|
|
prev = c; |
|
|
|
|
} |
|
|
|
|
prev = c; |
|
|
|
|
gpr_mu_unlock(cq->mu); |
|
|
|
|
} |
|
|
|
|
gpr_mu_unlock(cq->mu); |
|
|
|
|
return gpr_time_cmp(a->deadline, gpr_now(a->deadline.clock_type)) < 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -543,12 +553,13 @@ grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag, |
|
|
|
|
|
|
|
|
|
deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC); |
|
|
|
|
|
|
|
|
|
cq_is_finished_arg is_finished_arg = {cc, deadline, NULL, tag}; |
|
|
|
|
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT_WITH_FINISH_CHECK( |
|
|
|
|
cq_is_pluck_finished, &is_finished_arg); |
|
|
|
|
|
|
|
|
|
GRPC_CQ_INTERNAL_REF(cc, "pluck"); |
|
|
|
|
gpr_mu_lock(cc->mu); |
|
|
|
|
cq_is_finished_arg is_finished_arg = { |
|
|
|
|
gpr_atm_no_barrier_load(&cc->things_queued_ever), cc, deadline, NULL, |
|
|
|
|
tag}; |
|
|
|
|
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT_WITH_FINISH_CHECK( |
|
|
|
|
cq_is_pluck_finished, &is_finished_arg); |
|
|
|
|
for (;;) { |
|
|
|
|
if (is_finished_arg.stolen_completion != NULL) { |
|
|
|
|
gpr_mu_unlock(cc->mu); |
|
|
|
|