Example #1
0
int grpc_chttp2_unlocking_check_writes(
    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
    grpc_chttp2_transport_writing *transport_writing) {
  grpc_chttp2_stream_global *stream_global;
  grpc_chttp2_stream_writing *stream_writing;

  GPR_TIMER_BEGIN("grpc_chttp2_unlocking_check_writes", 0);

  /* simple writes are queued to qbuf, and flushed here */
  gpr_slice_buffer_swap(&transport_global->qbuf, &transport_writing->outbuf);
  GPR_ASSERT(transport_global->qbuf.count == 0);

  grpc_chttp2_hpack_compressor_set_max_table_size(
      &transport_writing->hpack_compressor,
      transport_global->settings[GRPC_PEER_SETTINGS]
                                [GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE]);

  if (transport_global->dirtied_local_settings &&
      !transport_global->sent_local_settings) {
    gpr_slice_buffer_add(
        &transport_writing->outbuf,
        grpc_chttp2_settings_create(
            transport_global->settings[GRPC_SENT_SETTINGS],
            transport_global->settings[GRPC_LOCAL_SETTINGS],
            transport_global->force_send_settings, GRPC_CHTTP2_NUM_SETTINGS));
    transport_global->force_send_settings = 0;
    transport_global->dirtied_local_settings = 0;
    transport_global->sent_local_settings = 1;
  }

  GRPC_CHTTP2_FLOW_MOVE_TRANSPORT("write", transport_writing, outgoing_window,
                                  transport_global, outgoing_window);
  if (transport_writing->outgoing_window > 0) {
    while (grpc_chttp2_list_pop_stalled_by_transport(transport_global,
                                                     &stream_global)) {
      grpc_chttp2_become_writable(exec_ctx, transport_global, stream_global,
                                  false, "transport.read_flow_control");
    }
  }

  /* for each grpc_chttp2_stream that's become writable, frame it's data
     (according to available window sizes) and add to the output buffer */
  while (grpc_chttp2_list_pop_writable_stream(
      transport_global, transport_writing, &stream_global, &stream_writing)) {
    bool sent_initial_metadata = stream_writing->sent_initial_metadata;
    bool become_writable = false;

    stream_writing->id = stream_global->id;
    stream_writing->read_closed = stream_global->read_closed;

    GRPC_CHTTP2_FLOW_MOVE_STREAM("write", transport_writing, stream_writing,
                                 outgoing_window, stream_global,
                                 outgoing_window);

    if (!sent_initial_metadata && stream_global->send_initial_metadata) {
      stream_writing->send_initial_metadata =
          stream_global->send_initial_metadata;
      stream_global->send_initial_metadata = NULL;
      become_writable = true;
      sent_initial_metadata = true;
    }
    if (sent_initial_metadata) {
      if (stream_global->send_message != NULL) {
        gpr_slice hdr = gpr_slice_malloc(5);
        uint8_t *p = GPR_SLICE_START_PTR(hdr);
        uint32_t len = stream_global->send_message->length;
        GPR_ASSERT(stream_writing->send_message == NULL);
        p[0] = (stream_global->send_message->flags &
                GRPC_WRITE_INTERNAL_COMPRESS) != 0;
        p[1] = (uint8_t)(len >> 24);
        p[2] = (uint8_t)(len >> 16);
        p[3] = (uint8_t)(len >> 8);
        p[4] = (uint8_t)(len);
        gpr_slice_buffer_add(&stream_writing->flow_controlled_buffer, hdr);
        if (stream_global->send_message->length > 0) {
          stream_writing->send_message = stream_global->send_message;
        } else {
          stream_writing->send_message = NULL;
        }
        stream_writing->stream_fetched = 0;
        stream_global->send_message = NULL;
      }
      if ((stream_writing->send_message != NULL ||
           stream_writing->flow_controlled_buffer.length > 0) &&
          stream_writing->outgoing_window > 0) {
        if (transport_writing->outgoing_window > 0) {
          become_writable = true;
        } else {
          grpc_chttp2_list_add_stalled_by_transport(transport_writing,
                                                    stream_writing);
        }
      }
      if (stream_global->send_trailing_metadata) {
        stream_writing->send_trailing_metadata =
            stream_global->send_trailing_metadata;
        stream_global->send_trailing_metadata = NULL;
        become_writable = true;
      }
    }

    if (!stream_global->read_closed &&
        stream_global->unannounced_incoming_window_for_writing > 1024) {
      GRPC_CHTTP2_FLOW_MOVE_STREAM("write", transport_global, stream_writing,
                                   announce_window, stream_global,
                                   unannounced_incoming_window_for_writing);
      become_writable = true;
    }

    if (become_writable) {
      grpc_chttp2_list_add_writing_stream(transport_writing, stream_writing);
    } else {
      GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2_writing");
    }
  }
Example #2
0
int grpc_chttp2_unlocking_check_writes(
    grpc_chttp2_transport_global *transport_global,
    grpc_chttp2_transport_writing *transport_writing) {
    grpc_chttp2_stream_global *stream_global;
    grpc_chttp2_stream_writing *stream_writing;
    grpc_chttp2_stream_global *first_reinserted_stream = NULL;
    gpr_uint32 window_delta;

    /* simple writes are queued to qbuf, and flushed here */
    gpr_slice_buffer_swap(&transport_global->qbuf, &transport_writing->outbuf);
    GPR_ASSERT(transport_global->qbuf.count == 0);

    if (transport_global->dirtied_local_settings &&
            !transport_global->sent_local_settings) {
        gpr_slice_buffer_add(
            &transport_writing->outbuf,
            grpc_chttp2_settings_create(
                transport_global->settings[GRPC_SENT_SETTINGS],
                transport_global->settings[GRPC_LOCAL_SETTINGS],
                transport_global->force_send_settings, GRPC_CHTTP2_NUM_SETTINGS));
        transport_global->force_send_settings = 0;
        transport_global->dirtied_local_settings = 0;
        transport_global->sent_local_settings = 1;
    }

    /* for each grpc_chttp2_stream that's become writable, frame it's data
       (according to available window sizes) and add to the output buffer */
    while (grpc_chttp2_list_pop_writable_stream(
                transport_global, transport_writing, &stream_global, &stream_writing)) {
        if (stream_global == first_reinserted_stream) {
            /* prevent infinite loop */
            grpc_chttp2_list_add_first_writable_stream(transport_global,
                    stream_global);
            break;
        }

        stream_writing->id = stream_global->id;
        stream_writing->send_closed = GRPC_DONT_SEND_CLOSED;

        if (stream_global->outgoing_sopb) {
            window_delta =
                grpc_chttp2_preencode(stream_global->outgoing_sopb->ops,
                                      &stream_global->outgoing_sopb->nops,
                                      GPR_MIN(transport_global->outgoing_window,
                                              stream_global->outgoing_window),
                                      &stream_writing->sopb);
            GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT(
                "write", transport_global, outgoing_window, -(gpr_int64)window_delta);
            GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("write", transport_global, stream_global,
                                             outgoing_window,
                                             -(gpr_int64)window_delta);
            transport_global->outgoing_window -= window_delta;
            stream_global->outgoing_window -= window_delta;

            if (stream_global->write_state == GRPC_WRITE_STATE_QUEUED_CLOSE &&
                    stream_global->outgoing_sopb->nops == 0) {
                if (!transport_global->is_client && !stream_global->read_closed) {
                    stream_writing->send_closed = GRPC_SEND_CLOSED_WITH_RST_STREAM;
                } else {
                    stream_writing->send_closed = GRPC_SEND_CLOSED;
                }
            }

            if (stream_global->outgoing_window > 0 &&
                    stream_global->outgoing_sopb->nops != 0) {
                grpc_chttp2_list_add_writable_stream(transport_global, stream_global);
                if (first_reinserted_stream == NULL &&
                        transport_global->outgoing_window == 0) {
                    first_reinserted_stream = stream_global;
                }
            }
        }

        if (!stream_global->read_closed && stream_global->unannounced_incoming_window > 0) {
            stream_writing->announce_window = stream_global->unannounced_incoming_window;
            GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("write", transport_global, stream_global,
                                             incoming_window, stream_global->unannounced_incoming_window);
            GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("write", transport_global, stream_global,
                                             unannounced_incoming_window, -(gpr_int64)stream_global->unannounced_incoming_window);
            stream_global->incoming_window += stream_global->unannounced_incoming_window;
            stream_global->unannounced_incoming_window = 0;
            grpc_chttp2_list_add_incoming_window_updated(transport_global,
                    stream_global);
            stream_global->writing_now |= GRPC_CHTTP2_WRITING_WINDOW;
        }
        if (stream_writing->sopb.nops > 0 ||
                stream_writing->send_closed != GRPC_DONT_SEND_CLOSED) {
            stream_global->writing_now |= GRPC_CHTTP2_WRITING_DATA;
        }
        if (stream_global->writing_now != 0) {
            grpc_chttp2_list_add_writing_stream(transport_writing, stream_writing);
        }
    }

    /* if the grpc_chttp2_transport is ready to send a window update, do so here
       also; 3/4 is a magic number that will likely get tuned soon */
    if (transport_global->incoming_window <
            transport_global->connection_window_target * 3 / 4) {
        window_delta = transport_global->connection_window_target -
                       transport_global->incoming_window;
        gpr_slice_buffer_add(&transport_writing->outbuf,
                             grpc_chttp2_window_update_create(0, window_delta));
        GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT("write", transport_global,
                                            incoming_window, window_delta);
        transport_global->incoming_window += window_delta;
    }

    return transport_writing->outbuf.count > 0 ||
           grpc_chttp2_list_have_writing_streams(transport_writing);
}