BUG/MEDIUM: connection: always disable polling upon error

Commit 0ffde2cc in 1.5-dev13 tried to always disable polling on file
descriptors when errors were encountered. Unfortunately it did not
always succeed in doing so because it relied on detecting polling
changes to disable it. Let's use a dedicated conn_stop_polling()
function that is inconditionally called upon error instead.

This managed to stop a busy loop observed when a health check makes
use of the send-proxy protocol and fails before the connection can
be established.
This commit is contained in:
Willy Tarreau 2012-11-24 11:09:07 +01:00
parent f0837b259b
commit 36fb02c526
2 changed files with 14 additions and 17 deletions

View File

@ -180,6 +180,17 @@ static inline void conn_cond_update_sock_polling(struct connection *c)
conn_update_sock_polling(c);
}
/* Stop all polling on the fd. This might be used when an error is encountered
* for example.
*/
static inline void conn_stop_polling(struct connection *c)
{
c->flags &= ~(CO_FL_CURR_RD_ENA | CO_FL_CURR_WR_ENA |
CO_FL_SOCK_RD_ENA | CO_FL_SOCK_WR_ENA |
CO_FL_DATA_RD_ENA | CO_FL_DATA_WR_ENA);
fd_stop_both(c->t.sock.fd);
}
/* Automatically update polling on connection <c> depending on the DATA and
* SOCK flags, and on whether a handshake is in progress or not. This may be
* called at any moment when there is a doubt about the effectiveness of the
@ -187,7 +198,9 @@ static inline void conn_cond_update_sock_polling(struct connection *c)
*/
static inline void conn_cond_update_polling(struct connection *c)
{
if (!(c->flags & CO_FL_POLL_SOCK) && conn_data_polling_changes(c))
if (unlikely(c->flags & CO_FL_ERROR))
conn_stop_polling(c);
else if (!(c->flags & CO_FL_POLL_SOCK) && conn_data_polling_changes(c))
conn_update_data_polling(c);
else if ((c->flags & CO_FL_POLL_SOCK) && conn_sock_polling_changes(c))
conn_update_sock_polling(c);

View File

@ -166,14 +166,6 @@ void conn_update_data_polling(struct connection *c)
{
unsigned int f = c->flags;
if (unlikely(f & CO_FL_ERROR)) {
c->flags &= ~(CO_FL_CURR_RD_ENA | CO_FL_CURR_WR_ENA |
CO_FL_SOCK_RD_ENA | CO_FL_SOCK_WR_ENA |
CO_FL_DATA_RD_ENA | CO_FL_DATA_WR_ENA);
fd_stop_both(c->t.sock.fd);
return;
}
/* update read status if needed */
if (unlikely((f & (CO_FL_DATA_RD_ENA|CO_FL_WAIT_RD)) == (CO_FL_DATA_RD_ENA|CO_FL_WAIT_RD))) {
fd_poll_recv(c->t.sock.fd);
@ -214,14 +206,6 @@ void conn_update_sock_polling(struct connection *c)
{
unsigned int f = c->flags;
if (unlikely(f & CO_FL_ERROR)) {
c->flags &= ~(CO_FL_CURR_RD_ENA | CO_FL_CURR_WR_ENA |
CO_FL_SOCK_RD_ENA | CO_FL_SOCK_WR_ENA |
CO_FL_DATA_RD_ENA | CO_FL_DATA_WR_ENA);
fd_stop_both(c->t.sock.fd);
return;
}
/* update read status if needed */
if (unlikely((f & (CO_FL_SOCK_RD_ENA|CO_FL_WAIT_RD)) == (CO_FL_SOCK_RD_ENA|CO_FL_WAIT_RD))) {
fd_poll_recv(c->t.sock.fd);