static void unlock_check_channel_callbacks(grpc_chttp2_transport *t) { if (t->channel_callback.executing) { return; } if (t->global.goaway_state != GRPC_CHTTP2_ERROR_STATE_NONE) { if (t->global.goaway_state == GRPC_CHTTP2_ERROR_STATE_SEEN && t->global.error_state != GRPC_CHTTP2_ERROR_STATE_NOTIFIED) { notify_goaways_args *a = gpr_malloc(sizeof(*a)); a->t = t; a->error = t->global.goaway_error; a->text = t->global.goaway_text; t->global.goaway_state = GRPC_CHTTP2_ERROR_STATE_NOTIFIED; t->channel_callback.executing = 1; grpc_iomgr_closure_init(&a->closure, notify_goaways, a); REF_TRANSPORT(t, "notify_goaways"); grpc_chttp2_schedule_closure(&t->global, &a->closure, 1); return; } else if (t->global.goaway_state != GRPC_CHTTP2_ERROR_STATE_NOTIFIED) { return; } } if (t->global.error_state == GRPC_CHTTP2_ERROR_STATE_SEEN) { t->global.error_state = GRPC_CHTTP2_ERROR_STATE_NOTIFIED; t->channel_callback.executing = 1; REF_TRANSPORT(t, "notify_closed"); grpc_chttp2_schedule_closure(&t->global, &t->channel_callback.notify_closed, 1); } }
static void perform_op_locked(grpc_chttp2_transport_global *transport_global, grpc_chttp2_stream_global *stream_global, grpc_transport_op *op) { if (op->cancel_with_status != GRPC_STATUS_OK) { cancel_from_api(transport_global, stream_global, op->cancel_with_status); } if (op->send_ops) { GPR_ASSERT(stream_global->outgoing_sopb == NULL); stream_global->send_done_closure = op->on_done_send; if (!stream_global->cancelled) { stream_global->outgoing_sopb = op->send_ops; if (op->is_last_send && stream_global->write_state == GRPC_WRITE_STATE_OPEN) { stream_global->write_state = GRPC_WRITE_STATE_QUEUED_CLOSE; } if (stream_global->id == 0) { GRPC_CHTTP2_IF_TRACING(gpr_log( GPR_DEBUG, "HTTP:%s: New grpc_chttp2_stream %p waiting for concurrency", transport_global->is_client ? "CLI" : "SVR", stream_global)); grpc_chttp2_list_add_waiting_for_concurrency(transport_global, stream_global); maybe_start_some_streams(transport_global); } else if (stream_global->outgoing_window > 0) { grpc_chttp2_list_add_writable_stream(transport_global, stream_global); } } else { grpc_sopb_reset(op->send_ops); grpc_chttp2_schedule_closure(transport_global, stream_global->send_done_closure, 0); } } if (op->recv_ops) { GPR_ASSERT(stream_global->publish_sopb == NULL); GPR_ASSERT(stream_global->published_state != GRPC_STREAM_CLOSED); stream_global->recv_done_closure = op->on_done_recv; stream_global->publish_sopb = op->recv_ops; stream_global->publish_sopb->nops = 0; stream_global->publish_state = op->recv_state; grpc_chttp2_incoming_metadata_live_op_buffer_end( &stream_global->outstanding_metadata); grpc_chttp2_list_add_read_write_state_changed(transport_global, stream_global); grpc_chttp2_list_add_writable_window_update_stream(transport_global, stream_global); } if (op->bind_pollset) { add_to_pollset_locked(TRANSPORT_FROM_GLOBAL(transport_global), op->bind_pollset); } if (op->on_consumed) { grpc_chttp2_schedule_closure(transport_global, op->on_consumed, 1); } }
void grpc_chttp2_cleanup_writing( grpc_chttp2_transport_global *transport_global, grpc_chttp2_transport_writing *transport_writing) { grpc_chttp2_stream_writing *stream_writing; grpc_chttp2_stream_global *stream_global; while (grpc_chttp2_list_pop_written_stream( transport_global, transport_writing, &stream_global, &stream_writing)) { GPR_ASSERT(stream_global->writing_now != 0); if (stream_writing->send_closed != GRPC_DONT_SEND_CLOSED) { stream_global->write_state = GRPC_WRITE_STATE_SENT_CLOSE; if (!transport_global->is_client) { stream_global->read_closed = 1; } } if (stream_global->writing_now & GRPC_CHTTP2_WRITING_DATA) { if (stream_global->outgoing_sopb != NULL && stream_global->outgoing_sopb->nops == 0) { GPR_ASSERT(stream_global->write_state != GRPC_WRITE_STATE_QUEUED_CLOSE); stream_global->outgoing_sopb = NULL; grpc_chttp2_schedule_closure(transport_global, stream_global->send_done_closure, 1); } } stream_global->writing_now = 0; grpc_chttp2_list_add_read_write_state_changed(transport_global, stream_global); } transport_writing->outbuf.count = 0; transport_writing->outbuf.length = 0; }
static void perform_transport_op(grpc_transport *gt, grpc_transport_op *op) { grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt; int close_transport = 0; lock(t); if (op->on_consumed) { grpc_chttp2_schedule_closure(&t->global, op->on_consumed, 1); } if (op->on_connectivity_state_change) { grpc_connectivity_state_notify_on_state_change( &t->channel_callback.state_tracker, op->connectivity_state, op->on_connectivity_state_change); } if (op->send_goaway) { t->global.sent_goaway = 1; grpc_chttp2_goaway_append( t->global.last_incoming_stream_id, grpc_chttp2_grpc_status_to_http2_error(op->goaway_status), gpr_slice_ref(*op->goaway_message), &t->global.qbuf); close_transport = !grpc_chttp2_has_streams(t); } if (op->set_accept_stream != NULL) { t->channel_callback.accept_stream = op->set_accept_stream; t->channel_callback.accept_stream_user_data = op->set_accept_stream_user_data; } if (op->bind_pollset) { add_to_pollset_locked(t, op->bind_pollset); } if (op->bind_pollset_set) { add_to_pollset_set_locked(t, op->bind_pollset_set); } if (op->send_ping) { send_ping_locked(t, op->send_ping); } if (op->disconnect) { close_transport_locked(t); } unlock(t); if (close_transport) { lock(t); close_transport_locked(t); unlock(t); } }
static void unlock(grpc_chttp2_transport *t) { grpc_iomgr_closure *run_closures; unlock_check_read_write_state(t); if (!t->writing_active && !t->closed && grpc_chttp2_unlocking_check_writes(&t->global, &t->writing)) { t->writing_active = 1; REF_TRANSPORT(t, "writing"); grpc_chttp2_schedule_closure(&t->global, &t->writing_action, 1); } run_closures = t->global.pending_closures_head; t->global.pending_closures_head = NULL; t->global.pending_closures_tail = NULL; gpr_mu_unlock(&t->mu); while (run_closures) { grpc_iomgr_closure *next = run_closures->next; run_closures->cb(run_closures->cb_arg, run_closures->success); run_closures = next; } }
static void unlock(grpc_chttp2_transport *t) { grpc_iomgr_closure *run_closures; unlock_check_read_write_state(t); if (!t->writing_active && t->global.error_state == GRPC_CHTTP2_ERROR_STATE_NONE && grpc_chttp2_unlocking_check_writes(&t->global, &t->writing)) { t->writing_active = 1; REF_TRANSPORT(t, "writing"); grpc_chttp2_schedule_closure(&t->global, &t->writing_action, 1); } /* unlock_check_parser(t); */ unlock_check_channel_callbacks(t); run_closures = t->global.pending_closures; t->global.pending_closures = NULL; gpr_mu_unlock(&t->mu); while (run_closures) { grpc_iomgr_closure *next = run_closures->next; run_closures->cb(run_closures->cb_arg, run_closures->success); run_closures = next; } }
/* tcp read callback */ static void recv_data(void *tp, gpr_slice *slices, size_t nslices, grpc_endpoint_cb_status error) { grpc_chttp2_transport *t = tp; size_t i; int unref = 0; switch (error) { case GRPC_ENDPOINT_CB_SHUTDOWN: case GRPC_ENDPOINT_CB_EOF: case GRPC_ENDPOINT_CB_ERROR: lock(t); drop_connection(t); read_error_locked(t); unlock(t); unref = 1; for (i = 0; i < nslices; i++) gpr_slice_unref(slices[i]); break; case GRPC_ENDPOINT_CB_OK: lock(t); i = 0; GPR_ASSERT(!t->parsing_active); if (t->global.error_state == GRPC_CHTTP2_ERROR_STATE_NONE) { t->parsing_active = 1; /* merge stream lists */ grpc_chttp2_stream_map_move_into(&t->new_stream_map, &t->parsing_stream_map); grpc_chttp2_prepare_to_read(&t->global, &t->parsing); gpr_mu_unlock(&t->mu); for (; i < nslices && grpc_chttp2_perform_read(&t->parsing, slices[i]); i++) { gpr_slice_unref(slices[i]); } gpr_mu_lock(&t->mu); if (i != nslices) { drop_connection(t); } /* merge stream lists */ grpc_chttp2_stream_map_move_into(&t->new_stream_map, &t->parsing_stream_map); t->global.concurrent_stream_count = grpc_chttp2_stream_map_size(&t->parsing_stream_map); if (t->parsing.initial_window_update != 0) { grpc_chttp2_stream_map_for_each(&t->parsing_stream_map, update_global_window, t); } /* handle higher level things */ grpc_chttp2_publish_reads(&t->global, &t->parsing); t->parsing_active = 0; } if (i == nslices) { grpc_chttp2_schedule_closure(&t->global, &t->reading_action, 1); } else { read_error_locked(t); unref = 1; } unlock(t); for (; i < nslices; i++) gpr_slice_unref(slices[i]); break; } if (unref) { UNREF_TRANSPORT(t, "recv_data"); } }
static void unlock_check_read_write_state(grpc_chttp2_transport *t) { grpc_chttp2_transport_global *transport_global = &t->global; grpc_chttp2_stream_global *stream_global; grpc_stream_state state; if (!t->parsing_active) { /* if a stream is in the stream map, and gets cancelled, we need to ensure we are not parsing before continuing the cancellation to keep things in a sane state */ while (grpc_chttp2_list_pop_closed_waiting_for_parsing(transport_global, &stream_global)) { GPR_ASSERT(stream_global->in_stream_map); GPR_ASSERT(stream_global->write_state != GRPC_WRITE_STATE_OPEN); GPR_ASSERT(stream_global->read_closed); remove_stream(t, stream_global->id); grpc_chttp2_list_add_read_write_state_changed(transport_global, stream_global); } } while (grpc_chttp2_list_pop_read_write_state_changed(transport_global, &stream_global)) { if (stream_global->cancelled) { stream_global->write_state = GRPC_WRITE_STATE_SENT_CLOSE; stream_global->read_closed = 1; if (!stream_global->published_cancelled) { char buffer[GPR_LTOA_MIN_BUFSIZE]; gpr_ltoa(stream_global->cancelled_status, buffer); grpc_chttp2_incoming_metadata_buffer_add(&stream_global->incoming_metadata, grpc_mdelem_from_strings(t->metadata_context, "grpc-status", buffer)); grpc_chttp2_incoming_metadata_buffer_place_metadata_batch_into( &stream_global->incoming_metadata, &stream_global->incoming_sopb); stream_global->published_cancelled = 1; } } if (stream_global->write_state == GRPC_WRITE_STATE_SENT_CLOSE && stream_global->read_closed && stream_global->in_stream_map) { if (t->parsing_active) { grpc_chttp2_list_add_closed_waiting_for_parsing(transport_global, stream_global); } else { remove_stream(t, stream_global->id); } } if (!stream_global->publish_sopb) { continue; } /* FIXME(ctiller): we include in_stream_map in our computation of whether the stream is write-closed. This is completely bogus, but has the effect of delaying stream-closed until the stream is indeed evicted from the stream map, making it safe to delete. To fix this will require having an edge after stream-closed indicating that the stream is closed AND safe to delete. */ state = compute_state( stream_global->write_state == GRPC_WRITE_STATE_SENT_CLOSE && !stream_global->in_stream_map, stream_global->read_closed); if (stream_global->incoming_sopb.nops == 0 && state == stream_global->published_state) { continue; } grpc_chttp2_incoming_metadata_buffer_postprocess_sopb_and_begin_live_op( &stream_global->incoming_metadata, &stream_global->incoming_sopb, &stream_global->outstanding_metadata); grpc_sopb_swap(stream_global->publish_sopb, &stream_global->incoming_sopb); stream_global->published_state = *stream_global->publish_state = state; grpc_chttp2_schedule_closure(transport_global, stream_global->recv_done_closure, 1); stream_global->recv_done_closure = NULL; stream_global->publish_sopb = NULL; stream_global->publish_state = NULL; } }
static void schedule_closure_for_connectivity(void *a, grpc_iomgr_closure *closure) { grpc_chttp2_schedule_closure(a, closure, 1); }