]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
multi: fix polling with pending input
authorStefan Eissing <stefan@eissing.org>
Mon, 16 Jun 2025 10:19:52 +0000 (12:19 +0200)
committerViktor Szakats <commit@vsz.me>
Mon, 16 Jun 2025 11:04:03 +0000 (13:04 +0200)
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

lib/cfilters.c
lib/cfilters.h
lib/multi.c

index 4c83657e87d10055b67e5493c84e2f2eb1785bdf..69cbb68e2747eed79e2e58f970c02ac9c36b7349 100644 (file)
@@ -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;
+}
index 4f678f868951718bb9c81ca07808b8382631b88f..edcbb6f375972aaa2366e9c68b3470aca1f22d7a 100644 (file)
@@ -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.
index 51a5fb3f719cab897c0cdb4ada64cd7dc2a83254..ef41650b329d4198a67521c338cf366536f3ad4c 100644 (file)
@@ -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)",