1
0
mirror of https://github.com/moparisthebest/curl synced 2024-11-12 04:25:08 -05:00

multi: make sure the next timeout is used when one expires

Each easy handle has a list of timeouts, so as soon as the main timeout
for a handle expires, we must make sure to get the next entry from the
list and re-add the handle to the splay tree.

This was attempted previously but was done poorly in my commit
232ad6549a.
This commit is contained in:
Daniel Stenberg 2010-08-31 00:08:45 +02:00
parent 55c266de6d
commit 0db9140747

View File

@ -192,6 +192,9 @@ static void moveHandleFromRecvToDonePipeline(struct SessionHandle *handle,
struct connectdata *conn); struct connectdata *conn);
static bool isHandleAtHead(struct SessionHandle *handle, static bool isHandleAtHead(struct SessionHandle *handle,
struct curl_llist *pipeline); struct curl_llist *pipeline);
static CURLMcode add_next_timeout(struct timeval now,
struct Curl_multi *multi,
struct SessionHandle *d);
#ifdef DEBUGBUILD #ifdef DEBUGBUILD
static const char * const statename[]={ static const char * const statename[]={
@ -1690,37 +1693,9 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
*/ */
do { do {
multi->timetree = Curl_splaygetbest(now, multi->timetree, &t); multi->timetree = Curl_splaygetbest(now, multi->timetree, &t);
if(t) { if(t)
struct SessionHandle *d = t->payload; /* the removed may have another timeout in queue */
struct timeval *tv = &d->state.expiretime; (void)add_next_timeout(now, multi, t->payload);
struct curl_llist *list = d->state.timeoutlist;
struct curl_llist_element *e;
/* move over the timeout list for this specific handle and remove all
timeouts that are now passed tense and store the next pending
timeout in *tv */
for(e = list->head; e; ) {
struct curl_llist_element *n = e->next;
if(curlx_tvdiff(*(struct timeval *)e->ptr, now) < 0)
/* remove outdated entry */
Curl_llist_remove(list, e, NULL);
e = n;
}
if(!list->size) {
/* clear the expire times within the handles that we remove from the
splay tree */
tv->tv_sec = 0;
tv->tv_usec = 0;
}
else {
e = list->head;
/* copy the first entry to 'tv' */
memcpy(tv, e->ptr, sizeof(*tv));
/* remove first entry from list */
Curl_llist_remove(list, e, NULL);
}
}
} while(t); } while(t);
@ -1992,6 +1967,62 @@ static void singlesocket(struct Curl_multi *multi,
easy->numsocks = num; easy->numsocks = num;
} }
/*
* add_next_timeout()
*
* Each SessionHandle has a list of timeouts. The add_next_timeout() is called
* when it has just been removed from the splay tree because the timeout has
* expired. This function is then to advance in the list to pick the next
* timeout to use (skip the already expired ones) and add this node back to
* the splay tree again.
*
* The splay tree only has each sessionhandle as a single node and the nearest
* timeout is used to sort it on.
*/
static CURLMcode add_next_timeout(struct timeval now,
struct Curl_multi *multi,
struct SessionHandle *d)
{
struct timeval *tv = &d->state.expiretime;
struct curl_llist *list = d->state.timeoutlist;
struct curl_llist_element *e;
/* move over the timeout list for this specific handle and remove all
timeouts that are now passed tense and store the next pending
timeout in *tv */
for(e = list->head; e; ) {
struct curl_llist_element *n = e->next;
long diff = curlx_tvdiff(*(struct timeval *)e->ptr, now);
if(diff <= 0)
/* remove outdated entry */
Curl_llist_remove(list, e, NULL);
else
/* the list is sorted so get out on the first mismatch */
break;
e = n;
}
if(!list->size) {
/* clear the expire times within the handles that we remove from the
splay tree */
tv->tv_sec = 0;
tv->tv_usec = 0;
}
else {
e = list->head;
/* copy the first entry to 'tv' */
memcpy(tv, e->ptr, sizeof(*tv));
/* remove first entry from list */
Curl_llist_remove(list, e, NULL);
/* insert this node again into the splay */
multi->timetree = Curl_splayinsert(*tv, multi->timetree,
&d->state.timenode);
}
return CURLM_OK;
}
static CURLMcode multi_socket(struct Curl_multi *multi, static CURLMcode multi_socket(struct Curl_multi *multi,
bool checkall, bool checkall,
curl_socket_t s, curl_socket_t s,
@ -2106,15 +2137,8 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
} }
multi->timetree = Curl_splaygetbest(now, multi->timetree, &t); multi->timetree = Curl_splaygetbest(now, multi->timetree, &t);
if(t) { if(t)
/* assign 'data' to be the easy handle we just removed from the splay (void)add_next_timeout(now, multi, t->payload);
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); } while(t);