From: Alexandre Ferrieux Date: Tue, 12 Jul 2022 21:40:05 +0000 (+0200) Subject: CURLOPT_QUICK_EXIT: don't wait for DNS thread on exit X-Git-Tag: curl-7_87_0~142 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=49798cac832ab1;p=thirdparty%2Fcurl.git CURLOPT_QUICK_EXIT: don't wait for DNS thread on exit Fixes #2975 Closes #9147 --- diff --git a/.github/scripts/spellcheck.words b/.github/scripts/spellcheck.words index d8836d1376..73b65d46f6 100644 --- a/.github/scripts/spellcheck.words +++ b/.github/scripts/spellcheck.words @@ -755,6 +755,7 @@ Tomtom toolchain toolchains toolset +toplevel TPF TrackMemory Tru diff --git a/docs/libcurl/curl_easy_setopt.3 b/docs/libcurl/curl_easy_setopt.3 index da7752767b..9295d84aa3 100644 --- a/docs/libcurl/curl_easy_setopt.3 +++ b/docs/libcurl/curl_easy_setopt.3 @@ -699,6 +699,8 @@ Share object to use. See \fICURLOPT_SHARE(3)\fP Mode for creating new remote files. See \fICURLOPT_NEW_FILE_PERMS(3)\fP .IP CURLOPT_NEW_DIRECTORY_PERMS Mode for creating new remote directories. See \fICURLOPT_NEW_DIRECTORY_PERMS(3)\fP +.IP CURLOPT_QUICK_EXIT +To be set by toplevel tools like "curl" to skip lengthy cleanups when they are about to call exit() anyway. See \fICURLOPT_QUICK_EXIT(3)\fP .SH TELNET OPTIONS .IP CURLOPT_TELNETOPTIONS TELNET options. See \fICURLOPT_TELNETOPTIONS(3)\fP diff --git a/docs/libcurl/opts/CURLOPT_QUICK_EXIT.3 b/docs/libcurl/opts/CURLOPT_QUICK_EXIT.3 new file mode 100644 index 0000000000..5f800bbd15 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_QUICK_EXIT.3 @@ -0,0 +1,59 @@ +.\" ************************************************************************** +.\" * _ _ ____ _ +.\" * Project ___| | | | _ \| | +.\" * / __| | | | |_) | | +.\" * | (__| |_| | _ <| |___ +.\" * \___|\___/|_| \_\_____| +.\" * +.\" * Copyright (C) 1998 - 2022, Daniel Stenberg, , et al. +.\" * +.\" * 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 +.\" * +.\" ************************************************************************** +.\" +.TH CURLOPT_QUICK_EXIT 3 "30 Sep 2022" "libcurl 7.87.0" "curl_easy_setopt options" +.SH NAME +CURLOPT_QUICK_EXIT \- allow to exit quickly +.SH SYNOPSIS +.nf +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_QUICK_EXIT, + long value); +.SH DESCRIPTION +Pass a long as a parameter, 1L meaning that when recovering from a timeout, +libcurl should skip lengthy cleanups that are intended to avoid all kinds of +leaks (threads etc.), as the caller program is about to call exit() anyway. +This allows for a swift termination after a DNS timeout for example, by +canceling and/or forgetting about a resolver thread, at the expense of a +possible (though short-lived) leak of associated resources. +.SH DEFAULT +0 +.SH PROTOCOLS +All +.SH EXAMPLE +.nf +CURL *curl = curl_easy_init(); +if(curl) { + CURLcode ret; + curl_easy_setopt(curl, CURLOPT_QUICK_EXIT, 1L); + ret = curl_easy_perform(curl); +} +.fi +.SH AVAILABILITY +Added in 7.87.0 +.SH RETURN VALUE +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. +.SH "SEE ALSO" +.BR CURLOPT_RESOLVE "(3), " diff --git a/docs/libcurl/symbols-in-versions b/docs/libcurl/symbols-in-versions index 59c66b4e35..5ee245d361 100644 --- a/docs/libcurl/symbols-in-versions +++ b/docs/libcurl/symbols-in-versions @@ -687,6 +687,7 @@ CURLOPT_MAIL_AUTH 7.25.0 CURLOPT_MAIL_FROM 7.20.0 CURLOPT_MAIL_RCPT 7.20.0 CURLOPT_MAIL_RCPT_ALLLOWFAILS 7.69.0 +CURLOPT_QUICK_EXIT 7.87.0 CURLOPT_MAX_RECV_SPEED_LARGE 7.15.5 CURLOPT_MAX_SEND_SPEED_LARGE 7.15.5 CURLOPT_MAXAGE_CONN 7.65.0 diff --git a/include/curl/curl.h b/include/curl/curl.h index 6b8b10bd1a..efbba31f80 100644 --- a/include/curl/curl.h +++ b/include/curl/curl.h @@ -2201,6 +2201,9 @@ typedef enum { /* CA cache timeout */ CURLOPT(CURLOPT_CA_CACHE_TIMEOUT, CURLOPTTYPE_LONG, 321), + /* Can leak things, gonna exit() soon */ + CURLOPT(CURLOPT_QUICK_EXIT, CURLOPTTYPE_LONG, 322), + CURLOPT_LASTENTRY /* the last unused */ } CURLoption; diff --git a/lib/asyn-thread.c b/lib/asyn-thread.c index 283629e845..3524ada584 100644 --- a/lib/asyn-thread.c +++ b/lib/asyn-thread.c @@ -534,7 +534,8 @@ void Curl_resolver_kill(struct Curl_easy *data) /* If we're still resolving, we must wait for the threads to fully clean up, unfortunately. Otherwise, we can simply cancel to clean up any resolver data. */ - if(td && td->thread_hnd != curl_thread_t_null) + if(td && td->thread_hnd != curl_thread_t_null + && (data->set.quick_exit != 1L)) (void)thread_wait_resolv(data, NULL, FALSE); else Curl_resolver_cancel(data); diff --git a/lib/easyoptions.c b/lib/easyoptions.c index 594150178a..03b814e5aa 100644 --- a/lib/easyoptions.c +++ b/lib/easyoptions.c @@ -242,6 +242,7 @@ struct curl_easyoption Curl_easyopts[] = { CURLOT_STRING, 0}, {"PROXY_TRANSFER_MODE", CURLOPT_PROXY_TRANSFER_MODE, CURLOT_LONG, 0}, {"PUT", CURLOPT_PUT, CURLOT_LONG, 0}, + {"QUICK_EXIT", CURLOPT_QUICK_EXIT, CURLOT_LONG, 0}, {"QUOTE", CURLOPT_QUOTE, CURLOT_SLIST, 0}, {"RANDOM_FILE", CURLOPT_RANDOM_FILE, CURLOT_STRING, 0}, {"RANGE", CURLOPT_RANGE, CURLOT_STRING, 0}, @@ -369,6 +370,6 @@ struct curl_easyoption Curl_easyopts[] = { */ int Curl_easyopts_check(void) { - return ((CURLOPT_LASTENTRY%10000) != (321 + 1)); + return ((CURLOPT_LASTENTRY%10000) != (322 + 1)); } #endif diff --git a/lib/setopt.c b/lib/setopt.c index 51335b8cd7..d53131a0ec 100644 --- a/lib/setopt.c +++ b/lib/setopt.c @@ -3116,6 +3116,9 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) break; } #endif + case CURLOPT_QUICK_EXIT: + data->set.quick_exit = (0 != va_arg(param, long)) ? 1L:0L; + break; default: /* unknown tag and its companion, just ignore: */ result = CURLE_UNKNOWN_OPTION; diff --git a/lib/url.c b/lib/url.c index a9d89cc2c1..f2ad31742c 100644 --- a/lib/url.c +++ b/lib/url.c @@ -655,6 +655,7 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data) #endif ; Curl_http2_init_userset(set); + set->quick_exit = 0L; return result; } diff --git a/lib/urldata.h b/lib/urldata.h index 638763cf77..c50171e73c 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -1826,6 +1826,10 @@ struct UserDefined { /* Here follows boolean settings that define how to behave during this session. They are STATIC, set by libcurl users or at least initially and they don't change during operations. */ + BIT(quick_exit); /* set 1L when it is okay to leak things (like + threads), as we're about to exit() anyway and + don't want lengthy cleanups to delay termination, + e.g. after a DNS timeout */ BIT(get_filetime); /* get the time and get of the remote file */ BIT(tunnel_thru_httpproxy); /* use CONNECT through an HTTP proxy */ BIT(prefer_ascii); /* ASCII rather than binary */ diff --git a/src/tool_operate.c b/src/tool_operate.c index 095c24bacf..cd137ec10d 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c @@ -1237,6 +1237,15 @@ static CURLcode single_transfer(struct GlobalConfig *global, use_proto = url_proto(per->this_url); + /* On most modern OSes, exiting works thoroughly, + we'll clean everything up via exit(), so don't bother with + slow cleanups. Crappy ones might need to skip this. + Note: avoid having this setopt added to the --libcurl source + output. */ + result = curl_easy_setopt(curl, CURLOPT_QUICK_EXIT, 1L); + if(result) + break; + if(!config->tcp_nodelay) my_setopt(curl, CURLOPT_TCP_NODELAY, 0L);