]> granicus.if.org Git - curl/commitdiff
each socket is used by exactly one easy handle, but of course each easy handle
authorDaniel Stenberg <daniel@haxx.se>
Fri, 21 Apr 2006 13:40:07 +0000 (13:40 +0000)
committerDaniel Stenberg <daniel@haxx.se>
Fri, 21 Apr 2006 13:40:07 +0000 (13:40 +0000)
can and will use more than one socket

lib/README.multi_socket
lib/multi.c

index e18b90497f99b5827dbe2db911643dad18eacf54..22e788bf55cc600436c51b824b3ef5ea9ee92517 100644 (file)
@@ -43,15 +43,12 @@ Implementation of the curl_multi_socket API
   handle conversion on its own. I find it very unlikely that applications
   would want to do that and since libcurl would need such a lookup on its own
   anyway since we didn't want to force applications to do that translation
-  code (it would be optional), it seemed like an unnecessary option. I also
-  realized that when we use underlying libraries such as c-ares (for DNS
-  asynch resolving) there might in fact be more than one transfer waiting for
-  action on the same socket and thus it makes the lookup even tricker and even
-  less likely to ever get done by applications. Instead I created an internal
-  "socket to easy handles" hash table that given a socket (file descriptor)
-  returns a list of easy handles that waits for some action on that socket.
-  This hash is made using the already existing hash code (previously only used
-  for the DNS cache).
+  code (it would be optional), it seemed like an unnecessary option.
+
+  Instead I created an internal "socket to easy handles" hash table that given
+  a socket (file descriptor) return the easy handle that waits for action on
+  that socket.  This hash is made using the already existing hash code
+  (previously only used for the DNS cache).
 
   To make libcurl be able to report plain sockets in the socket callback, I
   had to re-organize the internals of the curl_multi_fdset() etc so that the
