|  | @@ -104,11 +104,14 @@ grpc_core::DebugOnlyTraceFlag grpc_trace_chttp2_refcount(false,
 | 
	
		
			
				|  |  |  /* forward declarations of various callbacks that we'll build closures around */
 | 
	
		
			
				|  |  |  static void write_action_begin_locked(void* t, grpc_error* error);
 | 
	
		
			
				|  |  |  static void write_action(void* t, grpc_error* error);
 | 
	
		
			
				|  |  | +static void write_action_end(void* t, grpc_error* error);
 | 
	
		
			
				|  |  |  static void write_action_end_locked(void* t, grpc_error* error);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +static void read_action(void* t, grpc_error* error);
 | 
	
		
			
				|  |  |  static void read_action_locked(void* t, grpc_error* error);
 | 
	
		
			
				|  |  |  static void continue_read_action_locked(grpc_chttp2_transport* t);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +static void complete_fetch(void* gs, grpc_error* error);
 | 
	
		
			
				|  |  |  static void complete_fetch_locked(void* gs, grpc_error* error);
 | 
	
		
			
				|  |  |  /** Set a transport level setting, and push it to our peer */
 | 
	
		
			
				|  |  |  static void queue_setting_update(grpc_chttp2_transport* t,
 | 
	
	
		
			
				|  | @@ -124,6 +127,8 @@ static void connectivity_state_set(grpc_chttp2_transport* t,
 | 
	
		
			
				|  |  |                                     grpc_connectivity_state state,
 | 
	
		
			
				|  |  |                                     const char* reason);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +static void benign_reclaimer(void* t, grpc_error* error);
 | 
	
		
			
				|  |  | +static void destructive_reclaimer(void* t, grpc_error* error);
 | 
	
		
			
				|  |  |  static void benign_reclaimer_locked(void* t, grpc_error* error);
 | 
	
		
			
				|  |  |  static void destructive_reclaimer_locked(void* t, grpc_error* error);
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -134,8 +139,11 @@ static void close_transport_locked(grpc_chttp2_transport* t, grpc_error* error);
 | 
	
		
			
				|  |  |  static void end_all_the_calls(grpc_chttp2_transport* t, grpc_error* error);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void schedule_bdp_ping_locked(grpc_chttp2_transport* t);
 | 
	
		
			
				|  |  | +static void start_bdp_ping(void* tp, grpc_error* error);
 | 
	
		
			
				|  |  | +static void finish_bdp_ping(void* tp, grpc_error* error);
 | 
	
		
			
				|  |  |  static void start_bdp_ping_locked(void* tp, grpc_error* error);
 | 
	
		
			
				|  |  |  static void finish_bdp_ping_locked(void* tp, grpc_error* error);
 | 
	
		
			
				|  |  | +static void next_bdp_ping_timer_expired(void* tp, grpc_error* error);
 | 
	
		
			
				|  |  |  static void next_bdp_ping_timer_expired_locked(void* tp, grpc_error* error);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void cancel_pings(grpc_chttp2_transport* t, grpc_error* error);
 | 
	
	
		
			
				|  | @@ -145,9 +153,13 @@ static void send_ping_locked(grpc_chttp2_transport* t,
 | 
	
		
			
				|  |  |  static void retry_initiate_ping_locked(void* tp, grpc_error* error);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /** keepalive-relevant functions */
 | 
	
		
			
				|  |  | +static void init_keepalive_ping(void* arg, grpc_error* error);
 | 
	
		
			
				|  |  |  static void init_keepalive_ping_locked(void* arg, grpc_error* error);
 | 
	
		
			
				|  |  | +static void start_keepalive_ping(void* arg, grpc_error* error);
 | 
	
		
			
				|  |  | +static void finish_keepalive_ping(void* arg, grpc_error* error);
 | 
	
		
			
				|  |  |  static void start_keepalive_ping_locked(void* arg, grpc_error* error);
 | 
	
		
			
				|  |  |  static void finish_keepalive_ping_locked(void* arg, grpc_error* error);
 | 
	
		
			
				|  |  | +static void keepalive_watchdog_fired(void* arg, grpc_error* error);
 | 
	
		
			
				|  |  |  static void keepalive_watchdog_fired_locked(void* arg, grpc_error* error);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void reset_byte_stream(void* arg, grpc_error* error);
 | 
	
	
		
			
				|  | @@ -377,36 +389,6 @@ static bool read_channel_args(grpc_chttp2_transport* t,
 | 
	
		
			
				|  |  |    return enable_bdp;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -static void init_transport_closures(grpc_chttp2_transport* t) {
 | 
	
		
			
				|  |  | -  GRPC_CLOSURE_INIT(&t->read_action_locked, read_action_locked, t,
 | 
	
		
			
				|  |  | -                    grpc_combiner_scheduler(t->combiner));
 | 
	
		
			
				|  |  | -  GRPC_CLOSURE_INIT(&t->benign_reclaimer_locked, benign_reclaimer_locked, t,
 | 
	
		
			
				|  |  | -                    grpc_combiner_scheduler(t->combiner));
 | 
	
		
			
				|  |  | -  GRPC_CLOSURE_INIT(&t->destructive_reclaimer_locked,
 | 
	
		
			
				|  |  | -                    destructive_reclaimer_locked, t,
 | 
	
		
			
				|  |  | -                    grpc_combiner_scheduler(t->combiner));
 | 
	
		
			
				|  |  | -  GRPC_CLOSURE_INIT(&t->retry_initiate_ping_locked, retry_initiate_ping_locked,
 | 
	
		
			
				|  |  | -                    t, grpc_combiner_scheduler(t->combiner));
 | 
	
		
			
				|  |  | -  GRPC_CLOSURE_INIT(&t->start_bdp_ping_locked, start_bdp_ping_locked, t,
 | 
	
		
			
				|  |  | -                    grpc_combiner_scheduler(t->combiner));
 | 
	
		
			
				|  |  | -  GRPC_CLOSURE_INIT(&t->finish_bdp_ping_locked, finish_bdp_ping_locked, t,
 | 
	
		
			
				|  |  | -                    grpc_combiner_scheduler(t->combiner));
 | 
	
		
			
				|  |  | -  GRPC_CLOSURE_INIT(&t->next_bdp_ping_timer_expired_locked,
 | 
	
		
			
				|  |  | -                    next_bdp_ping_timer_expired_locked, t,
 | 
	
		
			
				|  |  | -                    grpc_combiner_scheduler(t->combiner));
 | 
	
		
			
				|  |  | -  GRPC_CLOSURE_INIT(&t->init_keepalive_ping_locked, init_keepalive_ping_locked,
 | 
	
		
			
				|  |  | -                    t, grpc_combiner_scheduler(t->combiner));
 | 
	
		
			
				|  |  | -  GRPC_CLOSURE_INIT(&t->start_keepalive_ping_locked,
 | 
	
		
			
				|  |  | -                    start_keepalive_ping_locked, t,
 | 
	
		
			
				|  |  | -                    grpc_combiner_scheduler(t->combiner));
 | 
	
		
			
				|  |  | -  GRPC_CLOSURE_INIT(&t->finish_keepalive_ping_locked,
 | 
	
		
			
				|  |  | -                    finish_keepalive_ping_locked, t,
 | 
	
		
			
				|  |  | -                    grpc_combiner_scheduler(t->combiner));
 | 
	
		
			
				|  |  | -  GRPC_CLOSURE_INIT(&t->keepalive_watchdog_fired_locked,
 | 
	
		
			
				|  |  | -                    keepalive_watchdog_fired_locked, t,
 | 
	
		
			
				|  |  | -                    grpc_combiner_scheduler(t->combiner));
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  static void init_transport_keepalive_settings(grpc_chttp2_transport* t) {
 | 
	
		
			
				|  |  |    if (t->is_client) {
 | 
	
		
			
				|  |  |      t->keepalive_time = g_default_client_keepalive_time_ms == INT_MAX
 | 
	
	
		
			
				|  | @@ -442,6 +424,8 @@ static void init_keepalive_pings_if_enabled(grpc_chttp2_transport* t) {
 | 
	
		
			
				|  |  |    if (t->keepalive_time != GRPC_MILLIS_INF_FUTURE) {
 | 
	
		
			
				|  |  |      t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_WAITING;
 | 
	
		
			
				|  |  |      GRPC_CHTTP2_REF_TRANSPORT(t, "init keepalive ping");
 | 
	
		
			
				|  |  | +    GRPC_CLOSURE_INIT(&t->init_keepalive_ping_locked, init_keepalive_ping, t,
 | 
	
		
			
				|  |  | +                      grpc_schedule_on_exec_ctx);
 | 
	
		
			
				|  |  |      grpc_timer_init(&t->keepalive_ping_timer,
 | 
	
		
			
				|  |  |                      grpc_core::ExecCtx::Get()->Now() + t->keepalive_time,
 | 
	
		
			
				|  |  |                      &t->init_keepalive_ping_locked);
 | 
	
	
		
			
				|  | @@ -494,8 +478,6 @@ grpc_chttp2_transport::grpc_chttp2_transport(
 | 
	
		
			
				|  |  |    grpc_chttp2_hpack_parser_init(&hpack_parser);
 | 
	
		
			
				|  |  |    grpc_chttp2_goaway_parser_init(&goaway_parser);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  init_transport_closures(this);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |    /* configure http2 the way we like it */
 | 
	
		
			
				|  |  |    if (is_client) {
 | 
	
		
			
				|  |  |      queue_setting_update(this, GRPC_CHTTP2_SETTINGS_ENABLE_PUSH, 0);
 | 
	
	
		
			
				|  | @@ -556,9 +538,8 @@ static void destroy_transport_locked(void* tp, grpc_error* error) {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void destroy_transport(grpc_transport* gt) {
 | 
	
		
			
				|  |  |    grpc_chttp2_transport* t = reinterpret_cast<grpc_chttp2_transport*>(gt);
 | 
	
		
			
				|  |  | -  GRPC_CLOSURE_SCHED(GRPC_CLOSURE_CREATE(destroy_transport_locked, t,
 | 
	
		
			
				|  |  | -                                         grpc_combiner_scheduler(t->combiner)),
 | 
	
		
			
				|  |  | -                     GRPC_ERROR_NONE);
 | 
	
		
			
				|  |  | +  t->combiner->Run(GRPC_CLOSURE_CREATE(destroy_transport_locked, t, nullptr),
 | 
	
		
			
				|  |  | +                   GRPC_ERROR_NONE);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void close_transport_locked(grpc_chttp2_transport* t,
 | 
	
	
		
			
				|  | @@ -669,11 +650,7 @@ grpc_chttp2_stream::grpc_chttp2_stream(grpc_chttp2_transport* t,
 | 
	
		
			
				|  |  |    grpc_slice_buffer_init(&frame_storage);
 | 
	
		
			
				|  |  |    grpc_slice_buffer_init(&unprocessed_incoming_frames_buffer);
 | 
	
		
			
				|  |  |    grpc_slice_buffer_init(&flow_controlled_buffer);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  GRPC_CLOSURE_INIT(&complete_fetch_locked, ::complete_fetch_locked, this,
 | 
	
		
			
				|  |  | -                    grpc_combiner_scheduler(t->combiner));
 | 
	
		
			
				|  |  | -  GRPC_CLOSURE_INIT(&reset_byte_stream, ::reset_byte_stream, this,
 | 
	
		
			
				|  |  | -                    grpc_combiner_scheduler(t->combiner));
 | 
	
		
			
				|  |  | +  GRPC_CLOSURE_INIT(&reset_byte_stream, ::reset_byte_stream, this, nullptr);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  grpc_chttp2_stream::~grpc_chttp2_stream() {
 | 
	
	
		
			
				|  | @@ -766,9 +743,8 @@ static void destroy_stream(grpc_transport* gt, grpc_stream* gs,
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    s->destroy_stream_arg = then_schedule_closure;
 | 
	
		
			
				|  |  | -  GRPC_CLOSURE_SCHED(
 | 
	
		
			
				|  |  | -      GRPC_CLOSURE_INIT(&s->destroy_stream, destroy_stream_locked, s,
 | 
	
		
			
				|  |  | -                        grpc_combiner_scheduler(t->combiner)),
 | 
	
		
			
				|  |  | +  t->combiner->Run(
 | 
	
		
			
				|  |  | +      GRPC_CLOSURE_INIT(&s->destroy_stream, destroy_stream_locked, s, nullptr),
 | 
	
		
			
				|  |  |        GRPC_ERROR_NONE);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -929,10 +905,9 @@ void grpc_chttp2_initiate_write(grpc_chttp2_transport* t,
 | 
	
		
			
				|  |  |         * Also, 'write_action_begin_locked' only gathers the bytes into outbuf.
 | 
	
		
			
				|  |  |         * It does not call the endpoint to write the bytes. That is done by the
 | 
	
		
			
				|  |  |         * 'write_action' (which is scheduled by 'write_action_begin_locked') */
 | 
	
		
			
				|  |  | -      GRPC_CLOSURE_SCHED(
 | 
	
		
			
				|  |  | +      t->combiner->FinallyRun(
 | 
	
		
			
				|  |  |            GRPC_CLOSURE_INIT(&t->write_action_begin_locked,
 | 
	
		
			
				|  |  | -                            write_action_begin_locked, t,
 | 
	
		
			
				|  |  | -                            grpc_combiner_finally_scheduler(t->combiner)),
 | 
	
		
			
				|  |  | +                            write_action_begin_locked, t, nullptr),
 | 
	
		
			
				|  |  |            GRPC_ERROR_NONE);
 | 
	
		
			
				|  |  |        break;
 | 
	
		
			
				|  |  |      case GRPC_CHTTP2_WRITE_STATE_WRITING:
 | 
	
	
		
			
				|  | @@ -1006,11 +981,18 @@ static void write_action(void* gt, grpc_error* error) {
 | 
	
		
			
				|  |  |    t->cl = nullptr;
 | 
	
		
			
				|  |  |    grpc_endpoint_write(
 | 
	
		
			
				|  |  |        t->ep, &t->outbuf,
 | 
	
		
			
				|  |  | -      GRPC_CLOSURE_INIT(&t->write_action_end_locked, write_action_end_locked, t,
 | 
	
		
			
				|  |  | -                        grpc_combiner_scheduler(t->combiner)),
 | 
	
		
			
				|  |  | +      GRPC_CLOSURE_INIT(&t->write_action_end_locked, write_action_end, t,
 | 
	
		
			
				|  |  | +                        grpc_schedule_on_exec_ctx),
 | 
	
		
			
				|  |  |        cl);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +static void write_action_end(void* tp, grpc_error* error) {
 | 
	
		
			
				|  |  | +  grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp);
 | 
	
		
			
				|  |  | +  t->combiner->Run(GRPC_CLOSURE_INIT(&t->write_action_end_locked,
 | 
	
		
			
				|  |  | +                                     write_action_end_locked, t, nullptr),
 | 
	
		
			
				|  |  | +                   GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  /* Callback from the grpc_endpoint after bytes have been written by calling
 | 
	
		
			
				|  |  |   * sendmsg */
 | 
	
		
			
				|  |  |  static void write_action_end_locked(void* tp, grpc_error* error) {
 | 
	
	
		
			
				|  | @@ -1051,10 +1033,9 @@ static void write_action_end_locked(void* tp, grpc_error* error) {
 | 
	
		
			
				|  |  |        if (!closed) {
 | 
	
		
			
				|  |  |          GRPC_CLOSURE_LIST_SCHED(&t->run_after_write);
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  | -      GRPC_CLOSURE_RUN(
 | 
	
		
			
				|  |  | +      t->combiner->FinallyRun(
 | 
	
		
			
				|  |  |            GRPC_CLOSURE_INIT(&t->write_action_begin_locked,
 | 
	
		
			
				|  |  | -                            write_action_begin_locked, t,
 | 
	
		
			
				|  |  | -                            grpc_combiner_finally_scheduler(t->combiner)),
 | 
	
		
			
				|  |  | +                            write_action_begin_locked, t, nullptr),
 | 
	
		
			
				|  |  |            GRPC_ERROR_NONE);
 | 
	
		
			
				|  |  |        break;
 | 
	
		
			
				|  |  |    }
 | 
	
	
		
			
				|  | @@ -1305,8 +1286,10 @@ static void continue_fetching_send_locked(grpc_chttp2_transport* t,
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |        s->fetching_send_message.reset();
 | 
	
		
			
				|  |  |        return; /* early out */
 | 
	
		
			
				|  |  | -    } else if (s->fetching_send_message->Next(UINT32_MAX,
 | 
	
		
			
				|  |  | -                                              &s->complete_fetch_locked)) {
 | 
	
		
			
				|  |  | +    } else if (s->fetching_send_message->Next(
 | 
	
		
			
				|  |  | +                   UINT32_MAX, GRPC_CLOSURE_INIT(&s->complete_fetch_locked,
 | 
	
		
			
				|  |  | +                                                 ::complete_fetch, s,
 | 
	
		
			
				|  |  | +                                                 grpc_schedule_on_exec_ctx))) {
 | 
	
		
			
				|  |  |        grpc_error* error = s->fetching_send_message->Pull(&s->fetching_slice);
 | 
	
		
			
				|  |  |        if (error != GRPC_ERROR_NONE) {
 | 
	
		
			
				|  |  |          s->fetching_send_message.reset();
 | 
	
	
		
			
				|  | @@ -1318,6 +1301,13 @@ static void continue_fetching_send_locked(grpc_chttp2_transport* t,
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +static void complete_fetch(void* gs, grpc_error* error) {
 | 
	
		
			
				|  |  | +  grpc_chttp2_stream* s = static_cast<grpc_chttp2_stream*>(gs);
 | 
	
		
			
				|  |  | +  s->t->combiner->Run(GRPC_CLOSURE_INIT(&s->complete_fetch_locked,
 | 
	
		
			
				|  |  | +                                        ::complete_fetch_locked, s, nullptr),
 | 
	
		
			
				|  |  | +                      GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  static void complete_fetch_locked(void* gs, grpc_error* error) {
 | 
	
		
			
				|  |  |    grpc_chttp2_stream* s = static_cast<grpc_chttp2_stream*>(gs);
 | 
	
		
			
				|  |  |    grpc_chttp2_transport* t = s->t;
 | 
	
	
		
			
				|  | @@ -1668,10 +1658,9 @@ static void perform_stream_op(grpc_transport* gt, grpc_stream* gs,
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    GRPC_CHTTP2_STREAM_REF(s, "perform_stream_op");
 | 
	
		
			
				|  |  |    op->handler_private.extra_arg = gs;
 | 
	
		
			
				|  |  | -  GRPC_CLOSURE_SCHED(
 | 
	
		
			
				|  |  | -      GRPC_CLOSURE_INIT(&op->handler_private.closure, perform_stream_op_locked,
 | 
	
		
			
				|  |  | -                        op, grpc_combiner_scheduler(t->combiner)),
 | 
	
		
			
				|  |  | -      GRPC_ERROR_NONE);
 | 
	
		
			
				|  |  | +  t->combiner->Run(GRPC_CLOSURE_INIT(&op->handler_private.closure,
 | 
	
		
			
				|  |  | +                                     perform_stream_op_locked, op, nullptr),
 | 
	
		
			
				|  |  | +                   GRPC_ERROR_NONE);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void cancel_pings(grpc_chttp2_transport* t, grpc_error* error) {
 | 
	
	
		
			
				|  | @@ -1707,24 +1696,45 @@ static void send_ping_locked(grpc_chttp2_transport* t,
 | 
	
		
			
				|  |  |   */
 | 
	
		
			
				|  |  |  static void send_keepalive_ping_locked(grpc_chttp2_transport* t) {
 | 
	
		
			
				|  |  |    if (t->closed_with_error != GRPC_ERROR_NONE) {
 | 
	
		
			
				|  |  | -    GRPC_CLOSURE_RUN(&t->start_keepalive_ping_locked,
 | 
	
		
			
				|  |  | -                     GRPC_ERROR_REF(t->closed_with_error));
 | 
	
		
			
				|  |  | -    GRPC_CLOSURE_RUN(&t->finish_keepalive_ping_locked,
 | 
	
		
			
				|  |  | +    t->combiner->Run(GRPC_CLOSURE_INIT(&t->start_keepalive_ping_locked,
 | 
	
		
			
				|  |  | +                                       start_keepalive_ping_locked, t, nullptr),
 | 
	
		
			
				|  |  |                       GRPC_ERROR_REF(t->closed_with_error));
 | 
	
		
			
				|  |  | +    t->combiner->Run(
 | 
	
		
			
				|  |  | +        GRPC_CLOSURE_INIT(&t->finish_keepalive_ping_locked,
 | 
	
		
			
				|  |  | +                          finish_keepalive_ping_locked, t, nullptr),
 | 
	
		
			
				|  |  | +        GRPC_ERROR_REF(t->closed_with_error));
 | 
	
		
			
				|  |  |      return;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    grpc_chttp2_ping_queue* pq = &t->ping_queue;
 | 
	
		
			
				|  |  |    if (!grpc_closure_list_empty(pq->lists[GRPC_CHTTP2_PCL_INFLIGHT])) {
 | 
	
		
			
				|  |  |      /* There is a ping in flight. Add yourself to the inflight closure list. */
 | 
	
		
			
				|  |  | -    GRPC_CLOSURE_RUN(&t->start_keepalive_ping_locked, GRPC_ERROR_NONE);
 | 
	
		
			
				|  |  | -    grpc_closure_list_append(&pq->lists[GRPC_CHTTP2_PCL_INFLIGHT],
 | 
	
		
			
				|  |  | -                             &t->finish_keepalive_ping_locked, GRPC_ERROR_NONE);
 | 
	
		
			
				|  |  | +    t->combiner->Run(GRPC_CLOSURE_INIT(&t->start_keepalive_ping_locked,
 | 
	
		
			
				|  |  | +                                       start_keepalive_ping_locked, t, nullptr),
 | 
	
		
			
				|  |  | +                     GRPC_ERROR_REF(t->closed_with_error));
 | 
	
		
			
				|  |  | +    grpc_closure_list_append(
 | 
	
		
			
				|  |  | +        &pq->lists[GRPC_CHTTP2_PCL_INFLIGHT],
 | 
	
		
			
				|  |  | +        GRPC_CLOSURE_INIT(&t->finish_keepalive_ping_locked,
 | 
	
		
			
				|  |  | +                          finish_keepalive_ping, t, grpc_schedule_on_exec_ctx),
 | 
	
		
			
				|  |  | +        GRPC_ERROR_NONE);
 | 
	
		
			
				|  |  |      return;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -  grpc_closure_list_append(&pq->lists[GRPC_CHTTP2_PCL_INITIATE],
 | 
	
		
			
				|  |  | -                           &t->start_keepalive_ping_locked, GRPC_ERROR_NONE);
 | 
	
		
			
				|  |  | -  grpc_closure_list_append(&pq->lists[GRPC_CHTTP2_PCL_NEXT],
 | 
	
		
			
				|  |  | -                           &t->finish_keepalive_ping_locked, GRPC_ERROR_NONE);
 | 
	
		
			
				|  |  | +  grpc_closure_list_append(
 | 
	
		
			
				|  |  | +      &pq->lists[GRPC_CHTTP2_PCL_INITIATE],
 | 
	
		
			
				|  |  | +      GRPC_CLOSURE_INIT(&t->start_keepalive_ping_locked, start_keepalive_ping,
 | 
	
		
			
				|  |  | +                        t, grpc_schedule_on_exec_ctx),
 | 
	
		
			
				|  |  | +      GRPC_ERROR_NONE);
 | 
	
		
			
				|  |  | +  grpc_closure_list_append(
 | 
	
		
			
				|  |  | +      &pq->lists[GRPC_CHTTP2_PCL_NEXT],
 | 
	
		
			
				|  |  | +      GRPC_CLOSURE_INIT(&t->finish_keepalive_ping_locked, finish_keepalive_ping,
 | 
	
		
			
				|  |  | +                        t, grpc_schedule_on_exec_ctx),
 | 
	
		
			
				|  |  | +      GRPC_ERROR_NONE);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void grpc_chttp2_retry_initiate_ping(void* tp, grpc_error* error) {
 | 
	
		
			
				|  |  | +  grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp);
 | 
	
		
			
				|  |  | +  t->combiner->Run(GRPC_CLOSURE_INIT(&t->retry_initiate_ping_locked,
 | 
	
		
			
				|  |  | +                                     retry_initiate_ping_locked, t, nullptr),
 | 
	
		
			
				|  |  | +                   GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void retry_initiate_ping_locked(void* tp, grpc_error* error) {
 | 
	
	
		
			
				|  | @@ -1835,10 +1845,9 @@ static void perform_transport_op(grpc_transport* gt, grpc_transport_op* op) {
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    op->handler_private.extra_arg = gt;
 | 
	
		
			
				|  |  |    GRPC_CHTTP2_REF_TRANSPORT(t, "transport_op");
 | 
	
		
			
				|  |  | -  GRPC_CLOSURE_SCHED(GRPC_CLOSURE_INIT(&op->handler_private.closure,
 | 
	
		
			
				|  |  | -                                       perform_transport_op_locked, op,
 | 
	
		
			
				|  |  | -                                       grpc_combiner_scheduler(t->combiner)),
 | 
	
		
			
				|  |  | -                     GRPC_ERROR_NONE);
 | 
	
		
			
				|  |  | +  t->combiner->Run(GRPC_CLOSURE_INIT(&op->handler_private.closure,
 | 
	
		
			
				|  |  | +                                     perform_transport_op_locked, op, nullptr),
 | 
	
		
			
				|  |  | +                   GRPC_ERROR_NONE);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /*******************************************************************************
 | 
	
	
		
			
				|  | @@ -2479,6 +2488,13 @@ static grpc_error* try_http_parsing(grpc_chttp2_transport* t) {
 | 
	
		
			
				|  |  |    return error;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +static void read_action(void* tp, grpc_error* error) {
 | 
	
		
			
				|  |  | +  grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp);
 | 
	
		
			
				|  |  | +  t->combiner->Run(
 | 
	
		
			
				|  |  | +      GRPC_CLOSURE_INIT(&t->read_action_locked, read_action_locked, t, nullptr),
 | 
	
		
			
				|  |  | +      GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  static void read_action_locked(void* tp, grpc_error* error) {
 | 
	
		
			
				|  |  |    GPR_TIMER_SCOPE("reading_action_locked", 0);
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -2576,6 +2592,8 @@ static void read_action_locked(void* tp, grpc_error* error) {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void continue_read_action_locked(grpc_chttp2_transport* t) {
 | 
	
		
			
				|  |  |    const bool urgent = t->goaway_error != GRPC_ERROR_NONE;
 | 
	
		
			
				|  |  | +  GRPC_CLOSURE_INIT(&t->read_action_locked, read_action, t,
 | 
	
		
			
				|  |  | +                    grpc_schedule_on_exec_ctx);
 | 
	
		
			
				|  |  |    grpc_endpoint_read(t->ep, &t->read_buffer, &t->read_action_locked, urgent);
 | 
	
		
			
				|  |  |    grpc_chttp2_act_on_flowctl_action(t->flow_control->MakeAction(), t, nullptr);
 | 
	
		
			
				|  |  |  }
 | 
	
	
		
			
				|  | @@ -2584,7 +2602,19 @@ static void continue_read_action_locked(grpc_chttp2_transport* t) {
 | 
	
		
			
				|  |  |  // that kicks off finishes, it's unreffed
 | 
	
		
			
				|  |  |  static void schedule_bdp_ping_locked(grpc_chttp2_transport* t) {
 | 
	
		
			
				|  |  |    t->flow_control->bdp_estimator()->SchedulePing();
 | 
	
		
			
				|  |  | -  send_ping_locked(t, &t->start_bdp_ping_locked, &t->finish_bdp_ping_locked);
 | 
	
		
			
				|  |  | +  send_ping_locked(
 | 
	
		
			
				|  |  | +      t,
 | 
	
		
			
				|  |  | +      GRPC_CLOSURE_INIT(&t->start_bdp_ping_locked, start_bdp_ping, t,
 | 
	
		
			
				|  |  | +                        grpc_schedule_on_exec_ctx),
 | 
	
		
			
				|  |  | +      GRPC_CLOSURE_INIT(&t->finish_bdp_ping_locked, finish_bdp_ping, t,
 | 
	
		
			
				|  |  | +                        grpc_schedule_on_exec_ctx));
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void start_bdp_ping(void* tp, grpc_error* error) {
 | 
	
		
			
				|  |  | +  grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp);
 | 
	
		
			
				|  |  | +  t->combiner->Run(GRPC_CLOSURE_INIT(&t->start_bdp_ping_locked,
 | 
	
		
			
				|  |  | +                                     start_bdp_ping_locked, t, nullptr),
 | 
	
		
			
				|  |  | +                   GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void start_bdp_ping_locked(void* tp, grpc_error* error) {
 | 
	
	
		
			
				|  | @@ -2601,6 +2631,14 @@ static void start_bdp_ping_locked(void* tp, grpc_error* error) {
 | 
	
		
			
				|  |  |      grpc_timer_cancel(&t->keepalive_ping_timer);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    t->flow_control->bdp_estimator()->StartPing();
 | 
	
		
			
				|  |  | +  t->bdp_ping_started = true;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void finish_bdp_ping(void* tp, grpc_error* error) {
 | 
	
		
			
				|  |  | +  grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp);
 | 
	
		
			
				|  |  | +  t->combiner->Run(GRPC_CLOSURE_INIT(&t->finish_bdp_ping_locked,
 | 
	
		
			
				|  |  | +                                     finish_bdp_ping_locked, t, nullptr),
 | 
	
		
			
				|  |  | +                   GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void finish_bdp_ping_locked(void* tp, grpc_error* error) {
 | 
	
	
		
			
				|  | @@ -2613,15 +2651,34 @@ static void finish_bdp_ping_locked(void* tp, grpc_error* error) {
 | 
	
		
			
				|  |  |      GRPC_CHTTP2_UNREF_TRANSPORT(t, "bdp_ping");
 | 
	
		
			
				|  |  |      return;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | +  if (!t->bdp_ping_started) {
 | 
	
		
			
				|  |  | +    /* start_bdp_ping_locked has not been run yet. Schedule
 | 
	
		
			
				|  |  | +     * finish_bdp_ping_locked to be run later. */
 | 
	
		
			
				|  |  | +    t->combiner->Run(GRPC_CLOSURE_INIT(&t->finish_bdp_ping_locked,
 | 
	
		
			
				|  |  | +                                       finish_bdp_ping_locked, t, nullptr),
 | 
	
		
			
				|  |  | +                     GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  | +    return;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  t->bdp_ping_started = false;
 | 
	
		
			
				|  |  |    grpc_millis next_ping = t->flow_control->bdp_estimator()->CompletePing();
 | 
	
		
			
				|  |  |    grpc_chttp2_act_on_flowctl_action(t->flow_control->PeriodicUpdate(), t,
 | 
	
		
			
				|  |  |                                      nullptr);
 | 
	
		
			
				|  |  |    GPR_ASSERT(!t->have_next_bdp_ping_timer);
 | 
	
		
			
				|  |  |    t->have_next_bdp_ping_timer = true;
 | 
	
		
			
				|  |  | +  GRPC_CLOSURE_INIT(&t->next_bdp_ping_timer_expired_locked,
 | 
	
		
			
				|  |  | +                    next_bdp_ping_timer_expired, t, grpc_schedule_on_exec_ctx);
 | 
	
		
			
				|  |  |    grpc_timer_init(&t->next_bdp_ping_timer, next_ping,
 | 
	
		
			
				|  |  |                    &t->next_bdp_ping_timer_expired_locked);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +static void next_bdp_ping_timer_expired(void* tp, grpc_error* error) {
 | 
	
		
			
				|  |  | +  grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp);
 | 
	
		
			
				|  |  | +  t->combiner->Run(
 | 
	
		
			
				|  |  | +      GRPC_CLOSURE_INIT(&t->next_bdp_ping_timer_expired_locked,
 | 
	
		
			
				|  |  | +                        next_bdp_ping_timer_expired_locked, t, nullptr),
 | 
	
		
			
				|  |  | +      GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  static void next_bdp_ping_timer_expired_locked(void* tp, grpc_error* error) {
 | 
	
		
			
				|  |  |    grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp);
 | 
	
		
			
				|  |  |    GPR_ASSERT(t->have_next_bdp_ping_timer);
 | 
	
	
		
			
				|  | @@ -2700,6 +2757,13 @@ void grpc_chttp2_config_default_keepalive_args(grpc_channel_args* args,
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +static void init_keepalive_ping(void* arg, grpc_error* error) {
 | 
	
		
			
				|  |  | +  grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(arg);
 | 
	
		
			
				|  |  | +  t->combiner->Run(GRPC_CLOSURE_INIT(&t->init_keepalive_ping_locked,
 | 
	
		
			
				|  |  | +                                     init_keepalive_ping_locked, t, nullptr),
 | 
	
		
			
				|  |  | +                   GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  static void init_keepalive_ping_locked(void* arg, grpc_error* error) {
 | 
	
		
			
				|  |  |    grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(arg);
 | 
	
		
			
				|  |  |    GPR_ASSERT(t->keepalive_state == GRPC_CHTTP2_KEEPALIVE_STATE_WAITING);
 | 
	
	
		
			
				|  | @@ -2715,6 +2779,8 @@ static void init_keepalive_ping_locked(void* arg, grpc_error* error) {
 | 
	
		
			
				|  |  |        grpc_chttp2_initiate_write(t, GRPC_CHTTP2_INITIATE_WRITE_KEEPALIVE_PING);
 | 
	
		
			
				|  |  |      } else {
 | 
	
		
			
				|  |  |        GRPC_CHTTP2_REF_TRANSPORT(t, "init keepalive ping");
 | 
	
		
			
				|  |  | +      GRPC_CLOSURE_INIT(&t->init_keepalive_ping_locked, init_keepalive_ping, t,
 | 
	
		
			
				|  |  | +                        grpc_schedule_on_exec_ctx);
 | 
	
		
			
				|  |  |        grpc_timer_init(&t->keepalive_ping_timer,
 | 
	
		
			
				|  |  |                        grpc_core::ExecCtx::Get()->Now() + t->keepalive_time,
 | 
	
		
			
				|  |  |                        &t->init_keepalive_ping_locked);
 | 
	
	
		
			
				|  | @@ -2722,6 +2788,8 @@ static void init_keepalive_ping_locked(void* arg, grpc_error* error) {
 | 
	
		
			
				|  |  |    } else if (error == GRPC_ERROR_CANCELLED) {
 | 
	
		
			
				|  |  |      /* The keepalive ping timer may be cancelled by bdp */
 | 
	
		
			
				|  |  |      GRPC_CHTTP2_REF_TRANSPORT(t, "init keepalive ping");
 | 
	
		
			
				|  |  | +    GRPC_CLOSURE_INIT(&t->init_keepalive_ping_locked, init_keepalive_ping, t,
 | 
	
		
			
				|  |  | +                      grpc_schedule_on_exec_ctx);
 | 
	
		
			
				|  |  |      grpc_timer_init(&t->keepalive_ping_timer,
 | 
	
		
			
				|  |  |                      grpc_core::ExecCtx::Get()->Now() + t->keepalive_time,
 | 
	
		
			
				|  |  |                      &t->init_keepalive_ping_locked);
 | 
	
	
		
			
				|  | @@ -2729,6 +2797,13 @@ static void init_keepalive_ping_locked(void* arg, grpc_error* error) {
 | 
	
		
			
				|  |  |    GRPC_CHTTP2_UNREF_TRANSPORT(t, "init keepalive ping");
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +static void start_keepalive_ping(void* arg, grpc_error* error) {
 | 
	
		
			
				|  |  | +  grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(arg);
 | 
	
		
			
				|  |  | +  t->combiner->Run(GRPC_CLOSURE_INIT(&t->start_keepalive_ping_locked,
 | 
	
		
			
				|  |  | +                                     start_keepalive_ping_locked, t, nullptr),
 | 
	
		
			
				|  |  | +                   GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  static void start_keepalive_ping_locked(void* arg, grpc_error* error) {
 | 
	
		
			
				|  |  |    grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(arg);
 | 
	
		
			
				|  |  |    if (error != GRPC_ERROR_NONE) {
 | 
	
	
		
			
				|  | @@ -2741,9 +2816,19 @@ static void start_keepalive_ping_locked(void* arg, grpc_error* error) {
 | 
	
		
			
				|  |  |      gpr_log(GPR_INFO, "%s: Start keepalive ping", t->peer_string);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    GRPC_CHTTP2_REF_TRANSPORT(t, "keepalive watchdog");
 | 
	
		
			
				|  |  | +  GRPC_CLOSURE_INIT(&t->keepalive_watchdog_fired_locked,
 | 
	
		
			
				|  |  | +                    keepalive_watchdog_fired, t, grpc_schedule_on_exec_ctx);
 | 
	
		
			
				|  |  |    grpc_timer_init(&t->keepalive_watchdog_timer,
 | 
	
		
			
				|  |  |                    grpc_core::ExecCtx::Get()->Now() + t->keepalive_timeout,
 | 
	
		
			
				|  |  |                    &t->keepalive_watchdog_fired_locked);
 | 
	
		
			
				|  |  | +  t->keepalive_ping_started = true;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void finish_keepalive_ping(void* arg, grpc_error* error) {
 | 
	
		
			
				|  |  | +  grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(arg);
 | 
	
		
			
				|  |  | +  t->combiner->Run(GRPC_CLOSURE_INIT(&t->finish_keepalive_ping_locked,
 | 
	
		
			
				|  |  | +                                     finish_keepalive_ping_locked, t, nullptr),
 | 
	
		
			
				|  |  | +                   GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void finish_keepalive_ping_locked(void* arg, grpc_error* error) {
 | 
	
	
		
			
				|  | @@ -2753,9 +2838,21 @@ static void finish_keepalive_ping_locked(void* arg, grpc_error* error) {
 | 
	
		
			
				|  |  |        if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) {
 | 
	
		
			
				|  |  |          gpr_log(GPR_INFO, "%s: Finish keepalive ping", t->peer_string);
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  | +      if (!t->keepalive_ping_started) {
 | 
	
		
			
				|  |  | +        /* start_keepalive_ping_locked has not run yet. Reschedule
 | 
	
		
			
				|  |  | +         * finish_keepalive_ping_locked for it to be run later. */
 | 
	
		
			
				|  |  | +        t->combiner->Run(
 | 
	
		
			
				|  |  | +            GRPC_CLOSURE_INIT(&t->finish_keepalive_ping_locked,
 | 
	
		
			
				|  |  | +                              finish_keepalive_ping_locked, t, nullptr),
 | 
	
		
			
				|  |  | +            GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  | +        return;
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +      t->keepalive_ping_started = false;
 | 
	
		
			
				|  |  |        t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_WAITING;
 | 
	
		
			
				|  |  |        grpc_timer_cancel(&t->keepalive_watchdog_timer);
 | 
	
		
			
				|  |  |        GRPC_CHTTP2_REF_TRANSPORT(t, "init keepalive ping");
 | 
	
		
			
				|  |  | +      GRPC_CLOSURE_INIT(&t->init_keepalive_ping_locked, init_keepalive_ping, t,
 | 
	
		
			
				|  |  | +                        grpc_schedule_on_exec_ctx);
 | 
	
		
			
				|  |  |        grpc_timer_init(&t->keepalive_ping_timer,
 | 
	
		
			
				|  |  |                        grpc_core::ExecCtx::Get()->Now() + t->keepalive_time,
 | 
	
		
			
				|  |  |                        &t->init_keepalive_ping_locked);
 | 
	
	
		
			
				|  | @@ -2764,6 +2861,14 @@ static void finish_keepalive_ping_locked(void* arg, grpc_error* error) {
 | 
	
		
			
				|  |  |    GRPC_CHTTP2_UNREF_TRANSPORT(t, "keepalive ping end");
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +static void keepalive_watchdog_fired(void* arg, grpc_error* error) {
 | 
	
		
			
				|  |  | +  grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(arg);
 | 
	
		
			
				|  |  | +  t->combiner->Run(
 | 
	
		
			
				|  |  | +      GRPC_CLOSURE_INIT(&t->keepalive_watchdog_fired_locked,
 | 
	
		
			
				|  |  | +                        keepalive_watchdog_fired_locked, t, nullptr),
 | 
	
		
			
				|  |  | +      GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  static void keepalive_watchdog_fired_locked(void* arg, grpc_error* error) {
 | 
	
		
			
				|  |  |    grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(arg);
 | 
	
		
			
				|  |  |    if (t->keepalive_state == GRPC_CHTTP2_KEEPALIVE_STATE_PINGING) {
 | 
	
	
		
			
				|  | @@ -2864,10 +2969,9 @@ void Chttp2IncomingByteStream::OrphanLocked(void* arg,
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  void Chttp2IncomingByteStream::Orphan() {
 | 
	
		
			
				|  |  |    GPR_TIMER_SCOPE("incoming_byte_stream_destroy", 0);
 | 
	
		
			
				|  |  | -  GRPC_CLOSURE_SCHED(
 | 
	
		
			
				|  |  | +  transport_->combiner->Run(
 | 
	
		
			
				|  |  |        GRPC_CLOSURE_INIT(&destroy_action_,
 | 
	
		
			
				|  |  | -                        &Chttp2IncomingByteStream::OrphanLocked, this,
 | 
	
		
			
				|  |  | -                        grpc_combiner_scheduler(transport_->combiner)),
 | 
	
		
			
				|  |  | +                        &Chttp2IncomingByteStream::OrphanLocked, this, nullptr),
 | 
	
		
			
				|  |  |        GRPC_ERROR_NONE);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -2924,10 +3028,9 @@ bool Chttp2IncomingByteStream::Next(size_t max_size_hint,
 | 
	
		
			
				|  |  |      Ref();
 | 
	
		
			
				|  |  |      next_action_.max_size_hint = max_size_hint;
 | 
	
		
			
				|  |  |      next_action_.on_complete = on_complete;
 | 
	
		
			
				|  |  | -    GRPC_CLOSURE_SCHED(
 | 
	
		
			
				|  |  | +    transport_->combiner->Run(
 | 
	
		
			
				|  |  |          GRPC_CLOSURE_INIT(&next_action_.closure,
 | 
	
		
			
				|  |  | -                          &Chttp2IncomingByteStream::NextLocked, this,
 | 
	
		
			
				|  |  | -                          grpc_combiner_scheduler(transport_->combiner)),
 | 
	
		
			
				|  |  | +                          &Chttp2IncomingByteStream::NextLocked, this, nullptr),
 | 
	
		
			
				|  |  |          GRPC_ERROR_NONE);
 | 
	
		
			
				|  |  |      return false;
 | 
	
		
			
				|  |  |    }
 | 
	
	
		
			
				|  | @@ -2980,7 +3083,8 @@ grpc_error* Chttp2IncomingByteStream::Pull(grpc_slice* slice) {
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    } else {
 | 
	
		
			
				|  |  |      error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Truncated message");
 | 
	
		
			
				|  |  | -    GRPC_CLOSURE_SCHED(&stream_->reset_byte_stream, GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  | +    stream_->t->combiner->Run(&stream_->reset_byte_stream,
 | 
	
		
			
				|  |  | +                              GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  |      return error;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    return GRPC_ERROR_NONE;
 | 
	
	
		
			
				|  | @@ -3000,7 +3104,8 @@ grpc_error* Chttp2IncomingByteStream::Push(const grpc_slice& slice,
 | 
	
		
			
				|  |  |    if (remaining_bytes_ < GRPC_SLICE_LENGTH(slice)) {
 | 
	
		
			
				|  |  |      grpc_error* error =
 | 
	
		
			
				|  |  |          GRPC_ERROR_CREATE_FROM_STATIC_STRING("Too many bytes in stream");
 | 
	
		
			
				|  |  | -    GRPC_CLOSURE_SCHED(&stream_->reset_byte_stream, GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  | +    transport_->combiner->Run(&stream_->reset_byte_stream,
 | 
	
		
			
				|  |  | +                              GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  |      grpc_slice_unref_internal(slice);
 | 
	
		
			
				|  |  |      return error;
 | 
	
		
			
				|  |  |    } else {
 | 
	
	
		
			
				|  | @@ -3020,7 +3125,8 @@ grpc_error* Chttp2IncomingByteStream::Finished(grpc_error* error,
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    if (error != GRPC_ERROR_NONE && reset_on_error) {
 | 
	
		
			
				|  |  | -    GRPC_CLOSURE_SCHED(&stream_->reset_byte_stream, GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  | +    transport_->combiner->Run(&stream_->reset_byte_stream,
 | 
	
		
			
				|  |  | +                              GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    Unref();
 | 
	
		
			
				|  |  |    return error;
 | 
	
	
		
			
				|  | @@ -3040,6 +3146,8 @@ static void post_benign_reclaimer(grpc_chttp2_transport* t) {
 | 
	
		
			
				|  |  |    if (!t->benign_reclaimer_registered) {
 | 
	
		
			
				|  |  |      t->benign_reclaimer_registered = true;
 | 
	
		
			
				|  |  |      GRPC_CHTTP2_REF_TRANSPORT(t, "benign_reclaimer");
 | 
	
		
			
				|  |  | +    GRPC_CLOSURE_INIT(&t->benign_reclaimer_locked, benign_reclaimer, t,
 | 
	
		
			
				|  |  | +                      grpc_schedule_on_exec_ctx);
 | 
	
		
			
				|  |  |      grpc_resource_user_post_reclaimer(grpc_endpoint_get_resource_user(t->ep),
 | 
	
		
			
				|  |  |                                        false, &t->benign_reclaimer_locked);
 | 
	
		
			
				|  |  |    }
 | 
	
	
		
			
				|  | @@ -3049,11 +3157,20 @@ static void post_destructive_reclaimer(grpc_chttp2_transport* t) {
 | 
	
		
			
				|  |  |    if (!t->destructive_reclaimer_registered) {
 | 
	
		
			
				|  |  |      t->destructive_reclaimer_registered = true;
 | 
	
		
			
				|  |  |      GRPC_CHTTP2_REF_TRANSPORT(t, "destructive_reclaimer");
 | 
	
		
			
				|  |  | +    GRPC_CLOSURE_INIT(&t->destructive_reclaimer_locked, destructive_reclaimer,
 | 
	
		
			
				|  |  | +                      t, grpc_schedule_on_exec_ctx);
 | 
	
		
			
				|  |  |      grpc_resource_user_post_reclaimer(grpc_endpoint_get_resource_user(t->ep),
 | 
	
		
			
				|  |  |                                        true, &t->destructive_reclaimer_locked);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +static void benign_reclaimer(void* arg, grpc_error* error) {
 | 
	
		
			
				|  |  | +  grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(arg);
 | 
	
		
			
				|  |  | +  t->combiner->Run(GRPC_CLOSURE_INIT(&t->benign_reclaimer_locked,
 | 
	
		
			
				|  |  | +                                     benign_reclaimer_locked, t, nullptr),
 | 
	
		
			
				|  |  | +                   GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  static void benign_reclaimer_locked(void* arg, grpc_error* error) {
 | 
	
		
			
				|  |  |    grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(arg);
 | 
	
		
			
				|  |  |    if (error == GRPC_ERROR_NONE &&
 | 
	
	
		
			
				|  | @@ -3083,6 +3200,13 @@ static void benign_reclaimer_locked(void* arg, grpc_error* error) {
 | 
	
		
			
				|  |  |    GRPC_CHTTP2_UNREF_TRANSPORT(t, "benign_reclaimer");
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +static void destructive_reclaimer(void* arg, grpc_error* error) {
 | 
	
		
			
				|  |  | +  grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(arg);
 | 
	
		
			
				|  |  | +  t->combiner->Run(GRPC_CLOSURE_INIT(&t->destructive_reclaimer_locked,
 | 
	
		
			
				|  |  | +                                     destructive_reclaimer_locked, t, nullptr),
 | 
	
		
			
				|  |  | +                   GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  static void destructive_reclaimer_locked(void* arg, grpc_error* error) {
 | 
	
		
			
				|  |  |    grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(arg);
 | 
	
		
			
				|  |  |    size_t n = grpc_chttp2_stream_map_size(&t->stream_map);
 | 
	
	
		
			
				|  | @@ -3209,5 +3333,7 @@ void grpc_chttp2_transport_start_reading(
 | 
	
		
			
				|  |  |      gpr_free(read_buffer);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    t->notify_on_receive_settings = notify_on_receive_settings;
 | 
	
		
			
				|  |  | -  GRPC_CLOSURE_SCHED(&t->read_action_locked, GRPC_ERROR_NONE);
 | 
	
		
			
				|  |  | +  t->combiner->Run(
 | 
	
		
			
				|  |  | +      GRPC_CLOSURE_INIT(&t->read_action_locked, read_action_locked, t, nullptr),
 | 
	
		
			
				|  |  | +      GRPC_ERROR_NONE);
 | 
	
		
			
				|  |  |  }
 |