]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
asyn-thrdd: use condition var more carefully
authorStefan Eissing <stefan@eissing.org>
Thu, 21 Aug 2025 19:19:27 +0000 (21:19 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Fri, 22 Aug 2025 06:40:40 +0000 (08:40 +0200)
When the thread started is too fast, the signal will come before the
wait. Add an additional check before the wait to catch the thread
having started or already ended.

Closes #18344

lib/asyn-thrdd.c
lib/asyn.h

index dbc13d072212910de03d2c780e07e6a181dcd665..5b451ac65ee3386520a3eaaa06ba147a67cd3911 100644 (file)
@@ -135,6 +135,13 @@ static void addr_ctx_unlink(struct async_thrdd_addr_ctx **paddr_ctx,
 #ifndef CURL_DISABLE_SOCKETPAIR
   if(!destroy) {
     if(!data) { /* Called from thread, transfer still waiting on results. */
+      /* Mark thread as done and signal the condition again, in case the
+       * one waiting missed our fist signal at the start. */
+      addr_ctx->thrd_done = TRUE;
+#ifdef USE_CURL_COND_T
+      Curl_cond_signal(&addr_ctx->cond);
+#endif
+
       if(addr_ctx->sock_pair[1] != CURL_SOCKET_BAD) {
 #ifdef USE_EVENTFD
         const uint64_t buf[1] = { 1 };
@@ -379,7 +386,7 @@ static void async_thrdd_destroy(struct Curl_easy *data)
     bool done = TRUE;
 
     Curl_mutex_acquire(&addr->mutx);
-    done = (addr->ref_count <= 1);
+    done = addr->thrd_done;
     Curl_mutex_release(&addr->mutx);
     if(done) {
       Curl_thread_join(&addr->thread_hnd);
@@ -504,9 +511,13 @@ static bool async_thrdd_init(struct Curl_easy *data,
   }
   else {
 #ifdef USE_CURL_COND_T
-    /* need to handshake with thread for participation in ref counting */
-    Curl_cond_wait(&addr_ctx->cond, &addr_ctx->mutx);
-    DEBUGASSERT(addr_ctx->ref_count >= 1);
+    /* need to handshake with thread for participation in ref counting.
+     * We wait to see the thread having incremented `ref_count`, so it
+     * started. However it may run to its end before we get the
+     * signal, in which case `ref_count` is 1 again, but then
+     * `thrd_done` is TRUE.*/
+    while((addr_ctx->ref_count <= 1) && !addr_ctx->thrd_done)
+      Curl_cond_wait(&addr_ctx->cond, &addr_ctx->mutx);
 #endif
     Curl_mutex_release(&addr_ctx->mutx);
   }
@@ -537,7 +548,7 @@ static void async_thrdd_shutdown(struct Curl_easy *data)
     return;
 
   Curl_mutex_acquire(&addr_ctx->mutx);
-  done = (addr_ctx->ref_count <= 1);
+  done = addr_ctx->thrd_done;
   /* We are no longer interested in wakeups */
   if(addr_ctx->sock_pair[1] != CURL_SOCKET_BAD) {
     wakeup_close(addr_ctx->sock_pair[1]);
@@ -660,7 +671,7 @@ CURLcode Curl_async_is_resolved(struct Curl_easy *data,
     return CURLE_FAILED_INIT;
 
   Curl_mutex_acquire(&thrdd->addr->mutx);
-  done = (thrdd->addr->ref_count == 1);
+  done = thrdd->addr->thrd_done;
   Curl_mutex_release(&thrdd->addr->mutx);
 
   if(done) {
index 5e56532bf09323c0bdb5344368cd5b577838d07e..58c09e98e3ff1764d03ea14dc215028fee1c3e22 100644 (file)
@@ -196,6 +196,7 @@ struct async_thrdd_addr_ctx {
   int port;
   int sock_error;
   int ref_count;
+  BIT(thrd_done);
 };
 
 /* Context for threaded resolver */