]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
multi: clear the dirty set of transfers no longer processing
authorStefan Eissing <stefan@eissing.org>
Mon, 23 Jun 2025 08:02:36 +0000 (10:02 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Mon, 23 Jun 2025 11:36:33 +0000 (13:36 +0200)
When a transfer is no longer processed, it might still apear in the
dirty bitset. Clear the dirty bit when this condition is encountered.

Closes #17718

lib/multi.c
tests/libtest/lib530.c

index d0cb60afd2aad0e6eb336f590ff64682864d6bf1..047fdc43f6e0174a2195cf8755bb37a4a0d7df75 100644 (file)
@@ -1187,6 +1187,7 @@ CURLMcode curl_multi_waitfds(CURLM *m,
       if(!data) {
         DEBUGASSERT(0);
         Curl_uint_bset_remove(&multi->process, mid);
+        Curl_uint_bset_remove(&multi->dirty, mid);
         continue;
       }
       Curl_multi_getsock(data, &ps, "curl_multi_waitfds");
@@ -1270,6 +1271,7 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
       if(!data) {
         DEBUGASSERT(0);
         Curl_uint_bset_remove(&multi->process, mid);
+        Curl_uint_bset_remove(&multi->dirty, mid);
         continue;
       }
       Curl_multi_getsock(data, &ps, "multi_wait");
@@ -2234,6 +2236,7 @@ static CURLMcode state_connect(struct Curl_multi *multi,
     multistate(data, MSTATE_PENDING);
     /* move from process to pending set */
     Curl_uint_bset_remove(&multi->process, data->mid);
+    Curl_uint_bset_remove(&multi->dirty, data->mid);
     Curl_uint_bset_add(&multi->pending, data->mid);
     *resultp = CURLE_OK;
     return rc;
@@ -2665,6 +2668,7 @@ statemachine_end:
 
       /* remove from the other sets, add to msgsent */
       Curl_uint_bset_remove(&multi->process, data->mid);
+      Curl_uint_bset_remove(&multi->dirty, data->mid);
       Curl_uint_bset_remove(&multi->pending, data->mid);
       Curl_uint_bset_add(&multi->msgsent, data->mid);
       --multi->xfers_alive;
@@ -2702,6 +2706,7 @@ CURLMcode curl_multi_perform(CURLM *m, int *running_handles)
       if(!data) {
         DEBUGASSERT(0);
         Curl_uint_bset_remove(&multi->process, mid);
+        Curl_uint_bset_remove(&multi->dirty, mid);
         continue;
       }
       if(data != multi->admin) {
@@ -3010,6 +3015,11 @@ static CURLMcode multi_run_dirty(struct multi_run_ctx *mrc)
           mrc->run_cpool = TRUE;
           continue;
         }
+        else if(!Curl_uint_bset_contains(&multi->process, mid)) {
+          /* We are no longer proecessing this transfer */
+          Curl_uint_bset_remove(&multi->dirty, mid);
+          continue;
+        }
 
         mrc->run_xfers++;
         sigpipe_apply(data, &mrc->pipe_st);
@@ -3225,7 +3235,10 @@ static bool multi_has_dirties(struct Curl_multi *multi)
     do {
       struct Curl_easy *data = Curl_multi_get_easy(multi, mid);
       if(data) {
-        return TRUE;
+        if(Curl_uint_bset_contains(&multi->process, mid))
+          return TRUE;
+        /* We are no longer proecessing this transfer */
+        Curl_uint_bset_remove(&multi->dirty, mid);
       }
       else {
         CURL_TRC_M(multi->admin, "dirty transfer %u no longer found", mid);
index 46a8ccba25972b7ede04542e5990a834546d98ab..957efa2d4f259aad90da83a4d5bb28ddf5760970 100644 (file)
 
 #include "memdebug.h"
 
+
+static struct t530_ctx {
+  int socket_calls;
+  int max_socket_calls;
+  int timer_calls;
+  int max_timer_calls;
+  char buf[1024];
+} t530_ctx;
+
+static const char *t530_tag(void)
+{
+  curl_msnprintf(t530_ctx.buf, sizeof(t530_ctx.buf),
+                "[T530-%d-%d] [%d/%d]",
+                t530_ctx.max_socket_calls, t530_ctx.max_timer_calls,
+                t530_ctx.socket_calls, t530_ctx.timer_calls);
+  return t530_ctx.buf;
+}
+
+static void t530_msg(const char *msg)
+{
+  curl_mfprintf(stderr, "%s %s\n", t530_tag(), msg);
+}
+
+
 struct t530_Sockets {
   curl_socket_t *sockets;
   int count;      /* number of sockets actually stored in array */
@@ -53,7 +77,7 @@ static void t530_removeFd(struct t530_Sockets *sockets, curl_socket_t fd,
   int i;
 
   if(mention)
-    curl_mfprintf(stderr, "Remove socket fd %d\n", (int) fd);
+    curl_mfprintf(stderr, "%s remove socket fd %d\n", t530_tag(), (int)fd);
 
   for(i = 0; i < sockets->count; ++i) {
     if(sockets->sockets[i] == fd) {
@@ -76,7 +100,8 @@ static int t530_addFd(struct t530_Sockets *sockets, curl_socket_t fd,
    * To ensure we only have each file descriptor once, we remove it then add
    * it again.
    */
-  curl_mfprintf(stderr, "Add socket fd %d for %s\n", (int) fd, what);
+  curl_mfprintf(stderr, "%s add socket fd %d for %s\n",
+                t530_tag(), (int)fd, what);
   t530_removeFd(sockets, fd, 0);
   /*
    * Allocate array storage when required.
@@ -104,9 +129,6 @@ static int t530_addFd(struct t530_Sockets *sockets, curl_socket_t fd,
   return 0;
 }
 
-static int max_socket_calls;
-static int socket_calls = 0;
-
 /**
  * Callback invoked by curl to poll reading / writing of a socket.
  */
@@ -118,10 +140,10 @@ static int t530_curlSocketCallback(CURL *easy, curl_socket_t s, int action,
   (void)easy; /* unused */
   (void)socketp; /* unused */
 
-  curl_mfprintf(stderr, "CURLMOPT_SOCKETFUNCTION called: %u\n",
-                socket_calls++);
-  if(socket_calls == max_socket_calls) {
-    curl_mfprintf(stderr, "curlSocketCallback returns error\n");
+  t530_ctx.socket_calls++;
+  t530_msg("-> CURLMOPT_SOCKETFUNCTION");
+  if(t530_ctx.socket_calls == t530_ctx.max_socket_calls) {
+    t530_msg("<- CURLMOPT_SOCKETFUNCTION returns error");
     return -1;
   }
 
@@ -141,9 +163,6 @@ static int t530_curlSocketCallback(CURL *easy, curl_socket_t s, int action,
   return 0;
 }
 
-static int max_timer_calls;
-static int timer_calls = 0;
-
 /**
  * Callback invoked by curl to set a timeout.
  */
@@ -152,9 +171,10 @@ static int t530_curlTimerCallback(CURLM *multi, long timeout_ms, void *userp)
   struct curltime *timeout = userp;
 
   (void)multi; /* unused */
-  curl_mfprintf(stderr, "CURLMOPT_TIMERFUNCTION called: %u\n", timer_calls++);
-  if(timer_calls == max_timer_calls) {
-    curl_mfprintf(stderr, "curlTimerCallback returns error\n");
+  t530_ctx.timer_calls++;
+  t530_msg("-> CURLMOPT_TIMERFUNCTION");
+  if(t530_ctx.timer_calls == t530_ctx.max_timer_calls) {
+    t530_msg("<- CURLMOPT_TIMERFUNCTION returns error");
     return -1;
   }
   if(timeout_ms != -1) {
@@ -187,8 +207,8 @@ static int t530_checkForCompletion(CURLM *curl, int *success)
         *success = 0;
     }
     else {
-      curl_mfprintf(stderr, "Got an unexpected message from curl: %i\n",
-                    (int)message->msg);
+      curl_mfprintf(stderr, "%s got an unexpected message from curl: %i\n",
+                    t530_tag(), (int)message->msg);
       result = 1;
       *success = 0;
     }
@@ -237,8 +257,8 @@ static int socket_action(CURLM *curl, curl_socket_t s, int evBitmask,
   int numhandles = 0;
   CURLMcode result = curl_multi_socket_action(curl, s, evBitmask, &numhandles);
   if(result != CURLM_OK) {
-    curl_mfprintf(stderr, "Curl error on %s (%i) %s\n",
-                  info, result, curl_multi_strerror(result));
+    curl_mfprintf(stderr, "%s Curl error on %s (%i) %s\n",
+                  t530_tag(), info, result, curl_multi_strerror(result));
   }
   return (int)result;
 }
@@ -261,7 +281,7 @@ static int t530_checkFdSet(CURLM *curl, struct t530_Sockets *sockets,
   return result;
 }
 
-static CURLcode testone(char *URL, int timercb, int socketcb)
+static CURLcode testone(char *URL, int timer_fail_at, int socket_fail_at)
 {
   CURLcode res = CURLE_OK;
   CURL *curl = NULL;  CURLM *m = NULL;
@@ -271,12 +291,11 @@ static CURLcode testone(char *URL, int timercb, int socketcb)
   timeout.tv_sec = (time_t)-1;
 
   /* set the limits */
-  max_timer_calls = timercb;
-  max_socket_calls = socketcb;
-  timer_calls = 0; /* reset the globals */
-  socket_calls = 0;
+  memset(&t530_ctx, 0, sizeof(t530_ctx));
+  t530_ctx.max_timer_calls = timer_fail_at;
+  t530_ctx.max_socket_calls = socket_fail_at;
 
-  curl_mfprintf(stderr, "start test: %d %d\n", timercb, socketcb);
+  t530_msg("start");
   start_test_timing();
 
   res_global_init(CURL_GLOBAL_ALL);
@@ -355,14 +374,14 @@ static CURLcode testone(char *URL, int timercb, int socketcb)
   }
 
   if(!success) {
-    curl_mfprintf(stderr, "Error getting file.\n");
+    t530_msg("Error getting file.");
     res = TEST_ERR_MAJOR_BAD;
   }
 
 test_cleanup:
 
   /* proper cleanup sequence */
-  curl_mfprintf(stderr, "cleanup: %d %d\n", timercb, socketcb);
+  t530_msg("cleanup");
   curl_multi_remove_handle(m, curl);
   curl_easy_cleanup(curl);
   curl_multi_cleanup(m);
@@ -371,6 +390,7 @@ test_cleanup:
   /* free local memory */
   free(sockets.read.sockets);
   free(sockets.write.sockets);
+  t530_msg("done");
 
   return res;
 }
@@ -380,25 +400,25 @@ static CURLcode test_lib530(char *URL)
   CURLcode rc;
   /* rerun the same transfer multiple times and make it fail in different
      callback calls */
-  rc = testone(URL, 0, 0);
+  rc = testone(URL, 0, 0); /* no callback fails */
   if(rc)
-    curl_mfprintf(stderr, "test 0/0 failed: %d\n", rc);
+    curl_mfprintf(stderr, "%s FAILED: %d\n", t530_tag(), rc);
 
-  rc = testone(URL, 1, 0);
+  rc = testone(URL, 1, 0); /* fail 1st call to timer callback */
   if(!rc)
-    curl_mfprintf(stderr, "test 1/0 failed: %d\n", rc);
+    curl_mfprintf(stderr, "%s FAILED: %d\n", t530_tag(), rc);
 
-  rc = testone(URL, 2, 0);
+  rc = testone(URL, 2, 0); /* fail 2nd call to timer callback */
   if(!rc)
-    curl_mfprintf(stderr, "test 2/0 failed: %d\n", rc);
+    curl_mfprintf(stderr, "%s FAILED: %d\n", t530_tag(), rc);
 
-  rc = testone(URL, 0, 1);
+  rc = testone(URL, 0, 1); /* fail 1st call to socket callback */
   if(!rc)
-    curl_mfprintf(stderr, "test 0/1 failed: %d\n", rc);
+    curl_mfprintf(stderr, "%s FAILED: %d\n", t530_tag(), rc);
 
-  rc = testone(URL, 0, 2);
+  rc = testone(URL, 0, 2); /* fail 2nd call to socket callback */
   if(!rc)
-    curl_mfprintf(stderr, "test 0/2 failed: %d\n", rc);
+    curl_mfprintf(stderr, "%s FAILED: %d\n", t530_tag(), rc);
 
   return CURLE_OK;
 }