1 //
2 //
3 // Copyright 2015 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18
19 #include <grpc/support/port_platform.h>
20
21 #include <grpc/support/log.h>
22
23 #include "src/core/ext/transport/chttp2/transport/frame.h"
24 #include "src/core/ext/transport/chttp2/transport/internal.h"
25 #include "src/core/lib/debug/trace.h"
26 #include "src/core/lib/gprpp/bitset.h"
27
stream_list_id_string(grpc_chttp2_stream_list_id id)28 static const char* stream_list_id_string(grpc_chttp2_stream_list_id id) {
29 switch (id) {
30 case GRPC_CHTTP2_LIST_WRITABLE:
31 return "writable";
32 case GRPC_CHTTP2_LIST_WRITING:
33 return "writing";
34 case GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT:
35 return "stalled_by_transport";
36 case GRPC_CHTTP2_LIST_STALLED_BY_STREAM:
37 return "stalled_by_stream";
38 case GRPC_CHTTP2_LIST_WAITING_FOR_CONCURRENCY:
39 return "waiting_for_concurrency";
40 case STREAM_LIST_COUNT:
41 GPR_UNREACHABLE_CODE(return "unknown");
42 }
43 GPR_UNREACHABLE_CODE(return "unknown");
44 }
45
46 grpc_core::TraceFlag grpc_trace_http2_stream_state(false, "http2_stream_state");
47
48 // core list management
49
stream_list_empty(grpc_chttp2_transport * t,grpc_chttp2_stream_list_id id)50 static bool stream_list_empty(grpc_chttp2_transport* t,
51 grpc_chttp2_stream_list_id id) {
52 return t->lists[id].head == nullptr;
53 }
54
stream_list_pop(grpc_chttp2_transport * t,grpc_chttp2_stream ** stream,grpc_chttp2_stream_list_id id)55 static bool stream_list_pop(grpc_chttp2_transport* t,
56 grpc_chttp2_stream** stream,
57 grpc_chttp2_stream_list_id id) {
58 grpc_chttp2_stream* s = t->lists[id].head;
59 if (s) {
60 grpc_chttp2_stream* new_head = s->links[id].next;
61 GPR_ASSERT(s->included.is_set(id));
62 if (new_head) {
63 t->lists[id].head = new_head;
64 new_head->links[id].prev = nullptr;
65 } else {
66 t->lists[id].head = nullptr;
67 t->lists[id].tail = nullptr;
68 }
69 s->included.clear(id);
70 }
71 *stream = s;
72 if (s && GRPC_TRACE_FLAG_ENABLED(grpc_trace_http2_stream_state)) {
73 gpr_log(GPR_INFO, "%p[%d][%s]: pop from %s", t, s->id,
74 t->is_client ? "cli" : "svr", stream_list_id_string(id));
75 }
76 return s != nullptr;
77 }
78
stream_list_remove(grpc_chttp2_transport * t,grpc_chttp2_stream * s,grpc_chttp2_stream_list_id id)79 static void stream_list_remove(grpc_chttp2_transport* t, grpc_chttp2_stream* s,
80 grpc_chttp2_stream_list_id id) {
81 GPR_ASSERT(s->included.is_set(id));
82 s->included.clear(id);
83 if (s->links[id].prev) {
84 s->links[id].prev->links[id].next = s->links[id].next;
85 } else {
86 GPR_ASSERT(t->lists[id].head == s);
87 t->lists[id].head = s->links[id].next;
88 }
89 if (s->links[id].next) {
90 s->links[id].next->links[id].prev = s->links[id].prev;
91 } else {
92 t->lists[id].tail = s->links[id].prev;
93 }
94 if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_http2_stream_state)) {
95 gpr_log(GPR_INFO, "%p[%d][%s]: remove from %s", t, s->id,
96 t->is_client ? "cli" : "svr", stream_list_id_string(id));
97 }
98 }
99
stream_list_maybe_remove(grpc_chttp2_transport * t,grpc_chttp2_stream * s,grpc_chttp2_stream_list_id id)100 static bool stream_list_maybe_remove(grpc_chttp2_transport* t,
101 grpc_chttp2_stream* s,
102 grpc_chttp2_stream_list_id id) {
103 if (s->included.is_set(id)) {
104 stream_list_remove(t, s, id);
105 return true;
106 } else {
107 return false;
108 }
109 }
110
stream_list_add_tail(grpc_chttp2_transport * t,grpc_chttp2_stream * s,grpc_chttp2_stream_list_id id)111 static void stream_list_add_tail(grpc_chttp2_transport* t,
112 grpc_chttp2_stream* s,
113 grpc_chttp2_stream_list_id id) {
114 grpc_chttp2_stream* old_tail;
115 GPR_ASSERT(!s->included.is_set(id));
116 old_tail = t->lists[id].tail;
117 s->links[id].next = nullptr;
118 s->links[id].prev = old_tail;
119 if (old_tail) {
120 old_tail->links[id].next = s;
121 } else {
122 t->lists[id].head = s;
123 }
124 t->lists[id].tail = s;
125 s->included.set(id);
126 if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_http2_stream_state)) {
127 gpr_log(GPR_INFO, "%p[%d][%s]: add to %s", t, s->id,
128 t->is_client ? "cli" : "svr", stream_list_id_string(id));
129 }
130 }
131
stream_list_add(grpc_chttp2_transport * t,grpc_chttp2_stream * s,grpc_chttp2_stream_list_id id)132 static bool stream_list_add(grpc_chttp2_transport* t, grpc_chttp2_stream* s,
133 grpc_chttp2_stream_list_id id) {
134 if (s->included.is_set(id)) {
135 return false;
136 }
137 stream_list_add_tail(t, s, id);
138 return true;
139 }
140
141 // wrappers for specializations
142
grpc_chttp2_list_add_writable_stream(grpc_chttp2_transport * t,grpc_chttp2_stream * s)143 bool grpc_chttp2_list_add_writable_stream(grpc_chttp2_transport* t,
144 grpc_chttp2_stream* s) {
145 GPR_ASSERT(s->id != 0);
146 return stream_list_add(t, s, GRPC_CHTTP2_LIST_WRITABLE);
147 }
148
grpc_chttp2_list_pop_writable_stream(grpc_chttp2_transport * t,grpc_chttp2_stream ** s)149 bool grpc_chttp2_list_pop_writable_stream(grpc_chttp2_transport* t,
150 grpc_chttp2_stream** s) {
151 return stream_list_pop(t, s, GRPC_CHTTP2_LIST_WRITABLE);
152 }
153
grpc_chttp2_list_remove_writable_stream(grpc_chttp2_transport * t,grpc_chttp2_stream * s)154 bool grpc_chttp2_list_remove_writable_stream(grpc_chttp2_transport* t,
155 grpc_chttp2_stream* s) {
156 return stream_list_maybe_remove(t, s, GRPC_CHTTP2_LIST_WRITABLE);
157 }
158
grpc_chttp2_list_add_writing_stream(grpc_chttp2_transport * t,grpc_chttp2_stream * s)159 bool grpc_chttp2_list_add_writing_stream(grpc_chttp2_transport* t,
160 grpc_chttp2_stream* s) {
161 return stream_list_add(t, s, GRPC_CHTTP2_LIST_WRITING);
162 }
163
grpc_chttp2_list_have_writing_streams(grpc_chttp2_transport * t)164 bool grpc_chttp2_list_have_writing_streams(grpc_chttp2_transport* t) {
165 return !stream_list_empty(t, GRPC_CHTTP2_LIST_WRITING);
166 }
167
grpc_chttp2_list_pop_writing_stream(grpc_chttp2_transport * t,grpc_chttp2_stream ** s)168 bool grpc_chttp2_list_pop_writing_stream(grpc_chttp2_transport* t,
169 grpc_chttp2_stream** s) {
170 return stream_list_pop(t, s, GRPC_CHTTP2_LIST_WRITING);
171 }
172
grpc_chttp2_list_add_waiting_for_concurrency(grpc_chttp2_transport * t,grpc_chttp2_stream * s)173 void grpc_chttp2_list_add_waiting_for_concurrency(grpc_chttp2_transport* t,
174 grpc_chttp2_stream* s) {
175 stream_list_add(t, s, GRPC_CHTTP2_LIST_WAITING_FOR_CONCURRENCY);
176 }
177
grpc_chttp2_list_pop_waiting_for_concurrency(grpc_chttp2_transport * t,grpc_chttp2_stream ** s)178 bool grpc_chttp2_list_pop_waiting_for_concurrency(grpc_chttp2_transport* t,
179 grpc_chttp2_stream** s) {
180 return stream_list_pop(t, s, GRPC_CHTTP2_LIST_WAITING_FOR_CONCURRENCY);
181 }
182
grpc_chttp2_list_remove_waiting_for_concurrency(grpc_chttp2_transport * t,grpc_chttp2_stream * s)183 void grpc_chttp2_list_remove_waiting_for_concurrency(grpc_chttp2_transport* t,
184 grpc_chttp2_stream* s) {
185 stream_list_maybe_remove(t, s, GRPC_CHTTP2_LIST_WAITING_FOR_CONCURRENCY);
186 }
187
grpc_chttp2_list_add_stalled_by_transport(grpc_chttp2_transport * t,grpc_chttp2_stream * s)188 void grpc_chttp2_list_add_stalled_by_transport(grpc_chttp2_transport* t,
189 grpc_chttp2_stream* s) {
190 stream_list_add(t, s, GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT);
191 }
192
grpc_chttp2_list_pop_stalled_by_transport(grpc_chttp2_transport * t,grpc_chttp2_stream ** s)193 bool grpc_chttp2_list_pop_stalled_by_transport(grpc_chttp2_transport* t,
194 grpc_chttp2_stream** s) {
195 return stream_list_pop(t, s, GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT);
196 }
197
grpc_chttp2_list_remove_stalled_by_transport(grpc_chttp2_transport * t,grpc_chttp2_stream * s)198 void grpc_chttp2_list_remove_stalled_by_transport(grpc_chttp2_transport* t,
199 grpc_chttp2_stream* s) {
200 stream_list_maybe_remove(t, s, GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT);
201 }
202
grpc_chttp2_list_add_stalled_by_stream(grpc_chttp2_transport * t,grpc_chttp2_stream * s)203 void grpc_chttp2_list_add_stalled_by_stream(grpc_chttp2_transport* t,
204 grpc_chttp2_stream* s) {
205 stream_list_add(t, s, GRPC_CHTTP2_LIST_STALLED_BY_STREAM);
206 }
207
grpc_chttp2_list_pop_stalled_by_stream(grpc_chttp2_transport * t,grpc_chttp2_stream ** s)208 bool grpc_chttp2_list_pop_stalled_by_stream(grpc_chttp2_transport* t,
209 grpc_chttp2_stream** s) {
210 return stream_list_pop(t, s, GRPC_CHTTP2_LIST_STALLED_BY_STREAM);
211 }
212
grpc_chttp2_list_remove_stalled_by_stream(grpc_chttp2_transport * t,grpc_chttp2_stream * s)213 bool grpc_chttp2_list_remove_stalled_by_stream(grpc_chttp2_transport* t,
214 grpc_chttp2_stream* s) {
215 return stream_list_maybe_remove(t, s, GRPC_CHTTP2_LIST_STALLED_BY_STREAM);
216 }
217