curl_multi_socket() and curl_multi_socket_all() got modified prototypes: they
authorDaniel Stenberg <daniel@haxx.se>
Sun, 30 Jul 2006 22:44:07 +0000 (22:44 +0000)
committerDaniel Stenberg <daniel@haxx.se>
Sun, 30 Jul 2006 22:44:07 +0000 (22:44 +0000)
both now provide the number of running handles back to the calling function.

CHANGES
hiper/STATUS
hiper/hipev.c
include/curl/multi.h
lib/multi.c

diff --git a/CHANGES b/CHANGES
index 3fcac9b..66a810b 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -6,6 +6,17 @@
 
                                   Changelog
 
+Daniel (31 July 2006)
+- *ARLERT* curl_multi_socket() and curl_multi_socket_all() got modified
+  prototypes: they both now provide the number of running handles back to the
+  calling function. It makes the functions resemble the good old
+  curl_multi_perform() more and provides a nice way to know when the multi
+  handle goes empty.
+
+  ALERT2: don't use the curl_multi_socket*() functionality in anything
+  production-like until I say it's somewhat settled, as I suspect there might
+  be some further API changes before I'm done...
+
 Daniel (28 July 2006)
 - Yves Lejeune fixed so that replacing Content-Type: when doing multipart
   formposts work exactly the way you want it (and the way you'd assume it
index 6b3e511..918611b 100644 (file)
@@ -289,3 +289,12 @@ July 9, 2006
 
  The set hashp pointer will then be passed on to the callback in upcoming
  calls when this same socket is used (in the brand new 'socketp' argument).
+
+---------------------------------------------------------------------------
+
+July 30, 2006
+
+ Shockingly stupid (of me not having realized this before), but we really need
+ to add a 'running_handles' argument to the curl_multi_socket() and
+ curl_multi_socket_all() prototypes so that the caller can get to know when
+ all the transfers are actually done!
index b5a0159..e99f908 100644 (file)
@@ -71,9 +71,6 @@ struct connection {
   size_t dlcounter;
   struct globalinfo *global;
   char error[CURL_ERROR_SIZE];
-  struct event ev[3]; /* maximum 3 events per handle NOTE: should this rather
-                         be a define in a public curl header file or possibly
-                         just documented somewhere or... ? */
 };
 
 struct fdinfo {
@@ -84,10 +81,27 @@ struct fdinfo {
   CURL *easy;
   int action; /* as set by libcurl */
   long timeout; /* as set by libcurl */
+  struct event ev; /* */
+  int evset; /* true if the 'ev' struct has been used in a event_set() call */
+  CURLMcode *multi; /* pointer to the multi handle */
+  int *running_handles; /* pointer to the running_handles counter */
 };
 
 static struct fdinfo *allsocks;
 
+static int running_handles;
+
+/* called from libevent on action on a particular socket ("event") */
+static void eventcallback(int fd, short type, void *userp)
+{
+  struct fdinfo *fdp = (struct fdinfo *)userp;
+
+  fprintf(stderr, "EVENT callback\n");
+
+  /* tell libcurl to deal with the transfer associated with this socket */
+  curl_multi_socket(fdp->multi, fd, fdp->running_handles);
+}
+
 static void remsock(struct fdinfo *f)
 {
   if(!f)
@@ -109,12 +123,29 @@ static void setsock(struct fdinfo *fdp, curl_socket_t s, CURL *easy,
   fdp->sockfd = s;
   fdp->action = action;
   fdp->easy = easy;
+
+  if(fdp->evset)
+    /* first remove the existing event if the old setup was used */
+    event_del(&fdp->ev);
+
+  /* now use and add the current socket setup */
+  event_set(&fdp->ev, fdp->sockfd,
+            (action&CURL_POLL_IN?EV_READ:0)|
+            (action&CURL_POLL_OUT?EV_WRITE:0),
+            eventcallback, fdp);
+
+  fdp->evset=1;
+
+  fprintf(stderr, "event_add() for fd %d\n", s);
+  event_add(&fdp->ev, NULL); /* no timeout */
 }
 
 static void addsock(curl_socket_t s, CURL *easy, int action, CURLM *multi)
 {
   struct fdinfo *fdp = calloc(sizeof(struct fdinfo), 1);
 
+  fdp->multi = multi;
+  fdp->running_handles = &running_handles;
   setsock(fdp, s, easy, action);
 
   if(allsocks) {
@@ -189,7 +220,7 @@ static int socket_callback(CURL *easy,      /* easy handle */
 {
   struct fdinfo *fdp = (struct fdinfo *)socketp;
 
-  printf("socket %d easy %p what %d\n", s, easy, what);
+  fprintf(stderr, "socket %d easy %p what %d\n", s, easy, what);
 
   if(what == CURL_POLL_REMOVE)
     remsock(fdp);
@@ -219,7 +250,7 @@ writecallback(void *ptr, size_t size, size_t nmemb, void *data)
   c->dlcounter += realsize;
   c->global->dlcounter += realsize;
 
-#if 0
+#if 1
   printf("%02d: %d, total %d\n",
          c->id, c->dlcounter, c->global->dlcounter);
 #endif
@@ -360,6 +391,7 @@ int main(int argc, char **argv)
   int selectmaxamount;
   struct fdinfo *fdp;
   char act;
+  long timeout_ms;
 
   memset(&info, 0, sizeof(struct globalinfo));
 
@@ -431,81 +463,40 @@ int main(int argc, char **argv)
   curl_multi_setopt(multi_handle, CURLMOPT_SOCKETDATA, multi_handle);
 
   /* we start the action by calling *socket() right away */
-  while(CURLM_CALL_MULTI_PERFORM == curl_multi_socket_all(multi_handle));
-
-  printf("Starting timer, expects to run for %ldus\n", RUN_FOR_THIS_LONG);
-  timer_start();
-  timer_pause();
+  while(CURLM_CALL_MULTI_PERFORM == curl_multi_socket_all(multi_handle,
+                                                          &running_handles));
 
-  while(1) {
-    struct timeval timeout;
-    int rc; /* select() return code */
-    long timeout_ms;
+  /* event_dispatch() isn't good enough for us, since we need a global timeout
+     to occur after a given time of inactivity
+   */
 
-    fd2_set fdread;
-    fd2_set fdwrite;
-    int maxfd;
+  /* get the timeout value from libcurl */
+  curl_multi_timeout(multi_handle, &timeout_ms);
 
-    curl_multi_timeout(multi_handle, &timeout_ms);
+  while(running_handles) {
+    struct timeval timeout;
 
-    /* set timeout to wait */
+    /* convert ms to timeval */
     timeout.tv_sec = timeout_ms/1000;
     timeout.tv_usec = (timeout_ms%1000)*1000;
 
-    /* convert file descriptors from the transfers to fd_sets */
-    fdinfo2fdset(&fdread, &fdwrite, &maxfd);
-
-    selects++;
-    rc = select(maxfd+1,
-                (fd_set *)&fdread,
-                (fd_set *)&fdwrite,
-                NULL, &timeout);
-    switch(rc) {
-    case -1:
-      /* select error */
-      break;
-    case 0:
-      timeouts++;
-      curl_multi_socket(multi_handle, CURL_SOCKET_TIMEOUT);
-      break;
-
-    default:
-      /* timeout or readable/writable sockets */
-
-      for(i=0, fdp = allsocks; fdp; fdp = fdp->next) {
-        act = 0;
-        if((fdp->action & CURL_POLL_IN) &&
-           FD_ISSET(fdp->sockfd, &fdread)) {
-          act |= CURL_POLL_IN;
-          i++;
-        }
-        if((fdp->action & CURL_POLL_OUT) &&
-           FD_ISSET(fdp->sockfd, &fdwrite)) {
-          act |= CURL_POLL_OUT;
-          i++;
-        }
-
-        if(act) {
-          multi_socket++;
-          timer_continue();
-          if(act & CURL_POLL_OUT)
-            act--;
-          curl_multi_socket(multi_handle, fdp->sockfd);
-          timer_pause();
-        }
-      }
+    event_loopexit(&timeout);
 
-      performselect += rc;
-      if(rc > topselect)
-        topselect = rc;
-      break;
-    }
+    /* The event_loopexit() function may have taken a while and it may or may
+       not have invoked libcurl calls during that time. During those calls,
+       the timeout situation might very well have changed, so we check the
+       timeout time again to see if we really need to call curl_multi_socket()
+       at this point! */
+
+    /* get the timeout value from libcurl */
+    curl_multi_timeout(multi_handle, &timeout_ms);
 
-    timer_total(); /* calculate the total time spent so far */
+    if(timeout_ms <= 0) {
+      /* no time left */
+      curl_multi_socket(multi_handle, CURL_SOCKET_TIMEOUT, &running_handles);
 
-    if(total > RUN_FOR_THIS_LONG) {
-      printf("Stopped after %ldus\n", total);
-      break;
+      /* and get the new timeout value again */
+      curl_multi_timeout(multi_handle, &timeout_ms);
     }
   }
 
index eb62446..3c8bb9e 100644 (file)
@@ -266,9 +266,11 @@ typedef int (*curl_socket_callback)(CURL *easy,      /* easy handle */
                                     void *socketp);  /* private socket
                                                         pointer */
 
-CURL_EXTERN CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s);
+CURL_EXTERN CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s,
+                                        int *running_handles);
 
-CURL_EXTERN CURLMcode curl_multi_socket_all(CURLM *multi_handle);
+CURL_EXTERN CURLMcode curl_multi_socket_all(CURLM *multi_handle,
+                                            int *running_handles);
 
 /*
  * Name:    curl_multi_timeout()
index 3296f09..7f553bd 100644 (file)
@@ -1123,6 +1123,15 @@ static void singlesocket(struct Curl_multi *multi,
           action |= CURL_POLL_OUT;
       }
 
+      /* Update the sockhash accordingly BEFORE the callback of not a removal,
+         in case the callback wants to use curl_multi_assign(), but do the
+         removal AFTER the callback for the very same reason (but then to be
+         able to pass the correct entry->socketp) */
+
+      if(action != CURL_POLL_REMOVE)
+        /* make sure this socket is present in the hash for this handle */
+        sh_addentry(multi->sockhash, s, easy->easy_handle);
+
       /* call the callback with this new info */
       if(multi->socket_cb) {
         struct Curl_sh_entry *entry =
@@ -1132,16 +1141,13 @@ static void singlesocket(struct Curl_multi *multi,
                          s,
                          action,
                          multi->socket_userp,
-                         entry->socketp);
+                         entry ? entry->socketp : NULL);
       }
 
-      /* Update the sockhash accordingly */
       if(action == CURL_POLL_REMOVE)
         /* remove from hash for this easy handle */
         sh_delentry(multi->sockhash, s);
-      else
-        /* make sure this socket is present in the hash for this handle */
-        sh_addentry(multi->sockhash, s, easy->easy_handle);
+
     }
     /* copy the current state to the storage area */
     memcpy(&easy->sockstate, &current, sizeof(struct socketstate));
@@ -1154,16 +1160,16 @@ static void singlesocket(struct Curl_multi *multi,
 
 static CURLMcode multi_socket(struct Curl_multi *multi,
                               bool checkall,
-                              curl_socket_t s)
+                              curl_socket_t s,
+                              int *running_handles)
 {
   CURLMcode result = CURLM_OK;
-  int running_handles;
   struct SessionHandle *data = NULL;
   struct Curl_tree *t;
 
   if(checkall) {
     struct Curl_one_easy *easyp;
-    result = curl_multi_perform(multi, &running_handles);
+    result = curl_multi_perform(multi, running_handles);
 
     /* walk through each easy handle and do the socket state change magic
        and callbacks */
@@ -1190,7 +1196,7 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
 
     data = entry->easy;
 
-    result = multi_runsingle(multi, data->set.one_easy, &running_handles);
+    result = multi_runsingle(multi, data->set.one_easy, running_handles);
 
     if(result == CURLM_OK)
       /* get the socket(s) and check if the state has been changed since
@@ -1212,7 +1218,7 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
 
     /* the first loop lap 'data' can be NULL */
     if(data) {
-      result = multi_runsingle(multi, data->set.one_easy, &running_handles);
+      result = multi_runsingle(multi, data->set.one_easy, running_handles);
 
       if(result == CURLM_OK)
         /* get the socket(s) and check if the state has been changed since
@@ -1269,20 +1275,18 @@ CURLMcode curl_multi_setopt(CURLM *multi_handle,
 }
 
 
-CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s)
+CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s,
+                            int *running_handles)
 {
-#if 0
-  printf("multi_socket(%d)\n", (int)s);
-#endif
-
-  return multi_socket((struct Curl_multi *)multi_handle, FALSE, s);
+  return multi_socket((struct Curl_multi *)multi_handle, FALSE, s,
+                      running_handles);
 }
 
-CURLMcode curl_multi_socket_all(CURLM *multi_handle)
+CURLMcode curl_multi_socket_all(CURLM *multi_handle, int *running_handles)
 
 {
   return multi_socket((struct Curl_multi *)multi_handle,
-                      TRUE, CURL_SOCKET_BAD);
+                      TRUE, CURL_SOCKET_BAD, running_handles);
 }
 
 CURLMcode curl_multi_timeout(CURLM *multi_handle,