|  | @@ -86,8 +86,11 @@ typedef enum {
 | 
	
		
			
				|  |  |    /* Status came from 'the wire' - or somewhere below the surface
 | 
	
		
			
				|  |  |       layer */
 | 
	
		
			
				|  |  |    STATUS_FROM_WIRE,
 | 
	
		
			
				|  |  | -  /* Status was created by some internal channel stack operation */
 | 
	
		
			
				|  |  | +  /* Status was created by some internal channel stack operation: must come via
 | 
	
		
			
				|  |  | +     add_batch_error */
 | 
	
		
			
				|  |  |    STATUS_FROM_CORE,
 | 
	
		
			
				|  |  | +  /* Status was created by some surface error */
 | 
	
		
			
				|  |  | +  STATUS_FROM_SURFACE,
 | 
	
		
			
				|  |  |    /* Status came from the server sending status */
 | 
	
		
			
				|  |  |    STATUS_FROM_SERVER_STATUS,
 | 
	
		
			
				|  |  |    STATUS_SOURCE_COUNT
 | 
	
	
		
			
				|  | @@ -221,11 +224,11 @@ struct grpc_call {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void execute_op(grpc_exec_ctx *exec_ctx, grpc_call *call,
 | 
	
		
			
				|  |  |                         grpc_transport_stream_op *op);
 | 
	
		
			
				|  |  | -static grpc_call_error cancel_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c,
 | 
	
		
			
				|  |  | -                                          grpc_status_code status,
 | 
	
		
			
				|  |  | -                                          const char *description);
 | 
	
		
			
				|  |  | +static void cancel_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c,
 | 
	
		
			
				|  |  | +                               status_source source, grpc_status_code status,
 | 
	
		
			
				|  |  | +                               const char *description);
 | 
	
		
			
				|  |  |  static void cancel_with_error(grpc_exec_ctx *exec_ctx, grpc_call *c,
 | 
	
		
			
				|  |  | -                              grpc_error *error);
 | 
	
		
			
				|  |  | +                              status_source source, grpc_error *error);
 | 
	
		
			
				|  |  |  static void destroy_call(grpc_exec_ctx *exec_ctx, void *call_stack,
 | 
	
		
			
				|  |  |                           grpc_error *error);
 | 
	
		
			
				|  |  |  static void receiving_slice_ready(grpc_exec_ctx *exec_ctx, void *bctlp,
 | 
	
	
		
			
				|  | @@ -337,7 +340,7 @@ grpc_error *grpc_call_create(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |        args->server_transport_data, path, call->start_time, send_deadline,
 | 
	
		
			
				|  |  |        CALL_STACK_FROM_CALL(call));
 | 
	
		
			
				|  |  |    if (error != GRPC_ERROR_NONE) {
 | 
	
		
			
				|  |  | -    cancel_with_error(exec_ctx, call, GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  | +    cancel_with_error(exec_ctx, call, STATUS_FROM_SURFACE, GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    if (args->cq != NULL) {
 | 
	
		
			
				|  |  |      GPR_ASSERT(
 | 
	
	
		
			
				|  | @@ -512,7 +515,6 @@ grpc_call_error grpc_call_cancel_with_status(grpc_call *c,
 | 
	
		
			
				|  |  |                                               grpc_status_code status,
 | 
	
		
			
				|  |  |                                               const char *description,
 | 
	
		
			
				|  |  |                                               void *reserved) {
 | 
	
		
			
				|  |  | -  grpc_call_error r;
 | 
	
		
			
				|  |  |    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
 | 
	
		
			
				|  |  |    GRPC_API_TRACE(
 | 
	
		
			
				|  |  |        "grpc_call_cancel_with_status("
 | 
	
	
		
			
				|  | @@ -520,16 +522,16 @@ grpc_call_error grpc_call_cancel_with_status(grpc_call *c,
 | 
	
		
			
				|  |  |        4, (c, (int)status, description, reserved));
 | 
	
		
			
				|  |  |    GPR_ASSERT(reserved == NULL);
 | 
	
		
			
				|  |  |    gpr_mu_lock(&c->mu);
 | 
	
		
			
				|  |  | -  r = cancel_with_status(&exec_ctx, c, status, description);
 | 
	
		
			
				|  |  | +  cancel_with_status(&exec_ctx, c, STATUS_FROM_API_OVERRIDE, status,
 | 
	
		
			
				|  |  | +                     description);
 | 
	
		
			
				|  |  |    gpr_mu_unlock(&c->mu);
 | 
	
		
			
				|  |  |    grpc_exec_ctx_finish(&exec_ctx);
 | 
	
		
			
				|  |  | -  return r;
 | 
	
		
			
				|  |  | +  return GRPC_CALL_OK;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  typedef struct termination_closure {
 | 
	
		
			
				|  |  |    grpc_closure closure;
 | 
	
		
			
				|  |  |    grpc_call *call;
 | 
	
		
			
				|  |  | -  grpc_error *error;
 | 
	
		
			
				|  |  |    grpc_transport_stream_op op;
 | 
	
		
			
				|  |  |  } termination_closure;
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -544,36 +546,27 @@ static void send_termination(grpc_exec_ctx *exec_ctx, void *tcp,
 | 
	
		
			
				|  |  |                               grpc_error *error) {
 | 
	
		
			
				|  |  |    termination_closure *tc = tcp;
 | 
	
		
			
				|  |  |    memset(&tc->op, 0, sizeof(tc->op));
 | 
	
		
			
				|  |  | -  tc->op.cancel_error = tc->error;
 | 
	
		
			
				|  |  | +  tc->op.cancel_error = GRPC_ERROR_REF(error);
 | 
	
		
			
				|  |  |    /* reuse closure to catch completion */
 | 
	
		
			
				|  |  | -  grpc_closure_init(&tc->closure, done_termination, tc,
 | 
	
		
			
				|  |  | -                    grpc_schedule_on_exec_ctx);
 | 
	
		
			
				|  |  | -  tc->op.on_complete = &tc->closure;
 | 
	
		
			
				|  |  | +  tc->op.on_complete = grpc_closure_init(&tc->closure, done_termination, tc,
 | 
	
		
			
				|  |  | +                                         grpc_schedule_on_exec_ctx);
 | 
	
		
			
				|  |  |    execute_op(exec_ctx, tc->call, &tc->op);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -static grpc_call_error terminate_with_status(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  | -                                             termination_closure *tc) {
 | 
	
		
			
				|  |  | -  set_status_from_error(exec_ctx, tc->call, STATUS_FROM_API_OVERRIDE,
 | 
	
		
			
				|  |  | -                        GRPC_ERROR_REF(tc->error));
 | 
	
		
			
				|  |  | -  grpc_closure_init(&tc->closure, send_termination, tc,
 | 
	
		
			
				|  |  | -                    grpc_schedule_on_exec_ctx);
 | 
	
		
			
				|  |  | -  GRPC_CALL_INTERNAL_REF(tc->call, "termination");
 | 
	
		
			
				|  |  | -  grpc_closure_sched(exec_ctx, &tc->closure, GRPC_ERROR_NONE);
 | 
	
		
			
				|  |  | -  return GRPC_CALL_OK;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -static grpc_call_error terminate_with_error(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  | -                                            grpc_call *c, grpc_error *error) {
 | 
	
		
			
				|  |  | +static void terminate_with_error(grpc_exec_ctx *exec_ctx, grpc_call *c,
 | 
	
		
			
				|  |  | +                                 grpc_error *error) {
 | 
	
		
			
				|  |  |    termination_closure *tc = gpr_malloc(sizeof(*tc));
 | 
	
		
			
				|  |  |    memset(tc, 0, sizeof(*tc));
 | 
	
		
			
				|  |  |    tc->call = c;
 | 
	
		
			
				|  |  | -  tc->error = error;
 | 
	
		
			
				|  |  | -  return terminate_with_status(exec_ctx, tc);
 | 
	
		
			
				|  |  | +  GRPC_CALL_INTERNAL_REF(tc->call, "termination");
 | 
	
		
			
				|  |  | +  grpc_closure_sched(exec_ctx, grpc_closure_init(&tc->closure, send_termination,
 | 
	
		
			
				|  |  | +                                                 tc, grpc_schedule_on_exec_ctx),
 | 
	
		
			
				|  |  | +                     error);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void cancel_with_error(grpc_exec_ctx *exec_ctx, grpc_call *c,
 | 
	
		
			
				|  |  | -                              grpc_error *error) {
 | 
	
		
			
				|  |  | +                              status_source source, grpc_error *error) {
 | 
	
		
			
				|  |  | +  set_status_from_error(exec_ctx, c, source, GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  |    terminate_with_error(exec_ctx, c, error);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -585,11 +578,11 @@ static grpc_error *error_from_status(grpc_status_code status,
 | 
	
		
			
				|  |  |        GRPC_ERROR_INT_GRPC_STATUS, status);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -static grpc_call_error cancel_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c,
 | 
	
		
			
				|  |  | -                                          grpc_status_code status,
 | 
	
		
			
				|  |  | -                                          const char *description) {
 | 
	
		
			
				|  |  | -  return terminate_with_error(exec_ctx, c,
 | 
	
		
			
				|  |  | -                              error_from_status(status, description));
 | 
	
		
			
				|  |  | +static void cancel_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c,
 | 
	
		
			
				|  |  | +                               status_source source, grpc_status_code status,
 | 
	
		
			
				|  |  | +                               const char *description) {
 | 
	
		
			
				|  |  | +  cancel_with_error(exec_ctx, c, source,
 | 
	
		
			
				|  |  | +                    error_from_status(status, description));
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /*******************************************************************************
 | 
	
	
		
			
				|  | @@ -1014,11 +1007,6 @@ static void post_batch_completion(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    gpr_mu_lock(&call->mu);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  if (error != GRPC_ERROR_NONE) {
 | 
	
		
			
				|  |  | -    set_status_from_error(exec_ctx, call, STATUS_FROM_CORE,
 | 
	
		
			
				|  |  | -                          GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |    if (bctl->send_initial_metadata) {
 | 
	
		
			
				|  |  |      grpc_metadata_batch_destroy(
 | 
	
		
			
				|  |  |          exec_ctx,
 | 
	
	
		
			
				|  | @@ -1161,7 +1149,7 @@ static void receiving_stream_ready(grpc_exec_ctx *exec_ctx, void *bctlp,
 | 
	
		
			
				|  |  |    grpc_call *call = bctl->call;
 | 
	
		
			
				|  |  |    gpr_mu_lock(&bctl->call->mu);
 | 
	
		
			
				|  |  |    if (error != GRPC_ERROR_NONE) {
 | 
	
		
			
				|  |  | -    cancel_with_error(exec_ctx, call, GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  | +    cancel_with_error(exec_ctx, call, STATUS_FROM_SURFACE, GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    if (call->has_initial_md_been_received || error != GRPC_ERROR_NONE ||
 | 
	
		
			
				|  |  |        call->receiving_stream == NULL) {
 | 
	
	
		
			
				|  | @@ -1188,7 +1176,8 @@ static void validate_filtered_metadata(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |        gpr_asprintf(&error_msg, "Invalid compression algorithm value '%d'.",
 | 
	
		
			
				|  |  |                     algo);
 | 
	
		
			
				|  |  |        gpr_log(GPR_ERROR, "%s", error_msg);
 | 
	
		
			
				|  |  | -      cancel_with_status(exec_ctx, call, GRPC_STATUS_UNIMPLEMENTED, error_msg);
 | 
	
		
			
				|  |  | +      cancel_with_status(exec_ctx, call, STATUS_FROM_SURFACE,
 | 
	
		
			
				|  |  | +                         GRPC_STATUS_UNIMPLEMENTED, error_msg);
 | 
	
		
			
				|  |  |      } else if (grpc_compression_options_is_algorithm_enabled(
 | 
	
		
			
				|  |  |                     &compression_options, algo) == 0) {
 | 
	
		
			
				|  |  |        /* check if algorithm is supported by current channel config */
 | 
	
	
		
			
				|  | @@ -1197,7 +1186,8 @@ static void validate_filtered_metadata(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |        gpr_asprintf(&error_msg, "Compression algorithm '%s' is disabled.",
 | 
	
		
			
				|  |  |                     algo_name);
 | 
	
		
			
				|  |  |        gpr_log(GPR_ERROR, "%s", error_msg);
 | 
	
		
			
				|  |  | -      cancel_with_status(exec_ctx, call, GRPC_STATUS_UNIMPLEMENTED, error_msg);
 | 
	
		
			
				|  |  | +      cancel_with_status(exec_ctx, call, STATUS_FROM_SURFACE,
 | 
	
		
			
				|  |  | +                         GRPC_STATUS_UNIMPLEMENTED, error_msg);
 | 
	
		
			
				|  |  |      } else {
 | 
	
		
			
				|  |  |        call->incoming_compression_algorithm = algo;
 | 
	
		
			
				|  |  |      }
 | 
	
	
		
			
				|  | @@ -1227,7 +1217,10 @@ static void add_batch_error(grpc_exec_ctx *exec_ctx, batch_control *bctl,
 | 
	
		
			
				|  |  |                              grpc_error *error) {
 | 
	
		
			
				|  |  |    if (error == GRPC_ERROR_NONE) return;
 | 
	
		
			
				|  |  |    int idx = (int)gpr_atm_no_barrier_fetch_add(&bctl->num_errors, 1);
 | 
	
		
			
				|  |  | -  if (idx == 0) cancel_with_error(exec_ctx, bctl->call, GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  | +  if (idx == 0) {
 | 
	
		
			
				|  |  | +    cancel_with_error(exec_ctx, bctl->call, STATUS_FROM_CORE,
 | 
	
		
			
				|  |  | +                      GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  |    bctl->errors[idx] = error;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 |