aboutsummaryrefslogtreecommitdiff
path: root/lib/multi.c
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2014-08-25 11:34:14 +0200
committerDaniel Stenberg <daniel@haxx.se>2014-08-31 23:50:01 +0200
commitcacdc27f52ba7b0bf08aa57886bfbd18bc82ebfb (patch)
tree6434aab273d0d6be76eb991bc96d6a276ca78571 /lib/multi.c
parent09b5a99816a24a12f769f61db5f7eafd4bc32795 (diff)
low-speed-limit: avoid timeout flood
Introducing Curl_expire_latest(). To be used when we the code flow only wants to get called at a later time that is "no later than X" so that something can be checked (and another timeout be added). The low-speed logic for example could easily be made to set very many expire timeouts if it would be called faster or sooner than what it had set its own timer and this goes for a few other timers too that aren't explictiy checked for timer expiration in the code. If there's no condition the code that says if(time-passed >= TIME), then Curl_expire_latest() is preferred to Curl_expire(). If there exists such a condition, it is on the other hand important that Curl_expire() is used and not the other. Bug: http://curl.haxx.se/mail/lib-2014-06/0235.html Reported-by: Florian Weimer
Diffstat (limited to 'lib/multi.c')
-rw-r--r--lib/multi.c46
1 files changed, 43 insertions, 3 deletions
diff --git a/lib/multi.c b/lib/multi.c
index 20fc372fa..557be06df 100644
--- a/lib/multi.c
+++ b/lib/multi.c
@@ -1491,7 +1491,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
data->set.buffer_size : BUFSIZE);
timeout_ms = Curl_sleep_time(data->set.max_send_speed,
data->progress.ulspeed, buffersize);
- Curl_expire(data, timeout_ms);
+ Curl_expire_latest(data, timeout_ms);
break;
}
@@ -1507,7 +1507,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
data->set.buffer_size : BUFSIZE);
timeout_ms = Curl_sleep_time(data->set.max_recv_speed,
data->progress.dlspeed, buffersize);
- Curl_expire(data, timeout_ms);
+ Curl_expire_latest(data, timeout_ms);
break;
}
@@ -1569,7 +1569,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* expire the new receiving pipeline head */
if(data->easy_conn->recv_pipe->head)
- Curl_expire(data->easy_conn->recv_pipe->head->ptr, 1);
+ Curl_expire_latest(data->easy_conn->recv_pipe->head->ptr, 1);
/* Check if we can move pending requests to send pipe */
Curl_multi_process_pending_handles(multi);
@@ -2682,6 +2682,46 @@ void Curl_expire(struct SessionHandle *data, long milli)
#endif
}
+/*
+ * Curl_expire_latest()
+ *
+ * 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.
+ *
+ */
+void Curl_expire_latest(struct SessionHandle *data, long milli)
+{
+ struct timeval *exp = &data->state.expiretime;
+
+ struct timeval set;
+
+ set = Curl_tvnow();
+ set.tv_sec += milli/1000;
+ set.tv_usec += (milli%1000)*1000;
+
+ if(set.tv_usec >= 1000000) {
+ set.tv_sec++;
+ set.tv_usec -= 1000000;
+ }
+
+ if(exp->tv_sec || exp->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. */
+ long diff = curlx_tvdiff(set, *exp);
+ if(diff > 0)
+ /* the new expire time was later than the top time, so just skip this */
+ return;
+ }
+
+ /* Just add the timeout like normal */
+ Curl_expire(data, milli);
+}
+
CURLMcode curl_multi_assign(CURLM *multi_handle,
curl_socket_t s, void *hashp)
{