grpc_call *grpc_call_create(grpc_channel *channel, grpc_completion_queue *cq, const void *server_transport_data) { size_t i; grpc_channel_stack *channel_stack = grpc_channel_get_channel_stack(channel); grpc_call *call = gpr_malloc(sizeof(grpc_call) + channel_stack->call_stack_size); memset(call, 0, sizeof(grpc_call)); gpr_mu_init(&call->mu); call->channel = channel; call->cq = cq; call->is_client = server_transport_data == NULL; for (i = 0; i < GRPC_IOREQ_OP_COUNT; i++) { call->request_set[i] = REQSET_EMPTY; } if (call->is_client) { call->request_set[GRPC_IOREQ_SEND_TRAILING_METADATA] = REQSET_DONE; call->request_set[GRPC_IOREQ_SEND_STATUS] = REQSET_DONE; } grpc_channel_internal_ref(channel); call->metadata_context = grpc_channel_get_metadata_context(channel); /* one ref is dropped in response to destroy, the other in stream_closed */ gpr_ref_init(&call->internal_refcount, 2); grpc_call_stack_init(channel_stack, server_transport_data, CALL_STACK_FROM_CALL(call)); return call; }
grpc_call *grpc_call_create(grpc_channel *channel, grpc_completion_queue *cq, const void *server_transport_data, grpc_mdelem **add_initial_metadata, size_t add_initial_metadata_count, gpr_timespec send_deadline) { size_t i; grpc_transport_op initial_op; grpc_transport_op *initial_op_ptr = NULL; grpc_channel_stack *channel_stack = grpc_channel_get_channel_stack(channel); grpc_call *call = gpr_malloc(sizeof(grpc_call) + channel_stack->call_stack_size); memset(call, 0, sizeof(grpc_call)); gpr_mu_init(&call->mu); call->channel = channel; call->cq = cq; call->is_client = server_transport_data == NULL; for (i = 0; i < GRPC_IOREQ_OP_COUNT; i++) { call->request_set[i] = REQSET_EMPTY; } if (call->is_client) { call->request_set[GRPC_IOREQ_SEND_TRAILING_METADATA] = REQSET_DONE; call->request_set[GRPC_IOREQ_SEND_STATUS] = REQSET_DONE; } GPR_ASSERT(add_initial_metadata_count < MAX_SEND_INITIAL_METADATA_COUNT); for (i = 0; i < add_initial_metadata_count; i++) { call->send_initial_metadata[i].md = add_initial_metadata[i]; } call->send_initial_metadata_count = add_initial_metadata_count; call->send_deadline = send_deadline; grpc_channel_internal_ref(channel); call->metadata_context = grpc_channel_get_metadata_context(channel); grpc_sopb_init(&call->send_ops); grpc_sopb_init(&call->recv_ops); gpr_slice_buffer_init(&call->incoming_message); /* dropped in destroy */ gpr_ref_init(&call->internal_refcount, 1); /* server hack: start reads immediately so we can get initial metadata. TODO(ctiller): figure out a cleaner solution */ if (!call->is_client) { memset(&initial_op, 0, sizeof(initial_op)); initial_op.recv_ops = &call->recv_ops; initial_op.recv_state = &call->recv_state; initial_op.on_done_recv = call_on_done_recv; initial_op.recv_user_data = call; initial_op.context = call->context; call->receiving = 1; GRPC_CALL_INTERNAL_REF(call, "receiving"); initial_op_ptr = &initial_op; } grpc_call_stack_init(channel_stack, server_transport_data, initial_op_ptr, CALL_STACK_FROM_CALL(call)); if (gpr_time_cmp(send_deadline, gpr_inf_future) != 0) { set_deadline_alarm(call, send_deadline); } return call; }
static void shutdown_internal(grpc_server *server, gpr_uint8 have_shutdown_tag, void *shutdown_tag) { listener *l; requested_call_array requested_calls; channel_data **channels; channel_data *c; size_t nchannels; size_t i, j; grpc_channel_op op; grpc_channel_element *elem; registered_method *rm; /* lock, and gather up some stuff to do */ gpr_mu_lock(&server->mu); if (have_shutdown_tag) { for (i = 0; i < server->cq_count; i++) { grpc_cq_begin_op(server->cqs[i], NULL, GRPC_SERVER_SHUTDOWN); } server->shutdown_tags = gpr_realloc(server->shutdown_tags, sizeof(void *) * (server->num_shutdown_tags + 1)); server->shutdown_tags[server->num_shutdown_tags++] = shutdown_tag; } if (server->shutdown) { gpr_mu_unlock(&server->mu); return; } nchannels = 0; for (c = server->root_channel_data.next; c != &server->root_channel_data; c = c->next) { nchannels++; } channels = gpr_malloc(sizeof(channel_data *) * nchannels); i = 0; for (c = server->root_channel_data.next; c != &server->root_channel_data; c = c->next) { grpc_channel_internal_ref(c->channel); channels[i] = c; i++; } /* collect all unregistered then registered calls */ requested_calls = server->requested_calls; memset(&server->requested_calls, 0, sizeof(server->requested_calls)); for (rm = server->registered_methods; rm; rm = rm->next) { if (requested_calls.count + rm->requested.count > requested_calls.capacity) { requested_calls.capacity = GPR_MAX(requested_calls.count + rm->requested.count, 2 * requested_calls.capacity); requested_calls.calls = gpr_realloc(requested_calls.calls, sizeof(*requested_calls.calls) * requested_calls.capacity); } memcpy(requested_calls.calls + requested_calls.count, rm->requested.calls, sizeof(*requested_calls.calls) * rm->requested.count); requested_calls.count += rm->requested.count; gpr_free(rm->requested.calls); memset(&rm->requested, 0, sizeof(rm->requested)); } server->shutdown = 1; if (server->lists[ALL_CALLS] == NULL) { for (i = 0; i < server->num_shutdown_tags; i++) { for (j = 0; j < server->cq_count; j++) { grpc_cq_end_server_shutdown(server->cqs[j], server->shutdown_tags[i]); } } } gpr_mu_unlock(&server->mu); for (i = 0; i < nchannels; i++) { c = channels[i]; elem = grpc_channel_stack_element( grpc_channel_get_channel_stack(c->channel), 0); op.type = GRPC_CHANNEL_GOAWAY; op.dir = GRPC_CALL_DOWN; op.data.goaway.status = GRPC_STATUS_OK; op.data.goaway.message = gpr_slice_from_copied_string("Server shutdown"); elem->filter->channel_op(elem, NULL, &op); grpc_channel_internal_unref(c->channel); } gpr_free(channels); /* terminate all the requested calls */ for (i = 0; i < requested_calls.count; i++) { fail_call(server, &requested_calls.calls[i]); } gpr_free(requested_calls.calls); /* Shutdown listeners */ for (l = server->listeners; l; l = l->next) { l->destroy(server, l->arg); } }
static void shutdown_channel(channel_data *chand) { grpc_channel_internal_ref(chand->channel); grpc_iomgr_add_callback(finish_shutdown_channel, chand); }