MEDIUM: stream-int: always call si_chk_rcv() when we make room in the buffer

Instead of clearing the SI_FL_WAIT_ROOM flag and losing the information
about the need from the producer to be woken up, we now call si_chk_rcv()
immediately. This is cheap to do and it could possibly be further improved
by only doing it when SI_FL_WAIT_ROOM was still set, though this will
require some extra auditing of the code paths.

The only remaining place where the flag was cleared without a call to
si_chk_rcv() is si_alloc_ibuf(), but since this one is called from a
receive path woken up from si_chk_rcv() or not having failed, the
clearing was not necessary anymore either.

And there was one place in stream_int_notify() where si_chk_rcv() was
called with SI_FL_WAIT_ROOM still explicitly set so this place was
adjusted in order to clear the flag prior to calling si_chk_rcv().

Now we don't have any situation where we randomly clear SI_FL_WAIT_ROOM
without trying to wake the other side up, nor where we call si_chk_rcv()
with the flag set, so this flag should accurately represent a failed
attempt at putting data into the buffer.
This commit is contained in:
Willy Tarreau 2018-11-07 18:53:29 +01:00
parent 1f9de21c38
commit abf531caa0
2 changed files with 9 additions and 12 deletions

View File

@ -315,9 +315,8 @@ static inline struct conn_stream *si_alloc_cs(struct stream_interface *si, struc
}
/* Try to allocate a buffer for the stream-int's input channel. It relies on
* channel_alloc_buffer() for this so it abides by its rules. It returns 0 in
* case of failure, non-zero otherwise. The stream-int's flag SI_FL_WAIT_ROOM
* is cleared before trying. If no buffer are available, the requester,
* channel_alloc_buffer() for this so it abides by its rules. It returns 0 on
* failure, non-zero otherwise. If no buffer is available, the requester,
* represented by <wait> pointer, will be added in the list of objects waiting
* for an available buffer, and SI_FL_WAIT_ROOM will be set on the stream-int.
* The requester will be responsible for calling this function to try again
@ -327,7 +326,6 @@ static inline int si_alloc_ibuf(struct stream_interface *si, struct buffer_wait
{
int ret;
si->flags &= ~SI_FL_WAIT_ROOM;
ret = channel_alloc_buffer(si_ic(si), wait);
if (!ret)
si_cant_put(si);

View File

@ -480,8 +480,10 @@ void stream_int_notify(struct stream_interface *si)
if (likely((oc->flags & (CF_SHUTW|CF_WRITE_PARTIAL|CF_DONT_READ)) == CF_WRITE_PARTIAL &&
channel_may_recv(oc) &&
(si_opposite(si)->flags & SI_FL_WAIT_ROOM)))
(si_opposite(si)->flags & SI_FL_WAIT_ROOM))) {
si_opposite(si)->flags &= ~SI_FL_WAIT_ROOM;
si_chk_rcv(si_opposite(si));
}
}
/* Notify the other side when we've injected data into the IC that
@ -513,8 +515,10 @@ void stream_int_notify(struct stream_interface *si)
/* check if the consumer has freed some space either in the
* buffer or in the pipe.
*/
if (channel_may_recv(ic) && new_len < last_len)
if (channel_may_recv(ic) && new_len < last_len) {
si->flags &= ~SI_FL_WAIT_ROOM;
si_chk_rcv(si);
}
}
if (si->flags & SI_FL_WAIT_ROOM) {
@ -561,7 +565,6 @@ static int si_cs_process(struct conn_stream *cs)
struct stream_interface *si = cs->data;
struct channel *ic = si_ic(si);
struct channel *oc = si_oc(si);
int wait_room = si->flags & SI_FL_WAIT_ROOM;
/* If we have data to send, try it now */
if (!channel_is_empty(oc) && !(si->wait_event.wait_reason & SUB_CAN_SEND))
@ -597,10 +600,6 @@ static int si_cs_process(struct conn_stream *cs)
stream_int_notify(si);
channel_release_buffer(ic, &(si_strm(si)->buffer_wait));
/* Try to run again if we free'd some room in the process */
if (wait_room && !(si->flags & SI_FL_WAIT_ROOM))
tasklet_wakeup(si->wait_event.task);
return 0;
}
@ -769,7 +768,7 @@ void stream_int_update(struct stream_interface *si)
* have updated it if there has been a completed I/O.
*/
si->flags &= ~SI_FL_WAIT_ROOM;
tasklet_wakeup(si->wait_event.task);
si_chk_rcv(si);
if (!(ic->flags & (CF_READ_NOEXP|CF_DONT_READ)) && !tick_isset(ic->rex))
ic->rex = tick_add_ifset(now_ms, ic->rto);
}