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.
This commit is contained in:
80
lib/multi.c
80
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)
|
||||
|
||||
Reference in New Issue
Block a user