]>
Commit | Line | Data |
---|---|---|
b9863c88 MT |
1 | Index: modules/http2/h2_bucket_beam.c |
2 | =================================================================== | |
3 | --- modules/http2/h2_bucket_beam.c (revision 1804645) | |
4 | +++ modules/http2/h2_bucket_beam.c (working copy) | |
5 | @@ -287,7 +287,7 @@ | |
6 | /* do not count */ | |
7 | } | |
8 | else if (APR_BUCKET_IS_FILE(b)) { | |
9 | - /* if unread, has no real mem footprint. how to test? */ | |
10 | + /* if unread, has no real mem footprint. */ | |
11 | } | |
12 | else { | |
13 | len += b->length; | |
14 | @@ -316,32 +316,80 @@ | |
15 | return APR_SIZE_MAX; | |
16 | } | |
17 | ||
18 | -static apr_status_t wait_cond(h2_bucket_beam *beam, apr_thread_mutex_t *lock) | |
19 | +static int buffer_is_empty(h2_bucket_beam *beam) | |
20 | { | |
21 | - if (beam->timeout > 0) { | |
22 | - return apr_thread_cond_timedwait(beam->cond, lock, beam->timeout); | |
23 | + return ((!beam->recv_buffer || APR_BRIGADE_EMPTY(beam->recv_buffer)) | |
24 | + && H2_BLIST_EMPTY(&beam->send_list)); | |
25 | +} | |
26 | + | |
27 | +static apr_status_t wait_empty(h2_bucket_beam *beam, apr_read_type_e block, | |
28 | + apr_thread_mutex_t *lock) | |
29 | +{ | |
30 | + apr_status_t rv = APR_SUCCESS; | |
31 | + | |
32 | + while (!buffer_is_empty(beam) && APR_SUCCESS == rv) { | |
33 | + if (APR_BLOCK_READ != block || !lock) { | |
34 | + rv = APR_EAGAIN; | |
35 | + } | |
36 | + else if (beam->timeout > 0) { | |
37 | + rv = apr_thread_cond_timedwait(beam->change, lock, beam->timeout); | |
38 | + } | |
39 | + else { | |
40 | + rv = apr_thread_cond_wait(beam->change, lock); | |
41 | + } | |
42 | } | |
43 | - else { | |
44 | - return apr_thread_cond_wait(beam->cond, lock); | |
45 | + return rv; | |
46 | +} | |
47 | + | |
48 | +static apr_status_t wait_not_empty(h2_bucket_beam *beam, apr_read_type_e block, | |
49 | + apr_thread_mutex_t *lock) | |
50 | +{ | |
51 | + apr_status_t rv = APR_SUCCESS; | |
52 | + | |
53 | + while (buffer_is_empty(beam) && APR_SUCCESS == rv) { | |
54 | + if (beam->aborted) { | |
55 | + rv = APR_ECONNABORTED; | |
56 | + } | |
57 | + else if (beam->closed) { | |
58 | + rv = APR_EOF; | |
59 | + } | |
60 | + else if (APR_BLOCK_READ != block || !lock) { | |
61 | + rv = APR_EAGAIN; | |
62 | + } | |
63 | + else if (beam->timeout > 0) { | |
64 | + rv = apr_thread_cond_timedwait(beam->change, lock, beam->timeout); | |
65 | + } | |
66 | + else { | |
67 | + rv = apr_thread_cond_wait(beam->change, lock); | |
68 | + } | |
69 | } | |
70 | + return rv; | |
71 | } | |
72 | ||
73 | -static apr_status_t r_wait_space(h2_bucket_beam *beam, apr_read_type_e block, | |
74 | - h2_beam_lock *pbl, apr_size_t *premain) | |
75 | +static apr_status_t wait_not_full(h2_bucket_beam *beam, apr_read_type_e block, | |
76 | + apr_size_t *pspace_left, h2_beam_lock *bl) | |
77 | { | |
78 | - *premain = calc_space_left(beam); | |
79 | - while (!beam->aborted && *premain <= 0 | |
80 | - && (block == APR_BLOCK_READ) && pbl->mutex) { | |
81 | - apr_status_t status; | |
82 | - report_prod_io(beam, 1, pbl); | |
83 | - status = wait_cond(beam, pbl->mutex); | |
84 | - if (APR_STATUS_IS_TIMEUP(status)) { | |
85 | - return status; | |
86 | + apr_status_t rv = APR_SUCCESS; | |
87 | + apr_size_t left; | |
88 | + | |
89 | + while (0 == (left = calc_space_left(beam)) && APR_SUCCESS == rv) { | |
90 | + if (beam->aborted) { | |
91 | + rv = APR_ECONNABORTED; | |
92 | } | |
93 | - r_purge_sent(beam); | |
94 | - *premain = calc_space_left(beam); | |
95 | + else if (block != APR_BLOCK_READ || !bl->mutex) { | |
96 | + rv = APR_EAGAIN; | |
97 | + } | |
98 | + else { | |
99 | + if (beam->timeout > 0) { | |
100 | + rv = apr_thread_cond_timedwait(beam->change, bl->mutex, beam->timeout); | |
101 | + } | |
102 | + else { | |
103 | + rv = apr_thread_cond_wait(beam->change, bl->mutex); | |
104 | + } | |
105 | + } | |
106 | } | |
107 | - return beam->aborted? APR_ECONNABORTED : APR_SUCCESS; | |
108 | + *pspace_left = left; | |
109 | + return rv; | |
110 | } | |
111 | ||
112 | static void h2_beam_emitted(h2_bucket_beam *beam, h2_beam_proxy *proxy) | |
113 | @@ -404,8 +452,8 @@ | |
114 | if (!bl.mutex) { | |
115 | r_purge_sent(beam); | |
116 | } | |
117 | - else if (beam->cond) { | |
118 | - apr_thread_cond_broadcast(beam->cond); | |
119 | + else { | |
120 | + apr_thread_cond_broadcast(beam->change); | |
121 | } | |
122 | leave_yellow(beam, &bl); | |
123 | } | |
124 | @@ -425,9 +473,7 @@ | |
125 | { | |
126 | if (!beam->closed) { | |
127 | beam->closed = 1; | |
128 | - if (beam->cond) { | |
129 | - apr_thread_cond_broadcast(beam->cond); | |
130 | - } | |
131 | + apr_thread_cond_broadcast(beam->change); | |
132 | } | |
133 | return APR_SUCCESS; | |
134 | } | |
135 | @@ -582,7 +628,7 @@ | |
136 | apr_interval_time_t timeout) | |
137 | { | |
138 | h2_bucket_beam *beam; | |
139 | - apr_status_t status = APR_SUCCESS; | |
140 | + apr_status_t rv = APR_SUCCESS; | |
141 | ||
142 | beam = apr_pcalloc(pool, sizeof(*beam)); | |
143 | if (!beam) { | |
144 | @@ -601,16 +647,15 @@ | |
145 | beam->max_buf_size = max_buf_size; | |
146 | beam->timeout = timeout; | |
147 | ||
148 | - status = apr_thread_mutex_create(&beam->lock, APR_THREAD_MUTEX_DEFAULT, | |
149 | - pool); | |
150 | - if (status == APR_SUCCESS) { | |
151 | - status = apr_thread_cond_create(&beam->cond, pool); | |
152 | - if (status == APR_SUCCESS) { | |
153 | + rv = apr_thread_mutex_create(&beam->lock, APR_THREAD_MUTEX_DEFAULT, pool); | |
154 | + if (APR_SUCCESS == rv) { | |
155 | + rv = apr_thread_cond_create(&beam->change, pool); | |
156 | + if (APR_SUCCESS == rv) { | |
157 | apr_pool_pre_cleanup_register(pool, beam, beam_cleanup); | |
158 | *pbeam = beam; | |
159 | } | |
160 | } | |
161 | - return status; | |
162 | + return rv; | |
163 | } | |
164 | ||
165 | void h2_beam_buffer_size_set(h2_bucket_beam *beam, apr_size_t buffer_size) | |
166 | @@ -691,9 +736,7 @@ | |
167 | h2_blist_cleanup(&beam->send_list); | |
168 | report_consumption(beam, &bl); | |
169 | } | |
170 | - if (beam->cond) { | |
171 | - apr_thread_cond_broadcast(beam->cond); | |
172 | - } | |
173 | + apr_thread_cond_broadcast(beam->change); | |
174 | leave_yellow(beam, &bl); | |
175 | } | |
176 | } | |
177 | @@ -730,18 +773,7 @@ | |
178 | h2_beam_lock bl; | |
179 | ||
180 | if ((status = enter_yellow(beam, &bl)) == APR_SUCCESS) { | |
181 | - while (status == APR_SUCCESS | |
182 | - && !H2_BLIST_EMPTY(&beam->send_list) | |
183 | - && !H2_BPROXY_LIST_EMPTY(&beam->proxies)) { | |
184 | - if (block == APR_NONBLOCK_READ || !bl.mutex) { | |
185 | - status = APR_EAGAIN; | |
186 | - break; | |
187 | - } | |
188 | - if (beam->cond) { | |
189 | - apr_thread_cond_broadcast(beam->cond); | |
190 | - } | |
191 | - status = wait_cond(beam, bl.mutex); | |
192 | - } | |
193 | + status = wait_empty(beam, block, bl.mutex); | |
194 | leave_yellow(beam, &bl); | |
195 | } | |
196 | return status; | |
197 | @@ -761,13 +793,18 @@ | |
198 | static apr_status_t append_bucket(h2_bucket_beam *beam, | |
199 | apr_bucket *b, | |
200 | apr_read_type_e block, | |
201 | + apr_size_t *pspace_left, | |
202 | h2_beam_lock *pbl) | |
203 | { | |
204 | const char *data; | |
205 | apr_size_t len; | |
206 | - apr_size_t space_left = 0; | |
207 | apr_status_t status; | |
208 | + int can_beam, check_len; | |
209 | ||
210 | + if (beam->aborted) { | |
211 | + return APR_ECONNABORTED; | |
212 | + } | |
213 | + | |
214 | if (APR_BUCKET_IS_METADATA(b)) { | |
215 | if (APR_BUCKET_IS_EOS(b)) { | |
216 | beam->closed = 1; | |
217 | @@ -777,11 +814,31 @@ | |
218 | return APR_SUCCESS; | |
219 | } | |
220 | else if (APR_BUCKET_IS_FILE(b)) { | |
221 | - /* file bucket lengths do not really count */ | |
222 | + /* For file buckets the problem is their internal readpool that | |
223 | + * is used on the first read to allocate buffer/mmap. | |
224 | + * Since setting aside a file bucket will de-register the | |
225 | + * file cleanup function from the previous pool, we need to | |
226 | + * call that only from the sender thread. | |
227 | + * | |
228 | + * Currently, we do not handle file bucket with refcount > 1 as | |
229 | + * the beam is then not in complete control of the file's lifetime. | |
230 | + * Which results in the bug that a file get closed by the receiver | |
231 | + * while the sender or the beam still have buckets using it. | |
232 | + * | |
233 | + * Additionally, we allow callbacks to prevent beaming file | |
234 | + * handles across. The use case for this is to limit the number | |
235 | + * of open file handles and rather use a less efficient beam | |
236 | + * transport. */ | |
237 | + apr_bucket_file *bf = b->data; | |
238 | + apr_file_t *fd = bf->fd; | |
239 | + can_beam = (bf->refcount.refcount == 1); | |
240 | + if (can_beam && beam->can_beam_fn) { | |
241 | + can_beam = beam->can_beam_fn(beam->can_beam_ctx, beam, fd); | |
242 | + } | |
243 | + check_len = !can_beam; | |
244 | } | |
245 | else { | |
246 | - space_left = calc_space_left(beam); | |
247 | - if (space_left > 0 && b->length == ((apr_size_t)-1)) { | |
248 | + if (b->length == ((apr_size_t)-1)) { | |
249 | const char *data; | |
250 | status = apr_bucket_read(b, &data, &len, APR_BLOCK_READ); | |
251 | if (status != APR_SUCCESS) { | |
252 | @@ -788,19 +845,15 @@ | |
253 | return status; | |
254 | } | |
255 | } | |
256 | - | |
257 | - if (space_left <= 0) { | |
258 | - status = r_wait_space(beam, block, pbl, &space_left); | |
259 | - if (status != APR_SUCCESS) { | |
260 | - return status; | |
261 | - } | |
262 | - if (space_left <= 0) { | |
263 | - return APR_EAGAIN; | |
264 | - } | |
265 | + check_len = 1; | |
266 | + } | |
267 | + | |
268 | + if (check_len) { | |
269 | + if (b->length > *pspace_left) { | |
270 | + apr_bucket_split(b, *pspace_left); | |
271 | } | |
272 | - /* space available, maybe need bucket split */ | |
273 | + *pspace_left -= b->length; | |
274 | } | |
275 | - | |
276 | ||
277 | /* The fundamental problem is that reading a sender bucket from | |
278 | * a receiver thread is a total NO GO, because the bucket might use | |
279 | @@ -830,32 +883,8 @@ | |
280 | apr_bucket_heap_make(b, data, len, NULL); | |
281 | } | |
282 | } | |
283 | - else if (APR_BUCKET_IS_FILE(b)) { | |
284 | - /* For file buckets the problem is their internal readpool that | |
285 | - * is used on the first read to allocate buffer/mmap. | |
286 | - * Since setting aside a file bucket will de-register the | |
287 | - * file cleanup function from the previous pool, we need to | |
288 | - * call that only from the sender thread. | |
289 | - * | |
290 | - * Currently, we do not handle file bucket with refcount > 1 as | |
291 | - * the beam is then not in complete control of the file's lifetime. | |
292 | - * Which results in the bug that a file get closed by the receiver | |
293 | - * while the sender or the beam still have buckets using it. | |
294 | - * | |
295 | - * Additionally, we allow callbacks to prevent beaming file | |
296 | - * handles across. The use case for this is to limit the number | |
297 | - * of open file handles and rather use a less efficient beam | |
298 | - * transport. */ | |
299 | - apr_bucket_file *bf = b->data; | |
300 | - apr_file_t *fd = bf->fd; | |
301 | - int can_beam = (bf->refcount.refcount == 1); | |
302 | - if (can_beam && beam->can_beam_fn) { | |
303 | - can_beam = beam->can_beam_fn(beam->can_beam_ctx, beam, fd); | |
304 | - } | |
305 | - if (can_beam) { | |
306 | - status = apr_bucket_setaside(b, beam->send_pool); | |
307 | - } | |
308 | - /* else: enter ENOTIMPL case below */ | |
309 | + else if (APR_BUCKET_IS_FILE(b) && can_beam) { | |
310 | + status = apr_bucket_setaside(b, beam->send_pool); | |
311 | } | |
312 | ||
313 | if (status == APR_ENOTIMPL) { | |
314 | @@ -865,12 +894,6 @@ | |
315 | * a counter example). | |
316 | * We do the read while in the sender thread, so that the bucket may | |
317 | * use pools/allocators safely. */ | |
318 | - if (space_left < APR_BUCKET_BUFF_SIZE) { | |
319 | - space_left = APR_BUCKET_BUFF_SIZE; | |
320 | - } | |
321 | - if (space_left < b->length) { | |
322 | - apr_bucket_split(b, space_left); | |
323 | - } | |
324 | status = apr_bucket_read(b, &data, &len, APR_BLOCK_READ); | |
325 | if (status == APR_SUCCESS) { | |
326 | status = apr_bucket_setaside(b, beam->send_pool); | |
327 | @@ -884,7 +907,7 @@ | |
328 | APR_BUCKET_REMOVE(b); | |
329 | H2_BLIST_INSERT_TAIL(&beam->send_list, b); | |
330 | beam->sent_bytes += b->length; | |
331 | - | |
332 | + | |
333 | return APR_SUCCESS; | |
334 | } | |
335 | ||
336 | @@ -904,7 +927,8 @@ | |
337 | apr_read_type_e block) | |
338 | { | |
339 | apr_bucket *b; | |
340 | - apr_status_t status = APR_SUCCESS; | |
341 | + apr_status_t rv = APR_SUCCESS; | |
342 | + apr_size_t space_left = 0; | |
343 | h2_beam_lock bl; | |
344 | ||
345 | /* Called from the sender thread to add buckets to the beam */ | |
346 | @@ -914,23 +938,31 @@ | |
347 | ||
348 | if (beam->aborted) { | |
349 | move_to_hold(beam, sender_bb); | |
350 | - status = APR_ECONNABORTED; | |
351 | + rv = APR_ECONNABORTED; | |
352 | } | |
353 | else if (sender_bb) { | |
354 | - int force_report = !APR_BRIGADE_EMPTY(sender_bb); | |
355 | - while (!APR_BRIGADE_EMPTY(sender_bb) && status == APR_SUCCESS) { | |
356 | + int force_report = !APR_BRIGADE_EMPTY(sender_bb); | |
357 | + | |
358 | + space_left = calc_space_left(beam); | |
359 | + while (!APR_BRIGADE_EMPTY(sender_bb) && APR_SUCCESS == rv) { | |
360 | + if (space_left <= 0) { | |
361 | + report_prod_io(beam, force_report, &bl); | |
362 | + rv = wait_not_full(beam, block, &space_left, &bl); | |
363 | + if (APR_SUCCESS != rv) { | |
364 | + break; | |
365 | + } | |
366 | + } | |
367 | b = APR_BRIGADE_FIRST(sender_bb); | |
368 | - status = append_bucket(beam, b, block, &bl); | |
369 | + rv = append_bucket(beam, b, block, &space_left, &bl); | |
370 | } | |
371 | + | |
372 | report_prod_io(beam, force_report, &bl); | |
373 | - if (beam->cond) { | |
374 | - apr_thread_cond_broadcast(beam->cond); | |
375 | - } | |
376 | + apr_thread_cond_broadcast(beam->change); | |
377 | } | |
378 | report_consumption(beam, &bl); | |
379 | leave_yellow(beam, &bl); | |
380 | } | |
381 | - return status; | |
382 | + return rv; | |
383 | } | |
384 | ||
385 | apr_status_t h2_beam_receive(h2_bucket_beam *beam, | |
386 | @@ -942,11 +974,16 @@ | |
387 | apr_bucket *bsender, *brecv, *ng; | |
388 | int transferred = 0; | |
389 | apr_status_t status = APR_SUCCESS; | |
390 | - apr_off_t remain = readbytes; | |
391 | + apr_off_t remain; | |
392 | int transferred_buckets = 0; | |
393 | ||
394 | /* Called from the receiver thread to take buckets from the beam */ | |
395 | if (enter_yellow(beam, &bl) == APR_SUCCESS) { | |
396 | + if (readbytes <= 0) { | |
397 | + readbytes = APR_SIZE_MAX; | |
398 | + } | |
399 | + remain = readbytes; | |
400 | + | |
401 | transfer: | |
402 | if (beam->aborted) { | |
403 | recv_buffer_cleanup(beam, &bl); | |
404 | @@ -955,11 +992,12 @@ | |
405 | } | |
406 | ||
407 | /* transfer enough buckets from our receiver brigade, if we have one */ | |
408 | - while (beam->recv_buffer | |
409 | - && !APR_BRIGADE_EMPTY(beam->recv_buffer) | |
410 | - && (readbytes <= 0 || remain >= 0)) { | |
411 | + while (remain >= 0 | |
412 | + && beam->recv_buffer | |
413 | + && !APR_BRIGADE_EMPTY(beam->recv_buffer)) { | |
414 | + | |
415 | brecv = APR_BRIGADE_FIRST(beam->recv_buffer); | |
416 | - if (readbytes > 0 && brecv->length > 0 && remain <= 0) { | |
417 | + if (brecv->length > 0 && remain <= 0) { | |
418 | break; | |
419 | } | |
420 | APR_BUCKET_REMOVE(brecv); | |
421 | @@ -970,11 +1008,11 @@ | |
422 | ||
423 | /* transfer from our sender brigade, transforming sender buckets to | |
424 | * receiver ones until we have enough */ | |
425 | - while (!H2_BLIST_EMPTY(&beam->send_list) && (readbytes <= 0 || remain >= 0)) { | |
426 | - bsender = H2_BLIST_FIRST(&beam->send_list); | |
427 | + while (remain >= 0 && !H2_BLIST_EMPTY(&beam->send_list)) { | |
428 | + | |
429 | brecv = NULL; | |
430 | - | |
431 | - if (readbytes > 0 && bsender->length > 0 && remain <= 0) { | |
432 | + bsender = H2_BLIST_FIRST(&beam->send_list); | |
433 | + if (bsender->length > 0 && remain <= 0) { | |
434 | break; | |
435 | } | |
436 | ||
437 | @@ -1020,11 +1058,12 @@ | |
438 | * been handed out. See also PR 59348 */ | |
439 | apr_bucket_file_enable_mmap(ng, 0); | |
440 | #endif | |
441 | - remain -= bsender->length; | |
442 | - ++transferred; | |
443 | APR_BUCKET_REMOVE(bsender); | |
444 | H2_BLIST_INSERT_TAIL(&beam->hold_list, bsender); | |
445 | + | |
446 | + remain -= bsender->length; | |
447 | ++transferred; | |
448 | + ++transferred_buckets; | |
449 | continue; | |
450 | } | |
451 | else { | |
452 | @@ -1041,6 +1080,7 @@ | |
453 | * receiver bucket references it any more. */ | |
454 | APR_BUCKET_REMOVE(bsender); | |
455 | H2_BLIST_INSERT_TAIL(&beam->hold_list, bsender); | |
456 | + | |
457 | beam->received_bytes += bsender->length; | |
458 | ++transferred_buckets; | |
459 | ||
460 | @@ -1063,8 +1103,8 @@ | |
461 | } | |
462 | } | |
463 | ||
464 | - if (readbytes > 0 && remain < 0) { | |
465 | - /* too much, put some back */ | |
466 | + if (remain < 0) { | |
467 | + /* too much, put some back into out recv_buffer */ | |
468 | remain = readbytes; | |
469 | for (brecv = APR_BRIGADE_FIRST(bb); | |
470 | brecv != APR_BRIGADE_SENTINEL(bb); | |
471 | @@ -1081,15 +1121,7 @@ | |
472 | } | |
473 | } | |
474 | ||
475 | - if (transferred_buckets > 0) { | |
476 | - if (beam->cons_ev_cb) { | |
477 | - beam->cons_ev_cb(beam->cons_ctx, beam); | |
478 | - } | |
479 | - } | |
480 | - | |
481 | - if (beam->closed | |
482 | - && (!beam->recv_buffer || APR_BRIGADE_EMPTY(beam->recv_buffer)) | |
483 | - && H2_BLIST_EMPTY(&beam->send_list)) { | |
484 | + if (beam->closed && buffer_is_empty(beam)) { | |
485 | /* beam is closed and we have nothing more to receive */ | |
486 | if (!beam->close_sent) { | |
487 | apr_bucket *b = apr_bucket_eos_create(bb->bucket_alloc); | |
488 | @@ -1100,28 +1132,23 @@ | |
489 | } | |
490 | } | |
491 | ||
492 | + if (transferred_buckets > 0) { | |
493 | + if (beam->cons_ev_cb) { | |
494 | + beam->cons_ev_cb(beam->cons_ctx, beam); | |
495 | + } | |
496 | + } | |
497 | + | |
498 | if (transferred) { | |
499 | - if (beam->cond) { | |
500 | - apr_thread_cond_broadcast(beam->cond); | |
501 | - } | |
502 | + apr_thread_cond_broadcast(beam->change); | |
503 | status = APR_SUCCESS; | |
504 | } | |
505 | - else if (beam->closed) { | |
506 | - status = APR_EOF; | |
507 | - } | |
508 | - else if (block == APR_BLOCK_READ && bl.mutex && beam->cond) { | |
509 | - status = wait_cond(beam, bl.mutex); | |
510 | + else { | |
511 | + status = wait_not_empty(beam, block, bl.mutex); | |
512 | if (status != APR_SUCCESS) { | |
513 | goto leave; | |
514 | } | |
515 | goto transfer; | |
516 | } | |
517 | - else { | |
518 | - if (beam->cond) { | |
519 | - apr_thread_cond_broadcast(beam->cond); | |
520 | - } | |
521 | - status = APR_EAGAIN; | |
522 | - } | |
523 | leave: | |
524 | leave_yellow(beam, &bl); | |
525 | } | |
526 | Index: modules/http2/h2_bucket_beam.h | |
527 | =================================================================== | |
528 | --- modules/http2/h2_bucket_beam.h (revision 1804645) | |
529 | +++ modules/http2/h2_bucket_beam.h (working copy) | |
530 | @@ -190,7 +190,7 @@ | |
531 | unsigned int tx_mem_limits : 1; /* only memory size counts on transfers */ | |
532 | ||
533 | struct apr_thread_mutex_t *lock; | |
534 | - struct apr_thread_cond_t *cond; | |
535 | + struct apr_thread_cond_t *change; | |
536 | void *m_ctx; | |
537 | h2_beam_mutex_enter *m_enter; | |
538 | ||
539 | Index: modules/http2/h2_stream.c | |
540 | =================================================================== | |
541 | --- modules/http2/h2_stream.c (revision 1804645) | |
542 | +++ modules/http2/h2_stream.c (working copy) | |
543 | @@ -774,20 +774,20 @@ | |
544 | return NULL; | |
545 | } | |
546 | ||
547 | -static apr_status_t add_data(h2_stream *stream, apr_off_t requested, | |
548 | - apr_off_t *plen, int *peos, int *complete, | |
549 | - h2_headers **pheaders) | |
550 | +static apr_status_t add_buffered_data(h2_stream *stream, apr_off_t requested, | |
551 | + apr_off_t *plen, int *peos, int *is_all, | |
552 | + h2_headers **pheaders) | |
553 | { | |
554 | apr_bucket *b, *e; | |
555 | ||
556 | *peos = 0; | |
557 | *plen = 0; | |
558 | - *complete = 0; | |
559 | + *is_all = 0; | |
560 | if (pheaders) { | |
561 | *pheaders = NULL; | |
562 | } | |
563 | ||
564 | - H2_STREAM_OUT_LOG(APLOG_TRACE2, stream, "add_data"); | |
565 | + H2_STREAM_OUT_LOG(APLOG_TRACE2, stream, "add_buffered_data"); | |
566 | b = APR_BRIGADE_FIRST(stream->out_buffer); | |
567 | while (b != APR_BRIGADE_SENTINEL(stream->out_buffer)) { | |
568 | e = APR_BUCKET_NEXT(b); | |
569 | @@ -833,7 +833,7 @@ | |
570 | } | |
571 | b = e; | |
572 | } | |
573 | - *complete = 1; | |
574 | + *is_all = 1; | |
575 | return APR_SUCCESS; | |
576 | } | |
577 | ||
578 | @@ -865,7 +865,7 @@ | |
579 | requested = (*plen > 0)? H2MIN(*plen, max_chunk) : max_chunk; | |
580 | ||
581 | /* count the buffered data until eos or a headers bucket */ | |
582 | - status = add_data(stream, requested, plen, peos, &complete, pheaders); | |
583 | + status = add_buffered_data(stream, requested, plen, peos, &complete, pheaders); | |
584 | ||
585 | if (status == APR_EAGAIN) { | |
586 | /* TODO: ugly, someone needs to retrieve the response first */ | |
587 | @@ -882,29 +882,39 @@ | |
588 | return APR_SUCCESS; | |
589 | } | |
590 | ||
591 | + /* If there we do not have enough buffered data to satisfy the requested | |
592 | + * length *and* we counted the _complete_ buffer (and did not stop in the middle | |
593 | + * because of meta data there), lets see if we can read more from the | |
594 | + * output beam */ | |
595 | missing = H2MIN(requested, stream->max_mem) - *plen; | |
596 | if (complete && !*peos && missing > 0) { | |
597 | + apr_status_t rv = APR_EOF; | |
598 | + | |
599 | if (stream->output) { | |
600 | H2_STREAM_OUT_LOG(APLOG_TRACE2, stream, "pre"); | |
601 | - status = h2_beam_receive(stream->output, stream->out_buffer, | |
602 | - APR_NONBLOCK_READ, | |
603 | - stream->max_mem - *plen); | |
604 | + rv = h2_beam_receive(stream->output, stream->out_buffer, | |
605 | + APR_NONBLOCK_READ, stream->max_mem - *plen); | |
606 | H2_STREAM_OUT_LOG(APLOG_TRACE2, stream, "post"); | |
607 | } | |
608 | - else { | |
609 | - status = APR_EOF; | |
610 | + | |
611 | + if (rv == APR_SUCCESS) { | |
612 | + /* count the buffer again, now that we have read output */ | |
613 | + status = add_buffered_data(stream, requested, plen, peos, &complete, pheaders); | |
614 | } | |
615 | - | |
616 | - if (APR_STATUS_IS_EOF(status)) { | |
617 | + else if (APR_STATUS_IS_EOF(rv)) { | |
618 | apr_bucket *eos = apr_bucket_eos_create(c->bucket_alloc); | |
619 | APR_BRIGADE_INSERT_TAIL(stream->out_buffer, eos); | |
620 | *peos = 1; | |
621 | - status = APR_SUCCESS; | |
622 | } | |
623 | - else if (status == APR_SUCCESS) { | |
624 | - /* do it again, now that we have gotten more */ | |
625 | - status = add_data(stream, requested, plen, peos, &complete, pheaders); | |
626 | + else if (APR_STATUS_IS_EAGAIN(rv)) { | |
627 | + /* we set this is the status of this call only if there | |
628 | + * is no buffered data, see check below */ | |
629 | } | |
630 | + else { | |
631 | + /* real error reading. Give this back directly, even though | |
632 | + * we may have something buffered. */ | |
633 | + status = rv; | |
634 | + } | |
635 | } | |
636 | ||
637 | if (status == APR_SUCCESS) { | |
638 | Index: modules/http2/h2_task.c | |
639 | =================================================================== | |
640 | --- modules/http2/h2_task.c (revision 1804645) | |
641 | +++ modules/http2/h2_task.c (working copy) | |
642 | @@ -129,7 +129,7 @@ | |
643 | apr_bucket_brigade* bb) | |
644 | { | |
645 | apr_bucket *b; | |
646 | - apr_status_t status = APR_SUCCESS; | |
647 | + apr_status_t rv = APR_SUCCESS; | |
648 | int flush = 0, blocking; | |
649 | ||
650 | if (task->frozen) { | |
651 | @@ -148,17 +148,16 @@ | |
652 | return APR_SUCCESS; | |
653 | } | |
654 | ||
655 | +send: | |
656 | /* we send block once we opened the output, so someone is there | |
657 | * reading it *and* the task is not assigned to a h2_req_engine */ | |
658 | blocking = (!task->assigned && task->output.opened); | |
659 | - if (!task->output.opened) { | |
660 | - for (b = APR_BRIGADE_FIRST(bb); | |
661 | - b != APR_BRIGADE_SENTINEL(bb); | |
662 | - b = APR_BUCKET_NEXT(b)) { | |
663 | - if (APR_BUCKET_IS_FLUSH(b)) { | |
664 | - flush = 1; | |
665 | - break; | |
666 | - } | |
667 | + for (b = APR_BRIGADE_FIRST(bb); | |
668 | + b != APR_BRIGADE_SENTINEL(bb); | |
669 | + b = APR_BUCKET_NEXT(b)) { | |
670 | + if (APR_BUCKET_IS_FLUSH(b) || APR_BUCKET_IS_EOS(b) || AP_BUCKET_IS_EOR(b)) { | |
671 | + flush = 1; | |
672 | + break; | |
673 | } | |
674 | } | |
675 | ||
676 | @@ -166,32 +165,48 @@ | |
677 | /* still have data buffered from previous attempt. | |
678 | * setaside and append new data and try to pass the complete data */ | |
679 | if (!APR_BRIGADE_EMPTY(bb)) { | |
680 | - status = ap_save_brigade(f, &task->output.bb, &bb, task->pool); | |
681 | + if (APR_SUCCESS != (rv = ap_save_brigade(f, &task->output.bb, &bb, task->pool))) { | |
682 | + goto out; | |
683 | + } | |
684 | } | |
685 | - if (status == APR_SUCCESS) { | |
686 | - status = send_out(task, task->output.bb, blocking); | |
687 | - } | |
688 | + rv = send_out(task, task->output.bb, blocking); | |
689 | } | |
690 | else { | |
691 | - /* no data buffered here, try to pass the brigade directly */ | |
692 | - status = send_out(task, bb, blocking); | |
693 | - if (status == APR_SUCCESS && !APR_BRIGADE_EMPTY(bb)) { | |
694 | - /* could not write all, buffer the rest */ | |
695 | - ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, task->c, APLOGNO(03405) | |
696 | - "h2_slave_out(%s): saving brigade", | |
697 | - task->id); | |
698 | - status = ap_save_brigade(f, &task->output.bb, &bb, task->pool); | |
699 | - flush = 1; | |
700 | + /* no data buffered previously, pass brigade directly */ | |
701 | + rv = send_out(task, bb, blocking); | |
702 | + | |
703 | + if (APR_SUCCESS == rv && !APR_BRIGADE_EMPTY(bb)) { | |
704 | + /* output refused to buffer it all, time to open? */ | |
705 | + if (!task->output.opened && APR_SUCCESS == (rv = open_output(task))) { | |
706 | + /* Make another attempt to send the data. With the output open, | |
707 | + * the call might be blocking and send all data, so we do not need | |
708 | + * to save the brigade */ | |
709 | + goto send; | |
710 | + } | |
711 | + else if (blocking && flush) { | |
712 | + /* Need to keep on doing this. */ | |
713 | + goto send; | |
714 | + } | |
715 | + | |
716 | + if (APR_SUCCESS == rv) { | |
717 | + /* could not write all, buffer the rest */ | |
718 | + ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, task->c, APLOGNO(03405) | |
719 | + "h2_slave_out(%s): saving brigade", task->id); | |
720 | + ap_assert(NULL); | |
721 | + rv = ap_save_brigade(f, &task->output.bb, &bb, task->pool); | |
722 | + flush = 1; | |
723 | + } | |
724 | } | |
725 | } | |
726 | ||
727 | - if (status == APR_SUCCESS && !task->output.opened && flush) { | |
728 | + if (APR_SUCCESS == rv && !task->output.opened && flush) { | |
729 | /* got a flush or could not write all, time to tell someone to read */ | |
730 | - status = open_output(task); | |
731 | + rv = open_output(task); | |
732 | } | |
733 | - ap_log_cerror(APLOG_MARK, APLOG_TRACE2, status, task->c, | |
734 | +out: | |
735 | + ap_log_cerror(APLOG_MARK, APLOG_TRACE2, rv, task->c, | |
736 | "h2_slave_out(%s): slave_out leave", task->id); | |
737 | - return status; | |
738 | + return rv; | |
739 | } | |
740 | ||
741 | static apr_status_t output_finish(h2_task *task) | |
742 | Index: modules/http2/h2_version.h | |
743 | =================================================================== | |
744 | --- modules/http2/h2_version.h (revision 1804645) | |
745 | +++ modules/http2/h2_version.h (working copy) | |
746 | @@ -26,7 +26,7 @@ | |
747 | * @macro | |
748 | * Version number of the http2 module as c string | |
749 | */ | |
750 | -#define MOD_HTTP2_VERSION "1.10.7" | |
751 | +#define MOD_HTTP2_VERSION "1.10.10" | |
752 | ||
753 | /** | |
754 | * @macro | |
755 | @@ -34,7 +34,7 @@ | |
756 | * release. This is a 24 bit number with 8 bits for major number, 8 bits | |
757 | * for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203. | |
758 | */ | |
759 | -#define MOD_HTTP2_VERSION_NUM 0x010a06 | |
760 | +#define MOD_HTTP2_VERSION_NUM 0x010a0a | |
761 | ||
762 | ||
763 | #endif /* mod_h2_h2_version_h */ | |
764 | Index: modules/http2 | |
765 | =================================================================== | |
766 | --- modules/http2 (revision 1804645) | |
767 | +++ modules/http2 (working copy) | |
768 | ||
769 | Property changes on: modules/http2 | |
770 | ___________________________________________________________________ | |
771 | Modified: svn:mergeinfo | |
772 | ## -0,0 +0,1 ## | |
773 | Merged /httpd/httpd/trunk/modules/http2:r1803420,1803454,1804090 | |
774 | Index: . | |
775 | =================================================================== | |
776 | --- . (revision 1804645) | |
777 | +++ . (working copy) | |
778 | ||
779 | Property changes on: . | |
780 | ___________________________________________________________________ | |
781 | Modified: svn:mergeinfo | |
782 | ## -0,0 +0,1 ## | |
783 | Merged /httpd/httpd/trunk:r1803420,1803454,1804090 |