From 76627b322e369c209c60863b9e1f05e3ce02953d Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 16 Apr 2007 16:34:08 +0000 Subject: [PATCH] - Robert Iakobashvil added curl_multi_socket_action() to libcurl, which is a function that deprecates the curl_multi_socket() function. Using the new function the application tell libcurl what action that was found in the socket that it passes in. This gives a significant performance boost as it allows libcurl to avoid a call to poll()/select() for every call to curl_multi_socket*(). --- CHANGES | 8 ++++++ RELEASE-NOTES | 5 ++-- docs/libcurl/curl_multi_socket.3 | 42 +++++++++++++++++++++++--------- include/curl/multi.h | 18 +++++++++++++- lib/connect.c | 2 +- lib/multi.c | 23 +++++++++++++++-- lib/select.c | 18 +++++++------- lib/select.h | 7 ++---- lib/socks.c | 4 +-- lib/transfer.c | 17 ++++++++----- lib/urldata.h | 2 ++ 11 files changed, 106 insertions(+), 40 deletions(-) diff --git a/CHANGES b/CHANGES index 21d90e0bc..79863cbe9 100644 --- a/CHANGES +++ b/CHANGES @@ -6,6 +6,14 @@ Changelog +Daniel S (16 April 2007) +- Robert Iakobashvil added curl_multi_socket_action() to libcurl, which is a + function that deprecates the curl_multi_socket() function. Using the new + function the application tell libcurl what action that was found in the + socket that it passes in. This gives a significant performance boost as it + allows libcurl to avoid a call to poll()/select() for every call to + curl_multi_socket*(). + Daniel S (14 April 2007) - Jay Austin added "DH PARAMETERS" to the stunnel.pem certificate for the test suite to make stunnel run better in some (most?) environments. diff --git a/RELEASE-NOTES b/RELEASE-NOTES index db4a21622..1a6239a15 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -11,7 +11,8 @@ Curl and libcurl 7.16.3 This release includes the following changes: - o + o Added curl_multi_socket_action() + o Deprecated curl_multi_socket() This release includes the following bugfixes: @@ -37,6 +38,6 @@ New curl mirrors: This release would not have looked like this without help, code, reports and advice from friends like these: - Song Ma, Dan Fandrich, Yang Tse, Jay Austin + Song Ma, Dan Fandrich, Yang Tse, Jay Austin, Robert Iakobashvil Thanks! (and sorry if I forgot to mention someone) diff --git a/docs/libcurl/curl_multi_socket.3 b/docs/libcurl/curl_multi_socket.3 index 9ad8257f1..3cfd20b40 100644 --- a/docs/libcurl/curl_multi_socket.3 +++ b/docs/libcurl/curl_multi_socket.3 @@ -4,29 +4,40 @@ .SH NAME curl_multi_socket \- reads/writes available data .SH SYNOPSIS +.nf #include +CURLMcode curl_multi_socket_action(CURLM * multi_handle, + curl_socket_t sockfd, int ev_bitmask, + int *running_handles); + CURLMcode curl_multi_socket(CURLM * multi_handle, curl_socket_t sockfd, int *running_handles); CURLMcode curl_multi_socket_all(CURLM *multi_handle, int *running_handles); +.fi .SH DESCRIPTION Alternative versions of \fIcurl_multi_perform(3)\fP that allows the -application to pass in one of the file descriptors/sockets that have been -detected to have \&"action" on them and let libcurl perform. This allows -libcurl to not have to scan through all possible file descriptors to check for -action. When the application has detected action on a socket handled by -libcurl, it should call \fIcurl_multi_socket(3)\fP with the \fBsockfd\fP -argument set to the socket with the action. +application to pass in the file descriptor/socket that has been detected to +have \&"action" on it and let libcurl perform. This allows libcurl to not have +to scan through all possible file descriptors to check for action. When the +application has detected action on a socket handled by libcurl, it should call +\fIcurl_multi_socket_action(3)\fP with the \fBsockfd\fP argument set to the +socket with the action. When the events on a socket are known, they can be +passed as an events bitmask \fBev_bitmask\fP by first setting \fBev_bitmask\fP +to 0, and then adding using bitwise OR (|) any combination of events to be +choosen from CURL_CSELECT_IN, CURL_CSELECT_OUT or CURL_CSELECT_ERR. When the +events on a socket are unknown, pass 0 instead, and libcurl will test the +descriptor internally. At return, the int \fBrunning_handles\fP points to will contain the number of still running easy handles within the multi handle. When this number reaches zero, all transfers are complete/done. Note that when you call -\fIcurl_multi_socket(3)\fP on a specific socket and the counter decreases by -one, it DOES NOT necessarily mean that this exact socket/transfer is the one -that completed. Use \fIcurl_multi_info_read(3)\fP to figure out which easy -handle that completed. +\fIcurl_multi_socket_action(3)\fP on a specific socket and the counter +decreases by one, it DOES NOT necessarily mean that this exact socket/transfer +is the one that completed. Use \fIcurl_multi_info_read(3)\fP to figure out +which easy handle that completed. The curl_multi_socket functions inform the application about updates in the socket (file descriptor) status by doing none, one or multiple calls to the @@ -44,6 +55,10 @@ wait for socket actions \- at most \- before doing the timeout action: call the \fBcurl_multi_socket(3)\fP function with the \fBsockfd\fP argument set to CURL_SOCKET_TIMEOUT. +Usage of \fIcurl_multi_socket(3)\fP is depricated, whereas the function is +equivalent to \fIcurl_multi_socket_action(3)\fP, when \fBev_bitmask\fP is set +to 0. + .SH "CALLBACK DETAILS" The socket \fBcallback\fP function uses a prototype like this @@ -115,12 +130,15 @@ callback is called. 7. Wait for action on any of libcurl's sockets -8, When action happens, call curl_multi_socket() for the socket(s) that got +8, When action happens, call curl_multi_socket_action() for the socket(s) that got action. 9. Go back to step 6. .SH AVAILABILITY -This function was added in libcurl 7.15.4, although not deemed stable yet. +This function was added in libcurl 7.15.4, although deemed stablesince 7.16.0. + +\fIcurl_multi_socket(3)\fP is deprecated, use +\fIcurl_multi_socket_action(3)\fP instead! .SH "SEE ALSO" .BR curl_multi_cleanup "(3), " curl_multi_init "(3), " .BR curl_multi_fdset "(3), " curl_multi_info_read "(3)" diff --git a/include/curl/multi.h b/include/curl/multi.h index d2533728d..5eab527ae 100644 --- a/include/curl/multi.h +++ b/include/curl/multi.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2007, 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 @@ -224,6 +224,10 @@ CURL_EXTERN const char *curl_multi_strerror(CURLMcode); #define CURL_SOCKET_TIMEOUT CURL_SOCKET_BAD +#define CURL_CSELECT_IN 0x01 +#define CURL_CSELECT_OUT 0x02 +#define CURL_CSELECT_ERR 0x04 + typedef int (*curl_socket_callback)(CURL *easy, /* easy handle */ curl_socket_t s, /* socket */ int what, /* see above */ @@ -249,9 +253,21 @@ typedef int (*curl_multi_timer_callback)(CURLM *multi, /* multi handle */ CURL_EXTERN CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s, int *running_handles); +CURL_EXTERN CURLMcode curl_multi_socket_action(CURLM *multi_handle, + curl_socket_t s, + int ev_bitmask, + int *running_handles); + CURL_EXTERN CURLMcode curl_multi_socket_all(CURLM *multi_handle, int *running_handles); +#ifndef CURL_ALLOW_OLD_MULTI_SOCKET +/* This macro below was added in 7.16.3 to push users who recompile to use + the new curl_multi_socket_action() instead of the old curl_multi_socket() +*/ +#define curl_multi_socket(x,y,z) curl_multi_socket_action(x,y,0,z) +#endif + /* * Name: curl_multi_timeout() * diff --git a/lib/connect.c b/lib/connect.c index 95791cf5d..dd67638ff 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -206,7 +206,7 @@ int waitconnect(curl_socket_t sockfd, /* socket */ /* timeout, no connect today */ return WAITCONN_TIMEOUT; - if(rc & CSELECT_ERR) + if(rc & CURL_CSELECT_ERR) /* error condition caught */ return WAITCONN_FDSET_ERROR; diff --git a/lib/multi.c b/lib/multi.c index 530357392..76614c760 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -1661,6 +1661,7 @@ static void singlesocket(struct Curl_multi *multi, static CURLMcode multi_socket(struct Curl_multi *multi, bool checkall, curl_socket_t s, + int ev_bitmask, int *running_handles) { CURLMcode result = CURLM_OK; @@ -1698,8 +1699,14 @@ static CURLMcode multi_socket(struct Curl_multi *multi, /* bad bad bad bad bad bad bad */ return CURLM_INTERNAL_ERROR; + if (data->set.one_easy->easy_conn) /* set socket event bitmask */ + data->set.one_easy->easy_conn->cselect_bits = ev_bitmask; + result = multi_runsingle(multi, data->set.one_easy); + if (data->set.one_easy->easy_conn) + data->set.one_easy->easy_conn->cselect_bits = 0; + if(result == CURLM_OK) /* get the socket(s) and check if the state has been changed since last */ @@ -1791,12 +1798,24 @@ CURLMcode curl_multi_setopt(CURLM *multi_handle, return res; } +/* we define curl_multi_socket() in the public multi.h header */ +#undef curl_multi_socket CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s, int *running_handles) { CURLMcode result = multi_socket((struct Curl_multi *)multi_handle, FALSE, s, - running_handles); + 0, running_handles); + if (CURLM_OK == result) + update_timer((struct Curl_multi *)multi_handle); + return result; +} + +CURLMcode curl_multi_socket_action(CURLM *multi_handle, curl_socket_t s, + int ev_bitmask, int *running_handles) +{ + CURLMcode result = multi_socket((struct Curl_multi *)multi_handle, FALSE, s, + ev_bitmask, running_handles); if (CURLM_OK == result) update_timer((struct Curl_multi *)multi_handle); return result; @@ -1806,7 +1825,7 @@ CURLMcode curl_multi_socket_all(CURLM *multi_handle, int *running_handles) { CURLMcode result = multi_socket((struct Curl_multi *)multi_handle, - TRUE, CURL_SOCKET_BAD, running_handles); + TRUE, CURL_SOCKET_BAD, 0, running_handles); if (CURLM_OK == result) update_timer((struct Curl_multi *)multi_handle); return result; diff --git a/lib/select.c b/lib/select.c index 2af14eb36..1cc819a2a 100644 --- a/lib/select.c +++ b/lib/select.c @@ -161,7 +161,7 @@ static int wait_ms(int timeout_ms) * Return values: * -1 = system call error or fd >= FD_SETSIZE * 0 = timeout - * CSELECT_IN | CSELECT_OUT | CSELECT_ERR + * CURL_CSELECT_IN | CURL_CSELECT_OUT | CURL_CSELECT_ERR */ int Curl_socket_ready(curl_socket_t readfd, curl_socket_t writefd, int timeout_ms) { @@ -223,16 +223,16 @@ int Curl_socket_ready(curl_socket_t readfd, curl_socket_t writefd, int timeout_m num = 0; if (readfd != CURL_SOCKET_BAD) { if (pfd[num].revents & (POLLRDNORM|POLLIN|POLLERR|POLLHUP)) - ret |= CSELECT_IN; + ret |= CURL_CSELECT_IN; if (pfd[num].revents & (POLLRDBAND|POLLPRI|POLLNVAL)) - ret |= CSELECT_ERR; + ret |= CURL_CSELECT_ERR; num++; } if (writefd != CURL_SOCKET_BAD) { if (pfd[num].revents & (POLLWRNORM|POLLOUT)) - ret |= CSELECT_OUT; + ret |= CURL_CSELECT_OUT; if (pfd[num].revents & (POLLERR|POLLHUP|POLLNVAL)) - ret |= CSELECT_ERR; + ret |= CURL_CSELECT_ERR; } return ret; @@ -279,15 +279,15 @@ int Curl_socket_ready(curl_socket_t readfd, curl_socket_t writefd, int timeout_m ret = 0; if (readfd != CURL_SOCKET_BAD) { if (FD_ISSET(readfd, &fds_read)) - ret |= CSELECT_IN; + ret |= CURL_CSELECT_IN; if (FD_ISSET(readfd, &fds_err)) - ret |= CSELECT_ERR; + ret |= CURL_CSELECT_ERR; } if (writefd != CURL_SOCKET_BAD) { if (FD_ISSET(writefd, &fds_write)) - ret |= CSELECT_OUT; + ret |= CURL_CSELECT_OUT; if (FD_ISSET(writefd, &fds_err)) - ret |= CSELECT_ERR; + ret |= CURL_CSELECT_ERR; } return ret; diff --git a/lib/select.h b/lib/select.h index 5a62a6fd8..77b3e915f 100644 --- a/lib/select.h +++ b/lib/select.h @@ -76,11 +76,8 @@ struct pollfd #define POLLRDBAND POLLPRI #endif -#define CSELECT_IN 0x01 -#define CSELECT_OUT 0x02 -#define CSELECT_ERR 0x04 - -int Curl_socket_ready(curl_socket_t readfd, curl_socket_t writefd, int timeout_ms); +int Curl_socket_ready(curl_socket_t readfd, curl_socket_t writefd, + int timeout_ms); int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms); diff --git a/lib/socks.c b/lib/socks.c index 1157b960c..6b95e752d 100644 --- a/lib/socks.c +++ b/lib/socks.c @@ -383,7 +383,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name, return CURLE_OPERATION_TIMEDOUT; } - if(result & CSELECT_ERR) { + if(result & CURL_CSELECT_ERR) { failf(conn->data, "SOCKS5: error occured during connection"); return CURLE_COULDNT_CONNECT; } @@ -415,7 +415,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name, return CURLE_OPERATION_TIMEDOUT; } - if(result & CSELECT_ERR) { + if(result & CURL_CSELECT_ERR) { failf(conn->data, "SOCKS5 read error occured"); return CURLE_RECV_ERROR; } diff --git a/lib/transfer.c b/lib/transfer.c index b70f3b509..52b4c8966 100644 --- a/lib/transfer.c +++ b/lib/transfer.c @@ -314,9 +314,10 @@ CURLcode Curl_readwrite(struct connectdata *conn, curl_socket_t fd_read; curl_socket_t fd_write; - int select_res; - curl_off_t contentlength; + int select_res = conn->cselect_bits; + + conn->cselect_bits = 0; /* only use the proper socket if the *_HOLD bit is not set simultaneously as then we are in rate limiting state in that transfer direction */ @@ -331,8 +332,12 @@ CURLcode Curl_readwrite(struct connectdata *conn, else fd_write = CURL_SOCKET_BAD; - select_res = Curl_socket_ready(fd_read, fd_write, 0); - if(select_res == CSELECT_ERR) { + if (!select_res) { /* Call for select()/poll() only, if read/write/error + status is not known. */ + select_res = Curl_socket_ready(fd_read, fd_write, 0); + } + + if(select_res == CURL_CSELECT_ERR) { failf(data, "select/poll returned error"); return CURLE_SEND_ERROR; } @@ -342,7 +347,7 @@ CURLcode Curl_readwrite(struct connectdata *conn, the stream was rewound (in which case we have data in a buffer) */ if((k->keepon & KEEP_READ) && - ((select_res & CSELECT_IN) || conn->bits.stream_was_rewound)) { + ((select_res & CURL_CSELECT_IN) || conn->bits.stream_was_rewound)) { /* read */ bool is_empty_data = FALSE; @@ -1350,7 +1355,7 @@ CURLcode Curl_readwrite(struct connectdata *conn, /* If we still have writing to do, we check if we have a writable socket. */ - if((k->keepon & KEEP_WRITE) && (select_res & CSELECT_OUT)) { + if((k->keepon & KEEP_WRITE) && (select_res & CURL_CSELECT_OUT)) { /* write */ int i, si; diff --git a/lib/urldata.h b/lib/urldata.h index 419915569..b129ca708 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -900,6 +900,8 @@ struct connectdata { union { struct ftp_conn ftpc; } proto; + + int cselect_bits; /* bitmask of socket events */ }; /* The end of connectdata. */