|  | @@ -237,6 +237,9 @@ struct transport {
 | 
	
		
			
				|  |  |    /* state for a stream that's not yet been created */
 | 
	
		
			
				|  |  |    grpc_stream_op_buffer new_stream_sopb;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +  /* stream ops that need to be destroyed, but outside of the lock */
 | 
	
		
			
				|  |  | +  grpc_stream_op_buffer nuke_later_sopb;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    /* active parser */
 | 
	
		
			
				|  |  |    void *parser_data;
 | 
	
		
			
				|  |  |    stream *incoming_stream;
 | 
	
	
		
			
				|  | @@ -343,6 +346,7 @@ static void unref_transport(transport *t) {
 | 
	
		
			
				|  |  |    grpc_chttp2_hpack_parser_destroy(&t->hpack_parser);
 | 
	
		
			
				|  |  |    grpc_chttp2_hpack_compressor_destroy(&t->hpack_compressor);
 | 
	
		
			
				|  |  |    grpc_chttp2_goaway_parser_destroy(&t->goaway_parser);
 | 
	
		
			
				|  |  | +  grpc_sopb_destroy(&t->nuke_later_sopb);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    grpc_mdstr_unref(t->str_grpc_timeout);
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -416,6 +420,7 @@ static void init_transport(transport *t, grpc_transport_setup_callback setup,
 | 
	
		
			
				|  |  |    t->cap_pending_goaways = 0;
 | 
	
		
			
				|  |  |    gpr_slice_buffer_init(&t->outbuf);
 | 
	
		
			
				|  |  |    gpr_slice_buffer_init(&t->qbuf);
 | 
	
		
			
				|  |  | +  grpc_sopb_init(&t->nuke_later_sopb);
 | 
	
		
			
				|  |  |    if (is_client) {
 | 
	
		
			
				|  |  |      gpr_slice_buffer_add(&t->qbuf,
 | 
	
		
			
				|  |  |                           gpr_slice_from_copied_string(CLIENT_CONNECT_STRING));
 | 
	
	
		
			
				|  | @@ -525,7 +530,7 @@ static int init_stream(grpc_transport *gt, grpc_stream *gs,
 | 
	
		
			
				|  |  |      lock(t);
 | 
	
		
			
				|  |  |      s->id = 0;
 | 
	
		
			
				|  |  |    } else {
 | 
	
		
			
				|  |  | -    s->id = (gpr_uint32)(gpr_uintptr)server_data;
 | 
	
		
			
				|  |  | +    s->id = (gpr_uint32)(gpr_uintptr) server_data;
 | 
	
		
			
				|  |  |      t->incoming_stream = s;
 | 
	
		
			
				|  |  |      grpc_chttp2_stream_map_add(&t->stream_map, s->id, s);
 | 
	
		
			
				|  |  |    }
 | 
	
	
		
			
				|  | @@ -555,6 +560,11 @@ static int init_stream(grpc_transport *gt, grpc_stream *gs,
 | 
	
		
			
				|  |  |    return 0;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +static void schedule_nuke_sopb(transport *t, grpc_stream_op_buffer *sopb) {
 | 
	
		
			
				|  |  | +  grpc_sopb_append(&t->nuke_later_sopb, sopb->ops, sopb->nops);
 | 
	
		
			
				|  |  | +  sopb->nops = 0;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  static void destroy_stream(grpc_transport *gt, grpc_stream *gs) {
 | 
	
		
			
				|  |  |    transport *t = (transport *)gt;
 | 
	
		
			
				|  |  |    stream *s = (stream *)gs;
 | 
	
	
		
			
				|  | @@ -681,6 +691,11 @@ static void unlock(transport *t) {
 | 
	
		
			
				|  |  |    int i;
 | 
	
		
			
				|  |  |    pending_goaway *goaways = NULL;
 | 
	
		
			
				|  |  |    grpc_endpoint *ep = t->ep;
 | 
	
		
			
				|  |  | +  grpc_stream_op_buffer nuke_now = t->nuke_later_sopb;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if (nuke_now.nops) {
 | 
	
		
			
				|  |  | +    memset(&t->nuke_later_sopb, 0, sizeof(t->nuke_later_sopb));
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    /* see if we need to trigger a write - and if so, get the data ready */
 | 
	
		
			
				|  |  |    if (ep && !t->writing) {
 | 
	
	
		
			
				|  | @@ -750,6 +765,10 @@ static void unlock(transport *t) {
 | 
	
		
			
				|  |  |      unref_transport(t);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +  if (nuke_now.nops) {
 | 
	
		
			
				|  |  | +    grpc_sopb_reset(&nuke_now);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    gpr_free(goaways);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -1006,9 +1025,9 @@ static void cancel_stream_inner(transport *t, stream *s, gpr_uint32 id,
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    if (s) {
 | 
	
		
			
				|  |  |      /* clear out any unreported input & output: nobody cares anymore */
 | 
	
		
			
				|  |  | -    grpc_sopb_reset(&s->parser.incoming_sopb);
 | 
	
		
			
				|  |  |      had_outgoing = s->outgoing_sopb.nops != 0;
 | 
	
		
			
				|  |  | -    grpc_sopb_reset(&s->outgoing_sopb);
 | 
	
		
			
				|  |  | +    schedule_nuke_sopb(t, &s->parser.incoming_sopb);
 | 
	
		
			
				|  |  | +    schedule_nuke_sopb(t, &s->outgoing_sopb);
 | 
	
		
			
				|  |  |      if (s->cancelled) {
 | 
	
		
			
				|  |  |        send_rst = 0;
 | 
	
		
			
				|  |  |      } else if (!s->read_closed || !s->sent_write_closed || had_outgoing) {
 | 
	
	
		
			
				|  | @@ -1238,7 +1257,7 @@ static int init_header_frame_parser(transport *t, int is_continuation) {
 | 
	
		
			
				|  |  |      t->incoming_stream = NULL;
 | 
	
		
			
				|  |  |      /* if stream is accepted, we set incoming_stream in init_stream */
 | 
	
		
			
				|  |  |      t->cb->accept_stream(t->cb_user_data, &t->base,
 | 
	
		
			
				|  |  | -                         (void *)(gpr_uintptr)t->incoming_stream_id);
 | 
	
		
			
				|  |  | +                         (void *)(gpr_uintptr) t->incoming_stream_id);
 | 
	
		
			
				|  |  |      s = t->incoming_stream;
 | 
	
		
			
				|  |  |      if (!s) {
 | 
	
		
			
				|  |  |        gpr_log(GPR_ERROR, "stream not accepted");
 | 
	
	
		
			
				|  | @@ -1503,8 +1522,8 @@ static int process_read(transport *t, gpr_slice slice) {
 | 
	
		
			
				|  |  |                    "Connect string mismatch: expected '%c' (%d) got '%c' (%d) "
 | 
	
		
			
				|  |  |                    "at byte %d",
 | 
	
		
			
				|  |  |                    CLIENT_CONNECT_STRING[t->deframe_state],
 | 
	
		
			
				|  |  | -                  (int)(gpr_uint8)CLIENT_CONNECT_STRING[t->deframe_state], *cur,
 | 
	
		
			
				|  |  | -                  (int)*cur, t->deframe_state);
 | 
	
		
			
				|  |  | +                  (int)(gpr_uint8) CLIENT_CONNECT_STRING[t->deframe_state],
 | 
	
		
			
				|  |  | +                  *cur, (int)*cur, t->deframe_state);
 | 
	
		
			
				|  |  |            drop_connection(t);
 | 
	
		
			
				|  |  |            return 0;
 | 
	
		
			
				|  |  |          }
 | 
	
	
		
			
				|  | @@ -1518,7 +1537,7 @@ static int process_read(transport *t, gpr_slice slice) {
 | 
	
		
			
				|  |  |      dts_fh_0:
 | 
	
		
			
				|  |  |      case DTS_FH_0:
 | 
	
		
			
				|  |  |        GPR_ASSERT(cur < end);
 | 
	
		
			
				|  |  | -      t->incoming_frame_size = ((gpr_uint32) * cur) << 16;
 | 
	
		
			
				|  |  | +      t->incoming_frame_size = ((gpr_uint32)*cur) << 16;
 | 
	
		
			
				|  |  |        if (++cur == end) {
 | 
	
		
			
				|  |  |          t->deframe_state = DTS_FH_1;
 | 
	
		
			
				|  |  |          return 1;
 | 
	
	
		
			
				|  | @@ -1526,7 +1545,7 @@ static int process_read(transport *t, gpr_slice slice) {
 | 
	
		
			
				|  |  |      /* fallthrough */
 | 
	
		
			
				|  |  |      case DTS_FH_1:
 | 
	
		
			
				|  |  |        GPR_ASSERT(cur < end);
 | 
	
		
			
				|  |  | -      t->incoming_frame_size |= ((gpr_uint32) * cur) << 8;
 | 
	
		
			
				|  |  | +      t->incoming_frame_size |= ((gpr_uint32)*cur) << 8;
 | 
	
		
			
				|  |  |        if (++cur == end) {
 | 
	
		
			
				|  |  |          t->deframe_state = DTS_FH_2;
 | 
	
		
			
				|  |  |          return 1;
 | 
	
	
		
			
				|  | @@ -1558,7 +1577,7 @@ static int process_read(transport *t, gpr_slice slice) {
 | 
	
		
			
				|  |  |      /* fallthrough */
 | 
	
		
			
				|  |  |      case DTS_FH_5:
 | 
	
		
			
				|  |  |        GPR_ASSERT(cur < end);
 | 
	
		
			
				|  |  | -      t->incoming_stream_id = (((gpr_uint32) * cur) << 24) & 0x7f;
 | 
	
		
			
				|  |  | +      t->incoming_stream_id = (((gpr_uint32)*cur) << 24) & 0x7f;
 | 
	
		
			
				|  |  |        if (++cur == end) {
 | 
	
		
			
				|  |  |          t->deframe_state = DTS_FH_6;
 | 
	
		
			
				|  |  |          return 1;
 | 
	
	
		
			
				|  | @@ -1566,7 +1585,7 @@ static int process_read(transport *t, gpr_slice slice) {
 | 
	
		
			
				|  |  |      /* fallthrough */
 | 
	
		
			
				|  |  |      case DTS_FH_6:
 | 
	
		
			
				|  |  |        GPR_ASSERT(cur < end);
 | 
	
		
			
				|  |  | -      t->incoming_stream_id |= ((gpr_uint32) * cur) << 16;
 | 
	
		
			
				|  |  | +      t->incoming_stream_id |= ((gpr_uint32)*cur) << 16;
 | 
	
		
			
				|  |  |        if (++cur == end) {
 | 
	
		
			
				|  |  |          t->deframe_state = DTS_FH_7;
 | 
	
		
			
				|  |  |          return 1;
 | 
	
	
		
			
				|  | @@ -1574,7 +1593,7 @@ static int process_read(transport *t, gpr_slice slice) {
 | 
	
		
			
				|  |  |      /* fallthrough */
 | 
	
		
			
				|  |  |      case DTS_FH_7:
 | 
	
		
			
				|  |  |        GPR_ASSERT(cur < end);
 | 
	
		
			
				|  |  | -      t->incoming_stream_id |= ((gpr_uint32) * cur) << 8;
 | 
	
		
			
				|  |  | +      t->incoming_stream_id |= ((gpr_uint32)*cur) << 8;
 | 
	
		
			
				|  |  |        if (++cur == end) {
 | 
	
		
			
				|  |  |          t->deframe_state = DTS_FH_8;
 | 
	
		
			
				|  |  |          return 1;
 | 
	
	
		
			
				|  | @@ -1582,7 +1601,7 @@ static int process_read(transport *t, gpr_slice slice) {
 | 
	
		
			
				|  |  |      /* fallthrough */
 | 
	
		
			
				|  |  |      case DTS_FH_8:
 | 
	
		
			
				|  |  |        GPR_ASSERT(cur < end);
 | 
	
		
			
				|  |  | -      t->incoming_stream_id |= ((gpr_uint32) * cur);
 | 
	
		
			
				|  |  | +      t->incoming_stream_id |= ((gpr_uint32)*cur);
 | 
	
		
			
				|  |  |        t->deframe_state = DTS_FRAME;
 | 
	
		
			
				|  |  |        if (!init_frame_parser(t)) {
 | 
	
		
			
				|  |  |          return 0;
 |