aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2006-04-21 13:40:07 +0000
committerDaniel Stenberg <daniel@haxx.se>2006-04-21 13:40:07 +0000
commit0ec96e427987e157dfbee57c016c30b671f336f5 (patch)
tree75cb9024b66587147ad4814371b9b8112a3ca484
parent6e520c4cdc81bc5523534cc4153d9252b7fe2d5c (diff)
each socket is used by exactly one easy handle, but of course each easy handle
can and will use more than one socket
-rw-r--r--lib/README.multi_socket15
-rw-r--r--lib/multi.c117
2 files changed, 41 insertions, 91 deletions
diff --git a/lib/README.multi_socket b/lib/README.multi_socket
index e18b90497..22e788bf5 100644
--- a/lib/README.multi_socket
+++ b/lib/README.multi_socket
@@ -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
diff --git a/lib/multi.c b/lib/multi.c
index 78cd2af68..7a75eb3dc 100644
--- a/lib/multi.c
+++ b/lib/multi.c
@@ -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;
}