public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
From: Jan Macku <jamacku@redhat.com>
To: git-commits@fedoraproject.org
Subject: [rpms/curl] rawhide: fix multi_fdset must not report only the wakeup socket
Date: Thu, 18 Jun 2026 10:54:18 GMT [thread overview]
Message-ID: <178178005848.1.15778690615029135378.rpms-curl-b4df4148f935@fedoraproject.org> (raw)
A new commit has been pushed.
Repo : rpms/curl
Branch : rawhide
Commit : b4df4148f935bcae13ed56bcd87142439a7b736e
Author : Jan Macku <jamacku@redhat.com>
Date : 2026-06-18T12:29:27+02:00
Stats : +373/-2 in 2 file(s)
URL : https://src.fedoraproject.org/rpms/curl/c/b4df4148f935bcae13ed56bcd87142439a7b736e?branch=rawhide
Log:
fix multi_fdset must not report only the wakeup socket
Resolves: #2460719
---
diff --git a/0001-curl-8.21.0~rc3-multi-xfers_really_alive.patch b/0001-curl-8.21.0~rc3-multi-xfers_really_alive.patch
new file mode 100644
index 0000000..35682da
--- /dev/null
+++ b/0001-curl-8.21.0~rc3-multi-xfers_really_alive.patch
@@ -0,0 +1,365 @@
+From 6a92e7cf03e819b84b3d96ae7934cccbb1a6563b Mon Sep 17 00:00:00 2001
+From: Stefan Eissing <stefan@eissing.org>
+Date: Wed, 17 Jun 2026 14:20:02 +0200
+Subject: [PATCH] multi: xfers_really_alive
+
+Yes, we were counting the "live" transfers before, but were they
+*really* alive?
+
+When determining to add the wakeup socket to fdset/waitfds etc, we
+should only do that when the multi handle is actually processing
+transfers. Other wise, the application could wait on the wakeup socket
+forever.
+
+For this, we counted `multi->xfers_alive` (e.g. the "running" number
+returned by `curl_multi_perform()`). This was almost correct.
+
+The problem is that added easy handles are counted as "alive" right away
+on the addition. But the processing has not started yet. They did not
+trigger any DNS resolves or opened any sockets yet.
+
+Add two fields in multi and easy handle:
+
+* `multi->xfers_really_alive`: counts the "alive" transfers that have
+ passed `MSTATE_INIT` (at least once)
+* `data->state.really_alive`: to track if the transfer has been counted
+
+Add test 2412 to check that adding transfers without perform will not
+trigger the wakeup socket to be added.
+
+Fixes #22050
+Reported-by: Bryan Henderson
+Closes #22066
+
+(cherry picked from commit f0be41763542f68dce344beee8a5c5e5b858e6d1)
+---
+ lib/multi.c | 36 ++++++++++++---
+ lib/multihandle.h | 2 +
+ lib/urldata.h | 6 +--
+ tests/data/Makefile.am | 2 +-
+ tests/data/test2412 | 50 ++++++++++++++++++++
+ tests/libtest/Makefile.inc | 1 +
+ tests/libtest/lib2412.c | 95 ++++++++++++++++++++++++++++++++++++++
+ tests/libtest/lib530.c | 3 ++
+ 8 files changed, 182 insertions(+), 13 deletions(-)
+ create mode 100644 tests/data/test2412
+ create mode 100644 tests/libtest/lib2412.c
+
+diff --git a/lib/multi.c b/lib/multi.c
+index d0fa68ab4c..d6ae111d8e 100644
+--- a/lib/multi.c
++++ b/lib/multi.c
+@@ -531,6 +531,8 @@ CURLMcode curl_multi_add_handle(CURLM *m, CURL *curl)
+
+ /* set the easy handle */
+ multistate(data, MSTATE_INIT);
++ /* not yet passed INIT state */
++ data->state.really_alive = FALSE;
+
+ #ifdef USE_LIBPSL
+ /* Do the same for PSL. */
+@@ -570,12 +572,6 @@ CURLMcode curl_multi_add_handle(CURLM *m, CURL *curl)
+ data->set.server_response_timeout;
+ multi->admin->set.no_signal = data->set.no_signal;
+
+- mresult = multi_assess_wakeup(multi);
+- if(mresult) {
+- failf(data, "error enabling wakeup listening: %d", mresult);
+- return mresult;
+- }
+-
+ CURL_TRC_M(data, "added to multi, mid=%u, running=%u, total=%u",
+ data->mid, Curl_multi_xfers_running(multi),
+ Curl_uint32_tbl_count(&multi->xfers));
+@@ -851,6 +847,12 @@ CURLMcode curl_multi_remove_handle(CURLM *m, CURL *curl)
+ /* If in `msgsent`, it was deducted from `multi->xfers_alive` already. */
+ if(!Curl_uint32_bset_contains(&multi->msgsent, data->mid))
+ --multi->xfers_alive;
++ if(data->state.really_alive) {
++ data->state.really_alive = FALSE;
++ --multi->xfers_really_alive;
++ if(!multi->xfers_really_alive)
++ (void)multi_assess_wakeup(multi);
++ }
+
+ Curl_wildcard_dtor(&data->wildcard);
+
+@@ -1151,7 +1153,9 @@ CURLMcode Curl_multi_pollset(struct Curl_easy *data,
+ /* The admin handle always listens on the wakeup socket when there
+ * are transfers alive. */
+ if(data->multi && (data == data->multi->admin) &&
+- data->multi->xfers_alive) {
++ data->multi->xfers_really_alive) {
++ CURL_TRC_M(data, "adding wakeup, %u xfers really alive",
++ data->multi->xfers_really_alive);
+ result = Curl_pollset_add_in(data, ps, data->multi->wakeup_pair[0]);
+ }
+ #endif
+@@ -2459,6 +2463,12 @@ static void handle_completed(struct Curl_multi *multi,
+ Curl_uint32_bset_remove(&multi->dirty, data->mid);
+ Curl_uint32_bset_remove(&multi->pending, data->mid);
+ Curl_uint32_bset_add(&multi->msgsent, data->mid);
++ if(data->state.really_alive) {
++ data->state.really_alive = FALSE;
++ --multi->xfers_really_alive;
++ if(!multi->xfers_really_alive)
++ (void)multi_assess_wakeup(multi);
++ }
+ --multi->xfers_alive;
+ if(!multi->xfers_alive)
+ multi_assess_wakeup(multi);
+@@ -2466,6 +2476,18 @@ static void handle_completed(struct Curl_multi *multi,
+
+ static CURLMcode multistate_init(struct Curl_easy *data, CURLcode *result)
+ {
++ if(!data->state.really_alive) {
++ data->state.really_alive = TRUE;
++ ++data->multi->xfers_really_alive;
++ if(data->multi->xfers_really_alive == 1) {
++ CURLMcode mresult = multi_assess_wakeup(data->multi);
++ if(mresult) {
++ failf(data, "error enabling wakeup listening: %d", mresult);
++ return mresult;
++ }
++ }
++ }
++
+ *result = Curl_pretransfer(data);
+ if(*result)
+ return CURLM_OK;
+diff --git a/lib/multihandle.h b/lib/multihandle.h
+index c5cdfbe82e..19dd2ffcdf 100644
+--- a/lib/multihandle.h
++++ b/lib/multihandle.h
+@@ -85,6 +85,8 @@ struct Curl_multi {
+
+ unsigned int xfers_alive; /* amount of added transfers that have
+ not yet reached COMPLETE state */
++ unsigned int xfers_really_alive; /* amount of added transfers that have
++ passed INIT state but are not COMPLETE yet */
+ curl_off_t xfers_total_ever; /* total of added transfers, ever. */
+ struct uint32_tbl xfers; /* transfers added to this multi */
+ /* Each transfer's mid may be present in at most one of these */
+diff --git a/lib/urldata.h b/lib/urldata.h
+index 232364fcf3..d4d336d8db 100644
+--- a/lib/urldata.h
++++ b/lib/urldata.h
+@@ -704,11 +704,7 @@ struct UrlState {
+ uint8_t httpreq; /* Curl_HttpReq; what kind of HTTP request (if any)
+ is this */
+
+- /* when curl_easy_perform() is called, the multi handle is "owned" by
+- the easy handle so curl_easy_cleanup() on such an easy handle will
+- also close the multi handle! */
+- BIT(multi_owned_by_easy);
+-
++ BIT(really_alive); /* transfer is really alive in multi, passed INIT */
+ BIT(this_is_a_follow); /* this is a followed Location: request */
+ BIT(refused_stream); /* this was refused, try again */
+ BIT(errorbuf); /* Set to TRUE if the error buffer is already filled in.
+diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am
+index 0d5277d55b..676d49f4fd 100644
+--- a/tests/data/Makefile.am
++++ b/tests/data/Makefile.am
+@@ -261,7 +261,7 @@ test2300 test2301 test2302 test2303 test2304 test2306 test2307 test2308 \
+ test2309 test2310 \
+ \
+ test2400 test2401 test2402 test2403 test2404 test2405 test2406 test2407 \
+-test2408 test2409 test2410 test2411 \
++test2408 test2409 test2410 test2411 test2412 \
+ \
+ test2500 test2501 test2502 test2503 test2504 test2505 test2506 \
+ \
+diff --git a/tests/data/test2412 b/tests/data/test2412
+new file mode 100644
+index 0000000000..e0320e2ce4
+--- /dev/null
++++ b/tests/data/test2412
+@@ -0,0 +1,50 @@
++<?xml version="1.0" encoding="US-ASCII"?>
++<testcase>
++<info>
++<keywords>
++multi
++</keywords>
++</info>
++
++# Server-side
++<reply>
++<data nocheck="yes">
++HTTP/1.1 200 OK
++Date: Tue, 09 Nov 2010 14:49:00 GMT
++Server: test-server/fake
++Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
++ETag: "21025-dc7-39462498"
++Accept-Ranges: bytes
++Content-Length: 6007
++Connection: close
++Content-Type: text/html
++Funny-head: yesyes
++
++-foo-
++%repeat[1000 x foobar]%
++</data>
++</reply>
++
++# Client-side
++<client>
++<features>
++wakeup
++</features>
++<server>
++http
++</server>
++<tool>
++lib%TESTNUMBER
++</tool>
++<name>
++checking curl_multi_fdset on nothing to do
++</name>
++<command>
++http://%HOSTIP:%HTTPPORT/%TESTNUMBER
++</command>
++</client>
++
++# Verify data after the test has been "shot"
++<verify>
++</verify>
++</testcase>
+diff --git a/tests/libtest/Makefile.inc b/tests/libtest/Makefile.inc
+index 98c9939994..bec648542b 100644
+--- a/tests/libtest/Makefile.inc
++++ b/tests/libtest/Makefile.inc
+@@ -115,6 +115,7 @@ TESTS_C = \
+ lib2023.c lib2032.c lib2082.c \
+ lib2301.c lib2302.c lib2304.c lib2306.c lib2308.c lib2309.c \
+ lib2402.c lib2404.c lib2405.c \
++ lib2412.c \
+ lib2502.c lib2504.c lib2505.c lib2506.c \
+ lib2700.c \
+ lib3010.c lib3025.c lib3026.c lib3027.c lib3033.c lib3034.c \
+diff --git a/tests/libtest/lib2412.c b/tests/libtest/lib2412.c
+new file mode 100644
+index 0000000000..79d49a2d76
+--- /dev/null
++++ b/tests/libtest/lib2412.c
+@@ -0,0 +1,95 @@
++/***************************************************************************
++ * _ _ ____ _
++ * Project ___| | | | _ \| |
++ * / __| | | | |_) | |
++ * | (__| |_| | _ <| |___
++ * \___|\___/|_| \_\_____|
++ *
++ * Copyright (C) Dmitry Karpov <dkarpov1970@gmail.com>
++ *
++ * This software is licensed as described in the file COPYING, which
++ * you should have received as part of this distribution. The terms
++ * are also available at https://curl.se/docs/copyright.html.
++ *
++ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
++ * copies of the Software, and permit persons to whom the Software is
++ * furnished to do so, under the terms of the COPYING file.
++ *
++ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
++ * KIND, either express or implied.
++ *
++ * SPDX-License-Identifier: curl
++ *
++ ***************************************************************************/
++
++#include "first.h"
++#include "testtrace.h"
++
++static CURLcode test_lib2412(const char *URL)
++{
++ CURLcode result = CURLE_OK;
++ CURLM *multi = NULL;
++ CURL *easy = NULL;
++ CURLMcode rc;
++ fd_set readFdSet, writeFdSet, exceptFdSet;
++ int maxFd;
++
++ (void)URL;
++ global_init(CURL_GLOBAL_ALL);
++
++ multi = curl_multi_init();
++ if(!multi) {
++ curl_mfprintf(stderr, "curl_multi_init() failed\n");
++ result = TEST_ERR_MAJOR_BAD;
++ goto test_cleanup;
++ }
++
++ easy = curl_easy_init();
++ if(!easy) {
++ curl_mfprintf(stderr, "curl_easy_init() failed\n");
++ result = TEST_ERR_MAJOR_BAD;
++ goto test_cleanup;
++ }
++ debug_config.nohex = TRUE;
++ debug_config.tracetime = TRUE;
++ easy_setopt(easy, CURLOPT_DEBUGDATA, &debug_config);
++ easy_setopt(easy, CURLOPT_DEBUGFUNCTION, libtest_debug_cb);
++ easy_setopt(easy, CURLOPT_VERBOSE, 1L);
++
++ rc = curl_multi_add_handle(multi, easy);
++ if(rc) {
++ curl_mfprintf(stderr, "curl_multi_add_handle() failed: %d\n", rc);
++ result = TEST_ERR_MAJOR_BAD;
++ goto test_cleanup;
++ }
++
++ FD_ZERO(&readFdSet);
++ FD_ZERO(&writeFdSet);
++ FD_ZERO(&exceptFdSet);
++ maxFd = -1;
++ rc = curl_multi_fdset(multi, &readFdSet, &writeFdSet, &exceptFdSet,
++ &maxFd);
++ if(rc) {
++ curl_mfprintf(stderr, "curl_multi_fdset() failed: %d\n", rc);
++ result = TEST_ERR_MAJOR_BAD;
++ goto test_cleanup;
++ }
++
++ if(maxFd == -1)
++ curl_mfprintf(stderr, "There are no file descriptors to wait for\n");
++ else {
++ curl_mfprintf(stderr, "libcurl supplied a file descriptor to "
++ "wait for (maxFd=%d). Waiting now ...\n", maxFd);
++ result = TEST_ERR_FAILURE;
++ }
++
++test_cleanup:
++ if(easy) {
++ curl_multi_remove_handle(multi, easy);
++ curl_easy_cleanup(easy);
++ }
++ if(multi)
++ curl_multi_cleanup(multi);
++ curl_global_cleanup();
++ return result;
++}
+diff --git a/tests/libtest/lib530.c b/tests/libtest/lib530.c
+index d4c894d1d0..bddb857be0 100644
+--- a/tests/libtest/lib530.c
++++ b/tests/libtest/lib530.c
+@@ -29,6 +29,7 @@
+ */
+
+ #include "first.h"
++#include "testtrace.h"
+
+ static struct t530_ctx {
+ int socket_calls;
+@@ -300,6 +301,8 @@ static CURLcode testone(const char *URL, int timer_fail_at, int socket_fail_at)
+ easy_setopt(curl, CURLOPT_URL, URL);
+
+ /* go verbose */
++ easy_setopt(curl, CURLOPT_DEBUGDATA, &debug_config);
++ easy_setopt(curl, CURLOPT_DEBUGFUNCTION, libtest_debug_cb);
+ easy_setopt(curl, CURLOPT_VERBOSE, 1L);
+
+ multi_init(multi);
+--
+2.54.0
+
diff --git a/curl.spec b/curl.spec
index 1be531f..0492417 100644
--- a/curl.spec
+++ b/curl.spec
@@ -13,7 +13,7 @@
Summary: A utility for getting files from remote servers (FTP, HTTP, and others)
Name: curl
Version: 8.21.0~rc3
-Release: 1%{?dist}
+Release: 2%{?dist}
License: curl
Source0: https://curl.se/download/%{name}-%{version_no_tilde}.tar.xz
Source1: https://curl.se/download/%{name}-%{version_no_tilde}.tar.xz.asc
@@ -22,6 +22,9 @@ Source1: https://curl.se/download/%{name}-%{version_no_tilde}.tar.xz.asc
# which points to the GPG key as of April 7th 2016 of https://daniel.haxx.se/mykey.asc
Source2: mykey.asc
+# fix multi_fdset must not report only the wakeup socket (#2460719)
+Patch001: 0001-curl-8.21.0~rc3-multi-xfers_really_alive.patch
+
# patch making libcurl multilib ready
Patch101: 0101-curl-7.32.0-multilib.patch
@@ -256,7 +259,7 @@ printf "609\n610\n611\n612\n613\n614\n615\n616\n617\n618\n" >>tests/data/DISABLE
printf "619\n620\n621\n622\n623\n624\n625\n626\n627\n628\n" >>tests/data/DISABLED
printf "629\n630\n631\n633\n634\n635\n636\n637\n638\n639\n" >>tests/data/DISABLED
printf "640\n641\n642\n656\n664\n665\n" >>tests/data/DISABLED
-printf "1446\n1459\n1583\n2004\n2007\n" >>tests/data/DISABLED
+printf "1446\n1459\n1583\n1725\n2004\n2007\n" >>tests/data/DISABLED
printf "3021\n3022\n" >>tests/data/DISABLED
%endif
@@ -465,6 +468,9 @@ rm -f ${RPM_BUILD_ROOT}%{_mandir}/man1/wcurl.1*
%{_libdir}/libcurl.so.4.[0-9].[0-9].minimal
%changelog
+* Thu Jun 18 2026 Jan Macku <jamacku@redhat.com> - 8.21.0~rc3-2
+- fix multi_fdset must not report only the wakeup socket (#2460719)
+
* Wed Jun 17 2026 Jan Macku <jamacku@redhat.com> - 8.21.0~rc3-1
- new upstream release candidate
reply other threads:[~2026-06-18 10:54 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=178178005848.1.15778690615029135378.rpms-curl-b4df4148f935@fedoraproject.org \
--to=jamacku@redhat.com \
--cc=git-commits@fedoraproject.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox