|
|
|
@ -313,13 +313,37 @@ void grpc_cq_end_op(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc, |
|
|
|
|
GRPC_ERROR_UNREF(error); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
typedef struct { |
|
|
|
|
grpc_completion_queue *cq; |
|
|
|
|
gpr_timespec deadline; |
|
|
|
|
grpc_cq_completion *stolen_completion; |
|
|
|
|
void *tag; /* for pluck */ |
|
|
|
|
} cq_is_finished_arg; |
|
|
|
|
|
|
|
|
|
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_mu_unlock(cq->mu); |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
gpr_mu_unlock(cq->mu); |
|
|
|
|
return gpr_time_cmp(a->deadline, gpr_now(a->deadline.clock_type)) > 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
grpc_event grpc_completion_queue_next(grpc_completion_queue *cc, |
|
|
|
|
gpr_timespec deadline, void *reserved) { |
|
|
|
|
grpc_event ret; |
|
|
|
|
grpc_pollset_worker *worker = NULL; |
|
|
|
|
int first_loop = 1; |
|
|
|
|
gpr_timespec now; |
|
|
|
|
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; |
|
|
|
|
|
|
|
|
|
GPR_TIMER_BEGIN("grpc_completion_queue_next", 0); |
|
|
|
|
|
|
|
|
@ -335,9 +359,23 @@ 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); |
|
|
|
|
for (;;) { |
|
|
|
|
if (is_finished_arg.stolen_completion != NULL) { |
|
|
|
|
gpr_mu_unlock(cc->mu); |
|
|
|
|
grpc_cq_completion *c = is_finished_arg.stolen_completion; |
|
|
|
|
is_finished_arg.stolen_completion = NULL; |
|
|
|
|
ret.type = GRPC_OP_COMPLETE; |
|
|
|
|
ret.success = c->next & 1u; |
|
|
|
|
ret.tag = c->tag; |
|
|
|
|
c->done(&exec_ctx, c->done_arg, c); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
if (cc->completed_tail != &cc->completed_head) { |
|
|
|
|
grpc_cq_completion *c = (grpc_cq_completion *)cc->completed_head.next; |
|
|
|
|
cc->completed_head.next = c->next & ~(uintptr_t)1; |
|
|
|
@ -394,6 +432,7 @@ grpc_event grpc_completion_queue_next(grpc_completion_queue *cc, |
|
|
|
|
GRPC_SURFACE_TRACE_RETURNED_EVENT(cc, &ret); |
|
|
|
|
GRPC_CQ_INTERNAL_UNREF(cc, "next"); |
|
|
|
|
grpc_exec_ctx_finish(&exec_ctx); |
|
|
|
|
GPR_ASSERT(is_finished_arg.stolen_completion == NULL); |
|
|
|
|
|
|
|
|
|
GPR_TIMER_END("grpc_completion_queue_next", 0); |
|
|
|
|
|
|
|
|
@ -424,6 +463,30 @@ static void del_plucker(grpc_completion_queue *cc, void *tag, |
|
|
|
|
GPR_UNREACHABLE_CODE(return ); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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_mu_unlock(cq->mu); |
|
|
|
|
a->stolen_completion = c; |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
prev = c; |
|
|
|
|
} |
|
|
|
|
gpr_mu_unlock(cq->mu); |
|
|
|
|
return gpr_time_cmp(a->deadline, gpr_now(a->deadline.clock_type)) > 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag, |
|
|
|
|
gpr_timespec deadline, void *reserved) { |
|
|
|
|
grpc_event ret; |
|
|
|
@ -432,7 +495,6 @@ grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag, |
|
|
|
|
grpc_pollset_worker *worker = NULL; |
|
|
|
|
gpr_timespec now; |
|
|
|
|
int first_loop = 1; |
|
|
|
|
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; |
|
|
|
|
|
|
|
|
|
GPR_TIMER_BEGIN("grpc_completion_queue_pluck", 0); |
|
|
|
|
|
|
|
|
@ -450,9 +512,23 @@ 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); |
|
|
|
|
for (;;) { |
|
|
|
|
if (is_finished_arg.stolen_completion != NULL) { |
|
|
|
|
gpr_mu_unlock(cc->mu); |
|
|
|
|
grpc_cq_completion *c = is_finished_arg.stolen_completion; |
|
|
|
|
is_finished_arg.stolen_completion = NULL; |
|
|
|
|
ret.type = GRPC_OP_COMPLETE; |
|
|
|
|
ret.success = c->next & 1u; |
|
|
|
|
ret.tag = c->tag; |
|
|
|
|
c->done(&exec_ctx, c->done_arg, c); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
prev = &cc->completed_head; |
|
|
|
|
while ((c = (grpc_cq_completion *)(prev->next & ~(uintptr_t)1)) != |
|
|
|
|
&cc->completed_head) { |
|
|
|
@ -527,6 +603,7 @@ done: |
|
|
|
|
GRPC_SURFACE_TRACE_RETURNED_EVENT(cc, &ret); |
|
|
|
|
GRPC_CQ_INTERNAL_UNREF(cc, "pluck"); |
|
|
|
|
grpc_exec_ctx_finish(&exec_ctx); |
|
|
|
|
GPR_ASSERT(is_finished_arg.stolen_completion == NULL); |
|
|
|
|
|
|
|
|
|
GPR_TIMER_END("grpc_completion_queue_pluck", 0); |
|
|
|
|
|
|
|
|
|