multi: convert CURLM_STATE_CONNECT_PEND handling to a list
authorDaniel Stenberg <daniel@haxx.se>
Tue, 2 Sep 2014 07:29:50 +0000 (09:29 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Tue, 2 Sep 2014 08:17:47 +0000 (10:17 +0200)
... instead of scanning through all handles, stash only the actual
handles that are in that state in the new ->pending list and scan that
list only. It should be mostly empty or very short. And only used for
pipelining.

This avoids a rather hefty slow-down especially notable if you add many
handles to the same multi handle. Regression introduced in commit
0f147887 (version 7.30.0).

Bug: http://curl.haxx.se/mail/lib-2014-07/0206.html
Reported-by: David Meyer
lib/multi.c
lib/multihandle.h

index 557be06df3cb82f27e9f6ba5217b2582b6b0d228..7947436c7915744ef20bc50a968b6ae51efaa790 100644 (file)
@@ -309,6 +309,10 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */
   if(!multi->msglist)
     goto error;
 
+  multi->pending = Curl_llist_alloc(multi_freeamsg);
+  if(!multi->pending)
+    goto error;
+
   /* allocate a new easy handle to use when closing cached connections */
   multi->closure_handle = curl_easy_init();
   if(!multi->closure_handle)
@@ -334,6 +338,7 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */
   Curl_close(multi->closure_handle);
   multi->closure_handle = NULL;
   Curl_llist_destroy(multi->msglist, NULL);
+  Curl_llist_destroy(multi->pending, NULL);
 
   free(multi);
   return NULL;
@@ -1046,7 +1051,12 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
         /* There was no connection available. We will go to the pending
            state and wait for an available connection. */
         multistate(data, CURLM_STATE_CONNECT_PEND);
-        data->result = CURLE_OK;
+
+        /* add this handle to the list of connect-pending handles */
+        if(!Curl_llist_insert_next(multi->pending, multi->pending->tail, data))
+          data->result = CURLM_OUT_OF_MEMORY;
+        else
+          data->result = CURLE_OK;
         break;
       }
 
@@ -1884,6 +1894,10 @@ CURLMcode curl_multi_cleanup(CURLM *multi_handle)
     Curl_llist_destroy(multi->msglist, NULL);
     multi->msglist = NULL;
 
+    /* remove the pending handles queue */
+    Curl_llist_destroy(multi->pending, NULL);
+    multi->msglist = NULL;
+
     /* remove all easy handles */
     data = multi->easyp;
     while(data) {
@@ -2776,16 +2790,17 @@ struct curl_llist *Curl_multi_pipelining_server_bl(struct Curl_multi *multi)
 
 void Curl_multi_process_pending_handles(struct Curl_multi *multi)
 {
-  struct SessionHandle *data;
+  struct curl_llist_element *e;
 
-  data=multi->easyp;
-  while(data) {
+  for(e = multi->pending->head; e; e = e->next) {
+    struct SessionHandle *data = e->ptr;
     if(data->mstate == CURLM_STATE_CONNECT_PEND) {
       multistate(data, CURLM_STATE_CONNECT);
+      /* Remove this node from the list */
+      Curl_llist_remove(multi->pending, e, NULL);
       /* Make sure that the handle will be processed soonish. */
-      Curl_expire(data, 1);
+      Curl_expire_latest(data, 1);
     }
-    data = data->next; /* operate on next handle */
   }
 }
 
index 552aa93797135b2eefb97e2955bbc72c95a641f1..1a4b1d96681262dc83a884ef93a1e980f061432d 100644 (file)
@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2014, 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
@@ -75,6 +75,9 @@ struct Curl_multi {
 
   struct curl_llist *msglist; /* a list of messages from completed transfers */
 
+  struct curl_llist *pending; /* SessionHandles that are in the
+                                 CURLM_STATE_CONNECT_PEND state */
+
   /* callback function and user data pointer for the *socket() API */
   curl_socket_callback socket_cb;
   void *socket_userp;