> Am 20.09.2021 um 12:27 schrieb Ruediger Pluem <rpl...@apache.org>:
>
>
>
> On 9/20/21 11:17 AM, ste...@eissing.org wrote:
>>
>>
>>> Am 14.09.2021 um 13:43 schrieb Ruediger Pluem <rpl...@apache.org>:
>>>
>>> When looking at this again while researching something I couldn't answer
>>> myself the questions below
>>> and as event mpm and mod_http2 are sometimes pretty complex I thought I ask
>>> :-)
>>>
>>> On 7/3/19 3:46 PM, ic...@apache.org wrote:
>>>> Author: icing
>>>> Date: Wed Jul 3 13:46:31 2019
>>>> New Revision: 1862475
>>>>
>>>> URL: http://svn.apache.org/viewvc?rev=1862475&view=rev
>>>> Log:
>>>> *) mod_http2/mpm_event: Fixes the behaviour when a HTTP/2 connection has
>>>> nothing
>>>> more to write with streams ongoing (flow control block). The timeout
>>>> waiting
>>>> for the client to send WINODW_UPDATE was incorrectly KeepAliveTimeout
>>>> and not
>>>> Timeout as it should be. Fixes PR 63534. [Yann Ylavic, Stefan Eissing]
>>>>
>>>>
>>>> Modified:
>>>> httpd/httpd/trunk/CHANGES
>>>> httpd/httpd/trunk/modules/http2/h2_conn.c
>>>> httpd/httpd/trunk/modules/http2/h2_version.h
>>>> httpd/httpd/trunk/server/mpm/event/event.c
>>>>
>>>
>>>> Modified: httpd/httpd/trunk/modules/http2/h2_conn.c
>>>> URL:
>>>> http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_conn.c?rev=1862475&r1=1862474&r2=1862475&view=diff
>>>> ==============================================================================
>>>> --- httpd/httpd/trunk/modules/http2/h2_conn.c (original)
>>>> +++ httpd/httpd/trunk/modules/http2/h2_conn.c Wed Jul 3 13:46:31 2019
>>>> @@ -231,6 +231,13 @@ apr_status_t h2_conn_run(conn_rec *c)
>>>> case H2_SESSION_ST_BUSY:
>>>> case H2_SESSION_ST_WAIT:
>>>> c->cs->state = CONN_STATE_WRITE_COMPLETION;
>>>> + if (c->cs && (session->open_streams ||
>>>> !session->remote.emitted_count)) {
>>>> + /* let the MPM know that we are not done and want
>>>> + * the Timeout behaviour instead of a KeepAliveTimeout
>>>> + * See PR 63534.
>>>> + */
>>>> + c->cs->sense = CONN_SENSE_WANT_READ;
>>>
>>> Can we get here with session->open_streams > 0 and all the open streams are
>>> only producing output and none of them is waiting for
>>> something from the client?
>>
>> Yes, but only when the HTTP/2 flow control blocks any progress. New data has
>> to arrive from the client before the server is able to send more. So, we are
>> waiting for new data from the client in the form of window updates.
>
> Thanks, but as you state in this case it wants to read data, not for a new
> request for getting output data sending for existing
> requests started again. This sounds fine. I was worried that we could wait
> for input data here without expecting any.
>
>>
>>>> + }
>>>> break;
>>>> case H2_SESSION_ST_CLEANUP:
>>>> case H2_SESSION_ST_DONE:
>>>>
>>>
>>>> Modified: httpd/httpd/trunk/server/mpm/event/event.c
>>>> URL:
>>>> http://svn.apache.org/viewvc/httpd/httpd/trunk/server/mpm/event/event.c?rev=1862475&r1=1862474&r2=1862475&view=diff
>>>> ==============================================================================
>>>> --- httpd/httpd/trunk/server/mpm/event/event.c (original)
>>>> +++ httpd/httpd/trunk/server/mpm/event/event.c Wed Jul 3 13:46:31 2019
>>>> @@ -1153,10 +1153,11 @@ read_request:
>>>> else if (ap_filter_should_yield(c->output_filters)) {
>>>> pending = OK;
>>>> }
>>>> - if (pending == OK) {
>>>> + if (pending == OK || (pending == DECLINED &&
>>>> + cs->pub.sense == CONN_SENSE_WANT_READ)) {
>>>> /* Still in WRITE_COMPLETION_STATE:
>>>> - * Set a write timeout for this connection, and let the
>>>> - * event thread poll for writeability.
>>>> + * Set a read/write timeout for this connection, and let the
>>>> + * event thread poll for read/writeability.
>>>> */
>>>> cs->queue_timestamp = apr_time_now();
>>>> notify_suspend(cs);
>>>
>>> Hm. Showing following code lines from trunk for my next question:
>>>
>>>
>>> update_reqevents_from_sense(cs, -1);
>>>
>>> if cs->pub.sense == CONN_SENSE_WANT_READ we subscribe on to POLLIN only on
>>> the pfd
>>>
>>>
>>> apr_thread_mutex_lock(timeout_mutex);
>>> TO_QUEUE_APPEND(cs->sc->wc_q, cs);
>>> rv = apr_pollset_add(event_pollset, &cs->pfd);
>>>
>>> If the read event triggers we will get back to the
>>>
>>> if (cs->pub.state == CONN_STATE_WRITE_COMPLETION) {
>>> int pending = DECLINED;
>>>
>>> above. This means we try flush the output queue if it is not empty and if
>>> it is empty after this we would fall through to
>>> set cs->pub.state = CONN_STATE_CHECK_REQUEST_LINE_READABLE; and then add
>>> the pfd to the pollset again and poll again. This should
>>> trigger the read event again and we would process the input. But if I see
>>> this correctly we would need to poll twice for getting
>>> the read data processed.
>>> OTOH if we do not manage to clear the output queue above we would add the
>>> pfd to the pollset again but this time for writing and
>>> only once all output has been processed we would take care of the reading.
>>> Maybe we should take care of both?
>>
>> Hmm, but can it? In my understanding CONN_STATE_WRITE_COMPLETION is intended
>> to flush the out buffers before putting in new work.
>
> But a single call dies not need to flush all pending data from my
> understanding provided that no need to flush the data is found
> like too much in memory data or too much EOR buckets which mean that we have
> too much finished requests in the output queue.
> Hence CONN_STATE_WRITE_COMPLETION could happen multiple times only writing
> pieces from the data in the output queue.
>
>>
>> Since conn_rec's are limited to be processes in one thread-at-a-time only,
>> POLLIN would call process_connection and that alone would block any more
>> processing of the connection's output. Or?
>
> Yes and no. If we take the CONN_SENSE_WANT_READ example from h2_conn above it
> would mean that no further processing of pending
> output would happen until input is available since
> update_reqevents_from_sense(cs, -1) will cause that we only ask for read
> events
> on the FD. This looks wrong to me in cases where we still have output data
> that we could write to the client, provided we get an
> event for write on the socket. Hence my idea would be to ask for both and
> process them in write / read order provided that both
> events get back. If only write came back only process write but keep asking
> for read. If only read came back process read. In all
> cases only read comes back, we would not ask for any event on the FD any
> longer but just would process the input which should
> cause the output processing to start again.
>
The "only POLLIN" case would explain behaviour I experienced in the past where
output was sometimes not sent unless I really FLUSH it before a read. This
change sounds good to me.
> Regards
>
> RĂ¼diger