mirror of
https://github.com/moparisthebest/curl
synced 2025-01-10 21:48:10 -05:00
multi: add curl_multi_wakeup()
This commit adds curl_multi_wakeup() which was previously in the TODO list under the curl_multi_unblock name. On some platforms and with some configurations this feature might not be available or can fail, in these cases a new error code (CURLM_WAKEUP_FAILURE) is returned from curl_multi_wakeup(). Fixes #4418 Closes #4608
This commit is contained in:
parent
0a65febccf
commit
f3c35e371c
@ -51,7 +51,6 @@
|
|||||||
2.4 Split connect and authentication process
|
2.4 Split connect and authentication process
|
||||||
2.5 Edge-triggered sockets should work
|
2.5 Edge-triggered sockets should work
|
||||||
2.6 multi upkeep
|
2.6 multi upkeep
|
||||||
2.7 curl_multi_unblock
|
|
||||||
|
|
||||||
3. Documentation
|
3. Documentation
|
||||||
3.2 Provide cmake config-file
|
3.2 Provide cmake config-file
|
||||||
@ -448,13 +447,6 @@
|
|||||||
|
|
||||||
See https://github.com/curl/curl/issues/3199
|
See https://github.com/curl/curl/issues/3199
|
||||||
|
|
||||||
2.7 curl_multi_unblock
|
|
||||||
|
|
||||||
A portable way to unblock curl_multi_wait from another thread.
|
|
||||||
|
|
||||||
See https://github.com/curl/curl/issues/4418 and
|
|
||||||
https://github.com/curl/curl/wiki/curl_multi_unblock
|
|
||||||
|
|
||||||
3. Documentation
|
3. Documentation
|
||||||
|
|
||||||
3.2 Provide cmake config-file
|
3.2 Provide cmake config-file
|
||||||
|
@ -54,6 +54,7 @@ man_MANS = \
|
|||||||
curl_multi_socket_all.3 \
|
curl_multi_socket_all.3 \
|
||||||
curl_multi_strerror.3 \
|
curl_multi_strerror.3 \
|
||||||
curl_multi_timeout.3 \
|
curl_multi_timeout.3 \
|
||||||
|
curl_multi_wakeup.3 \
|
||||||
curl_multi_wait.3 \
|
curl_multi_wait.3 \
|
||||||
curl_share_cleanup.3 \
|
curl_share_cleanup.3 \
|
||||||
curl_share_init.3 \
|
curl_share_init.3 \
|
||||||
|
@ -48,10 +48,16 @@ total number of file descriptors on which interesting events occurred. This
|
|||||||
number can include both libcurl internal descriptors as well as descriptors
|
number can include both libcurl internal descriptors as well as descriptors
|
||||||
provided in \fIextra_fds\fP.
|
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.
|
||||||
|
|
||||||
If no extra file descriptors are provided and libcurl has no file descriptor
|
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
|
to offer to wait for, this function will instead wait during \fItimeout_ms\fP
|
||||||
milliseconds (or shorter if an internal timer indicates so). This is the
|
milliseconds (or shorter if an internal timer indicates so). This is the
|
||||||
detail that makes this function different than \fIcurl_multi_wait(3)\fP.
|
other detail that makes this function different than
|
||||||
|
\fIcurl_multi_wait(3)\fP.
|
||||||
|
|
||||||
This function is encouraged to be used instead of select(3) when using the
|
This function is encouraged to be used instead of select(3) when using the
|
||||||
multi interface to allow applications to easier circumvent the common problem
|
multi interface to allow applications to easier circumvent the common problem
|
||||||
@ -107,4 +113,5 @@ CURLMcode type, general libcurl multi interface error code. See
|
|||||||
.SH AVAILABILITY
|
.SH AVAILABILITY
|
||||||
This function was added in libcurl 7.66.0.
|
This function was added in libcurl 7.66.0.
|
||||||
.SH "SEE ALSO"
|
.SH "SEE ALSO"
|
||||||
.BR curl_multi_fdset "(3), " curl_multi_perform "(3), " curl_multi_wait "(3)"
|
.BR curl_multi_fdset "(3), " curl_multi_perform "(3), "
|
||||||
|
.BR curl_multi_wait "(3), " curl_multi_wakeup "(3)"
|
||||||
|
47
docs/libcurl/curl_multi_wakeup.3
Normal file
47
docs/libcurl/curl_multi_wakeup.3
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
.\" **************************************************************************
|
||||||
|
.\" * _ _ ____ _
|
||||||
|
.\" * Project ___| | | | _ \| |
|
||||||
|
.\" * / __| | | | |_) | |
|
||||||
|
.\" * | (__| |_| | _ <| |___
|
||||||
|
.\" * \___|\___/|_| \_\_____|
|
||||||
|
.\" *
|
||||||
|
.\" * Copyright (C) 1998 - 2019, 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_wakeup 3 "17 Nov 2019" "libcurl 7.68.0" "libcurl Manual"
|
||||||
|
.SH NAME
|
||||||
|
curl_multi_wakeup - wakes up a sleeping curl_multi_poll call
|
||||||
|
.SH SYNOPSIS
|
||||||
|
#include <curl/curl.h>
|
||||||
|
|
||||||
|
CURLMcode curl_multi_wakeup(CURLM *multi_handle);
|
||||||
|
.ad
|
||||||
|
.SH DESCRIPTION
|
||||||
|
This function can be called from any thread and it wakes up a
|
||||||
|
sleeping \fIcurl_multi_poll(3)\fP call that is currently (or will be)
|
||||||
|
waiting for activity or a timeout.
|
||||||
|
|
||||||
|
If the function is called when there is no \fIcurl_multi_poll(3)\fP call,
|
||||||
|
it will cause the next call to return immediately.
|
||||||
|
|
||||||
|
Calling this function only guarantees to wake up the current (or the next
|
||||||
|
if there is no current) \fIcurl_multi_poll(3)\fP call, which means it is
|
||||||
|
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.
|
||||||
|
.SH RETURN VALUE
|
||||||
|
CURLMcode type, general libcurl multi interface error code.
|
||||||
|
.SH "SEE ALSO"
|
||||||
|
.BR curl_multi_poll "(3), " curl_multi_wait "(3)"
|
@ -297,6 +297,8 @@ An easy handle already added to a multi handle was attempted to get added a
|
|||||||
second time. (Added in 7.32.1)
|
second time. (Added in 7.32.1)
|
||||||
.IP "CURLM_RECURSIVE_API_CALL (8)"
|
.IP "CURLM_RECURSIVE_API_CALL (8)"
|
||||||
An API function was called from inside a callback.
|
An API function was called from inside a callback.
|
||||||
|
.IP "CURLM_WAKEUP_FAILURE (9)"
|
||||||
|
Wakeup is unavailable or failed.
|
||||||
.SH "CURLSHcode"
|
.SH "CURLSHcode"
|
||||||
The "share" interface will return a CURLSHcode to indicate when an error has
|
The "share" interface will return a CURLSHcode to indicate when an error has
|
||||||
occurred. Also consider \fIcurl_share_strerror(3)\fP.
|
occurred. Also consider \fIcurl_share_strerror(3)\fP.
|
||||||
|
@ -342,6 +342,7 @@ CURLM_INTERNAL_ERROR 7.9.6
|
|||||||
CURLM_OK 7.9.6
|
CURLM_OK 7.9.6
|
||||||
CURLM_OUT_OF_MEMORY 7.9.6
|
CURLM_OUT_OF_MEMORY 7.9.6
|
||||||
CURLM_RECURSIVE_API_CALL 7.59.0
|
CURLM_RECURSIVE_API_CALL 7.59.0
|
||||||
|
CURLM_WAKEUP_FAILURE 7.68.0
|
||||||
CURLM_UNKNOWN_OPTION 7.15.4
|
CURLM_UNKNOWN_OPTION 7.15.4
|
||||||
CURLOPTTYPE_FUNCTIONPOINT 7.1
|
CURLOPTTYPE_FUNCTIONPOINT 7.1
|
||||||
CURLOPTTYPE_LONG 7.1
|
CURLOPTTYPE_LONG 7.1
|
||||||
|
@ -72,6 +72,7 @@ typedef enum {
|
|||||||
attempted to get added - again */
|
attempted to get added - again */
|
||||||
CURLM_RECURSIVE_API_CALL, /* an api function was called from inside a
|
CURLM_RECURSIVE_API_CALL, /* an api function was called from inside a
|
||||||
callback */
|
callback */
|
||||||
|
CURLM_WAKEUP_FAILURE, /* wakeup is unavailable or failed */
|
||||||
CURLM_LAST
|
CURLM_LAST
|
||||||
} CURLMcode;
|
} CURLMcode;
|
||||||
|
|
||||||
@ -187,6 +188,15 @@ CURL_EXTERN CURLMcode curl_multi_poll(CURLM *multi_handle,
|
|||||||
int timeout_ms,
|
int timeout_ms,
|
||||||
int *ret);
|
int *ret);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Name: curl_multi_wakeup()
|
||||||
|
*
|
||||||
|
* Desc: wakes up a sleeping curl_multi_poll call.
|
||||||
|
*
|
||||||
|
* Returns: CURLMcode type, general multi error code.
|
||||||
|
*/
|
||||||
|
CURL_EXTERN CURLMcode curl_multi_wakeup(CURLM *multi_handle);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Name: curl_multi_perform()
|
* Name: curl_multi_perform()
|
||||||
*
|
*
|
||||||
|
114
lib/multi.c
114
lib/multi.c
@ -46,6 +46,7 @@
|
|||||||
#include "connect.h"
|
#include "connect.h"
|
||||||
#include "http_proxy.h"
|
#include "http_proxy.h"
|
||||||
#include "http2.h"
|
#include "http2.h"
|
||||||
|
#include "socketpair.h"
|
||||||
/* The last 3 #include files should be in this order */
|
/* The last 3 #include files should be in this order */
|
||||||
#include "curl_printf.h"
|
#include "curl_printf.h"
|
||||||
#include "curl_memory.h"
|
#include "curl_memory.h"
|
||||||
@ -367,6 +368,21 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */
|
|||||||
|
|
||||||
/* -1 means it not set by user, use the default value */
|
/* -1 means it not set by user, use the default value */
|
||||||
multi->maxconnects = -1;
|
multi->maxconnects = -1;
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return multi;
|
return multi;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
@ -1005,7 +1021,8 @@ static CURLMcode Curl_multi_wait(struct Curl_multi *multi,
|
|||||||
unsigned int extra_nfds,
|
unsigned int extra_nfds,
|
||||||
int timeout_ms,
|
int timeout_ms,
|
||||||
int *ret,
|
int *ret,
|
||||||
bool extrawait) /* when no socket, wait */
|
bool extrawait, /* when no socket, wait */
|
||||||
|
bool use_wakeup)
|
||||||
{
|
{
|
||||||
struct Curl_easy *data;
|
struct Curl_easy *data;
|
||||||
curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE];
|
curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE];
|
||||||
@ -1059,6 +1076,12 @@ static CURLMcode Curl_multi_wait(struct Curl_multi *multi,
|
|||||||
curlfds = nfds; /* number of internal file descriptors */
|
curlfds = nfds; /* number of internal file descriptors */
|
||||||
nfds += extra_nfds; /* add the externally provided ones */
|
nfds += extra_nfds; /* add the externally provided ones */
|
||||||
|
|
||||||
|
#ifdef ENABLE_WAKEUP
|
||||||
|
if(use_wakeup && multi->wakeup_pair[0] != CURL_SOCKET_BAD) {
|
||||||
|
++nfds;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if(nfds > NUM_POLLS_ON_STACK) {
|
if(nfds > NUM_POLLS_ON_STACK) {
|
||||||
/* 'nfds' is a 32 bit value and 'struct pollfd' is typically 8 bytes
|
/* 'nfds' is a 32 bit value and 'struct pollfd' is typically 8 bytes
|
||||||
big, so at 2^29 sockets this value might wrap. When a process gets
|
big, so at 2^29 sockets this value might wrap. When a process gets
|
||||||
@ -1117,6 +1140,14 @@ static CURLMcode Curl_multi_wait(struct Curl_multi *multi,
|
|||||||
++nfds;
|
++nfds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_WAKEUP
|
||||||
|
if(use_wakeup && multi->wakeup_pair[0] != CURL_SOCKET_BAD) {
|
||||||
|
ufds[nfds].fd = multi->wakeup_pair[0];
|
||||||
|
ufds[nfds].events = POLLIN;
|
||||||
|
++nfds;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if(nfds) {
|
if(nfds) {
|
||||||
int pollrc;
|
int pollrc;
|
||||||
/* wait... */
|
/* wait... */
|
||||||
@ -1140,6 +1171,29 @@ static CURLMcode Curl_multi_wait(struct Curl_multi *multi,
|
|||||||
|
|
||||||
extra_fds[i].revents = mask;
|
extra_fds[i].revents = mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_WAKEUP
|
||||||
|
if(use_wakeup && multi->wakeup_pair[0] != CURL_SOCKET_BAD) {
|
||||||
|
if(ufds[curlfds + extra_nfds].revents & POLLIN) {
|
||||||
|
char buf[64];
|
||||||
|
while(1) {
|
||||||
|
/* the reading socket is non-blocking, try to read
|
||||||
|
data from it until it receives an error (except EINTR).
|
||||||
|
In normal cases it will get EAGAIN or EWOULDBLOCK
|
||||||
|
when there is no more data, breaking the loop. */
|
||||||
|
if(sread(multi->wakeup_pair[0], buf, sizeof(buf)) < 0) {
|
||||||
|
#ifndef USE_WINSOCK
|
||||||
|
if(EINTR == SOCKERRNO)
|
||||||
|
continue;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* do not count the wakeup socket into the returned value */
|
||||||
|
retcode--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1174,7 +1228,8 @@ CURLMcode curl_multi_wait(struct Curl_multi *multi,
|
|||||||
int timeout_ms,
|
int timeout_ms,
|
||||||
int *ret)
|
int *ret)
|
||||||
{
|
{
|
||||||
return Curl_multi_wait(multi, extra_fds, extra_nfds, timeout_ms, ret, FALSE);
|
return Curl_multi_wait(multi, extra_fds, extra_nfds, timeout_ms, ret, FALSE,
|
||||||
|
FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
CURLMcode curl_multi_poll(struct Curl_multi *multi,
|
CURLMcode curl_multi_poll(struct Curl_multi *multi,
|
||||||
@ -1183,7 +1238,55 @@ CURLMcode curl_multi_poll(struct Curl_multi *multi,
|
|||||||
int timeout_ms,
|
int timeout_ms,
|
||||||
int *ret)
|
int *ret)
|
||||||
{
|
{
|
||||||
return Curl_multi_wait(multi, extra_fds, extra_nfds, timeout_ms, ret, TRUE);
|
return Curl_multi_wait(multi, extra_fds, extra_nfds, timeout_ms, ret, TRUE,
|
||||||
|
TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
CURLMcode curl_multi_wakeup(struct Curl_multi *multi)
|
||||||
|
{
|
||||||
|
/* this function is usually called from another thread,
|
||||||
|
it has to be careful only to access parts of the
|
||||||
|
Curl_multi struct that are constant */
|
||||||
|
|
||||||
|
/* GOOD_MULTI_HANDLE can be safely called */
|
||||||
|
if(!GOOD_MULTI_HANDLE(multi))
|
||||||
|
return CURLM_BAD_HANDLE;
|
||||||
|
|
||||||
|
#ifdef ENABLE_WAKEUP
|
||||||
|
/* the wakeup_pair variable is only written during init and cleanup,
|
||||||
|
making it safe to access from another thread after the init part
|
||||||
|
and before cleanup */
|
||||||
|
if(multi->wakeup_pair[1] != CURL_SOCKET_BAD) {
|
||||||
|
char buf[1];
|
||||||
|
buf[0] = 1;
|
||||||
|
while(1) {
|
||||||
|
/* swrite() is not thread-safe in general, because concurrent calls
|
||||||
|
can have their messages interleaved, but in this case the content
|
||||||
|
of the messages does not matter, which makes it ok to call.
|
||||||
|
|
||||||
|
The write socket is set to non-blocking, this way this function
|
||||||
|
cannot block, making it safe to call even from the same thread
|
||||||
|
that will call Curl_multi_wait(). If swrite() returns that it
|
||||||
|
would block, it's considered successful because it means that
|
||||||
|
previous calls to this function will wake up the poll(). */
|
||||||
|
if(swrite(multi->wakeup_pair[1], buf, sizeof(buf)) < 0) {
|
||||||
|
int err = SOCKERRNO;
|
||||||
|
int return_success;
|
||||||
|
#ifdef USE_WINSOCK
|
||||||
|
return_success = WSAEWOULDBLOCK == err;
|
||||||
|
#else
|
||||||
|
if(EINTR == err)
|
||||||
|
continue;
|
||||||
|
return_success = EWOULDBLOCK == err || EAGAIN == err;
|
||||||
|
#endif
|
||||||
|
if(!return_success)
|
||||||
|
return CURLM_WAKEUP_FAILURE;
|
||||||
|
}
|
||||||
|
return CURLM_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return CURLM_WAKEUP_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2309,6 +2412,11 @@ CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
|
|||||||
|
|
||||||
Curl_hash_destroy(&multi->hostcache);
|
Curl_hash_destroy(&multi->hostcache);
|
||||||
Curl_psl_destroy(&multi->psl);
|
Curl_psl_destroy(&multi->psl);
|
||||||
|
|
||||||
|
#ifdef ENABLE_WAKEUP
|
||||||
|
sclose(multi->wakeup_pair[0]);
|
||||||
|
sclose(multi->wakeup_pair[1]);
|
||||||
|
#endif
|
||||||
free(multi);
|
free(multi);
|
||||||
|
|
||||||
return CURLM_OK;
|
return CURLM_OK;
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include "conncache.h"
|
#include "conncache.h"
|
||||||
#include "psl.h"
|
#include "psl.h"
|
||||||
|
#include "socketpair.h"
|
||||||
|
|
||||||
struct Curl_message {
|
struct Curl_message {
|
||||||
struct curl_llist_element list;
|
struct curl_llist_element list;
|
||||||
@ -66,6 +67,10 @@ typedef enum {
|
|||||||
|
|
||||||
#define CURLPIPE_ANY (CURLPIPE_MULTIPLEX)
|
#define CURLPIPE_ANY (CURLPIPE_MULTIPLEX)
|
||||||
|
|
||||||
|
#if defined(USE_SOCKETPAIR) && !defined(USE_BLOCKING_SOCKETS)
|
||||||
|
#define ENABLE_WAKEUP
|
||||||
|
#endif
|
||||||
|
|
||||||
/* This is the struct known as CURLM on the outside */
|
/* This is the struct known as CURLM on the outside */
|
||||||
struct Curl_multi {
|
struct Curl_multi {
|
||||||
/* First a simple identifier to easier detect if a user mix up
|
/* First a simple identifier to easier detect if a user mix up
|
||||||
@ -134,6 +139,11 @@ struct Curl_multi {
|
|||||||
previous callback */
|
previous callback */
|
||||||
bool in_callback; /* true while executing a callback */
|
bool in_callback; /* true while executing a callback */
|
||||||
long max_concurrent_streams; /* max concurrent streams client to support */
|
long max_concurrent_streams; /* max concurrent streams client to support */
|
||||||
|
|
||||||
|
#ifdef ENABLE_WAKEUP
|
||||||
|
curl_socket_t wakeup_pair[2]; /* socketpair() used for wakeup
|
||||||
|
0 is used for read, 1 is used for write */
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* HEADER_CURL_MULTIHANDLE_H */
|
#endif /* HEADER_CURL_MULTIHANDLE_H */
|
||||||
|
@ -389,6 +389,9 @@ curl_multi_strerror(CURLMcode error)
|
|||||||
case CURLM_RECURSIVE_API_CALL:
|
case CURLM_RECURSIVE_API_CALL:
|
||||||
return "API function called from within callback";
|
return "API function called from within callback";
|
||||||
|
|
||||||
|
case CURLM_WAKEUP_FAILURE:
|
||||||
|
return "Wakeup is unavailable or failed";
|
||||||
|
|
||||||
case CURLM_LAST:
|
case CURLM_LAST:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1804,7 +1804,11 @@
|
|||||||
d c 6
|
d c 6
|
||||||
d CURLM_ADDED_ALREADY...
|
d CURLM_ADDED_ALREADY...
|
||||||
d c 7
|
d c 7
|
||||||
d CURLM_LAST c 8
|
d CURLM_RECURSIVE_API_CALL...
|
||||||
|
d c 8
|
||||||
|
d CURLM_WAKEUP_FAILURE...
|
||||||
|
d c 9
|
||||||
|
d CURLM_LAST c 10
|
||||||
*
|
*
|
||||||
d CURLMSG s 10i 0 based(######ptr######) Enum
|
d CURLMSG s 10i 0 based(######ptr######) Enum
|
||||||
d CURLMSG_NONE c 0
|
d CURLMSG_NONE c 0
|
||||||
|
@ -179,7 +179,7 @@ test1525 test1526 test1527 test1528 test1529 test1530 test1531 test1532 \
|
|||||||
test1533 test1534 test1535 test1536 test1537 test1538 \
|
test1533 test1534 test1535 test1536 test1537 test1538 \
|
||||||
test1540 test1541 \
|
test1540 test1541 \
|
||||||
test1550 test1551 test1552 test1553 test1554 test1555 test1556 test1557 \
|
test1550 test1551 test1552 test1553 test1554 test1555 test1556 test1557 \
|
||||||
test1558 test1559 test1560 test1561 test1562 test1563 \
|
test1558 test1559 test1560 test1561 test1562 test1563 test1564 test1565 \
|
||||||
\
|
\
|
||||||
test1590 test1591 test1592 test1593 test1594 test1595 test1596 \
|
test1590 test1591 test1592 test1593 test1594 test1595 test1596 \
|
||||||
\
|
\
|
||||||
|
@ -92,6 +92,7 @@ CURL_EXTERN CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
|
|||||||
CURL_EXTERN CURLMcode curl_multi_fdset(CURLM *multi_handle,
|
CURL_EXTERN CURLMcode curl_multi_fdset(CURLM *multi_handle,
|
||||||
CURL_EXTERN CURLMcode curl_multi_wait(CURLM *multi_handle,
|
CURL_EXTERN CURLMcode curl_multi_wait(CURLM *multi_handle,
|
||||||
CURL_EXTERN CURLMcode curl_multi_poll(CURLM *multi_handle,
|
CURL_EXTERN CURLMcode curl_multi_poll(CURLM *multi_handle,
|
||||||
|
CURL_EXTERN CURLMcode curl_multi_wakeup(CURLM *multi_handle);
|
||||||
CURL_EXTERN CURLMcode curl_multi_perform(CURLM *multi_handle,
|
CURL_EXTERN CURLMcode curl_multi_perform(CURLM *multi_handle,
|
||||||
CURL_EXTERN CURLMcode curl_multi_cleanup(CURLM *multi_handle);
|
CURL_EXTERN CURLMcode curl_multi_cleanup(CURLM *multi_handle);
|
||||||
CURL_EXTERN CURLMsg *curl_multi_info_read(CURLM *multi_handle,
|
CURL_EXTERN CURLMsg *curl_multi_info_read(CURLM *multi_handle,
|
||||||
|
@ -139,7 +139,8 @@ m5: Invalid socket argument
|
|||||||
m6: Unknown option
|
m6: Unknown option
|
||||||
m7: The easy handle is already added to a multi handle
|
m7: The easy handle is already added to a multi handle
|
||||||
m8: API function called from within callback
|
m8: API function called from within callback
|
||||||
m9: Unknown error
|
m9: Wakeup is unavailable or failed
|
||||||
|
m10: Unknown error
|
||||||
s0: No error
|
s0: No error
|
||||||
s1: Unknown share option
|
s1: Unknown share option
|
||||||
s2: Share currently in use
|
s2: Share currently in use
|
||||||
|
31
tests/data/test1564
Normal file
31
tests/data/test1564
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<testcase>
|
||||||
|
<info>
|
||||||
|
<keywords>
|
||||||
|
multi
|
||||||
|
wakeup
|
||||||
|
</keywords>
|
||||||
|
</info>
|
||||||
|
|
||||||
|
# Server-side
|
||||||
|
<reply>
|
||||||
|
</reply>
|
||||||
|
|
||||||
|
# Client-side
|
||||||
|
<client>
|
||||||
|
<server>
|
||||||
|
none
|
||||||
|
</server>
|
||||||
|
<tool>
|
||||||
|
lib1564
|
||||||
|
</tool>
|
||||||
|
<name>
|
||||||
|
wakeup before poll with no easy handles
|
||||||
|
</name>
|
||||||
|
<command>
|
||||||
|
</command>
|
||||||
|
</client>
|
||||||
|
|
||||||
|
# Verify data after the test has been "shot"
|
||||||
|
<verify>
|
||||||
|
</verify>
|
||||||
|
</testcase>
|
41
tests/data/test1565
Normal file
41
tests/data/test1565
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<testcase>
|
||||||
|
<info>
|
||||||
|
<keywords>
|
||||||
|
HTTP
|
||||||
|
HTTP GET
|
||||||
|
multi
|
||||||
|
multi-threaded
|
||||||
|
wakeup
|
||||||
|
</keywords>
|
||||||
|
</info>
|
||||||
|
|
||||||
|
# Server-side
|
||||||
|
<reply>
|
||||||
|
<data nocheck="yes">
|
||||||
|
HTTP/1.1 200 OK
|
||||||
|
Content-Length: 3
|
||||||
|
|
||||||
|
OK
|
||||||
|
</data>
|
||||||
|
</reply>
|
||||||
|
|
||||||
|
# Client-side
|
||||||
|
<client>
|
||||||
|
<server>
|
||||||
|
http
|
||||||
|
</server>
|
||||||
|
<tool>
|
||||||
|
lib1565
|
||||||
|
</tool>
|
||||||
|
<name>
|
||||||
|
wakeup from another thread
|
||||||
|
</name>
|
||||||
|
<command>
|
||||||
|
http://%HOSTIP:%HTTPPORT/1
|
||||||
|
</command>
|
||||||
|
</client>
|
||||||
|
|
||||||
|
# Verify data after the test has been "shot"
|
||||||
|
<verify>
|
||||||
|
</verify>
|
||||||
|
</testcase>
|
@ -31,7 +31,7 @@ noinst_PROGRAMS = chkhostname libauthretry libntlmconnect \
|
|||||||
lib1534 lib1535 lib1536 lib1537 lib1538 \
|
lib1534 lib1535 lib1536 lib1537 lib1538 \
|
||||||
lib1540 lib1541 \
|
lib1540 lib1541 \
|
||||||
lib1550 lib1551 lib1552 lib1553 lib1554 lib1555 lib1556 lib1557 \
|
lib1550 lib1551 lib1552 lib1553 lib1554 lib1555 lib1556 lib1557 \
|
||||||
lib1558 lib1559 lib1560 \
|
lib1558 lib1559 lib1560 lib1564 lib1565 \
|
||||||
lib1591 lib1592 lib1593 lib1594 lib1596 \
|
lib1591 lib1592 lib1593 lib1594 lib1596 \
|
||||||
lib1900 lib1905 lib1906 lib1907 \
|
lib1900 lib1905 lib1906 lib1907 \
|
||||||
lib2033
|
lib2033
|
||||||
@ -536,6 +536,14 @@ lib1559_LDADD = $(TESTUTIL_LIBS)
|
|||||||
lib1560_SOURCES = lib1560.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
|
lib1560_SOURCES = lib1560.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
|
||||||
lib1560_LDADD = $(TESTUTIL_LIBS)
|
lib1560_LDADD = $(TESTUTIL_LIBS)
|
||||||
|
|
||||||
|
lib1564_SOURCES = lib1564.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
|
||||||
|
lib1564_LDADD = $(TESTUTIL_LIBS)
|
||||||
|
lib1564_CPPFLAGS = $(AM_CPPFLAGS)
|
||||||
|
|
||||||
|
lib1565_SOURCES = lib1565.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
|
||||||
|
lib1565_LDADD = $(TESTUTIL_LIBS)
|
||||||
|
lib1565_CPPFLAGS = $(AM_CPPFLAGS)
|
||||||
|
|
||||||
lib1591_SOURCES = lib1591.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
|
lib1591_SOURCES = lib1591.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
|
||||||
lib1591_LDADD = $(TESTUTIL_LIBS)
|
lib1591_LDADD = $(TESTUTIL_LIBS)
|
||||||
lib1591_CPPFLAGS = $(AM_CPPFLAGS) -DLIB1591
|
lib1591_CPPFLAGS = $(AM_CPPFLAGS) -DLIB1591
|
||||||
|
142
tests/libtest/lib1564.c
Normal file
142
tests/libtest/lib1564.c
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* _ _ ____ _
|
||||||
|
* Project ___| | | | _ \| |
|
||||||
|
* / __| | | | |_) | |
|
||||||
|
* | (__| |_| | _ <| |___
|
||||||
|
* \___|\___/|_| \_\_____|
|
||||||
|
*
|
||||||
|
* Copyright (C) 1998 - 2019, 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.
|
||||||
|
*
|
||||||
|
***************************************************************************/
|
||||||
|
#include "test.h"
|
||||||
|
|
||||||
|
#include "testutil.h"
|
||||||
|
#include "warnless.h"
|
||||||
|
#include "memdebug.h"
|
||||||
|
|
||||||
|
#define TEST_HANG_TIMEOUT 60 * 1000
|
||||||
|
#define WAKEUP_NUM 1234567
|
||||||
|
|
||||||
|
int test(char *URL)
|
||||||
|
{
|
||||||
|
CURLM *multi = NULL;
|
||||||
|
int numfds;
|
||||||
|
int i;
|
||||||
|
int res = 0;
|
||||||
|
struct timeval time_before_wait, time_after_wait;
|
||||||
|
|
||||||
|
(void)URL;
|
||||||
|
|
||||||
|
start_test_timing();
|
||||||
|
|
||||||
|
global_init(CURL_GLOBAL_ALL);
|
||||||
|
|
||||||
|
multi_init(multi);
|
||||||
|
|
||||||
|
/* no wakeup */
|
||||||
|
|
||||||
|
time_before_wait = tutil_tvnow();
|
||||||
|
multi_poll(multi, NULL, 0, 1000, &numfds);
|
||||||
|
time_after_wait = tutil_tvnow();
|
||||||
|
|
||||||
|
if(tutil_tvdiff(time_after_wait, time_before_wait) < 500) {
|
||||||
|
fprintf(stderr, "%s:%d curl_multi_poll returned too early\n",
|
||||||
|
__FILE__, __LINE__);
|
||||||
|
res = TEST_ERR_MAJOR_BAD;
|
||||||
|
goto test_cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
abort_on_test_timeout();
|
||||||
|
|
||||||
|
/* try a single wakeup */
|
||||||
|
|
||||||
|
multi_wakeup(multi);
|
||||||
|
|
||||||
|
time_before_wait = tutil_tvnow();
|
||||||
|
multi_poll(multi, NULL, 0, 1000, &numfds);
|
||||||
|
time_after_wait = tutil_tvnow();
|
||||||
|
|
||||||
|
if(tutil_tvdiff(time_after_wait, time_before_wait) > 500) {
|
||||||
|
fprintf(stderr, "%s:%d curl_multi_poll returned too late\n",
|
||||||
|
__FILE__, __LINE__);
|
||||||
|
res = TEST_ERR_MAJOR_BAD;
|
||||||
|
goto test_cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
abort_on_test_timeout();
|
||||||
|
|
||||||
|
/* previous wakeup should not wake up this */
|
||||||
|
|
||||||
|
time_before_wait = tutil_tvnow();
|
||||||
|
multi_poll(multi, NULL, 0, 1000, &numfds);
|
||||||
|
time_after_wait = tutil_tvnow();
|
||||||
|
|
||||||
|
if(tutil_tvdiff(time_after_wait, time_before_wait) < 500) {
|
||||||
|
fprintf(stderr, "%s:%d curl_multi_poll returned too early\n",
|
||||||
|
__FILE__, __LINE__);
|
||||||
|
res = TEST_ERR_MAJOR_BAD;
|
||||||
|
goto test_cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
abort_on_test_timeout();
|
||||||
|
|
||||||
|
/* try lots of wakeup */
|
||||||
|
|
||||||
|
for(i = 0; i < WAKEUP_NUM; ++i)
|
||||||
|
multi_wakeup(multi);
|
||||||
|
|
||||||
|
time_before_wait = tutil_tvnow();
|
||||||
|
multi_poll(multi, NULL, 0, 1000, &numfds);
|
||||||
|
time_after_wait = tutil_tvnow();
|
||||||
|
|
||||||
|
if(tutil_tvdiff(time_after_wait, time_before_wait) > 500) {
|
||||||
|
fprintf(stderr, "%s:%d curl_multi_poll returned too late\n",
|
||||||
|
__FILE__, __LINE__);
|
||||||
|
res = TEST_ERR_MAJOR_BAD;
|
||||||
|
goto test_cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
abort_on_test_timeout();
|
||||||
|
|
||||||
|
#if !defined(WIN32) && !defined(_WIN32) && !defined(__WIN32__) \
|
||||||
|
&& !defined(__CYGWIN__)
|
||||||
|
/* Even lots of previous wakeups should not wake up this.
|
||||||
|
|
||||||
|
On Windows (particularly when using MinGW), the socketpair
|
||||||
|
used for curl_multi_wakeup() is really asynchronous,
|
||||||
|
meaning when it's called a lot, it can take some time
|
||||||
|
before all of the data can be read. Sometimes it can wake
|
||||||
|
up more than one curl_multi_poll() call. */
|
||||||
|
|
||||||
|
time_before_wait = tutil_tvnow();
|
||||||
|
multi_poll(multi, NULL, 0, 1000, &numfds);
|
||||||
|
time_after_wait = tutil_tvnow();
|
||||||
|
|
||||||
|
if(tutil_tvdiff(time_after_wait, time_before_wait) < 500) {
|
||||||
|
fprintf(stderr, "%s:%d curl_multi_poll returned too early\n",
|
||||||
|
__FILE__, __LINE__);
|
||||||
|
res = TEST_ERR_MAJOR_BAD;
|
||||||
|
goto test_cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
abort_on_test_timeout();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
test_cleanup:
|
||||||
|
|
||||||
|
curl_multi_cleanup(multi);
|
||||||
|
curl_global_cleanup();
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
204
tests/libtest/lib1565.c
Normal file
204
tests/libtest/lib1565.c
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* _ _ ____ _
|
||||||
|
* Project ___| | | | _ \| |
|
||||||
|
* / __| | | | |_) | |
|
||||||
|
* | (__| |_| | _ <| |___
|
||||||
|
* \___|\___/|_| \_\_____|
|
||||||
|
*
|
||||||
|
* Copyright (C) 1998 - 2019, 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.
|
||||||
|
*
|
||||||
|
***************************************************************************/
|
||||||
|
#include "test.h"
|
||||||
|
|
||||||
|
#include "testutil.h"
|
||||||
|
#include "warnless.h"
|
||||||
|
#include "memdebug.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_PTHREAD_H
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#define TEST_HANG_TIMEOUT 60 * 1000
|
||||||
|
#define CONN_NUM 3
|
||||||
|
#define TIME_BETWEEN_START_SECS 2
|
||||||
|
|
||||||
|
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
static CURL *pending_handles[CONN_NUM];
|
||||||
|
static int pending_num = 0;
|
||||||
|
static int test_failure = 0;
|
||||||
|
|
||||||
|
static CURLM *multi = NULL;
|
||||||
|
static const char *url;
|
||||||
|
|
||||||
|
static void *run_thread(void *ptr)
|
||||||
|
{
|
||||||
|
CURL *easy = NULL;
|
||||||
|
int res = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
(void)ptr;
|
||||||
|
|
||||||
|
for(i = 0; i < CONN_NUM; i++) {
|
||||||
|
sleep(TIME_BETWEEN_START_SECS);
|
||||||
|
|
||||||
|
easy_init(easy);
|
||||||
|
|
||||||
|
easy_setopt(easy, CURLOPT_URL, url);
|
||||||
|
easy_setopt(easy, CURLOPT_VERBOSE, 0L);
|
||||||
|
|
||||||
|
pthread_mutex_lock(&lock);
|
||||||
|
|
||||||
|
if(test_failure) {
|
||||||
|
pthread_mutex_unlock(&lock);
|
||||||
|
goto test_cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
pending_handles[pending_num] = easy;
|
||||||
|
pending_num++;
|
||||||
|
easy = NULL;
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&lock);
|
||||||
|
|
||||||
|
multi_wakeup(multi);
|
||||||
|
}
|
||||||
|
|
||||||
|
test_cleanup:
|
||||||
|
|
||||||
|
curl_easy_cleanup(easy);
|
||||||
|
|
||||||
|
pthread_mutex_lock(&lock);
|
||||||
|
|
||||||
|
if(!test_failure)
|
||||||
|
test_failure = res;
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&lock);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int test(char *URL)
|
||||||
|
{
|
||||||
|
int still_running;
|
||||||
|
int num;
|
||||||
|
int i;
|
||||||
|
int res = 0;
|
||||||
|
CURL *started_handles[CONN_NUM];
|
||||||
|
int started_num = 0;
|
||||||
|
int finished_num = 0;
|
||||||
|
pthread_t tid = 0;
|
||||||
|
struct CURLMsg *message;
|
||||||
|
|
||||||
|
start_test_timing();
|
||||||
|
|
||||||
|
global_init(CURL_GLOBAL_ALL);
|
||||||
|
|
||||||
|
multi_init(multi);
|
||||||
|
|
||||||
|
url = URL;
|
||||||
|
|
||||||
|
res = pthread_create(&tid, NULL, run_thread, NULL);
|
||||||
|
if(0 != res) {
|
||||||
|
fprintf(stderr, "%s:%d Couldn't create thread, errno %d\n",
|
||||||
|
__FILE__, __LINE__, res);
|
||||||
|
goto test_cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
multi_perform(multi, &still_running);
|
||||||
|
|
||||||
|
abort_on_test_timeout();
|
||||||
|
|
||||||
|
while((message = curl_multi_info_read(multi, &num)) != NULL) {
|
||||||
|
if(message->msg == CURLMSG_DONE) {
|
||||||
|
res = message->data.result;
|
||||||
|
if(res)
|
||||||
|
goto test_cleanup;
|
||||||
|
multi_remove_handle(multi, message->easy_handle);
|
||||||
|
finished_num++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fprintf(stderr, "%s:%d Got an unexpected message from curl: %i\n",
|
||||||
|
__FILE__, __LINE__, (int)message->msg);
|
||||||
|
res = TEST_ERR_MAJOR_BAD;
|
||||||
|
goto test_cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
abort_on_test_timeout();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(CONN_NUM == finished_num)
|
||||||
|
break;
|
||||||
|
|
||||||
|
multi_poll(multi, NULL, 0, TEST_HANG_TIMEOUT, &num);
|
||||||
|
|
||||||
|
abort_on_test_timeout();
|
||||||
|
|
||||||
|
pthread_mutex_lock(&lock);
|
||||||
|
|
||||||
|
while(pending_num > 0) {
|
||||||
|
res_multi_add_handle(multi, pending_handles[pending_num - 1]);
|
||||||
|
if(res) {
|
||||||
|
pthread_mutex_unlock(&lock);
|
||||||
|
goto test_cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
started_handles[started_num] = pending_handles[pending_num - 1];
|
||||||
|
started_num++;
|
||||||
|
pending_num--;
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&lock);
|
||||||
|
|
||||||
|
abort_on_test_timeout();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(CONN_NUM != started_num) {
|
||||||
|
fprintf(stderr, "%s:%d Not all connections started: %d of %d\n",
|
||||||
|
__FILE__, __LINE__, started_num, CONN_NUM);
|
||||||
|
goto test_cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(CONN_NUM != finished_num) {
|
||||||
|
fprintf(stderr, "%s:%d Not all connections finished: %d of %d\n",
|
||||||
|
__FILE__, __LINE__, started_num, CONN_NUM);
|
||||||
|
goto test_cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
test_cleanup:
|
||||||
|
|
||||||
|
pthread_mutex_lock(&lock);
|
||||||
|
if(!test_failure)
|
||||||
|
test_failure = res;
|
||||||
|
pthread_mutex_unlock(&lock);
|
||||||
|
|
||||||
|
if(0 != tid)
|
||||||
|
pthread_join(tid, NULL);
|
||||||
|
|
||||||
|
curl_multi_cleanup(multi);
|
||||||
|
for(i = 0; i < pending_num; i++)
|
||||||
|
curl_easy_cleanup(pending_handles[i]);
|
||||||
|
for(i = 0; i < started_num; i++)
|
||||||
|
curl_easy_cleanup(started_handles[i]);
|
||||||
|
curl_global_cleanup();
|
||||||
|
|
||||||
|
return test_failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* without pthread, this test doesn't work */
|
||||||
|
int test(char *URL)
|
||||||
|
{
|
||||||
|
(void)URL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
@ -355,6 +355,60 @@ extern int unitfail;
|
|||||||
|
|
||||||
/* ---------------------------------------------------------------- */
|
/* ---------------------------------------------------------------- */
|
||||||
|
|
||||||
|
#define exe_multi_poll(A,B,C,D,E,Y,Z) do { \
|
||||||
|
CURLMcode ec; \
|
||||||
|
if((ec = curl_multi_poll((A), (B), (C), (D), (E))) != CURLM_OK) { \
|
||||||
|
fprintf(stderr, "%s:%d curl_multi_poll() failed, " \
|
||||||
|
"with code %d (%s)\n", \
|
||||||
|
(Y), (Z), (int)ec, curl_multi_strerror(ec)); \
|
||||||
|
res = (int)ec; \
|
||||||
|
} \
|
||||||
|
else if(*((E)) < 0) { \
|
||||||
|
fprintf(stderr, "%s:%d curl_multi_poll() succeeded, " \
|
||||||
|
"but returned invalid numfds value (%d)\n", \
|
||||||
|
(Y), (Z), (int)*((E))); \
|
||||||
|
res = TEST_ERR_NUM_HANDLES; \
|
||||||
|
} \
|
||||||
|
} WHILE_FALSE
|
||||||
|
|
||||||
|
#define res_multi_poll(A, B, C, D, E) \
|
||||||
|
exe_multi_poll((A), (B), (C), (D), (E), (__FILE__), (__LINE__))
|
||||||
|
|
||||||
|
#define chk_multi_poll(A, B, C, D, E, Y, Z) do { \
|
||||||
|
exe_multi_poll((A), (B), (C), (D), (E), (Y), (Z)); \
|
||||||
|
if(res) \
|
||||||
|
goto test_cleanup; \
|
||||||
|
} WHILE_FALSE
|
||||||
|
|
||||||
|
#define multi_poll(A, B, C, D, E) \
|
||||||
|
chk_multi_poll((A), (B), (C), (D), (E), (__FILE__), (__LINE__))
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------------- */
|
||||||
|
|
||||||
|
#define exe_multi_wakeup(A,Y,Z) do { \
|
||||||
|
CURLMcode ec; \
|
||||||
|
if((ec = curl_multi_wakeup((A))) != CURLM_OK) { \
|
||||||
|
fprintf(stderr, "%s:%d curl_multi_wakeup() failed, " \
|
||||||
|
"with code %d (%s)\n", \
|
||||||
|
(Y), (Z), (int)ec, curl_multi_strerror(ec)); \
|
||||||
|
res = (int)ec; \
|
||||||
|
} \
|
||||||
|
} WHILE_FALSE
|
||||||
|
|
||||||
|
#define res_multi_wakeup(A) \
|
||||||
|
exe_multi_wakeup((A), (__FILE__), (__LINE__))
|
||||||
|
|
||||||
|
#define chk_multi_wakeup(A, Y, Z) do { \
|
||||||
|
exe_multi_wakeup((A), (Y), (Z)); \
|
||||||
|
if(res) \
|
||||||
|
goto test_cleanup; \
|
||||||
|
} WHILE_FALSE
|
||||||
|
|
||||||
|
#define multi_wakeup(A) \
|
||||||
|
chk_multi_wakeup((A), (__FILE__), (__LINE__))
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------------- */
|
||||||
|
|
||||||
#define exe_select_test(A, B, C, D, E, Y, Z) do { \
|
#define exe_select_test(A, B, C, D, E, Y, Z) do { \
|
||||||
int ec; \
|
int ec; \
|
||||||
if(select_wrapper((A), (B), (C), (D), (E)) == -1) { \
|
if(select_wrapper((A), (B), (C), (D), (E)) == -1) { \
|
||||||
|
Loading…
Reference in New Issue
Block a user