Fixed the potential dead lock in flow control.

This commit is contained in:
Tatsuhiro Tsujikawa 2012-02-28 21:40:19 +09:00
parent 3d1b411895
commit a452893068
1 changed files with 25 additions and 29 deletions

View File

@ -489,21 +489,21 @@ static int spdylay_session_is_window_update_allowed(spdylay_session *session,
} }
/* /*
* Returns the available window size. * Returns the maximum length of next data read. If the flow control
* is enabled, the return value takes into account the current window
* size.
*/ */
static size_t spdylay_session_avail_window(spdylay_session *session, static size_t spdylay_session_next_data_read(spdylay_session *session,
spdylay_stream *stream) spdylay_stream *stream)
{ {
if(session->flow_control == 0) { if(session->flow_control == 0) {
return SPDYLAY_DATA_PAYLOAD_LENGTH; return SPDYLAY_DATA_PAYLOAD_LENGTH;
} else { } else if(stream->window_size > 0) {
if(stream->window_size >= SPDYLAY_DATA_PAYLOAD_LENGTH || return stream->window_size < SPDYLAY_DATA_PAYLOAD_LENGTH ?
stream->initial_window_size < stream->window_size*2) { stream->window_size : SPDYLAY_DATA_PAYLOAD_LENGTH;
return stream->window_size;
} else { } else {
return 0; return 0;
} }
}
} }
static int spdylay_session_is_data_allowed(spdylay_session *session, static int spdylay_session_is_data_allowed(spdylay_session *session,
@ -660,7 +660,7 @@ static ssize_t spdylay_session_prep_frame(spdylay_session *session,
} }
break; break;
case SPDYLAY_DATA: { case SPDYLAY_DATA: {
size_t avail_window; size_t next_readmax;
spdylay_stream *stream; spdylay_stream *stream;
if(!spdylay_session_is_data_allowed(session, item->frame->data.stream_id)) { if(!spdylay_session_is_data_allowed(session, item->frame->data.stream_id)) {
return SPDYLAY_ERR_INVALID_FRAME; return SPDYLAY_ERR_INVALID_FRAME;
@ -668,17 +668,15 @@ static ssize_t spdylay_session_prep_frame(spdylay_session *session,
stream = spdylay_session_get_stream(session, item->frame->data.stream_id); stream = spdylay_session_get_stream(session, item->frame->data.stream_id);
/* Assuming stream is not NULL */ /* Assuming stream is not NULL */
assert(stream); assert(stream);
avail_window = spdylay_session_avail_window(session, stream); next_readmax = spdylay_session_next_data_read(session, stream);
if(avail_window == 0) { if(next_readmax == 0) {
spdylay_stream_defer_data(stream, item, SPDYLAY_DEFERRED_FLOW_CONTROL); spdylay_stream_defer_data(stream, item, SPDYLAY_DEFERRED_FLOW_CONTROL);
return SPDYLAY_ERR_DEFERRED; return SPDYLAY_ERR_DEFERRED;
} }
framebuflen = spdylay_session_pack_data framebuflen = spdylay_session_pack_data(session,
(session,
&session->aob.framebuf, &session->aob.framebuf,
&session->aob.framebufmax, &session->aob.framebufmax,
(avail_window < SPDYLAY_DATA_PAYLOAD_LENGTH) ? next_readmax,
avail_window : SPDYLAY_DATA_PAYLOAD_LENGTH,
&item->frame->data); &item->frame->data);
if(framebuflen == SPDYLAY_ERR_DEFERRED) { if(framebuflen == SPDYLAY_ERR_DEFERRED) {
spdylay_stream_defer_data(stream, item, SPDYLAY_DEFERRED_NONE); spdylay_stream_defer_data(stream, item, SPDYLAY_DEFERRED_NONE);
@ -927,25 +925,23 @@ static int spdylay_session_after_frame_sent(spdylay_session *session)
waiting at the top of the queue, we continue to send this waiting at the top of the queue, we continue to send this
data. */ data. */
if(item == NULL || session->aob.item->pri <= item->pri) { if(item == NULL || session->aob.item->pri <= item->pri) {
size_t avail_window; size_t next_readmax;
spdylay_stream *stream; spdylay_stream *stream;
stream = spdylay_session_get_stream(session, frame->data.stream_id); stream = spdylay_session_get_stream(session, frame->data.stream_id);
/* Assuming stream is not NULL */ /* Assuming stream is not NULL */
assert(stream); assert(stream);
avail_window = spdylay_session_avail_window(session, stream); next_readmax = spdylay_session_next_data_read(session, stream);
if(avail_window == 0) { if(next_readmax == 0) {
spdylay_stream_defer_data(stream, session->aob.item, spdylay_stream_defer_data(stream, session->aob.item,
SPDYLAY_DEFERRED_FLOW_CONTROL); SPDYLAY_DEFERRED_FLOW_CONTROL);
session->aob.item = NULL; session->aob.item = NULL;
spdylay_active_outbound_item_reset(&session->aob); spdylay_active_outbound_item_reset(&session->aob);
return 0; return 0;
} }
r = spdylay_session_pack_data r = spdylay_session_pack_data(session,
(session,
&session->aob.framebuf, &session->aob.framebuf,
&session->aob.framebufmax, &session->aob.framebufmax,
(avail_window < SPDYLAY_DATA_PAYLOAD_LENGTH ? next_readmax,
avail_window : SPDYLAY_DATA_PAYLOAD_LENGTH),
&frame->data); &frame->data);
if(r == SPDYLAY_ERR_DEFERRED) { if(r == SPDYLAY_ERR_DEFERRED) {
spdylay_stream_defer_data(stream, session->aob.item, spdylay_stream_defer_data(stream, session->aob.item,