|  | @@ -83,8 +83,6 @@ struct call_data {
 | 
	
		
			
				|  |  |    /* owning element */
 | 
	
		
			
				|  |  |    grpc_call_element *elem;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  gpr_uint8 got_first_op;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |    call_state state;
 | 
	
		
			
				|  |  |    gpr_timespec deadline;
 | 
	
		
			
				|  |  |    union {
 | 
	
	
		
			
				|  | @@ -129,55 +127,6 @@ static void complete_activate(grpc_call_element *elem, grpc_transport_op *op) {
 | 
	
		
			
				|  |  |    child_elem->filter->start_transport_op(child_elem, op);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -static void start_rpc(grpc_call_element *elem, grpc_transport_op *op) {
 | 
	
		
			
				|  |  | -  call_data *calld = elem->call_data;
 | 
	
		
			
				|  |  | -  channel_data *chand = elem->channel_data;
 | 
	
		
			
				|  |  | -  gpr_mu_lock(&chand->mu);
 | 
	
		
			
				|  |  | -  if (calld->state == CALL_CANCELLED) {
 | 
	
		
			
				|  |  | -    gpr_mu_unlock(&chand->mu);
 | 
	
		
			
				|  |  | -    grpc_transport_op_finish_with_failure(op);
 | 
	
		
			
				|  |  | -    return;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  GPR_ASSERT(calld->state == CALL_CREATED);
 | 
	
		
			
				|  |  | -  calld->state = CALL_WAITING;
 | 
	
		
			
				|  |  | -  if (chand->active_child) {
 | 
	
		
			
				|  |  | -    /* channel is connected - use the connected stack */
 | 
	
		
			
				|  |  | -    if (prepare_activate(elem, chand->active_child)) {
 | 
	
		
			
				|  |  | -      gpr_mu_unlock(&chand->mu);
 | 
	
		
			
				|  |  | -      /* activate the request (pass it down) outside the lock */
 | 
	
		
			
				|  |  | -      complete_activate(elem, op);
 | 
	
		
			
				|  |  | -    } else {
 | 
	
		
			
				|  |  | -      gpr_mu_unlock(&chand->mu);
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -  } else {
 | 
	
		
			
				|  |  | -    /* check to see if we should initiate a connection (if we're not already),
 | 
	
		
			
				|  |  | -       but don't do so until outside the lock to avoid re-entrancy problems if
 | 
	
		
			
				|  |  | -       the callback is immediate */
 | 
	
		
			
				|  |  | -    int initiate_transport_setup = 0;
 | 
	
		
			
				|  |  | -    if (!chand->transport_setup_initiated) {
 | 
	
		
			
				|  |  | -      chand->transport_setup_initiated = 1;
 | 
	
		
			
				|  |  | -      initiate_transport_setup = 1;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    /* add this call to the waiting set to be resumed once we have a child
 | 
	
		
			
				|  |  | -       channel stack, growing the waiting set if needed */
 | 
	
		
			
				|  |  | -    if (chand->waiting_child_count == chand->waiting_child_capacity) {
 | 
	
		
			
				|  |  | -      chand->waiting_child_capacity =
 | 
	
		
			
				|  |  | -          GPR_MAX(chand->waiting_child_capacity * 2, 8);
 | 
	
		
			
				|  |  | -      chand->waiting_children =
 | 
	
		
			
				|  |  | -          gpr_realloc(chand->waiting_children,
 | 
	
		
			
				|  |  | -                      chand->waiting_child_capacity * sizeof(call_data *));
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    calld->s.waiting_op = *op;
 | 
	
		
			
				|  |  | -    chand->waiting_children[chand->waiting_child_count++] = calld;
 | 
	
		
			
				|  |  | -    gpr_mu_unlock(&chand->mu);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    /* finally initiate transport setup if needed */
 | 
	
		
			
				|  |  | -    if (initiate_transport_setup) {
 | 
	
		
			
				|  |  | -      grpc_transport_setup_initiate(chand->transport_setup);
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  static void remove_waiting_child(channel_data *chand, call_data *calld) {
 | 
	
		
			
				|  |  |    size_t new_count;
 | 
	
		
			
				|  |  |    size_t i;
 | 
	
	
		
			
				|  | @@ -217,11 +166,14 @@ static void handle_op_after_cancellation(grpc_call_element *elem, grpc_transport
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -static void cancel_rpc(grpc_call_element *elem, grpc_transport_op *op) {
 | 
	
		
			
				|  |  | +static void cc_start_transport_op(grpc_call_element *elem,
 | 
	
		
			
				|  |  | +                                  grpc_transport_op *op) {
 | 
	
		
			
				|  |  |    call_data *calld = elem->call_data;
 | 
	
		
			
				|  |  |    channel_data *chand = elem->channel_data;
 | 
	
		
			
				|  |  |    grpc_call_element *child_elem;
 | 
	
		
			
				|  |  |    grpc_transport_op waiting_op;
 | 
	
		
			
				|  |  | +  GPR_ASSERT(elem->filter == &grpc_client_channel_filter);
 | 
	
		
			
				|  |  | +  GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    gpr_mu_lock(&chand->mu);
 | 
	
		
			
				|  |  |    switch (calld->state) {
 | 
	
	
		
			
				|  | @@ -229,55 +181,82 @@ static void cancel_rpc(grpc_call_element *elem, grpc_transport_op *op) {
 | 
	
		
			
				|  |  |        child_elem = grpc_child_call_get_top_element(calld->s.active.child_call);
 | 
	
		
			
				|  |  |        gpr_mu_unlock(&chand->mu);
 | 
	
		
			
				|  |  |        child_elem->filter->start_transport_op(child_elem, op);
 | 
	
		
			
				|  |  | -      return; /* early out */
 | 
	
		
			
				|  |  | -    case CALL_WAITING:
 | 
	
		
			
				|  |  | -      waiting_op = calld->s.waiting_op;
 | 
	
		
			
				|  |  | -      remove_waiting_child(chand, calld);
 | 
	
		
			
				|  |  | -      calld->state = CALL_CANCELLED;
 | 
	
		
			
				|  |  | -      gpr_mu_unlock(&chand->mu);
 | 
	
		
			
				|  |  | -      handle_op_after_cancellation(elem, &waiting_op);
 | 
	
		
			
				|  |  | -      handle_op_after_cancellation(elem, op);
 | 
	
		
			
				|  |  | -      return; /* early out */
 | 
	
		
			
				|  |  | +      break;
 | 
	
		
			
				|  |  |      case CALL_CREATED:
 | 
	
		
			
				|  |  | -      calld->state = CALL_CANCELLED;
 | 
	
		
			
				|  |  | -      gpr_mu_unlock(&chand->mu);
 | 
	
		
			
				|  |  | -      handle_op_after_cancellation(elem, op);
 | 
	
		
			
				|  |  | -      return; /* early out */
 | 
	
		
			
				|  |  | +      if (op->cancel_with_status != GRPC_STATUS_OK) {
 | 
	
		
			
				|  |  | +        calld->state = CALL_CANCELLED;
 | 
	
		
			
				|  |  | +        gpr_mu_unlock(&chand->mu);
 | 
	
		
			
				|  |  | +        handle_op_after_cancellation(elem, op);
 | 
	
		
			
				|  |  | +      } else {
 | 
	
		
			
				|  |  | +        calld->state = CALL_WAITING;
 | 
	
		
			
				|  |  | +        if (chand->active_child) {
 | 
	
		
			
				|  |  | +          /* channel is connected - use the connected stack */
 | 
	
		
			
				|  |  | +          if (prepare_activate(elem, chand->active_child)) {
 | 
	
		
			
				|  |  | +            gpr_mu_unlock(&chand->mu);
 | 
	
		
			
				|  |  | +            /* activate the request (pass it down) outside the lock */
 | 
	
		
			
				|  |  | +            complete_activate(elem, op);
 | 
	
		
			
				|  |  | +          } else {
 | 
	
		
			
				|  |  | +            gpr_mu_unlock(&chand->mu);
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +        } else {
 | 
	
		
			
				|  |  | +          /* check to see if we should initiate a connection (if we're not already),
 | 
	
		
			
				|  |  | +             but don't do so until outside the lock to avoid re-entrancy problems if
 | 
	
		
			
				|  |  | +             the callback is immediate */
 | 
	
		
			
				|  |  | +          int initiate_transport_setup = 0;
 | 
	
		
			
				|  |  | +          if (!chand->transport_setup_initiated) {
 | 
	
		
			
				|  |  | +            chand->transport_setup_initiated = 1;
 | 
	
		
			
				|  |  | +            initiate_transport_setup = 1;
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +          /* add this call to the waiting set to be resumed once we have a child
 | 
	
		
			
				|  |  | +             channel stack, growing the waiting set if needed */
 | 
	
		
			
				|  |  | +          if (chand->waiting_child_count == chand->waiting_child_capacity) {
 | 
	
		
			
				|  |  | +            chand->waiting_child_capacity =
 | 
	
		
			
				|  |  | +                GPR_MAX(chand->waiting_child_capacity * 2, 8);
 | 
	
		
			
				|  |  | +            chand->waiting_children =
 | 
	
		
			
				|  |  | +                gpr_realloc(chand->waiting_children,
 | 
	
		
			
				|  |  | +                            chand->waiting_child_capacity * sizeof(call_data *));
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +          calld->s.waiting_op = *op;
 | 
	
		
			
				|  |  | +          chand->waiting_children[chand->waiting_child_count++] = calld;
 | 
	
		
			
				|  |  | +          gpr_mu_unlock(&chand->mu);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +          /* finally initiate transport setup if needed */
 | 
	
		
			
				|  |  | +          if (initiate_transport_setup) {
 | 
	
		
			
				|  |  | +            grpc_transport_setup_initiate(chand->transport_setup);
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +      break;
 | 
	
		
			
				|  |  | +    case CALL_WAITING:
 | 
	
		
			
				|  |  | +      if (op->cancel_with_status != GRPC_STATUS_OK) {
 | 
	
		
			
				|  |  | +        waiting_op = calld->s.waiting_op;
 | 
	
		
			
				|  |  | +        remove_waiting_child(chand, calld);
 | 
	
		
			
				|  |  | +        calld->state = CALL_CANCELLED;
 | 
	
		
			
				|  |  | +        gpr_mu_unlock(&chand->mu);
 | 
	
		
			
				|  |  | +        handle_op_after_cancellation(elem, &waiting_op);
 | 
	
		
			
				|  |  | +        handle_op_after_cancellation(elem, op);
 | 
	
		
			
				|  |  | +      } else {
 | 
	
		
			
				|  |  | +        GPR_ASSERT((calld->s.waiting_op.send_ops == NULL) != (op->send_ops == NULL));
 | 
	
		
			
				|  |  | +        GPR_ASSERT((calld->s.waiting_op.recv_ops == NULL) != (op->recv_ops == NULL));
 | 
	
		
			
				|  |  | +        if (op->send_ops) {
 | 
	
		
			
				|  |  | +          calld->s.waiting_op.send_ops = op->send_ops;
 | 
	
		
			
				|  |  | +          calld->s.waiting_op.is_last_send = op->is_last_send;
 | 
	
		
			
				|  |  | +          calld->s.waiting_op.on_done_send = op->on_done_send;
 | 
	
		
			
				|  |  | +          calld->s.waiting_op.send_user_data = op->send_user_data;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        if (op->recv_ops) {
 | 
	
		
			
				|  |  | +          calld->s.waiting_op.recv_ops = op->recv_ops;
 | 
	
		
			
				|  |  | +          calld->s.waiting_op.recv_state = op->recv_state;
 | 
	
		
			
				|  |  | +          calld->s.waiting_op.on_done_recv = op->on_done_recv;
 | 
	
		
			
				|  |  | +          calld->s.waiting_op.recv_user_data = op->recv_user_data;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        gpr_mu_unlock(&chand->mu);
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +      break;
 | 
	
		
			
				|  |  |      case CALL_CANCELLED:
 | 
	
		
			
				|  |  |        gpr_mu_unlock(&chand->mu);
 | 
	
		
			
				|  |  |        handle_op_after_cancellation(elem, op);
 | 
	
		
			
				|  |  | -      return; /* early out */
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  gpr_log(GPR_ERROR, "should never reach here");
 | 
	
		
			
				|  |  | -  abort();
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -static void cc_start_transport_op(grpc_call_element *elem,
 | 
	
		
			
				|  |  | -                                  grpc_transport_op *op) {
 | 
	
		
			
				|  |  | -  call_data *calld = elem->call_data;
 | 
	
		
			
				|  |  | -  GPR_ASSERT(elem->filter == &grpc_client_channel_filter);
 | 
	
		
			
				|  |  | -  GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (op->cancel_with_status != GRPC_STATUS_OK) {
 | 
	
		
			
				|  |  | -    GPR_ASSERT(op->send_ops == NULL);
 | 
	
		
			
				|  |  | -    GPR_ASSERT(op->recv_ops == NULL);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    cancel_rpc(elem, op);
 | 
	
		
			
				|  |  | -    return;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (calld->state == CALL_CANCELLED) {
 | 
	
		
			
				|  |  | -    handle_op_after_cancellation(elem, op);
 | 
	
		
			
				|  |  | -    return;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (!calld->got_first_op) {
 | 
	
		
			
				|  |  | -    calld->got_first_op = 1;
 | 
	
		
			
				|  |  | -    start_rpc(elem, op);
 | 
	
		
			
				|  |  | -  } else {
 | 
	
		
			
				|  |  | -    grpc_call_element *child_elem =
 | 
	
		
			
				|  |  | -        grpc_child_call_get_top_element(calld->s.active.child_call);
 | 
	
		
			
				|  |  | -    child_elem->filter->start_transport_op(child_elem, op);
 | 
	
		
			
				|  |  | +      break;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -375,7 +354,6 @@ static void init_call_elem(grpc_call_element *elem,
 | 
	
		
			
				|  |  |    calld->elem = elem;
 | 
	
		
			
				|  |  |    calld->state = CALL_CREATED;
 | 
	
		
			
				|  |  |    calld->deadline = gpr_inf_future;
 | 
	
		
			
				|  |  | -  calld->got_first_op = 0;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /* Destructor for call_data */
 |