Line data Source code
1 : /*
2 : *
3 : * Copyright 2015, Google Inc.
4 : * All rights reserved.
5 : *
6 : * Redistribution and use in source and binary forms, with or without
7 : * modification, are permitted provided that the following conditions are
8 : * met:
9 : *
10 : * * Redistributions of source code must retain the above copyright
11 : * notice, this list of conditions and the following disclaimer.
12 : * * Redistributions in binary form must reproduce the above
13 : * copyright notice, this list of conditions and the following disclaimer
14 : * in the documentation and/or other materials provided with the
15 : * distribution.
16 : * * Neither the name of Google Inc. nor the names of its
17 : * contributors may be used to endorse or promote products derived from
18 : * this software without specific prior written permission.
19 : *
20 : * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 : * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 : * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 : * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 : * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 : * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 : * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 : * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 : *
32 : */
33 :
34 : #include "src/core/transport/chttp2/internal.h"
35 :
36 : #include <limits.h>
37 :
38 : #include <grpc/support/log.h>
39 :
40 : #include "src/core/transport/chttp2/http2_errors.h"
41 :
42 : static void finalize_outbuf(grpc_chttp2_transport_writing *transport_writing);
43 :
44 12543663 : int grpc_chttp2_unlocking_check_writes(
45 : grpc_chttp2_transport_global *transport_global,
46 : grpc_chttp2_transport_writing *transport_writing) {
47 : grpc_chttp2_stream_global *stream_global;
48 : grpc_chttp2_stream_writing *stream_writing;
49 12543663 : grpc_chttp2_stream_global *first_reinserted_stream = NULL;
50 : gpr_uint32 window_delta;
51 :
52 : /* simple writes are queued to qbuf, and flushed here */
53 12543663 : gpr_slice_buffer_swap(&transport_global->qbuf, &transport_writing->outbuf);
54 12571375 : GPR_ASSERT(transport_global->qbuf.count == 0);
55 :
56 12575389 : if (transport_global->dirtied_local_settings &&
57 4014 : !transport_global->sent_local_settings) {
58 8028 : gpr_slice_buffer_add(
59 : &transport_writing->outbuf,
60 : grpc_chttp2_settings_create(
61 4014 : transport_global->settings[GRPC_SENT_SETTINGS],
62 4014 : transport_global->settings[GRPC_LOCAL_SETTINGS],
63 : transport_global->force_send_settings, GRPC_CHTTP2_NUM_SETTINGS));
64 4012 : transport_global->force_send_settings = 0;
65 4012 : transport_global->dirtied_local_settings = 0;
66 4012 : transport_global->sent_local_settings = 1;
67 : }
68 :
69 : /* for each grpc_chttp2_stream that's become writable, frame it's data
70 : (according to available window sizes) and add to the output buffer */
71 32492965 : while (grpc_chttp2_list_pop_writable_stream(
72 : transport_global, transport_writing, &stream_global, &stream_writing)) {
73 7345347 : if (stream_global == first_reinserted_stream) {
74 : /* prevent infinite loop */
75 1535 : grpc_chttp2_list_add_first_writable_stream(transport_global,
76 : stream_global);
77 37359 : break;
78 : }
79 :
80 7343812 : stream_writing->id = stream_global->id;
81 7343812 : stream_writing->send_closed = GRPC_DONT_SEND_CLOSED;
82 :
83 7343812 : if (stream_global->outgoing_sopb) {
84 18420468 : window_delta = grpc_chttp2_preencode(
85 3070078 : stream_global->outgoing_sopb->ops,
86 3070078 : &stream_global->outgoing_sopb->nops,
87 9210234 : (gpr_uint32)GPR_MIN(GPR_MIN(transport_global->outgoing_window,
88 : stream_global->outgoing_window),
89 : GPR_UINT32_MAX),
90 3070078 : &stream_writing->sopb);
91 3069581 : GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT(
92 : "write", transport_global, outgoing_window, -(gpr_int64)window_delta);
93 3075581 : GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("write", transport_global, stream_global,
94 : outgoing_window,
95 : -(gpr_int64)window_delta);
96 3075581 : transport_global->outgoing_window -= window_delta;
97 3075581 : stream_global->outgoing_window -= window_delta;
98 :
99 5778002 : if (stream_global->write_state == GRPC_WRITE_STATE_QUEUED_CLOSE &&
100 2702421 : stream_global->outgoing_sopb->nops == 0) {
101 2702411 : if (!transport_global->is_client && !stream_global->read_closed) {
102 251 : stream_writing->send_closed = GRPC_SEND_CLOSED_WITH_RST_STREAM;
103 : } else {
104 2702160 : stream_writing->send_closed = GRPC_SEND_CLOSED;
105 : }
106 : }
107 :
108 6080651 : if (stream_global->outgoing_window > 0 &&
109 3005070 : stream_global->outgoing_sopb->nops != 0) {
110 16 : grpc_chttp2_list_add_writable_stream(transport_global, stream_global);
111 32 : if (first_reinserted_stream == NULL &&
112 16 : transport_global->outgoing_window == 0) {
113 16 : first_reinserted_stream = stream_global;
114 : }
115 : }
116 : }
117 :
118 12133372 : if (!stream_global->read_closed &&
119 4784057 : stream_global->unannounced_incoming_window > 0) {
120 1699617 : GPR_ASSERT(stream_writing->announce_window == 0);
121 1699617 : GRPC_CHTTP2_FLOWCTL_TRACE_STREAM(
122 : "write", transport_writing, stream_writing, announce_window,
123 : stream_global->unannounced_incoming_window);
124 3399304 : stream_writing->announce_window =
125 1699652 : stream_global->unannounced_incoming_window;
126 1699652 : GRPC_CHTTP2_FLOWCTL_TRACE_STREAM(
127 : "write", transport_global, stream_global, incoming_window,
128 : stream_global->unannounced_incoming_window);
129 1699652 : GRPC_CHTTP2_FLOWCTL_TRACE_STREAM(
130 : "write", transport_global, stream_global, unannounced_incoming_window,
131 : -(gpr_int64)stream_global->unannounced_incoming_window);
132 3399304 : stream_global->incoming_window +=
133 1699652 : stream_global->unannounced_incoming_window;
134 1699652 : stream_global->unannounced_incoming_window = 0;
135 1699652 : grpc_chttp2_list_add_incoming_window_updated(transport_global,
136 : stream_global);
137 1699833 : stream_global->writing_now |= GRPC_CHTTP2_WRITING_WINDOW;
138 : }
139 11679918 : if (stream_writing->sopb.nops > 0 ||
140 4330387 : stream_writing->send_closed != GRPC_DONT_SEND_CLOSED) {
141 3018661 : stream_global->writing_now |= GRPC_CHTTP2_WRITING_DATA;
142 : }
143 7349531 : if (stream_global->writing_now != 0) {
144 4308858 : grpc_chttp2_list_add_writing_stream(transport_writing, stream_writing);
145 : }
146 : }
147 :
148 : /* if the grpc_chttp2_transport is ready to send a window update, do so here
149 : also; 3/4 is a magic number that will likely get tuned soon */
150 25131616 : if (transport_global->incoming_window <
151 12565808 : transport_global->connection_window_target * 3 / 4) {
152 8908 : window_delta = transport_global->connection_window_target -
153 4454 : transport_global->incoming_window;
154 4454 : gpr_slice_buffer_add(&transport_writing->outbuf,
155 : grpc_chttp2_window_update_create(0, window_delta));
156 4454 : GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT("write", transport_global,
157 : incoming_window, window_delta);
158 4455 : transport_global->incoming_window += window_delta;
159 : }
160 :
161 25112031 : return transport_writing->outbuf.count > 0 ||
162 12535352 : grpc_chttp2_list_have_writing_streams(transport_writing);
163 : }
164 :
165 3443731 : void grpc_chttp2_perform_writes(
166 : grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_writing *transport_writing,
167 : grpc_endpoint *endpoint) {
168 3443731 : GPR_ASSERT(transport_writing->outbuf.count > 0 ||
169 : grpc_chttp2_list_have_writing_streams(transport_writing));
170 :
171 3443792 : finalize_outbuf(transport_writing);
172 :
173 3442897 : GPR_ASSERT(transport_writing->outbuf.count > 0);
174 3442897 : GPR_ASSERT(endpoint);
175 :
176 3442897 : grpc_endpoint_write(exec_ctx, endpoint, &transport_writing->outbuf,
177 : &transport_writing->done_cb);
178 3442325 : }
179 :
180 3442494 : static void finalize_outbuf(grpc_chttp2_transport_writing *transport_writing) {
181 : grpc_chttp2_stream_writing *stream_writing;
182 :
183 11195061 : while (
184 7753409 : grpc_chttp2_list_pop_writing_stream(transport_writing, &stream_writing)) {
185 5602622 : if (stream_writing->sopb.nops > 0 ||
186 1293412 : stream_writing->send_closed != GRPC_DONT_SEND_CLOSED) {
187 9057021 : grpc_chttp2_encode(stream_writing->sopb.ops, stream_writing->sopb.nops,
188 3019007 : stream_writing->send_closed != GRPC_DONT_SEND_CLOSED,
189 3019007 : stream_writing->id,
190 : &transport_writing->hpack_compressor,
191 : &transport_writing->outbuf);
192 3020760 : stream_writing->sopb.nops = 0;
193 : }
194 4310963 : if (stream_writing->announce_window > 0) {
195 3399934 : gpr_slice_buffer_add(
196 : &transport_writing->outbuf,
197 1699967 : grpc_chttp2_window_update_create(stream_writing->id,
198 1699967 : stream_writing->announce_window));
199 1699999 : GRPC_CHTTP2_FLOWCTL_TRACE_STREAM(
200 : "write", transport_writing, stream_writing, announce_window,
201 : -(gpr_int64)stream_writing->announce_window);
202 1699998 : stream_writing->announce_window = 0;
203 : }
204 4310994 : if (stream_writing->send_closed == GRPC_SEND_CLOSED_WITH_RST_STREAM) {
205 251 : gpr_slice_buffer_add(&transport_writing->outbuf,
206 251 : grpc_chttp2_rst_stream_create(stream_writing->id,
207 : GRPC_CHTTP2_NO_ERROR));
208 : }
209 4310994 : grpc_chttp2_list_add_written_stream(transport_writing, stream_writing);
210 : }
211 3443357 : }
212 :
213 3445532 : void grpc_chttp2_cleanup_writing(
214 : grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
215 : grpc_chttp2_transport_writing *transport_writing) {
216 : grpc_chttp2_stream_writing *stream_writing;
217 : grpc_chttp2_stream_global *stream_global;
218 :
219 11198914 : while (grpc_chttp2_list_pop_written_stream(
220 : transport_global, transport_writing, &stream_global, &stream_writing)) {
221 4312031 : GPR_ASSERT(stream_global->writing_now != 0);
222 4312226 : if (stream_writing->send_closed != GRPC_DONT_SEND_CLOSED) {
223 2702871 : stream_global->write_state = GRPC_WRITE_STATE_SENT_CLOSE;
224 2702871 : if (!transport_global->is_client) {
225 1301321 : stream_global->read_closed = 1;
226 : }
227 : }
228 4312226 : if (stream_global->writing_now & GRPC_CHTTP2_WRITING_DATA) {
229 6038660 : if (stream_global->outgoing_sopb != NULL &&
230 3019618 : stream_global->outgoing_sopb->nops == 0) {
231 3006000 : GPR_ASSERT(stream_global->write_state != GRPC_WRITE_STATE_QUEUED_CLOSE);
232 3006000 : stream_global->outgoing_sopb = NULL;
233 3006000 : grpc_exec_ctx_enqueue(exec_ctx, stream_global->send_done_closure, 1);
234 : }
235 : }
236 4311906 : stream_global->writing_now = 0;
237 4311906 : grpc_chttp2_list_add_read_write_state_changed(transport_global,
238 : stream_global);
239 : }
240 3442583 : gpr_slice_buffer_reset_and_unref(&transport_writing->outbuf);
241 3441357 : }
|