|  | @@ -124,7 +124,7 @@ static grpc_error* non_polling_poller_work(grpc_pollset* pollset,
 | 
	
		
			
				|  |  |    while (!npp->shutdown && !w.kicked &&
 | 
	
		
			
				|  |  |           !gpr_cv_wait(&w.cv, &npp->mu, deadline_ts))
 | 
	
		
			
				|  |  |      ;
 | 
	
		
			
				|  |  | -  grpc_exec_ctx_invalidate_now();
 | 
	
		
			
				|  |  | +  ExecCtx::Get()->InvalidateNow();
 | 
	
		
			
				|  |  |    if (&w == npp->root) {
 | 
	
		
			
				|  |  |      npp->root = w.next;
 | 
	
		
			
				|  |  |      if (&w == npp->root) {
 | 
	
	
		
			
				|  | @@ -371,7 +371,6 @@ int grpc_completion_queue_thread_local_cache_flush(grpc_completion_queue* cq,
 | 
	
		
			
				|  |  |        gpr_mu_unlock(cq->mu);
 | 
	
		
			
				|  |  |        GRPC_CQ_INTERNAL_UNREF(cq, "shutting_down");
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | -    grpc_exec_ctx_finish();
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    gpr_tls_set(&g_cached_event, (intptr_t)0);
 | 
	
		
			
				|  |  |    gpr_tls_set(&g_cached_cq, (intptr_t)0);
 | 
	
	
		
			
				|  | @@ -412,8 +411,6 @@ static grpc_cq_completion* cq_event_queue_pop(grpc_cq_event_queue* q) {
 | 
	
		
			
				|  |  |      GRPC_STATS_INC_CQ_EV_QUEUE_TRYLOCK_FAILURES();
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  grpc_exec_ctx_finish();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |    if (c) {
 | 
	
		
			
				|  |  |      gpr_atm_no_barrier_fetch_add(&q->num_queue_items, -1);
 | 
	
		
			
				|  |  |    }
 | 
	
	
		
			
				|  | @@ -445,7 +442,6 @@ grpc_completion_queue* grpc_completion_queue_create_internal(
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    ExecCtx _local_exec_ctx;
 | 
	
		
			
				|  |  |    GRPC_STATS_INC_CQS_CREATED();
 | 
	
		
			
				|  |  | -  grpc_exec_ctx_finish();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    cq = (grpc_completion_queue*)gpr_zalloc(sizeof(grpc_completion_queue) +
 | 
	
		
			
				|  |  |                                            vtable->data_size +
 | 
	
	
		
			
				|  | @@ -639,9 +635,9 @@ static void cq_end_op_for_next(grpc_completion_queue* cq, void* tag,
 | 
	
		
			
				|  |  |         error != GRPC_ERROR_NONE)) {
 | 
	
		
			
				|  |  |      const char* errmsg = grpc_error_string(error);
 | 
	
		
			
				|  |  |      GRPC_API_TRACE(
 | 
	
		
			
				|  |  | -        "cq_end_op_for_next(=%p, cq=%p, tag=%p, error=%s, "
 | 
	
		
			
				|  |  | +        "cq_end_op_for_next(cq=%p, tag=%p, error=%s, "
 | 
	
		
			
				|  |  |          "done=%p, done_arg=%p, storage=%p)",
 | 
	
		
			
				|  |  | -        7, (exec_ctx, cq, tag, errmsg, done, done_arg, storage));
 | 
	
		
			
				|  |  | +        6, (cq, tag, errmsg, done, done_arg, storage));
 | 
	
		
			
				|  |  |      if (GRPC_TRACER_ON(grpc_trace_operation_failures) &&
 | 
	
		
			
				|  |  |          error != GRPC_ERROR_NONE) {
 | 
	
		
			
				|  |  |        gpr_log(GPR_ERROR, "Operation failed: tag=%p, error=%s", tag, errmsg);
 | 
	
	
		
			
				|  | @@ -726,9 +722,9 @@ static void cq_end_op_for_pluck(grpc_completion_queue* cq, void* tag,
 | 
	
		
			
				|  |  |         error != GRPC_ERROR_NONE)) {
 | 
	
		
			
				|  |  |      const char* errmsg = grpc_error_string(error);
 | 
	
		
			
				|  |  |      GRPC_API_TRACE(
 | 
	
		
			
				|  |  | -        "cq_end_op_for_pluck(=%p, cq=%p, tag=%p, error=%s, "
 | 
	
		
			
				|  |  | +        "cq_end_op_for_pluck(cq=%p, tag=%p, error=%s, "
 | 
	
		
			
				|  |  |          "done=%p, done_arg=%p, storage=%p)",
 | 
	
		
			
				|  |  | -        7, (exec_ctx, cq, tag, errmsg, done, done_arg, storage));
 | 
	
		
			
				|  |  | +        6, (cq, tag, errmsg, done, done_arg, storage));
 | 
	
		
			
				|  |  |      if (GRPC_TRACER_ON(grpc_trace_operation_failures) &&
 | 
	
		
			
				|  |  |          error != GRPC_ERROR_NONE) {
 | 
	
		
			
				|  |  |        gpr_log(GPR_ERROR, "Operation failed: tag=%p, error=%s", tag, errmsg);
 | 
	
	
		
			
				|  | @@ -794,31 +790,40 @@ typedef struct {
 | 
	
		
			
				|  |  |    bool first_loop;
 | 
	
		
			
				|  |  |  } cq_is_finished_arg;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -static bool cq_is_next_finished(void* arg) {
 | 
	
		
			
				|  |  | -  cq_is_finished_arg* a = (cq_is_finished_arg*)arg;
 | 
	
		
			
				|  |  | -  grpc_completion_queue* cq = a->cq;
 | 
	
		
			
				|  |  | -  cq_next_data* cqd = (cq_next_data*)DATA_FROM_CQ(cq);
 | 
	
		
			
				|  |  | -  GPR_ASSERT(a->stolen_completion == NULL);
 | 
	
		
			
				|  |  | +class ExecCtxNext : public ExecCtx {
 | 
	
		
			
				|  |  | + public:
 | 
	
		
			
				|  |  | +  ExecCtxNext(void* arg) : ExecCtx(0), check_ready_to_finish_arg_(arg) {}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  gpr_atm current_last_seen_things_queued_ever =
 | 
	
		
			
				|  |  | -      gpr_atm_no_barrier_load(&cqd->things_queued_ever);
 | 
	
		
			
				|  |  | +  bool CheckReadyToFinish() override {
 | 
	
		
			
				|  |  | +    cq_is_finished_arg* a = (cq_is_finished_arg*)check_ready_to_finish_arg_;
 | 
	
		
			
				|  |  | +    grpc_completion_queue* cq = a->cq;
 | 
	
		
			
				|  |  | +    cq_next_data* cqd = (cq_next_data*)DATA_FROM_CQ(cq);
 | 
	
		
			
				|  |  | +    GPR_ASSERT(a->stolen_completion == NULL);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  if (current_last_seen_things_queued_ever != a->last_seen_things_queued_ever) {
 | 
	
		
			
				|  |  | -    a->last_seen_things_queued_ever =
 | 
	
		
			
				|  |  | +    gpr_atm current_last_seen_things_queued_ever =
 | 
	
		
			
				|  |  |          gpr_atm_no_barrier_load(&cqd->things_queued_ever);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    /* Pop a cq_completion from the queue. Returns NULL if the queue is empty
 | 
	
		
			
				|  |  | -     * might return NULL in some cases even if the queue is not empty; but
 | 
	
		
			
				|  |  | -     * that
 | 
	
		
			
				|  |  | -     * is ok and doesn't affect correctness. Might effect the tail latencies a
 | 
	
		
			
				|  |  | -     * bit) */
 | 
	
		
			
				|  |  | -    a->stolen_completion = cq_event_queue_pop(&cqd->queue);
 | 
	
		
			
				|  |  | -    if (a->stolen_completion != NULL) {
 | 
	
		
			
				|  |  | -      return true;
 | 
	
		
			
				|  |  | +    if (current_last_seen_things_queued_ever !=
 | 
	
		
			
				|  |  | +        a->last_seen_things_queued_ever) {
 | 
	
		
			
				|  |  | +      a->last_seen_things_queued_ever =
 | 
	
		
			
				|  |  | +          gpr_atm_no_barrier_load(&cqd->things_queued_ever);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      /* Pop a cq_completion from the queue. Returns NULL if the queue is empty
 | 
	
		
			
				|  |  | +       * might return NULL in some cases even if the queue is not empty; but
 | 
	
		
			
				|  |  | +       * that
 | 
	
		
			
				|  |  | +       * is ok and doesn't affect correctness. Might effect the tail latencies a
 | 
	
		
			
				|  |  | +       * bit) */
 | 
	
		
			
				|  |  | +      a->stolen_completion = cq_event_queue_pop(&cqd->queue);
 | 
	
		
			
				|  |  | +      if (a->stolen_completion != NULL) {
 | 
	
		
			
				|  |  | +        return true;
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | +    return !a->first_loop && a->deadline < ExecCtx::Get()->Now();
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -  return !a->first_loop && a->deadline < grpc_exec_ctx_now();
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | + private:
 | 
	
		
			
				|  |  | +  void* check_ready_to_finish_arg_;
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #ifndef NDEBUG
 | 
	
		
			
				|  |  |  static void dump_pending_tags(grpc_completion_queue* cq) {
 | 
	
	
		
			
				|  | @@ -873,7 +878,7 @@ static grpc_event cq_next(grpc_completion_queue* cq, gpr_timespec deadline,
 | 
	
		
			
				|  |  |        NULL,
 | 
	
		
			
				|  |  |        NULL,
 | 
	
		
			
				|  |  |        true};
 | 
	
		
			
				|  |  | -  ExecCtx _local_exec_ctx(0, cq_is_next_finished, &is_finished_arg);
 | 
	
		
			
				|  |  | +  ExecCtxNext _local_exec_ctx(&is_finished_arg);
 | 
	
		
			
				|  |  |    for (;;) {
 | 
	
		
			
				|  |  |      grpc_millis iteration_deadline = deadline_millis;
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -923,7 +928,8 @@ static grpc_event cq_next(grpc_completion_queue* cq, gpr_timespec deadline,
 | 
	
		
			
				|  |  |        break;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    if (!is_finished_arg.first_loop && grpc_exec_ctx_now() >= deadline_millis) {
 | 
	
		
			
				|  |  | +    if (!is_finished_arg.first_loop &&
 | 
	
		
			
				|  |  | +        ExecCtx::Get()->Now() >= deadline_millis) {
 | 
	
		
			
				|  |  |        memset(&ret, 0, sizeof(ret));
 | 
	
		
			
				|  |  |        ret.type = GRPC_QUEUE_TIMEOUT;
 | 
	
		
			
				|  |  |        dump_pending_tags(cq);
 | 
	
	
		
			
				|  | @@ -959,7 +965,7 @@ static grpc_event cq_next(grpc_completion_queue* cq, gpr_timespec deadline,
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    GRPC_SURFACE_TRACE_RETURNED_EVENT(cq, &ret);
 | 
	
		
			
				|  |  |    GRPC_CQ_INTERNAL_UNREF(cq, "next");
 | 
	
		
			
				|  |  | -  grpc_exec_ctx_finish();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    GPR_ASSERT(is_finished_arg.stolen_completion == NULL);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    GPR_TIMER_END("grpc_completion_queue_next", 0);
 | 
	
	
		
			
				|  | @@ -1039,37 +1045,46 @@ static void del_plucker(grpc_completion_queue* cq, void* tag,
 | 
	
		
			
				|  |  |    GPR_UNREACHABLE_CODE(return );
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -static bool cq_is_pluck_finished(void* arg) {
 | 
	
		
			
				|  |  | -  cq_is_finished_arg* a = (cq_is_finished_arg*)arg;
 | 
	
		
			
				|  |  | -  grpc_completion_queue* cq = a->cq;
 | 
	
		
			
				|  |  | -  cq_pluck_data* cqd = (cq_pluck_data*)DATA_FROM_CQ(cq);
 | 
	
		
			
				|  |  | +class ExecCtxPluck : public ExecCtx {
 | 
	
		
			
				|  |  | + public:
 | 
	
		
			
				|  |  | +  ExecCtxPluck(void* arg) : ExecCtx(0), check_ready_to_finish_arg_(arg) {}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  GPR_ASSERT(a->stolen_completion == NULL);
 | 
	
		
			
				|  |  | -  gpr_atm current_last_seen_things_queued_ever =
 | 
	
		
			
				|  |  | -      gpr_atm_no_barrier_load(&cqd->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 =
 | 
	
		
			
				|  |  | +  bool CheckReadyToFinish() override {
 | 
	
		
			
				|  |  | +    cq_is_finished_arg* a = (cq_is_finished_arg*)check_ready_to_finish_arg_;
 | 
	
		
			
				|  |  | +    grpc_completion_queue* cq = a->cq;
 | 
	
		
			
				|  |  | +    cq_pluck_data* cqd = (cq_pluck_data*)DATA_FROM_CQ(cq);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    GPR_ASSERT(a->stolen_completion == NULL);
 | 
	
		
			
				|  |  | +    gpr_atm current_last_seen_things_queued_ever =
 | 
	
		
			
				|  |  |          gpr_atm_no_barrier_load(&cqd->things_queued_ever);
 | 
	
		
			
				|  |  | -    grpc_cq_completion* c;
 | 
	
		
			
				|  |  | -    grpc_cq_completion* prev = &cqd->completed_head;
 | 
	
		
			
				|  |  | -    while ((c = (grpc_cq_completion*)(prev->next & ~(uintptr_t)1)) !=
 | 
	
		
			
				|  |  | -           &cqd->completed_head) {
 | 
	
		
			
				|  |  | -      if (c->tag == a->tag) {
 | 
	
		
			
				|  |  | -        prev->next = (prev->next & (uintptr_t)1) | (c->next & ~(uintptr_t)1);
 | 
	
		
			
				|  |  | -        if (c == cqd->completed_tail) {
 | 
	
		
			
				|  |  | -          cqd->completed_tail = prev;
 | 
	
		
			
				|  |  | +    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(&cqd->things_queued_ever);
 | 
	
		
			
				|  |  | +      grpc_cq_completion* c;
 | 
	
		
			
				|  |  | +      grpc_cq_completion* prev = &cqd->completed_head;
 | 
	
		
			
				|  |  | +      while ((c = (grpc_cq_completion*)(prev->next & ~(uintptr_t)1)) !=
 | 
	
		
			
				|  |  | +             &cqd->completed_head) {
 | 
	
		
			
				|  |  | +        if (c->tag == a->tag) {
 | 
	
		
			
				|  |  | +          prev->next = (prev->next & (uintptr_t)1) | (c->next & ~(uintptr_t)1);
 | 
	
		
			
				|  |  | +          if (c == cqd->completed_tail) {
 | 
	
		
			
				|  |  | +            cqd->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 !a->first_loop && a->deadline < ExecCtx::Get()->Now();
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -  return !a->first_loop && a->deadline < grpc_exec_ctx_now();
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | + private:
 | 
	
		
			
				|  |  | +  void* check_ready_to_finish_arg_;
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static grpc_event cq_pluck(grpc_completion_queue* cq, void* tag,
 | 
	
		
			
				|  |  |                             gpr_timespec deadline, void* reserved) {
 | 
	
	
		
			
				|  | @@ -1106,7 +1121,7 @@ static grpc_event cq_pluck(grpc_completion_queue* cq, void* tag,
 | 
	
		
			
				|  |  |        NULL,
 | 
	
		
			
				|  |  |        tag,
 | 
	
		
			
				|  |  |        true};
 | 
	
		
			
				|  |  | -  ExecCtx _local_exec_ctx(0, cq_is_pluck_finished, &is_finished_arg);
 | 
	
		
			
				|  |  | +  ExecCtxPluck _local_exec_ctx(&is_finished_arg);
 | 
	
		
			
				|  |  |    for (;;) {
 | 
	
		
			
				|  |  |      if (is_finished_arg.stolen_completion != NULL) {
 | 
	
		
			
				|  |  |        gpr_mu_unlock(cq->mu);
 | 
	
	
		
			
				|  | @@ -1153,7 +1168,8 @@ static grpc_event cq_pluck(grpc_completion_queue* cq, void* tag,
 | 
	
		
			
				|  |  |        dump_pending_tags(cq);
 | 
	
		
			
				|  |  |        break;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | -    if (!is_finished_arg.first_loop && grpc_exec_ctx_now() >= deadline_millis) {
 | 
	
		
			
				|  |  | +    if (!is_finished_arg.first_loop &&
 | 
	
		
			
				|  |  | +        ExecCtx::Get()->Now() >= deadline_millis) {
 | 
	
		
			
				|  |  |        del_plucker(cq, tag, &worker);
 | 
	
		
			
				|  |  |        gpr_mu_unlock(cq->mu);
 | 
	
		
			
				|  |  |        memset(&ret, 0, sizeof(ret));
 | 
	
	
		
			
				|  | @@ -1182,7 +1198,7 @@ static grpc_event cq_pluck(grpc_completion_queue* cq, void* tag,
 | 
	
		
			
				|  |  |  done:
 | 
	
		
			
				|  |  |    GRPC_SURFACE_TRACE_RETURNED_EVENT(cq, &ret);
 | 
	
		
			
				|  |  |    GRPC_CQ_INTERNAL_UNREF(cq, "pluck");
 | 
	
		
			
				|  |  | -  grpc_exec_ctx_finish();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    GPR_ASSERT(is_finished_arg.stolen_completion == NULL);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    GPR_TIMER_END("grpc_completion_queue_pluck", 0);
 | 
	
	
		
			
				|  | @@ -1238,7 +1254,7 @@ void grpc_completion_queue_shutdown(grpc_completion_queue* cq) {
 | 
	
		
			
				|  |  |    GPR_TIMER_BEGIN("grpc_completion_queue_shutdown", 0);
 | 
	
		
			
				|  |  |    GRPC_API_TRACE("grpc_completion_queue_shutdown(cq=%p)", 1, (cq));
 | 
	
		
			
				|  |  |    cq->vtable->shutdown(cq);
 | 
	
		
			
				|  |  | -  grpc_exec_ctx_finish();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    GPR_TIMER_END("grpc_completion_queue_shutdown", 0);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -1249,7 +1265,7 @@ void grpc_completion_queue_destroy(grpc_completion_queue* cq) {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    ExecCtx _local_exec_ctx;
 | 
	
		
			
				|  |  |    GRPC_CQ_INTERNAL_UNREF(cq, "destroy");
 | 
	
		
			
				|  |  | -  grpc_exec_ctx_finish();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    GPR_TIMER_END("grpc_completion_queue_destroy", 0);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 |