static grpc_call_error queue_call_request(grpc_exec_ctx *exec_ctx, grpc_server *server, size_t cq_idx, requested_call *rc) { call_data *calld = NULL; request_matcher *rm = NULL; int request_id; if (gpr_atm_acq_load(&server->shutdown_flag)) { fail_call(exec_ctx, server, cq_idx, rc, GRPC_ERROR_CREATE("Server Shutdown")); return GRPC_CALL_OK; } request_id = gpr_stack_lockfree_pop(server->request_freelist_per_cq[cq_idx]); if (request_id == -1) { /* out of request ids: just fail this one */ fail_call(exec_ctx, server, cq_idx, rc, grpc_error_set_int(GRPC_ERROR_CREATE("Out of request ids"), GRPC_ERROR_INT_LIMIT, server->max_requested_calls_per_cq)); return GRPC_CALL_OK; } switch (rc->type) { case BATCH_CALL: rm = &server->unregistered_request_matcher; break; case REGISTERED_CALL: rm = &rc->data.registered.registered_method->request_matcher; break; } server->requested_calls_per_cq[cq_idx][request_id] = *rc; gpr_free(rc); if (gpr_stack_lockfree_push(rm->requests_per_cq[cq_idx], request_id)) { /* this was the first queued request: we need to lock and start matching calls */ gpr_mu_lock(&server->mu_call); while ((calld = rm->pending_head) != NULL) { request_id = gpr_stack_lockfree_pop(rm->requests_per_cq[cq_idx]); if (request_id == -1) break; rm->pending_head = calld->pending_next; gpr_mu_unlock(&server->mu_call); gpr_mu_lock(&calld->mu_state); if (calld->state == ZOMBIED) { gpr_mu_unlock(&calld->mu_state); grpc_closure_init( &calld->kill_zombie_closure, kill_zombie, grpc_call_stack_element(grpc_call_get_call_stack(calld->call), 0)); grpc_exec_ctx_sched(exec_ctx, &calld->kill_zombie_closure, GRPC_ERROR_NONE, NULL); } else { GPR_ASSERT(calld->state == PENDING); calld->state = ACTIVATED; gpr_mu_unlock(&calld->mu_state); publish_call(exec_ctx, server, calld, cq_idx, &server->requested_calls_per_cq[cq_idx][request_id]); } gpr_mu_lock(&server->mu_call); } gpr_mu_unlock(&server->mu_call); } return GRPC_CALL_OK; }
static void publish_registered_or_batch(grpc_call *call, grpc_op_error status, void *tag) { grpc_call_element *elem = grpc_call_stack_element(grpc_call_get_call_stack(call), 0); call_data *calld = elem->call_data; grpc_cq_end_op_complete(calld->cq_new, tag, call, do_nothing, NULL, status); }
static void publish_registered_or_batch(grpc_call *call, int success, void *tag) { grpc_call_element *elem = grpc_call_stack_element(grpc_call_get_call_stack(call), 0); call_data *calld = elem->call_data; grpc_cq_end_op(calld->cq_new, tag, call, success); }
static void publish_registered_or_batch(grpc_exec_ctx *exec_ctx, void *prc, bool success) { requested_call *rc = prc; grpc_call *call = *rc->call; grpc_call_element *elem = grpc_call_stack_element(grpc_call_get_call_stack(call), 0); call_data *calld = elem->call_data; channel_data *chand = elem->channel_data; server_ref(chand->server); grpc_cq_end_op(exec_ctx, calld->cq_new, rc->tag, success, done_request_event, rc, &rc->completion); GRPC_CALL_INTERNAL_UNREF(exec_ctx, call, "server"); }
static void request_matcher_zombify_all_pending_calls(grpc_exec_ctx *exec_ctx, request_matcher *rm) { while (rm->pending_head) { call_data *calld = rm->pending_head; rm->pending_head = calld->pending_next; gpr_mu_lock(&calld->mu_state); calld->state = ZOMBIED; gpr_mu_unlock(&calld->mu_state); grpc_closure_init( &calld->kill_zombie_closure, kill_zombie, grpc_call_stack_element(grpc_call_get_call_stack(calld->call), 0)); grpc_exec_ctx_enqueue(exec_ctx, &calld->kill_zombie_closure, true, NULL); } }
static void publish_new_rpc(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { grpc_call_element *call_elem = arg; call_data *calld = call_elem->call_data; channel_data *chand = call_elem->channel_data; request_matcher *rm = calld->request_matcher; grpc_server *server = rm->server; if (error != GRPC_ERROR_NONE || gpr_atm_acq_load(&server->shutdown_flag)) { gpr_mu_lock(&calld->mu_state); calld->state = ZOMBIED; gpr_mu_unlock(&calld->mu_state); grpc_closure_init( &calld->kill_zombie_closure, kill_zombie, grpc_call_stack_element(grpc_call_get_call_stack(calld->call), 0)); grpc_exec_ctx_sched(exec_ctx, &calld->kill_zombie_closure, error, NULL); return; } for (size_t i = 0; i < server->cq_count; i++) { size_t cq_idx = (chand->cq_idx + i) % server->cq_count; int request_id = gpr_stack_lockfree_pop(rm->requests_per_cq[cq_idx]); if (request_id == -1) { continue; } else { gpr_mu_lock(&calld->mu_state); calld->state = ACTIVATED; gpr_mu_unlock(&calld->mu_state); publish_call(exec_ctx, server, calld, cq_idx, &server->requested_calls_per_cq[cq_idx][request_id]); return; /* early out */ } } /* no cq to take the request found: queue it on the slow list */ gpr_mu_lock(&server->mu_call); gpr_mu_lock(&calld->mu_state); calld->state = PENDING; gpr_mu_unlock(&calld->mu_state); if (rm->pending_head == NULL) { rm->pending_tail = rm->pending_head = calld; } else { rm->pending_tail->pending_next = calld; rm->pending_tail = calld; } calld->pending_next = NULL; gpr_mu_unlock(&server->mu_call); }
void grpc_server_destroy(grpc_server *server) { channel_data *c; listener *l; size_t i; call_data *calld; gpr_mu_lock(&server->mu); if (!server->shutdown) { gpr_mu_unlock(&server->mu); grpc_server_shutdown(server); gpr_mu_lock(&server->mu); } while (server->listeners_destroyed != num_listeners(server)) { for (i = 0; i < server->cq_count; i++) { gpr_mu_unlock(&server->mu); grpc_cq_hack_spin_pollset(server->cqs[i]); gpr_mu_lock(&server->mu); } gpr_cv_wait(&server->cv, &server->mu, gpr_time_add(gpr_now(), gpr_time_from_millis(100))); } while (server->listeners) { l = server->listeners; server->listeners = l->next; gpr_free(l); } while ((calld = call_list_remove_head(&server->lists[PENDING_START], PENDING_START)) != NULL) { gpr_log(GPR_DEBUG, "server destroys call %p", calld->call); calld->state = ZOMBIED; grpc_iomgr_add_callback( kill_zombie, grpc_call_stack_element(grpc_call_get_call_stack(calld->call), 0)); } for (c = server->root_channel_data.next; c != &server->root_channel_data; c = c->next) { shutdown_channel(c); } gpr_mu_unlock(&server->mu); server_unref(server); }
static void publish_legacy(grpc_call *call, grpc_op_error status, void *tag) { grpc_call_element *elem = grpc_call_stack_element(grpc_call_get_call_stack(call), 0); call_data *calld = elem->call_data; channel_data *chand = elem->channel_data; grpc_server *server = chand->server; if (status == GRPC_OP_OK) { grpc_cq_end_new_rpc(server->unregistered_cq, tag, call, do_nothing, NULL, grpc_mdstr_as_c_string(calld->path), grpc_mdstr_as_c_string(calld->host), calld->deadline, calld->legacy->initial_metadata.count, calld->legacy->initial_metadata.metadata); } else { gpr_log(GPR_ERROR, "should never reach here"); abort(); } }
static void accept_stream(grpc_exec_ctx *exec_ctx, void *cd, grpc_transport *transport, const void *transport_server_data) { channel_data *chand = cd; /* create a call */ grpc_call *call = grpc_call_create(chand->channel, NULL, 0, NULL, NULL, transport_server_data, NULL, 0, gpr_inf_future(GPR_CLOCK_MONOTONIC)); grpc_call_element *elem = grpc_call_stack_element(grpc_call_get_call_stack(call), 0); call_data *calld = elem->call_data; grpc_op op; memset(&op, 0, sizeof(op)); op.op = GRPC_OP_RECV_INITIAL_METADATA; op.data.recv_initial_metadata = &calld->initial_metadata; grpc_closure_init(&calld->got_initial_metadata, got_initial_metadata, elem); grpc_call_start_batch_and_execute(exec_ctx, call, &op, 1, &calld->got_initial_metadata); }
static void publish_call(grpc_exec_ctx *exec_ctx, grpc_server *server, call_data *calld, size_t cq_idx, requested_call *rc) { grpc_call_set_completion_queue(exec_ctx, calld->call, rc->cq_bound_to_call); grpc_call *call = calld->call; *rc->call = call; calld->cq_new = server->cqs[cq_idx]; GPR_SWAP(grpc_metadata_array, *rc->initial_metadata, calld->initial_metadata); switch (rc->type) { case BATCH_CALL: GPR_ASSERT(calld->host != NULL); GPR_ASSERT(calld->path != NULL); cpstr(&rc->data.batch.details->host, &rc->data.batch.details->host_capacity, calld->host); cpstr(&rc->data.batch.details->method, &rc->data.batch.details->method_capacity, calld->path); rc->data.batch.details->deadline = calld->deadline; rc->data.batch.details->flags = 0 | (calld->recv_idempotent_request ? GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST : 0); break; case REGISTERED_CALL: *rc->data.registered.deadline = calld->deadline; if (rc->data.registered.optional_payload) { *rc->data.registered.optional_payload = calld->payload; } break; default: GPR_UNREACHABLE_CODE(return ); } grpc_call_element *elem = grpc_call_stack_element(grpc_call_get_call_stack(call), 0); channel_data *chand = elem->channel_data; server_ref(chand->server); grpc_cq_end_op(exec_ctx, calld->cq_new, rc->tag, GRPC_ERROR_NONE, done_request_event, rc, &rc->completion); }