CURLOPT_QUICK_EXIT: don't wait for DNS thread on exit

Fixes #2975
Closes #9147
This commit is contained in:
Alexandre Ferrieux 2022-07-12 23:40:05 +02:00 committed by Daniel Stenberg
parent b473df52bb
commit 49798cac83
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
11 changed files with 87 additions and 2 deletions

View File

@ -755,6 +755,7 @@ Tomtom
toolchain toolchain
toolchains toolchains
toolset toolset
toplevel
TPF TPF
TrackMemory TrackMemory
Tru Tru

View File

@ -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 Mode for creating new remote files. See \fICURLOPT_NEW_FILE_PERMS(3)\fP
.IP CURLOPT_NEW_DIRECTORY_PERMS .IP CURLOPT_NEW_DIRECTORY_PERMS
Mode for creating new remote directories. See \fICURLOPT_NEW_DIRECTORY_PERMS(3)\fP 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 .SH TELNET OPTIONS
.IP CURLOPT_TELNETOPTIONS .IP CURLOPT_TELNETOPTIONS
TELNET options. See \fICURLOPT_TELNETOPTIONS(3)\fP TELNET options. See \fICURLOPT_TELNETOPTIONS(3)\fP

View File

@ -0,0 +1,59 @@
.\" **************************************************************************
.\" * _ _ ____ _
.\" * Project ___| | | | _ \| |
.\" * / __| | | | |_) | |
.\" * | (__| |_| | _ <| |___
.\" * \___|\___/|_| \_\_____|
.\" *
.\" * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, 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 <curl/curl.h>
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), "

View File

@ -687,6 +687,7 @@ CURLOPT_MAIL_AUTH 7.25.0
CURLOPT_MAIL_FROM 7.20.0 CURLOPT_MAIL_FROM 7.20.0
CURLOPT_MAIL_RCPT 7.20.0 CURLOPT_MAIL_RCPT 7.20.0
CURLOPT_MAIL_RCPT_ALLLOWFAILS 7.69.0 CURLOPT_MAIL_RCPT_ALLLOWFAILS 7.69.0
CURLOPT_QUICK_EXIT 7.87.0
CURLOPT_MAX_RECV_SPEED_LARGE 7.15.5 CURLOPT_MAX_RECV_SPEED_LARGE 7.15.5
CURLOPT_MAX_SEND_SPEED_LARGE 7.15.5 CURLOPT_MAX_SEND_SPEED_LARGE 7.15.5
CURLOPT_MAXAGE_CONN 7.65.0 CURLOPT_MAXAGE_CONN 7.65.0

View File

@ -2201,6 +2201,9 @@ typedef enum {
/* CA cache timeout */ /* CA cache timeout */
CURLOPT(CURLOPT_CA_CACHE_TIMEOUT, CURLOPTTYPE_LONG, 321), 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 */ CURLOPT_LASTENTRY /* the last unused */
} CURLoption; } CURLoption;

View File

@ -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, /* 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 unfortunately. Otherwise, we can simply cancel to clean up any resolver
data. */ 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); (void)thread_wait_resolv(data, NULL, FALSE);
else else
Curl_resolver_cancel(data); Curl_resolver_cancel(data);

View File

@ -242,6 +242,7 @@ struct curl_easyoption Curl_easyopts[] = {
CURLOT_STRING, 0}, CURLOT_STRING, 0},
{"PROXY_TRANSFER_MODE", CURLOPT_PROXY_TRANSFER_MODE, CURLOT_LONG, 0}, {"PROXY_TRANSFER_MODE", CURLOPT_PROXY_TRANSFER_MODE, CURLOT_LONG, 0},
{"PUT", CURLOPT_PUT, CURLOT_LONG, 0}, {"PUT", CURLOPT_PUT, CURLOT_LONG, 0},
{"QUICK_EXIT", CURLOPT_QUICK_EXIT, CURLOT_LONG, 0},
{"QUOTE", CURLOPT_QUOTE, CURLOT_SLIST, 0}, {"QUOTE", CURLOPT_QUOTE, CURLOT_SLIST, 0},
{"RANDOM_FILE", CURLOPT_RANDOM_FILE, CURLOT_STRING, 0}, {"RANDOM_FILE", CURLOPT_RANDOM_FILE, CURLOT_STRING, 0},
{"RANGE", CURLOPT_RANGE, CURLOT_STRING, 0}, {"RANGE", CURLOPT_RANGE, CURLOT_STRING, 0},
@ -369,6 +370,6 @@ struct curl_easyoption Curl_easyopts[] = {
*/ */
int Curl_easyopts_check(void) int Curl_easyopts_check(void)
{ {
return ((CURLOPT_LASTENTRY%10000) != (321 + 1)); return ((CURLOPT_LASTENTRY%10000) != (322 + 1));
} }
#endif #endif

View File

@ -3116,6 +3116,9 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
break; break;
} }
#endif #endif
case CURLOPT_QUICK_EXIT:
data->set.quick_exit = (0 != va_arg(param, long)) ? 1L:0L;
break;
default: default:
/* unknown tag and its companion, just ignore: */ /* unknown tag and its companion, just ignore: */
result = CURLE_UNKNOWN_OPTION; result = CURLE_UNKNOWN_OPTION;

View File

@ -655,6 +655,7 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
#endif #endif
; ;
Curl_http2_init_userset(set); Curl_http2_init_userset(set);
set->quick_exit = 0L;
return result; return result;
} }

View File

@ -1826,6 +1826,10 @@ struct UserDefined {
/* Here follows boolean settings that define how to behave during /* Here follows boolean settings that define how to behave during
this session. They are STATIC, set by libcurl users or at least initially this session. They are STATIC, set by libcurl users or at least initially
and they don't change during operations. */ 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(get_filetime); /* get the time and get of the remote file */
BIT(tunnel_thru_httpproxy); /* use CONNECT through an HTTP proxy */ BIT(tunnel_thru_httpproxy); /* use CONNECT through an HTTP proxy */
BIT(prefer_ascii); /* ASCII rather than binary */ BIT(prefer_ascii); /* ASCII rather than binary */

View File

@ -1237,6 +1237,15 @@ static CURLcode single_transfer(struct GlobalConfig *global,
use_proto = url_proto(per->this_url); 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) if(!config->tcp_nodelay)
my_setopt(curl, CURLOPT_TCP_NODELAY, 0L); my_setopt(curl, CURLOPT_TCP_NODELAY, 0L);