Prevent thread deadlock if cq-next timeout is infinity

pull/10662/head
Sree Kuchibhotla 8 years ago
parent a1a012da0d
commit 55d0b49011
  1. 16
      src/core/lib/surface/completion_queue.c

@ -543,6 +543,8 @@ grpc_event grpc_completion_queue_next(grpc_completion_queue *cc,
GRPC_EXEC_CTX_INITIALIZER(0, cq_is_next_finished, &is_finished_arg);
for (;;) {
gpr_timespec iteration_deadline = deadline;
if (is_finished_arg.stolen_completion != NULL) {
grpc_cq_completion *c = is_finished_arg.stolen_completion;
is_finished_arg.stolen_completion = NULL;
@ -555,16 +557,21 @@ grpc_event grpc_completion_queue_next(grpc_completion_queue *cc,
grpc_cq_completion *c = cq_event_queue_pop(&cc->queue);
/* TODO: sreek - If c == NULL it means either the queue is empty OR in an
transient inconsistent state. Consider doing a 0-timeout poll if
(cc->num_queue_items > 0 and c == NULL) so that the thread comes back
quickly from poll to make a second attempt at popping */
if (c != NULL) {
ret.type = GRPC_OP_COMPLETE;
ret.success = c->next & 1u;
ret.tag = c->tag;
c->done(&exec_ctx, c->done_arg, c);
break;
} else {
/* If c == NULL it means either the queue is empty OR in an transient
inconsistent state. If it is the latter, we shold do a 0-timeout poll
so that the thread comes back quickly from poll to make a second
attempt at popping. Not doing this can potentially deadlock this thread
forever (if the deadline is infinity) */
if (cq_event_queue_num_items(&cc->queue) > 0) {
iteration_deadline = gpr_time_0(GPR_CLOCK_MONOTONIC);
}
}
if (gpr_atm_no_barrier_load(&cc->shutdown)) {
@ -594,7 +601,6 @@ grpc_event grpc_completion_queue_next(grpc_completion_queue *cc,
/* Check alarms - these are a global resource so we just ping each time
through on every pollset. May update deadline to ensure timely wakeups.*/
gpr_timespec iteration_deadline = deadline;
if (grpc_timer_check(&exec_ctx, now, &iteration_deadline)) {
GPR_TIMER_MARK("alarm_triggered", 0);
grpc_exec_ctx_flush(&exec_ctx);

Loading…
Cancel
Save