cURL / Mailing Lists / curl-library / Single Mail

curl-library

proposal for new curl_mutli_socket API

From: Christopher Palow <cpalow_at_facebook.com>
Date: Thu, 24 Apr 2008 18:00:55 -0700

Hi all,

I'd like to propose a new function for use when starting a new easy handle
that has just been added to a multi handle.

In the current API after adding an easy handle to a multi handle with
curl_multi_add_handle() you then have to call curl_multi_socket_all() to
start the this newly added easy handle. curl_multi_socket_all() is O(N) of
the number of easy handles associated with the multi handle. When youšre
adding an easy handle to a multi handle with thousands of connections this
becomes a performance issue.

What do you guys think? If you like it Išll write up blurb for it in the
man page too.

Thanks,
Christopher Palow

cvs diff -uwp include/curl/multi.h lib/multi.c
Index: include/curl/multi.h
===================================================================
RCS file: /cvsroot/curl/curl/include/curl/multi.h,v
retrieving revision 1.44
diff -u -w -p -r1.44 multi.h
--- include/curl/multi.h 30 May 2007 20:04:44 -0000 1.44
+++ include/curl/multi.h 25 Apr 2008 00:44:39 -0000
@@ -261,6 +261,12 @@ CURL_EXTERN CURLMcode curl_multi_socket_
 CURL_EXTERN CURLMcode curl_multi_socket_all(CURLM *multi_handle,
                                             int *running_handles);
 
+
+CURL_EXTERN CURLMcode curl_multi_socket_easy(CURLM *multi_handle,
+ CURL *easy_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()
Index: lib/multi.c
===================================================================
RCS file: /cvsroot/curl/curl/lib/multi.c,v
retrieving revision 1.167
diff -u -w -p -r1.167 multi.c
--- lib/multi.c 18 Mar 2008 08:14:37 -0000 1.167
+++ lib/multi.c 25 Apr 2008 00:44:40 -0000
@@ -1851,6 +1851,86 @@ CURLMcode curl_multi_socket_all(CURLM *m
   return result;
 }
 
+/* This is a mix of the code from multi_socket and curl_multi_perform */
+CURLMcode curl_multi_socket_easy(CURLM *multi_handle, CURL *easy_handle,
+ int *running_handles)
+{
+ struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
+ struct SessionHandle *data = (struct SessionHandle *)easy_handle;
+ CURLMcode result = CURLM_OK;
+ struct Curl_tree *t;
+
+ if(!GOOD_MULTI_HANDLE(multi))
+ return CURLM_BAD_HANDLE;
+
+ /* Verify that we got a somewhat good easy handle too */
+ if(!GOOD_EASY_HANDLE(easy_handle))
+ return CURLM_BAD_EASY_HANDLE;
+
+ 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(CURLM_OK >= result)
+ /* get the socket(s) and check if the state has been changed since
+ last */
+ singlesocket(multi, data->set.one_easy);
+
+ /* Now we fall-through and do the timer-based stuff, since we don't want
+ to force the user to have to deal with timeouts as long as at least
one
+ connection in fact has traffic. */
+
+ data = NULL; /* set data to NULL again to avoid calling multi_runsingle()
+ in case there's no need to */
+
+ /*
+ * The loop following here will go on as long as there are expire-times
left
+ * to process in the splay and 'data' will be re-assigned for every
expired
+ * handle we deal with.
+ */
+ do {
+ int key;
+ struct timeval now;
+
+ /* the first loop lap 'data' can be NULL */
+ if(data) {
+ result = multi_runsingle(multi, data->set.one_easy);
+
+ if(CURLM_OK >= result)
+ /* get the socket(s) and check if the state has been changed since
+ last */
+ singlesocket(multi, data->set.one_easy);
+ }
+
+ /* Check if there's one (more) expired timer to deal with! This
function
+ extracts a matching node if there is one */
+
+ now = Curl_tvnow();
+ key = now.tv_sec; /* drop the usec part */
+
+ multi->timetree = Curl_splaygetbest(key, multi->timetree, &t);
+ if(t) {
+ /* assign 'data' to be the easy handle we just removed from the splay
+ tree */
+ data = t->payload;
+ /* clear the expire time within the handle we removed from the
+ splay tree */
+ data->state.expiretime.tv_sec = 0;
+ data->state.expiretime.tv_usec = 0;
+ }
+
+ } while(t);
+
+
+ *running_handles = multi->num_alive;
+
+ if(CURLM_OK >= result)
+ update_timer((struct Curl_multi *)multi_handle);
+ return result;
+}
+
+
 static CURLMcode multi_timeout(struct Curl_multi *multi,
                                long *timeout_ms)
 {
Received on 2008-04-25