diff options
Diffstat (limited to 'Utilities/cmcurl/lib/multi.c')
-rw-r--r-- | Utilities/cmcurl/lib/multi.c | 164 |
1 files changed, 68 insertions, 96 deletions
diff --git a/Utilities/cmcurl/lib/multi.c b/Utilities/cmcurl/lib/multi.c index b24ce19..c3a0d12 100644 --- a/Utilities/cmcurl/lib/multi.c +++ b/Utilities/cmcurl/lib/multi.c @@ -99,8 +99,6 @@ static const char * const statename[]={ }; #endif -static void multi_freetimeout(void *a, void *b); - /* function pointer called once when switching TO a state */ typedef void (*init_multistate_func)(struct Curl_easy *data); @@ -280,9 +278,8 @@ static int sh_init(struct curl_hash *hash, int hashsize) static CURLMcode multi_addmsg(struct Curl_multi *multi, struct Curl_message *msg) { - if(!Curl_llist_insert_next(&multi->msglist, multi->msglist.tail, msg)) - return CURLM_OUT_OF_MEMORY; - + Curl_llist_insert_next(&multi->msglist, multi->msglist.tail, msg, + &msg->list); return CURLM_OK; } @@ -370,7 +367,7 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi, return CURLM_ADDED_ALREADY; /* Initialize timeout list for this handle */ - Curl_llist_init(&data->state.timeoutlist, multi_freetimeout); + Curl_llist_init(&data->state.timeoutlist, NULL); /* * No failure allowed in this function beyond this point. And no @@ -431,7 +428,7 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi, sockets that time-out or have actions will be dealt with. Since this handle has no action yet, we make sure it times out to get things to happen. */ - Curl_expire(data, 0); + Curl_expire(data, 0, EXPIRE_RUN_NOW); /* increase the node-counter */ multi->num_easy++; @@ -1015,7 +1012,7 @@ CURLMcode curl_multi_wait(struct Curl_multi *multi, curlfds = nfds; /* number of internal file descriptors */ nfds += extra_nfds; /* add the externally provided ones */ - if(nfds || extra_nfds) { + if(nfds) { if(nfds > NUM_POLLS_ON_STACK) { ufds = malloc(nfds * sizeof(struct pollfd)); if(!ufds) @@ -1432,10 +1429,9 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, multistate(data, CURLM_STATE_CONNECT_PEND); /* add this handle to the list of connect-pending handles */ - if(!Curl_llist_insert_next(&multi->pending, multi->pending.tail, data)) - result = CURLE_OUT_OF_MEMORY; - else - result = CURLE_OK; + Curl_llist_insert_next(&multi->pending, multi->pending.tail, data, + &data->connect_queue); + result = CURLE_OK; break; } @@ -1719,20 +1715,18 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, else { /* Follow failed */ result = drc; - free(newurl); } } else { /* done didn't return OK or SEND_ERROR */ result = drc; - free(newurl); } } else { /* Have error handler disconnect conn if we can't retry */ stream_error = TRUE; - free(newurl); } + free(newurl); } else { /* failure detected */ @@ -1846,9 +1840,9 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, if(send_timeout_ms <= 0 && recv_timeout_ms <= 0) multistate(data, CURLM_STATE_PERFORM); else if(send_timeout_ms >= recv_timeout_ms) - Curl_expire_latest(data, send_timeout_ms); + Curl_expire(data, send_timeout_ms, EXPIRE_TOOFAST); else - Curl_expire_latest(data, recv_timeout_ms); + Curl_expire(data, recv_timeout_ms, EXPIRE_TOOFAST); } break; @@ -1879,9 +1873,9 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, if(send_timeout_ms > 0 || recv_timeout_ms > 0) { multistate(data, CURLM_STATE_TOOFAST); if(send_timeout_ms >= recv_timeout_ms) - Curl_expire_latest(data, send_timeout_ms); + Curl_expire(data, send_timeout_ms, EXPIRE_TOOFAST); else - Curl_expire_latest(data, recv_timeout_ms); + Curl_expire(data, recv_timeout_ms, EXPIRE_TOOFAST); break; } @@ -1942,7 +1936,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* expire the new receiving pipeline head */ if(data->easy_conn->recv_pipe.head) - Curl_expire_latest(data->easy_conn->recv_pipe.head->ptr, 0); + Curl_expire(data->easy_conn->recv_pipe.head->ptr, 0, EXPIRE_RUN_NOW); /* Check if we can move pending requests to send pipe */ Curl_multi_process_pending_handles(multi); @@ -1966,9 +1960,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, if(!result) { multistate(data, CURLM_STATE_CONNECT); rc = CURLM_CALL_MULTI_PERFORM; - newurl = NULL; /* handed over the memory ownership to - Curl_follow(), make sure we don't free() it - here */ } } } @@ -1982,9 +1973,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, newurl = data->req.location; data->req.location = NULL; result = Curl_follow(data, newurl, FOLLOW_FAKE); - if(!result) - newurl = NULL; /* allocation was handed over Curl_follow() */ - else + if(result) stream_error = TRUE; } @@ -2483,8 +2472,6 @@ void Curl_multi_closed(struct connectdata *conn, curl_socket_t s) } } - - /* * add_next_timeout() * @@ -2504,13 +2491,16 @@ static CURLMcode add_next_timeout(struct timeval now, struct timeval *tv = &d->state.expiretime; struct curl_llist *list = &d->state.timeoutlist; struct curl_llist_element *e; + struct time_node *node = NULL; /* 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; - time_t diff = curlx_tvdiff(*(struct timeval *)e->ptr, now); + time_t diff; + node = (struct time_node *)e->ptr; + diff = curlx_tvdiff(node->time, now); if(diff <= 0) /* remove outdated entry */ Curl_llist_remove(list, e, NULL); @@ -2528,7 +2518,7 @@ static CURLMcode add_next_timeout(struct timeval now, } else { /* copy the first entry to 'tv' */ - memcpy(tv, e->ptr, sizeof(*tv)); + memcpy(tv, &node->time, sizeof(*tv)); /* remove first entry from list */ Curl_llist_remove(list, e, NULL); @@ -2854,17 +2844,23 @@ static int update_timer(struct Curl_multi *multi) } /* - * multi_freetimeout() + * multi_deltimeout() * - * Callback used by the llist system when a single timeout list entry is - * destroyed. + * Remove a given timestamp from the list of timeouts. */ -static void multi_freetimeout(void *user, void *entryptr) +static void +multi_deltimeout(struct Curl_easy *data, expire_id eid) { - (void)user; - - /* the entry was plain malloc()'ed */ - free(entryptr); + struct curl_llist_element *e; + struct curl_llist *timeoutlist = &data->state.timeoutlist; + /* find and remove the specific node from the list */ + for(e = timeoutlist->head; e; e = e->next) { + struct time_node *n = (struct time_node *)e->ptr; + if(n->eid == eid) { + Curl_llist_remove(timeoutlist, e, NULL); + return; + } + } } /* @@ -2875,25 +2871,28 @@ static void multi_freetimeout(void *user, void *entryptr) * */ static CURLMcode -multi_addtimeout(struct curl_llist *timeoutlist, - struct timeval *stamp) +multi_addtimeout(struct Curl_easy *data, + struct timeval *stamp, + expire_id eid) { struct curl_llist_element *e; - struct timeval *timedup; + struct time_node *node; struct curl_llist_element *prev = NULL; + size_t n; + struct curl_llist *timeoutlist = &data->state.timeoutlist; - timedup = malloc(sizeof(*timedup)); - if(!timedup) - return CURLM_OUT_OF_MEMORY; + node = &data->state.expires[eid]; - /* copy the timestamp */ - memcpy(timedup, stamp, sizeof(*timedup)); + /* copy the timestamp and id */ + memcpy(&node->time, stamp, sizeof(*stamp)); + node->eid = eid; /* also marks it as in use */ - if(Curl_llist_count(timeoutlist)) { + n = Curl_llist_count(timeoutlist); + if(n) { /* find the correct spot in the list */ for(e = timeoutlist->head; e; e = e->next) { - struct timeval *checktime = e->ptr; - time_t diff = curlx_tvdiff(*checktime, *timedup); + struct time_node *check = (struct time_node *)e->ptr; + time_t diff = curlx_tvdiff(check->time, node->time); if(diff > 0) break; prev = e; @@ -2903,11 +2902,7 @@ multi_addtimeout(struct curl_llist *timeoutlist, /* else this is the first timeout on the list */ - if(!Curl_llist_insert_next(timeoutlist, prev, timedup)) { - free(timedup); - return CURLM_OUT_OF_MEMORY; - } - + Curl_llist_insert_next(timeoutlist, prev, node, &node->list); return CURLM_OK; } @@ -2919,8 +2914,10 @@ multi_addtimeout(struct curl_llist *timeoutlist, * * The timeout will be added to a queue of timeouts if it defines a moment in * time that is later than the current head of queue. + * + * Expire replaces a former timeout using the same id if already set. */ -void Curl_expire(struct Curl_easy *data, time_t milli) +void Curl_expire(struct Curl_easy *data, time_t milli, expire_id id) { struct Curl_multi *multi = data->multi; struct timeval *nowp = &data->state.expiretime; @@ -2932,6 +2929,8 @@ void Curl_expire(struct Curl_easy *data, time_t milli) if(!multi) return; + DEBUGASSERT(id < EXPIRE_LAST); + set = Curl_tvnow(); set.tv_sec += (long)(milli/1000); set.tv_usec += (long)(milli%1000)*1000; @@ -2946,16 +2945,20 @@ void Curl_expire(struct Curl_easy *data, time_t milli) Compare if the new time is earlier, and only remove-old/add-new if it is. */ time_t diff = curlx_tvdiff(set, *nowp); + + /* remove the previous timer first, if there */ + multi_deltimeout(data, id); + if(diff > 0) { /* the new expire time was later so just add it to the queue and get out */ - multi_addtimeout(&data->state.timeoutlist, &set); + multi_addtimeout(data, &set, id); return; } /* the new time is newer than the presently set one, so add the current to the queue and update the head */ - multi_addtimeout(&data->state.timeoutlist, nowp); + multi_addtimeout(data, nowp, id); /* Since this is an updated time, we must remove the previous entry from the splay tree first and then re-add the new value */ @@ -2973,49 +2976,17 @@ void Curl_expire(struct Curl_easy *data, time_t milli) } /* - * Curl_expire_latest() + * Curl_expire_done() * - * This is like Curl_expire() but will only add a timeout node to the list of - * timers if there is no timeout that will expire before the given time. - * - * Use this function if the code logic risks calling this function many times - * or if there's no particular conditional wait in the code for this specific - * time-out period to expire. + * Removes the expire timer. Marks it as done. * */ -void Curl_expire_latest(struct Curl_easy *data, time_t milli) +void Curl_expire_done(struct Curl_easy *data, expire_id id) { - struct timeval *expire = &data->state.expiretime; - - struct timeval set; - - set = Curl_tvnow(); - set.tv_sec += (long)(milli / 1000); - set.tv_usec += (long)(milli % 1000) * 1000; - - if(set.tv_usec >= 1000000) { - set.tv_sec++; - set.tv_usec -= 1000000; - } - - if(expire->tv_sec || expire->tv_usec) { - /* This means that the struct is added as a node in the splay tree. - Compare if the new time is earlier, and only remove-old/add-new if it - is. */ - time_t diff = curlx_tvdiff(set, *expire); - if((diff > 0) && (diff < milli)) { - /* if the new expire time is later than the top time, skip it, but not - if the diff is larger than the new offset since then the previous - time is already expired! */ - return; - } - } - - /* Just add the timeout like normal */ - Curl_expire(data, milli); + /* remove the timer, if there */ + multi_deltimeout(data, id); } - /* * Curl_expire_clear() * @@ -3044,8 +3015,9 @@ void Curl_expire_clear(struct Curl_easy *data) infof(data, "Internal error clearing splay node = %d\n", rc); /* flush the timeout list too */ - while(list->size > 0) + while(list->size > 0) { Curl_llist_remove(list, list->tail, NULL); + } #ifdef DEBUGBUILD infof(data, "Expire cleared\n"); @@ -3118,7 +3090,7 @@ void Curl_multi_process_pending_handles(struct Curl_multi *multi) Curl_llist_remove(&multi->pending, e, NULL); /* Make sure that the handle will be processed soonish. */ - Curl_expire_latest(data, 0); + Curl_expire(data, 0, EXPIRE_RUN_NOW); } e = next; /* operate on next handle */ |