void grpc_sopb_move_to(grpc_stream_op_buffer *src, grpc_stream_op_buffer *dst) { if (src->nops == 0) { return; } if (dst->nops == 0) { grpc_sopb_swap(src, dst); return; } grpc_sopb_append(dst, src->ops, src->nops); src->nops = 0; }
/** Assembles a new grpc_stream_op_buffer with the compressed slices, modifying * the associated GRPC_OP_BEGIN_MESSAGE accordingly (new compressed length, * flags indicating compression is in effect) and replaces \a send_ops with it. * */ static void finish_compressed_sopb(grpc_stream_op_buffer *send_ops, grpc_call_element *elem) { size_t i; call_data *calld = elem->call_data; int new_slices_added = 0; /* GPR_FALSE */ grpc_metadata_batch metadata; grpc_stream_op_buffer new_send_ops; grpc_sopb_init(&new_send_ops); for (i = 0; i < send_ops->nops; i++) { grpc_stream_op *sop = &send_ops->ops[i]; switch (sop->type) { case GRPC_OP_BEGIN_MESSAGE: GPR_ASSERT(calld->slices.length <= GPR_UINT32_MAX); grpc_sopb_add_begin_message( &new_send_ops, (gpr_uint32)calld->slices.length, sop->data.begin_message.flags | GRPC_WRITE_INTERNAL_COMPRESS); break; case GRPC_OP_SLICE: /* Once we reach the slices section of the original buffer, simply add * all the new (compressed) slices. We obviously want to do this only * once, hence the "new_slices_added" guard. */ if (!new_slices_added) { size_t j; for (j = 0; j < calld->slices.count; ++j) { grpc_sopb_add_slice(&new_send_ops, gpr_slice_ref(calld->slices.slices[j])); } new_slices_added = 1; /* GPR_TRUE */ } break; case GRPC_OP_METADATA: /* move the metadata to the new buffer. */ grpc_metadata_batch_move(&metadata, &sop->data.metadata); grpc_sopb_add_metadata(&new_send_ops, metadata); break; case GRPC_NO_OP: break; } } grpc_sopb_swap(send_ops, &new_send_ops); grpc_sopb_destroy(&new_send_ops); }
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; } }