/* Currently we assume all channel operations should just be pushed up. */ static void lb_channel_op(grpc_channel_element *elem, grpc_channel_element *from_elem, grpc_channel_op *op) { lb_channel_data *chand = elem->channel_data; grpc_channel_element *back; int calling_back = 0; switch (op->dir) { case GRPC_CALL_UP: gpr_mu_lock(&chand->mu); back = chand->back; if (back) { chand->calling_back++; calling_back = 1; } gpr_mu_unlock(&chand->mu); if (back) { back->filter->channel_op(chand->back, elem, op); } else if (op->type == GRPC_TRANSPORT_GOAWAY) { gpr_slice_unref(op->data.goaway.message); } break; case GRPC_CALL_DOWN: grpc_channel_next_op(elem, op); break; } gpr_mu_lock(&chand->mu); switch (op->type) { case GRPC_TRANSPORT_CLOSED: chand->disconnected = 1; maybe_destroy_channel(grpc_channel_stack_from_top_element(elem)); break; case GRPC_CHANNEL_GOAWAY: chand->sent_goaway = 1; break; case GRPC_CHANNEL_DISCONNECT: case GRPC_TRANSPORT_GOAWAY: case GRPC_ACCEPT_CALL: break; } if (calling_back) { chand->calling_back--; gpr_cv_signal(&chand->cv); maybe_destroy_channel(grpc_channel_stack_from_top_element(elem)); } gpr_mu_unlock(&chand->mu); }
static void channel_op(grpc_channel_element *elem, grpc_channel_element *from_elem, grpc_channel_op *op) { channel_data *chand = elem->channel_data; grpc_child_channel *child_channel; grpc_channel_op rop; GPR_ASSERT(elem->filter == &grpc_client_channel_filter); switch (op->type) { case GRPC_CHANNEL_GOAWAY: /* sending goaway: clear out the active child on the way through */ gpr_mu_lock(&chand->mu); child_channel = chand->active_child; chand->active_child = NULL; gpr_mu_unlock(&chand->mu); if (child_channel) { grpc_child_channel_handle_op(child_channel, op); grpc_child_channel_destroy(child_channel, 1); } else { gpr_slice_unref(op->data.goaway.message); } break; case GRPC_CHANNEL_DISCONNECT: /* sending disconnect: clear out the active child on the way through */ gpr_mu_lock(&chand->mu); child_channel = chand->active_child; chand->active_child = NULL; gpr_mu_unlock(&chand->mu); if (child_channel) { grpc_child_channel_destroy(child_channel, 1); } /* fake a transport closed to satisfy the refcounting in client */ rop.type = GRPC_TRANSPORT_CLOSED; rop.dir = GRPC_CALL_UP; grpc_channel_next_op(elem, &rop); break; case GRPC_TRANSPORT_GOAWAY: /* receiving goaway: if it's from our active child, drop the active child; in all cases consume the event here */ gpr_mu_lock(&chand->mu); child_channel = grpc_channel_stack_from_top_element(from_elem); if (child_channel == chand->active_child) { chand->active_child = NULL; } else { child_channel = NULL; } gpr_mu_unlock(&chand->mu); if (child_channel) { grpc_child_channel_destroy(child_channel, 0); } gpr_slice_unref(op->data.goaway.message); break; case GRPC_TRANSPORT_CLOSED: /* receiving disconnect: if it's from our active child, drop the active child; in all cases consume the event here */ gpr_mu_lock(&chand->mu); child_channel = grpc_channel_stack_from_top_element(from_elem); if (child_channel == chand->active_child) { chand->active_child = NULL; } else { child_channel = NULL; } gpr_mu_unlock(&chand->mu); if (child_channel) { grpc_child_channel_destroy(child_channel, 0); } break; default: switch (op->dir) { case GRPC_CALL_UP: grpc_channel_next_op(elem, op); break; case GRPC_CALL_DOWN: gpr_log(GPR_ERROR, "unhandled channel op: %d", op->type); abort(); break; } break; } }