|  | @@ -59,6 +59,9 @@ typedef struct {
 | 
	
		
			
				|  |  |    grpc_recv_status status_in;
 | 
	
		
			
				|  |  |    size_t msg_in_read_idx;
 | 
	
		
			
				|  |  |    grpc_byte_buffer_array msg_in;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  gpr_uint8 got_status;
 | 
	
		
			
				|  |  | +  void *finished_tag;
 | 
	
		
			
				|  |  |  } legacy_state;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  typedef enum { REQ_INITIAL = 0, REQ_READY, REQ_DONE } req_state;
 | 
	
	
		
			
				|  | @@ -596,7 +599,8 @@ static grpc_call_error start_ioreq(grpc_call *call, const grpc_ioreq *reqs,
 | 
	
		
			
				|  |  |          break;
 | 
	
		
			
				|  |  |        case GRPC_IOREQ_SEND_INITIAL_METADATA:
 | 
	
		
			
				|  |  |          if (call->stream_closed) {
 | 
	
		
			
				|  |  | -          finish_ioreq_op(call, GRPC_IOREQ_SEND_INITIAL_METADATA, GRPC_OP_ERROR);
 | 
	
		
			
				|  |  | +          finish_ioreq_op(call, GRPC_IOREQ_SEND_INITIAL_METADATA,
 | 
	
		
			
				|  |  | +                          GRPC_OP_ERROR);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |          break;
 | 
	
		
			
				|  |  |        case GRPC_IOREQ_RECV_INITIAL_METADATA:
 | 
	
	
		
			
				|  | @@ -608,7 +612,8 @@ static grpc_call_error start_ioreq(grpc_call *call, const grpc_ioreq *reqs,
 | 
	
		
			
				|  |  |          if (call->got_initial_metadata) {
 | 
	
		
			
				|  |  |            finish_ioreq_op(call, GRPC_IOREQ_RECV_INITIAL_METADATA, GRPC_OP_OK);
 | 
	
		
			
				|  |  |          } else if (call->stream_closed) {
 | 
	
		
			
				|  |  | -          finish_ioreq_op(call, GRPC_IOREQ_RECV_INITIAL_METADATA, GRPC_OP_ERROR);
 | 
	
		
			
				|  |  | +          finish_ioreq_op(call, GRPC_IOREQ_RECV_INITIAL_METADATA,
 | 
	
		
			
				|  |  | +                          GRPC_OP_ERROR);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |          break;
 | 
	
		
			
				|  |  |        case GRPC_IOREQ_RECV_TRAILING_METADATA:
 | 
	
	
		
			
				|  | @@ -725,16 +730,25 @@ grpc_call_error grpc_call_add_metadata(grpc_call *call, grpc_metadata *metadata,
 | 
	
		
			
				|  |  |    return GRPC_CALL_OK;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -static void finish_status(grpc_call *call, grpc_op_error status, void *tag) {
 | 
	
		
			
				|  |  | +static void maybe_finish_legacy(grpc_call *call) {
 | 
	
		
			
				|  |  | +  legacy_state *ls = get_legacy_state(call);
 | 
	
		
			
				|  |  | +  gpr_log(GPR_DEBUG, "%d %d %d", ls->got_status, ls->msg_in_read_idx, ls->msg_in.count);
 | 
	
		
			
				|  |  | +  if (ls->got_status && ls->msg_in_read_idx == ls->msg_in.count) {
 | 
	
		
			
				|  |  | +    grpc_cq_end_finished(call->cq, ls->finished_tag, call, do_nothing, NULL,
 | 
	
		
			
				|  |  | +                         ls->status_in.status, ls->status_in.details,
 | 
	
		
			
				|  |  | +                         ls->trail_md_in.metadata, ls->trail_md_in.count);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void finish_status(grpc_call *call, grpc_op_error status,
 | 
	
		
			
				|  |  | +                          void *ignored) {
 | 
	
		
			
				|  |  |    legacy_state *ls;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    lock(call);
 | 
	
		
			
				|  |  |    ls = get_legacy_state(call);
 | 
	
		
			
				|  |  | +  ls->got_status = 1;
 | 
	
		
			
				|  |  | +  maybe_finish_legacy(call);
 | 
	
		
			
				|  |  |    unlock(call);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  grpc_cq_end_finished(call->cq, tag, call, do_nothing, NULL,
 | 
	
		
			
				|  |  | -                       ls->status_in.status, ls->status_in.details,
 | 
	
		
			
				|  |  | -                       ls->trail_md_in.metadata, ls->trail_md_in.count);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void finish_recv_metadata(grpc_call *call, grpc_op_error status,
 | 
	
	
		
			
				|  | @@ -754,7 +768,8 @@ static void finish_recv_metadata(grpc_call *call, grpc_op_error status,
 | 
	
		
			
				|  |  |    unlock(call);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -static void finish_send_metadata(grpc_call *call, grpc_op_error status, void *tag) {}
 | 
	
		
			
				|  |  | +static void finish_send_metadata(grpc_call *call, grpc_op_error status,
 | 
	
		
			
				|  |  | +                                 void *tag) {}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  grpc_call_error grpc_call_invoke(grpc_call *call, grpc_completion_queue *cq,
 | 
	
		
			
				|  |  |                                   void *metadata_read_tag, void *finished_tag,
 | 
	
	
		
			
				|  | @@ -771,6 +786,8 @@ grpc_call_error grpc_call_invoke(grpc_call *call, grpc_completion_queue *cq,
 | 
	
		
			
				|  |  |    err = bind_cq(call, cq);
 | 
	
		
			
				|  |  |    if (err != GRPC_CALL_OK) goto done;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +  ls->finished_tag = finished_tag;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    reqs[0].op = GRPC_IOREQ_SEND_INITIAL_METADATA;
 | 
	
		
			
				|  |  |    reqs[0].data.send_metadata.count = ls->md_out_count;
 | 
	
		
			
				|  |  |    reqs[0].data.send_metadata.metadata = ls->md_out;
 | 
	
	
		
			
				|  | @@ -780,15 +797,14 @@ grpc_call_error grpc_call_invoke(grpc_call *call, grpc_completion_queue *cq,
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    reqs[0].op = GRPC_IOREQ_RECV_INITIAL_METADATA;
 | 
	
		
			
				|  |  |    reqs[0].data.recv_metadata = &ls->md_in;
 | 
	
		
			
				|  |  | -  err = start_ioreq(call, reqs, 1, finish_recv_metadata,
 | 
	
		
			
				|  |  | -                                         metadata_read_tag);
 | 
	
		
			
				|  |  | +  err = start_ioreq(call, reqs, 1, finish_recv_metadata, metadata_read_tag);
 | 
	
		
			
				|  |  |    if (err != GRPC_CALL_OK) goto done;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    reqs[0].op = GRPC_IOREQ_RECV_TRAILING_METADATA;
 | 
	
		
			
				|  |  |    reqs[0].data.recv_metadata = &ls->trail_md_in;
 | 
	
		
			
				|  |  |    reqs[1].op = GRPC_IOREQ_RECV_STATUS;
 | 
	
		
			
				|  |  |    reqs[1].data.recv_status = &ls->status_in;
 | 
	
		
			
				|  |  | -  err = start_ioreq(call, reqs, 2, finish_status, finished_tag);
 | 
	
		
			
				|  |  | +  err = start_ioreq(call, reqs, 2, finish_status, NULL);
 | 
	
		
			
				|  |  |    if (err != GRPC_CALL_OK) goto done;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  done:
 | 
	
	
		
			
				|  | @@ -810,9 +826,11 @@ grpc_call_error grpc_call_server_accept(grpc_call *call,
 | 
	
		
			
				|  |  |    err = bind_cq(call, cq);
 | 
	
		
			
				|  |  |    if (err != GRPC_CALL_OK) return err;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +  get_legacy_state(call)->finished_tag = finished_tag;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    req.op = GRPC_IOREQ_RECV_STATUS;
 | 
	
		
			
				|  |  |    req.data.recv_status = &get_legacy_state(call)->status_in;
 | 
	
		
			
				|  |  | -  err = start_ioreq(call, &req, 1, finish_status, finished_tag);
 | 
	
		
			
				|  |  | +  err = start_ioreq(call, &req, 1, finish_status, NULL);
 | 
	
		
			
				|  |  |    unlock(call);
 | 
	
		
			
				|  |  |    return err;
 | 
	
		
			
				|  |  |  }
 | 
	
	
		
			
				|  | @@ -854,6 +872,7 @@ static void finish_read(grpc_call *call, grpc_op_error error, void *tag) {
 | 
	
		
			
				|  |  |    } else {
 | 
	
		
			
				|  |  |      grpc_cq_end_read(call->cq, tag, call, do_nothing, NULL,
 | 
	
		
			
				|  |  |                       ls->msg_in.buffers[ls->msg_in_read_idx++]);
 | 
	
		
			
				|  |  | +    maybe_finish_legacy(call);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    unlock(call);
 | 
	
		
			
				|  |  |  }
 | 
	
	
		
			
				|  | @@ -877,6 +896,7 @@ grpc_call_error grpc_call_start_read(grpc_call *call, void *tag) {
 | 
	
		
			
				|  |  |      err = GRPC_CALL_OK;
 | 
	
		
			
				|  |  |      grpc_cq_end_read(call->cq, tag, call, do_nothing, NULL,
 | 
	
		
			
				|  |  |                       ls->msg_in.buffers[ls->msg_in_read_idx++]);
 | 
	
		
			
				|  |  | +    maybe_finish_legacy(call);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    unlock(call);
 | 
	
		
			
				|  |  |    return err;
 | 
	
	
		
			
				|  | @@ -1069,10 +1089,11 @@ void grpc_call_recv_metadata(grpc_call_element *elem, grpc_mdelem *md) {
 | 
	
		
			
				|  |  |                         .data.recv_metadata
 | 
	
		
			
				|  |  |                   : &call->buffered_initial_metadata;
 | 
	
		
			
				|  |  |      } else {
 | 
	
		
			
				|  |  | -      dest = call->requests[GRPC_IOREQ_RECV_TRAILING_METADATA].state == REQ_READY
 | 
	
		
			
				|  |  | -                 ? call->requests[GRPC_IOREQ_RECV_TRAILING_METADATA]
 | 
	
		
			
				|  |  | -                       .data.recv_metadata
 | 
	
		
			
				|  |  | -                 : &call->buffered_trailing_metadata;
 | 
	
		
			
				|  |  | +      dest =
 | 
	
		
			
				|  |  | +          call->requests[GRPC_IOREQ_RECV_TRAILING_METADATA].state == REQ_READY
 | 
	
		
			
				|  |  | +              ? call->requests[GRPC_IOREQ_RECV_TRAILING_METADATA]
 | 
	
		
			
				|  |  | +                    .data.recv_metadata
 | 
	
		
			
				|  |  | +              : &call->buffered_trailing_metadata;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      if (dest->count == dest->capacity) {
 | 
	
		
			
				|  |  |        dest->capacity = GPR_MAX(dest->capacity + 8, dest->capacity * 2);
 |