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 f537ba181b..705b8be4cd 100644
--- a/tests/data/Makefile.am
+++ b/tests/data/Makefile.am
@@ -262,7 +262,7 @@ test2300 test2301 test2302 test2303 test2304 test2306 test2307 test2308 \
test2309 test2310 test2311 \
\
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 @@
+
+
+
+
+multi
+
+
+
+# Server-side
+
+
+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]%
+
+
+
+# Client-side
+
+
+wakeup
+
+
+http
+
+
+lib%TESTNUMBER
+
+
+checking curl_multi_fdset on nothing to do
+
+
+http://%HOSTIP:%HTTPPORT/%TESTNUMBER
+
+
+
+# Verify data after the test has been "shot"
+
+
+
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
+ *
+ * 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);