From: Stefan Eissing Date: Thu, 21 Aug 2025 19:19:27 +0000 (+0200) Subject: asyn-thrdd: use condition var more carefully X-Git-Tag: curl-8_16_0~131 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=bd4622bfaf0929141e6b81653c88ea06e47afe9e;p=thirdparty%2Fcurl.git asyn-thrdd: use condition var more carefully 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 --- diff --git a/lib/asyn-thrdd.c b/lib/asyn-thrdd.c index dbc13d0722..5b451ac65e 100644 --- a/lib/asyn-thrdd.c +++ b/lib/asyn-thrdd.c @@ -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) { diff --git a/lib/asyn.h b/lib/asyn.h index 5e56532bf0..58c09e98e3 100644 --- a/lib/asyn.h +++ b/lib/asyn.h @@ -196,6 +196,7 @@ struct async_thrdd_addr_ctx { int port; int sock_error; int ref_count; + BIT(thrd_done); }; /* Context for threaded resolver */