Skip to content

Commit

Permalink
multi: add curl_multi_init2 for advanced multi init
Browse files Browse the repository at this point in the history
Allow initializing a multi with a specific socket table hash size,
connection cache hash size, and flags. Flag
CURL_MULTI_DISABLE_POLL_WAKEUP can be used to disable the
curl_multi_poll wakeup socketpair. A user requested the option to
disable creating those sockets due to resource constraints.

Prior to this change it was not possible to disable the wakeup
socketpair (added in 7.68.0) used by the multi.

Reported-by: Anders Bakken

Fixes curl#4829
Closes #xxxx
  • Loading branch information
jay committed Jan 21, 2020
1 parent 599d92e commit 80b0bd3
Show file tree
Hide file tree
Showing 11 changed files with 132 additions and 23 deletions.
1 change: 1 addition & 0 deletions docs/libcurl/Makefile.inc
Expand Up @@ -45,6 +45,7 @@ man_MANS = \
curl_multi_fdset.3 \
curl_multi_info_read.3 \
curl_multi_init.3 \
curl_multi_init2.3 \
curl_multi_perform.3 \
curl_multi_poll.3 \
curl_multi_remove_handle.3 \
Expand Down
6 changes: 5 additions & 1 deletion docs/libcurl/curl_multi_init.3
Expand Up @@ -5,7 +5,7 @@
.\" * | (__| |_| | _ <| |___
.\" * \___|\___/|_| \_\_____|
.\" *
.\" * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
.\" * Copyright (C) 1998 - 2020, 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
Expand All @@ -32,8 +32,12 @@ This function returns a CURLM handle to be used as input to all the other
multi-functions, sometimes referred to as a multi handle in some places in the
documentation. This init call MUST have a corresponding call to
\fIcurl_multi_cleanup(3)\fP when the operation is complete.

\fIcurl_multi_init2(3)\fP is the same as this function except that it allows
setting advanced init options. (7.69.0)
.SH RETURN VALUE
If this function returns NULL, something went wrong and you cannot use the
other curl functions.
.SH "SEE ALSO"
.BR curl_multi_init2 "(3)"
.BR curl_multi_cleanup "(3)," curl_global_init "(3)," curl_easy_init "(3)"
61 changes: 61 additions & 0 deletions docs/libcurl/curl_multi_init2.3
@@ -0,0 +1,61 @@
.\" **************************************************************************
.\" * _ _ ____ _
.\" * Project ___| | | | _ \| |
.\" * / __| | | | |_) | |
.\" * | (__| |_| | _ <| |___
.\" * \___|\___/|_| \_\_____|
.\" *
.\" * Copyright (C) 1998 - 2020, 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.haxx.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.
.\" *
.\" **************************************************************************
.TH curl_multi_init2 3 "21 January 2020" "libcurl 7.69.0" "libcurl Manual"
.SH NAME
curl_multi_init2 - create a multi handle with advanced init options
.SH SYNOPSIS
.B #include <curl/curl.h>
.sp
.BI "CURLM *curl_multi_init2(int" socket_table_hashsize ","
.BI "int" conn_cache_hashsize ", int" flags ");"
.ad
.SH DESCRIPTION
This function returns a CURLM handle to be used as input to all the other
multi-functions, sometimes referred to as a multi handle in some places in the
documentation. This init call MUST have a corresponding call to
\fIcurl_multi_cleanup(3)\fP when the operation is complete.

\fBsocket_table_hashsize\fP sets the size of the hash table used to keep track
of sockets. \fBconnection_hashsize\fP sets the size of the hash table used to
keep track of the connections. Set both options to 0 to use the default values
unless a curl developer says otherwise.

\fBflags\fP refer to the FLAGS section below.

\fIcurl_multi_init(3)\fP is the same as this function except that it doesn't
allow setting advanced init options.
.SH FLAGS
.IP CURL_MULTI_DISABLE_POLL_WAKEUP
Since 7.68.0 each multi has a wakeup socket pair to allow waking
\fIcurl_multi_poll(3)\fP from a different thread. The wakeup socket pair is 2
sockets that remain open for the life of the multi. If your socket resources
are very limited you can use this flag to disable the wakeup socket pair. Note
\fIcurl_multi_wakeup(3)\fP will return an error if there is no wakeup socket
pair.
.SH AVAILABILITY
7.69.0
.SH RETURN VALUE
If this function returns NULL, something went wrong and you cannot use the
other curl functions.
.SH "SEE ALSO"
.BR curl_multi_init "(3)"
.BR curl_multi_cleanup "(3)," curl_global_init "(3)," curl_easy_init "(3)"
10 changes: 6 additions & 4 deletions docs/libcurl/curl_multi_poll.3
Expand Up @@ -5,7 +5,7 @@
.\" * | (__| |_| | _ <| |___
.\" * \___|\___/|_| \_\_____|
.\" *
.\" * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
.\" * Copyright (C) 1998 - 2020, 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
Expand Down Expand Up @@ -49,9 +49,11 @@ number can include both libcurl internal descriptors as well as descriptors
provided in \fIextra_fds\fP.

