aboutsummaryrefslogtreecommitdiff
path: root/lib/multi.c
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2006-10-12 08:36:47 +0000
committerDaniel Stenberg <daniel@haxx.se>2006-10-12 08:36:47 +0000
commitb61c06384ab88baf4b3231e84386c4a70126d888 (patch)
treeaac26b1242718b6093edcefd99c6e3e4b04cd52b /lib/multi.c
parente7742bfb7cc40d6b840fabc8632f9625cc2fc26f (diff)
Jeff Pohlmeyer has been working with the hiperfifo.c example source code,
and while doing so it became apparent that the current timeout system for the socket API really was a bit awkward since it become quite some work to be sure we have the correct timeout set. Jeff then provided the new CURLMOPT_TIMERFUNCTION that is yet another callback the app can set to get to know when the general timeout time changes and thus for an application like hiperfifo.c it makes everything a lot easier and nicer. There's a CURLMOPT_TIMERDATA option too of course in good old libcurl tradition.
Diffstat (limited to 'lib/multi.c')
-rw-r--r--lib/multi.c80
1 files changed, 68 insertions, 12 deletions
diff --git a/lib/multi.c b/lib/multi.c
index e901bddfd..aaa80b228 100644
--- a/lib/multi.c
+++ b/lib/multi.c
@@ -166,6 +166,12 @@ struct Curl_multi {
/* list of easy handles kept around for doing nice connection closures */
struct closure *closure;
+
+ /* timer callback and user data pointer for the *socket() API */
+ curl_multi_timer_callback timer_cb;
+ void *timer_userp;
+ time_t timer_lastcall; /* the fixed time for the timeout for the previous
+ callback */
};
static bool multi_conn_using(struct Curl_multi *multi,
@@ -174,6 +180,7 @@ static void singlesocket(struct Curl_multi *multi,
struct Curl_one_easy *easy);
static void add_closure(struct Curl_multi *multi,
struct SessionHandle *data);
+static int update_timer(struct Curl_multi *multi);
/* always use this function to change state, to make debugging easier */
static void multistate(struct Curl_one_easy *easy, CURLMstate state)
@@ -460,6 +467,7 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle,
/* increase the alive-counter */
multi->num_alive++;
+ update_timer(multi);
return CURLM_OK;
}
@@ -610,6 +618,7 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
multi->num_easy--; /* one less to care about now */
+ update_timer(multi);
return CURLM_OK;
}
else
@@ -1342,6 +1351,8 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
*running_handles = multi->num_alive;
+ if ( CURLM_OK == returncode )
+ update_timer(multi);
return returncode;
}
@@ -1673,8 +1684,15 @@ CURLMcode curl_multi_setopt(CURLM *multi_handle,
case CURLMOPT_PIPELINING:
multi->pipelining_enabled = (bool)(0 != va_arg(param, long));
break;
+ case CURLMOPT_TIMERFUNCTION:
+ multi->timer_cb = va_arg(param, curl_multi_timer_callback);
+ break;
+ case CURLMOPT_TIMERDATA:
+ multi->timer_userp = va_arg(param, void *);
+ break;
default:
res = CURLM_UNKNOWN_OPTION;
+ break;
}
va_end(param);
return res;
@@ -1684,26 +1702,26 @@ CURLMcode curl_multi_setopt(CURLM *multi_handle,
CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s,
int *running_handles)
{
- return multi_socket((struct Curl_multi *)multi_handle, FALSE, s,
- running_handles);
+ CURLMcode result = multi_socket((struct Curl_multi *)multi_handle, FALSE, s,
+ running_handles);
+ if (CURLM_OK == result)
+ update_timer((struct Curl_multi *)multi_handle);
+ return result;
}
CURLMcode curl_multi_socket_all(CURLM *multi_handle, int *running_handles)
{
- return multi_socket((struct Curl_multi *)multi_handle,
- TRUE, CURL_SOCKET_BAD, running_handles);
+ CURLMcode result = multi_socket((struct Curl_multi *)multi_handle,
+ TRUE, CURL_SOCKET_BAD, running_handles);
+ if (CURLM_OK == result)
+ update_timer((struct Curl_multi *)multi_handle);
+ return result;
}
-CURLMcode curl_multi_timeout(CURLM *multi_handle,
- long *timeout_ms)
+static CURLMcode multi_timeout(struct Curl_multi *multi,
+ long *timeout_ms)
{
- struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
-
- /* First, make some basic checks that the CURLM handle is a good handle */
- if(!GOOD_MULTI_HANDLE(multi))
- return CURLM_BAD_HANDLE;
-
if(multi->timetree) {
/* we have a tree of expire times */
struct timeval now = Curl_tvnow();
@@ -1724,6 +1742,44 @@ CURLMcode curl_multi_timeout(CURLM *multi_handle,
return CURLM_OK;
}
+CURLMcode curl_multi_timeout(CURLM *multi_handle,
+ long *timeout_ms)
+{
+ struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
+
+ /* First, make some basic checks that the CURLM handle is a good handle */
+ if(!GOOD_MULTI_HANDLE(multi))
+ return CURLM_BAD_HANDLE;
+
+ return multi_timeout(multi, timeout_ms);
+}
+
+/*
+ * Tell the application it should update its timers, if it subscribes to the
+ * update timer callback.
+ */
+static int update_timer(struct Curl_multi *multi)
+{
+ long timeout_ms;
+ if (!multi->timer_cb)
+ return 0;
+ if ( multi_timeout(multi, &timeout_ms) != CURLM_OK )
+ return -1;
+ if ( timeout_ms < 0 )
+ return 0;
+
+ /* When multi_timeout() is done, multi->timetree points to the node with the
+ * timeout we got the (relative) time-out time for. We can thus easily check
+ * if this is the same (fixed) time as we got in a previous call and then
+ * avoid calling the callback again. */
+ if(multi->timetree->key == multi->timer_lastcall)
+ return 0;
+
+ multi->timer_lastcall = multi->timetree->key;
+
+ return multi->timer_cb((CURLM*)multi, timeout_ms, multi->timer_userp);
+}
+
/* given a number of milliseconds from now to use to set the 'act before
this'-time for the transfer, to be extracted by curl_multi_timeout() */
void Curl_expire(struct SessionHandle *data, long milli)