index 78cd2af6807d616fcbdaa13779c5cfc7019f329b..7a75eb3dcf651a2aad01f954cf6d27ec1ab4fc0c 100644 (file)
@@ -83,7 +83,6 @@ typedef enum {
 struct socketstate {
   curl_socket_t socks[MAX_SOCKSPEREASYHANDLE];
   long action; /* socket action bitmap */
-  long timeout[MAX_SOCKSPEREASYHANDLE];
 };
 
 struct Curl_one_easy {
@@ -173,19 +172,20 @@ static void multistate(struct Curl_one_easy *easy, CURLMstate state)
 }
 
 /*
- * We add one of these structs to the sockhash, and then if we add more easy
- * handles for the same socket we just link them with the next/prev pointers
- * from the node added to the hash. We only remove the node from the hash when
- * the final easy handle/socket associated with the node is removed.
+ * We add one of these structs to the sockhash for a particular socket
  */
 
 struct Curl_sh_entry {
-  struct Curl_sh_entry *next;
-  struct Curl_sh_entry *prev;
   struct SessionHandle *easy;
   time_t timestamp;
   long inuse;
+  int action;  /* what action READ/WRITE this socket waits for */
+  void *userp; /* settable by users (not yet decided exactly how) */
 };
+/* bits for 'action' having no bits means this socket is not expecting any
+   action */
+#define SH_READ  1
+#define SG_WRITE 2
 
 /* make sure this socket is present in the hash for this handle */
 static int sh_addentry(struct curl_hash *sh,
@@ -196,16 +196,9 @@ static int sh_addentry(struct curl_hash *sh,
     Curl_hash_pick(sh, (char *)&s, sizeof(curl_socket_t));
   struct Curl_sh_entry *check;
 
-  if(there) {
-    /* verify that this particular handle is in here */
-    check = there;
-    while(check) {
-      if(check->easy == data)
-        /* it is, return fine */
-        return 0;
-      check = check->next;
-    }
-  }
+  if(there)
+    /* it is present, return fine */
+    return 0;
 
   /* not present, add it */
   check = calloc(sizeof(struct Curl_sh_entry), 1);
@@ -213,57 +206,25 @@ static int sh_addentry(struct curl_hash *sh,
     return 1; /* major failure */
   check->easy = data;
 
-  if(there) {
-    /* the node for this socket is already here, now link in the struct for
-       the new handle */
-
-    check->next = there->next; /* get the previous next to point to */
-    there->next = check;       /* make the new next point to the new entry */
+  /* make/add new hash entry */
+  if(NULL == Curl_hash_add(sh, (char *)&s, sizeof(curl_socket_t), check))
+    return 1; /* major failure */
 
-    check->next->prev = check; /* make sure the next one points back to the
-                                  new one */
-    /* check->prev = NULL;        is already cleared and we have no previous
-                                  node */
-  }
-  else {
-    /* make/add new hash entry */
-    if(NULL == Curl_hash_add(sh, (char *)&s, sizeof(curl_socket_t), check))
-      return 1; /* major failure */
-  }
   return 0; /* things are good in sockhash land */
 }
 
 
 /* delete the given socket + handle from the hash */
-static void sh_delentry(struct curl_hash *sh,
-                        curl_socket_t s,
-                        struct SessionHandle *data)
+static void sh_delentry(struct curl_hash *sh, curl_socket_t s)
 {
   struct Curl_sh_entry *there =
     Curl_hash_pick(sh, (char *)&s, sizeof(curl_socket_t));
 
-  while(there) {
-    /* this socket is in the hash, now scan the list at this point and see if
-       the given easy handle is in there and if so remote that singe entry */
-    if(there->easy == data) {
-      /* match! */
-      if(there->next || there->prev) {
-        /* it is not the only handle for this socket, so only unlink this
-           particular easy handle and leave the actional hash entry */
-
-        /* unlink */
-        there->next->prev = there->prev;
-        there->prev->next = there->next;
-        free(there);
-      }
-      else {
-        /* This is the only easy handle for this socket, we must remove the
-           hash entry. (This'll end up in a call to sh_freeentry().) */
-        Curl_hash_delete(sh, (char *)&s, sizeof(curl_socket_t));
-      }
-      break;
-    }
-    there = there->next;
+  if(there) {
+    /* this socket is in the hash */
+    /* We remove the hash entry. (This'll end up in a call to
+       sh_freeentry().) */
+    Curl_hash_delete(sh, (char *)&s, sizeof(curl_socket_t));
   }
 }
 
@@ -273,14 +234,6 @@ static void sh_delentry(struct curl_hash *sh,
 static void sh_freeentry(void *freethis)
 {
   struct Curl_sh_entry *p = (struct Curl_sh_entry *) freethis;
-  struct Curl_sh_entry *more = p->next;
-
-  /* if there's a chain of more handles, remove that chain first */
-  while(more) {
-    struct Curl_sh_entry *next = more->next;
-    free(more);
-    more = next;
-  }
 
   free(p);
 }
@@ -1034,8 +987,9 @@ CURLMsg *curl_multi_info_read(CURLM *multi_handle, int *msgs_in_queue)
 }
 
 /*
- * Check what sockets we deal with and their "action state" and if we have a
- * difference from last time we call the callback accordingly.
+ * singlesocket() checks what sockets we deal with and their "action state"
+ * and if we have a different state in any of those sockets from last time we
+ * call the callback accordingly.
  */
 static void singlesocket(struct Curl_multi *multi,
                          struct Curl_one_easy *easy)
@@ -1050,9 +1004,11 @@ static void singlesocket(struct Curl_multi *multi,
   /* first fill in the 'current' struct with the state as it is now */
   current.action = multi_getsock(easy, current.socks, MAX_SOCKSPEREASYHANDLE);
 
-  /* when filled in, we compare with the previous round's state */
+  /* when filled in, we compare with the previous round's state in a first
+     quick memory compare check */
   if(memcmp(&current, &easy->sockstate, sizeof(struct socketstate))) {
-    /* difference, call the callback once for every socket change ! */
+
+    /* there is difference, call the callback once for every socket change ! */
     for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) {
       int action;
       curl_socket_t s = current.socks[i];
@@ -1103,7 +1059,7 @@ static void singlesocket(struct Curl_multi *multi,
       /* Update the sockhash accordingly */
       if(action == CURL_POLL_REMOVE)
         /* remove from hash for this easy handle */
-        sh_delentry(multi->sockhash, s, easy->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);
@@ -1138,6 +1094,7 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
       easyp = easyp->next;
     }
 
+    /* or should we fall-through and do the timer-based stuff? */
     return result;
   }
   else if (s != CURL_SOCKET_TIMEOUT) {
@@ -1152,20 +1109,16 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
     /* Now, there is potentially a chain of easy handles in this hash
        entry struct and we need to deal with all of them */
 
-    do {
-      data = entry->easy;
-
-      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
-           last */
-        singlesocket(multi, data->set.one_easy);
+    data = entry->easy;
 
-      entry = entry->next;
+    result = multi_runsingle(multi, data->set.one_easy, &running_handles);
 
-    } while(entry);
+    if(result == CURLM_OK)
+      /* get the socket(s) and check if the state has been changed since
+         last */
+      singlesocket(multi, data->set.one_easy);
 
+    /* or should we fall-through and do the timer-based stuff? */
     return result;
   }