The \fIcurl_multi_wakeup(3)\fP function can be used from another thread to
wake up this function and return faster. This is one of the details
that makes this function different than \fIcurl_multi_wait(3)\fP which cannot
be woken up this way.
wake up this function and return faster. The ability to wake up is one of the
details that makes this function different than \fIcurl_multi_wait(3)\fP which
cannot be woken up this way. (Note wakeup can be disabled and libcurl has no
internal thread synchronization; refer to the wakeup function's documentation
for more info.)

If no extra file descriptors are provided and libcurl has no file descriptor
to offer to wait for, this function will instead wait during \fItimeout_ms\fP
Expand Down
12 changes: 10 additions & 2 deletions docs/libcurl/curl_multi_wakeup.3
Expand Up @@ -5,7 +5,7 @@
.\" * | (__| |_| | _ <| |___
.\" * \___|\___/|_| \_\_____|
.\" *
.\" * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
.\" * Copyright (C) 1998 - 2020, 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
Expand Down Expand Up @@ -41,6 +41,14 @@ possible that multiple calls to this function will wake up the same waiting
operation.

This function has no effect on \fIcurl_multi_wait(3)\fP calls.

The wakeup feature may be disabled for a multi via \fIcurl_multi_init2(3)\fP.
If the wakeup feature is disabled then this function will return an error.
.SH WARNING
\fBlibcurl has no internal thread synchronization.\fP You will need to ensure
that your code does not call this function on the multi after it calls
curl_multi_cleanup. For more on thread safety read
https://curl.haxx.se/libcurl/c/threadsafe.html
.SH RETURN VALUE
CURLMcode type, general libcurl multi interface error code.
.SH AVAILABILITY
Expand Down Expand Up @@ -83,4 +91,4 @@ if(something makes us decide to stop thread 1) {

.fi
.SH "SEE ALSO"
.BR curl_multi_poll "(3), " curl_multi_wait "(3)"
.BR curl_multi_poll "(3), " curl_multi_wait "(3)," curl_multi_init2 "(3)"
1 change: 1 addition & 0 deletions docs/libcurl/symbols-in-versions
Expand Up @@ -863,6 +863,7 @@ CURL_LOCK_TYPE_COOKIE 7.10 - 7.10.2
CURL_LOCK_TYPE_DNS 7.10 - 7.10.2
CURL_LOCK_TYPE_NONE 7.10 - 7.10.2
CURL_LOCK_TYPE_SSL_SESSION 7.10 - 7.10.2
CURL_MULTI_DISABLE_POLL_WAKEUP 7.69.0
CURL_MAX_HTTP_HEADER 7.19.7
CURL_MAX_READ_SIZE 7.53.0
CURL_MAX_WRITE_SIZE 7.9.7
Expand Down
15 changes: 15 additions & 0 deletions include/curl/multi.h
Expand Up @@ -449,6 +449,21 @@ typedef int (*curl_push_callback)(CURL *parent,
struct curl_pushheaders *headers,
void *userp);


/* Initialization flags for curl_multi_init2 (Curl_multi_handle) */
#define CURL_MULTI_DISABLE_POLL_WAKEUP (1<<0)

/*
* Name: curl_multi_init2()
*
* Desc: inititalize multi-style curl usage, with initialization options
*
* Returns: a new CURLM handle to use in all 'curl_multi' functions.
*/
CURL_EXTERN CURLM *curl_multi_init2(int socket_table_hashsize,
int conn_cache_hashsize,
int flags);

#ifdef __cplusplus
} /* end of extern "C" */
#endif
Expand Down
2 changes: 1 addition & 1 deletion lib/easy.c
Expand Up @@ -673,7 +673,7 @@ static CURLcode easy_perform(struct Curl_easy *data, bool events)
else {
/* this multi handle will only ever have a single easy handled attached
to it, so make it use minimal hashes */
multi = Curl_multi_handle(1, 3);
multi = Curl_multi_handle(1, 3, 0);
if(!multi)
return CURLE_OUT_OF_MEMORY;
data->multi_easy = multi;
Expand Down
44 changes: 30 additions & 14 deletions lib/multi.c
Expand Up @@ -344,7 +344,8 @@ static CURLMcode multi_addmsg(struct Curl_multi *multi,
}

struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */
int chashsize) /* connection hash */
int chashsize, /* connection hash */
int flags)
{
struct Curl_multi *multi = calloc(1, sizeof(struct Curl_multi));

Expand Down Expand Up @@ -372,16 +373,18 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */
multi->max_concurrent_streams = 100;

#ifdef ENABLE_WAKEUP
if(Curl_socketpair(AF_UNIX, SOCK_STREAM, 0, multi->wakeup_pair) < 0) {
multi->wakeup_pair[0] = CURL_SOCKET_BAD;
multi->wakeup_pair[1] = CURL_SOCKET_BAD;
}
else if(curlx_nonblock(multi->wakeup_pair[0], TRUE) < 0 ||
curlx_nonblock(multi->wakeup_pair[1], TRUE) < 0) {
sclose(multi->wakeup_pair[0]);
sclose(multi->wakeup_pair[1]);
multi->wakeup_pair[0] = CURL_SOCKET_BAD;
multi->wakeup_pair[1] = CURL_SOCKET_BAD;
if(!(flags & CURL_MULTI_DISABLE_POLL_WAKEUP)) {
if(Curl_socketpair(AF_UNIX, SOCK_STREAM, 0, multi->wakeup_pair) < 0) {
multi->wakeup_pair[0] = CURL_SOCKET_BAD;
multi->wakeup_pair[1] = CURL_SOCKET_BAD;
}
else if(curlx_nonblock(multi->wakeup_pair[0], TRUE) < 0 ||
curlx_nonblock(multi->wakeup_pair[1], TRUE) < 0) {
sclose(multi->wakeup_pair[0]);
sclose(multi->wakeup_pair[1]);
multi->wakeup_pair[0] = CURL_SOCKET_BAD;
multi->wakeup_pair[1] = CURL_SOCKET_BAD;
}
}
#endif

Expand All @@ -402,7 +405,18 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */
struct Curl_multi *curl_multi_init(void)
{
return Curl_multi_handle(CURL_SOCKET_HASH_TABLE_SIZE,
CURL_CONNECTION_HASH_SIZE);
CURL_CONNECTION_HASH_SIZE, 0);
}

struct Curl_multi *curl_multi_init2(int socket_table_hashsize,
int conn_cache_hashsize,
int flags)
{
if(!socket_table_hashsize <= 0)
socket_table_hashsize = CURL_SOCKET_HASH_TABLE_SIZE;
if(!conn_cache_hashsize <= 0)
conn_cache_hashsize = CURL_CONNECTION_HASH_SIZE;
return Curl_multi_handle(socket_table_hashsize, conn_cache_hashsize, flags);
}

CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
Expand Down Expand Up @@ -2425,8 +2439,10 @@ CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
Curl_psl_destroy(&multi->psl);

#ifdef ENABLE_WAKEUP
sclose(multi->wakeup_pair[0]);
sclose(multi->wakeup_pair[1]);
if(multi->wakeup_pair[0] != CURL_SOCKET_BAD)
sclose(multi->wakeup_pair[0]);
if(multi->wakeup_pair[1] != CURL_SOCKET_BAD)
sclose(multi->wakeup_pair[1]);
#endif
free(multi);

Expand Down
2 changes: 1 addition & 1 deletion lib/multiif.h
Expand Up @@ -39,7 +39,7 @@ bool Curl_is_in_callback(struct Curl_easy *easy);

/* Internal version of curl_multi_init() accepts size parameters for the
socket and connection hashes */
struct Curl_multi *Curl_multi_handle(int hashsize, int chashsize);
struct Curl_multi *Curl_multi_handle(int hashsize, int chashsize, int flags);

/* the write bits start at bit 16 for the *getsock() bitmap */
#define GETSOCK_WRITEBITSTART 16
Expand Down
1 change: 1 addition & 0 deletions tests/data/test1135
Expand Up @@ -105,6 +105,7 @@ CURL_EXTERN CURLMcode curl_multi_setopt(CURLM *multi_handle,
CURL_EXTERN CURLMcode curl_multi_assign(CURLM *multi_handle,
CURL_EXTERN char *curl_pushheader_bynum(struct curl_pushheaders *h,
CURL_EXTERN char *curl_pushheader_byname(struct curl_pushheaders *h,
CURL_EXTERN CURLM *curl_multi_init2(int socket_table_hashsize,
</stdout>
</verify>

Expand Down

0 comments on commit 80b0bd3

Please sign in to comment.