From: Stefan Eissing Date: Mon, 16 Jun 2025 10:19:52 +0000 (+0200) Subject: multi: fix polling with pending input X-Git-Tag: curl-8_15_0~251 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=62349e45a818e50b5cdcd017c149f9dc87fce9fe;p=thirdparty%2Fcurl.git multi: fix polling with pending input When multi creates the pollset of a transfer, it checks now if a connection (FIRST/SECONDARY) socket waits on POLLIN and has input data pending in filters (relevant to OpenSSL's new read ahead). If so, it triggers a timeout on the transfer via EXPIRE_RUN_NOW. This fixes sporadic stalls in test 988 when running event based. Closes #17636 --- diff --git a/lib/cfilters.c b/lib/cfilters.c index 4c83657e87..69cbb68e27 100644 --- a/lib/cfilters.c +++ b/lib/cfilters.c @@ -1069,3 +1069,16 @@ void Curl_pollset_check(struct Curl_easy *data, } *pwant_read = *pwant_write = FALSE; } + +bool Curl_pollset_want_read(struct Curl_easy *data, + struct easy_pollset *ps, + curl_socket_t sock) +{ + unsigned int i; + (void)data; + for(i = 0; i < ps->num; ++i) { + if((ps->sockets[i] == sock) && (ps->actions[i] & CURL_POLL_IN)) + return TRUE; + } + return FALSE; +} diff --git a/lib/cfilters.h b/lib/cfilters.h index 4f678f8689..edcbb6f375 100644 --- a/lib/cfilters.h +++ b/lib/cfilters.h @@ -620,6 +620,13 @@ void Curl_pollset_check(struct Curl_easy *data, struct easy_pollset *ps, curl_socket_t sock, bool *pwant_read, bool *pwant_write); +/** + * Return TRUE if the pollset contains socket with CURL_POLL_IN. + */ +bool Curl_pollset_want_read(struct Curl_easy *data, + struct easy_pollset *ps, + curl_socket_t sock); + /** * Types and macros used to keep the current easy handle in filter calls, * allowing for nested invocations. See #10336. diff --git a/lib/multi.c b/lib/multi.c index 51a5fb3f71..ef41650b32 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -1038,6 +1038,18 @@ void Curl_multi_getsock(struct Curl_easy *data, break; } + + /* Waiting to receive with buffered input. + * Make transfer run again at next opportunity. */ + if((Curl_pollset_want_read(data, ps, data->conn->sock[FIRSTSOCKET]) && + Curl_conn_data_pending(data, FIRSTSOCKET)) || + (Curl_pollset_want_read(data, ps, data->conn->sock[SECONDARYSOCKET]) && + Curl_conn_data_pending(data, SECONDARYSOCKET))) { + CURL_TRC_M(data, "%s pollset[] has POLLIN, but there is still " + "buffered input to consume -> EXPIRE_RUN_NOW", caller); + Curl_expire(data, 0, EXPIRE_RUN_NOW); + } + switch(ps->num) { case 0: CURL_TRC_M(data, "%s pollset[], timeouts=%zu, paused %d/%d (r/w)",