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:
parent
e7742bfb7c
commit
b61c06384a
14
CHANGES
14
CHANGES
@ -6,6 +6,20 @@
|
|||||||
|
|
||||||
Changelog
|
Changelog
|
||||||
|
|
||||||
|
Daniel (12 October 2006)
|
||||||
|
- 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.
|
||||||
|
|
||||||
|
Jeff has also updated the hiperfifo.c example code to use this news.
|
||||||
|
|
||||||
Daniel (9 October 2006)
|
Daniel (9 October 2006)
|
||||||
- Bogdan Nicula's second test case (posted Sun, 08 Oct 2006) converted to test
|
- Bogdan Nicula's second test case (posted Sun, 08 Oct 2006) converted to test
|
||||||
case 535 and it now runs fine. Again a problem with the pipelining code not
|
case 535 and it now runs fine. Again a problem with the pipelining code not
|
||||||
|
@ -11,6 +11,7 @@ Curl and libcurl 7.16.0
|
|||||||
|
|
||||||
This release includes the following changes:
|
This release includes the following changes:
|
||||||
|
|
||||||
|
o Added CURLMOPT_TIMERFUNCTION
|
||||||
o The CURLOPT_SOURCE_* options are removed and so are the --3p* command line
|
o The CURLOPT_SOURCE_* options are removed and so are the --3p* command line
|
||||||
options
|
options
|
||||||
o curl_multi_socket() and family are suitable to start using
|
o curl_multi_socket() and family are suitable to start using
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
To get fixed in 7.16.0 (planned release: October 2006)
|
To get fixed in 7.16.0 (planned release: October 2006)
|
||||||
======================
|
======================
|
||||||
|
|
||||||
67 - Jeff Pohlmeyer's test case
|
67 - Jeff Pohlmeyer's crashing pipelining test case
|
||||||
|
|
||||||
68 - Dmitriy Sergeyev's test02.c and test03.c
|
69 -
|
||||||
|
|
||||||
69 -
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
.\" $Id$
|
.\" $Id$
|
||||||
.\"
|
.\"
|
||||||
.TH curl_multi_setopt 3 "8 Jan 2006" "libcurl 7.16.0" "libcurl Manual"
|
.TH curl_multi_setopt 3 "10 Oct 2006" "libcurl 7.16.0" "libcurl Manual"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
curl_multi_setopt \- set options for a curl multi handle
|
curl_multi_setopt \- set options for a curl multi handle
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
@ -9,7 +9,7 @@ curl_multi_setopt \- set options for a curl multi handle
|
|||||||
CURLMcode curl_multi_setopt(CURLM * multi_handle, CURLMoption option, param);
|
CURLMcode curl_multi_setopt(CURLM * multi_handle, CURLMoption option, param);
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
curl_multi_setopt() is used to tell a libcurl multi handle how to behave. By
|
curl_multi_setopt() is used to tell a libcurl multi handle how to behave. By
|
||||||
using the appropriate options to \fIcurl_multi_setopt\fP, you can change
|
using the appropriate options to \fIcurl_multi_setopt(3)\fP, you can change
|
||||||
libcurl's behaviour when using that multi handle. All options are set with
|
libcurl's behaviour when using that multi handle. All options are set with
|
||||||
the \fIoption\fP followed by the parameter \fIparam\fP. That parameter can be
|
the \fIoption\fP followed by the parameter \fIparam\fP. That parameter can be
|
||||||
a \fBlong\fP, a \fBfunction pointer\fP, an \fBobject pointer\fP or a
|
a \fBlong\fP, a \fBfunction pointer\fP, an \fBobject pointer\fP or a
|
||||||
@ -19,19 +19,20 @@ You can only set one option in each function call.
|
|||||||
|
|
||||||
.SH OPTIONS
|
.SH OPTIONS
|
||||||
.IP CURLMOPT_SOCKETFUNCTION
|
.IP CURLMOPT_SOCKETFUNCTION
|
||||||
Pass a pointer to a function matching the curl_socket_callback prototype. The
|
Pass a pointer to a function matching the \fBcurl_socket_callback\fP
|
||||||
\fIcurl_multi_socket(3)\fP functions inform the application about updates in
|
prototype. The \fIcurl_multi_socket(3)\fP functions inform the application
|
||||||
the socket (file descriptor) status by doing none, one or multiple calls to
|
about updates in the socket (file descriptor) status by doing none, one or
|
||||||
the curl_socket_callback given in the \fBparam\fP argument. They update the
|
multiple calls to the curl_socket_callback given in the \fBparam\fP
|
||||||
status with changes since the previous time a \fIcurl_multi_socket(3)\fP
|
argument. They update the status with changes since the previous time a
|
||||||
function was called. If the given callback pointer is NULL, no callback will
|
\fIcurl_multi_socket(3)\fP function was called. If the given callback pointer
|
||||||
be called. Set the callback's \fBuserp\fP argument with
|
is NULL, no callback will be called. Set the callback's \fBuserp\fP argument
|
||||||
\fICURLMOPT_SOCKETDATA\fP. See \fIcurl_multi_socket(3)\fP for more callback
|
with \fICURLMOPT_SOCKETDATA\fP. See \fIcurl_multi_socket(3)\fP for more
|
||||||
details.
|
callback details.
|
||||||
.IP CURLMOPT_SOCKETDATA
|
.IP CURLMOPT_SOCKETDATA
|
||||||
Pass a pointer to whatever you want passed to the curl_socket_callback's forth
|
Pass a pointer to whatever you want passed to the \fBcurl_socket_callback\fP's
|
||||||
argument, the userp pointer. This is not used by libcurl but only passed-thru
|
forth argument, the userp pointer. This is not used by libcurl but only
|
||||||
as-is. Set the callback pointer with \fICURLMOPT_SOCKETFUNCTION\fP.
|
passed-thru as-is. Set the callback pointer with
|
||||||
|
\fICURLMOPT_SOCKETFUNCTION\fP.
|
||||||
.IP CURLMOPT_PIPELINING
|
.IP CURLMOPT_PIPELINING
|
||||||
Pass a long set to 1 to enable or 0 to disable. Enabling pipelining on a multi
|
Pass a long set to 1 to enable or 0 to disable. Enabling pipelining on a multi
|
||||||
handle will make it attempt to perform HTTP Pipelining as far as possible for
|
handle will make it attempt to perform HTTP Pipelining as far as possible for
|
||||||
@ -39,6 +40,22 @@ transfers using this handle. This means that if you add a second request that
|
|||||||
can use an already existing connection, the second request will be \&"piped"
|
can use an already existing connection, the second request will be \&"piped"
|
||||||
on the same connection rather than being executed in parallell. (Added in
|
on the same connection rather than being executed in parallell. (Added in
|
||||||
7.16.0)
|
7.16.0)
|
||||||
|
.IP CURLMOPT_TIMERFUNCTION
|
||||||
|
Pass a pointer to a function matching the \fBcurl_multi_timer_callback\fP
|
||||||
|
prototype. This function will then be called when the timeout value
|
||||||
|
changes. The timeout value is at what latest time the application should call
|
||||||
|
one of the \&"performing" functions of the multi interface
|
||||||
|
(\fIcurl_multi_socket(3)\fP, \fIcurl_multi_socket_all(3)\fP and
|
||||||
|
\fIcurl_multi_perform(3)\fP) - to allow libcurl to keep timeouts and retries
|
||||||
|
etc to work. Libcurl attempts to limit calling this only when the fixed future
|
||||||
|
timeout time actually change. See also \fICURLMOPT_TIMERDATA\fP. This callback
|
||||||
|
can be used instead of, or in addition to, \fIcurl_multi_timeout(3)\fP. (Added
|
||||||
|
in 7.16.0)
|
||||||
|
.IP CURLMOPT_TIMERDATA
|
||||||
|
Pass a pointer to whatever you want passed to the
|
||||||
|
\fBcurl_multi_timer_callback\fP's third argument, the userp pointer. This is
|
||||||
|
not used by libcurl but only passed-thru as-is. Set the callback pointer with
|
||||||
|
\fICURLMOPT_TIMERFUNCTION\fP. (Added in 7.16.0)
|
||||||
.SH RETURNS
|
.SH RETURNS
|
||||||
The standard CURLMcode for multi interface error codes. Note that it returns a
|
The standard CURLMcode for multi interface error codes. Note that it returns a
|
||||||
CURLM_UNKNOWN_OPTION if you try setting an option that this version of libcurl
|
CURLM_UNKNOWN_OPTION if you try setting an option that this version of libcurl
|
||||||
|
@ -231,6 +231,20 @@ typedef int (*curl_socket_callback)(CURL *easy, /* easy handle */
|
|||||||
pointer */
|
pointer */
|
||||||
void *socketp); /* private socket
|
void *socketp); /* private socket
|
||||||
pointer */
|
pointer */
|
||||||
|
/*
|
||||||
|
* Name: curl_multi_timer_callback
|
||||||
|
*
|
||||||
|
* Desc: Called by libcurl whenever the library detects a change in the
|
||||||
|
* maximum number of milliseconds the app is allowed to wait before
|
||||||
|
* curl_multi_socket() or curl_multi_perform() must be called
|
||||||
|
* (to allow libcurl's timed events to take place).
|
||||||
|
*
|
||||||
|
* Returns: The callback should return zero.
|
||||||
|
*/
|
||||||
|
typedef int (*curl_multi_timer_callback)(CURLM *multi, /* multi handle */
|
||||||
|
long timeout_ms, /* see above */
|
||||||
|
void *userp); /* private callback
|
||||||
|
pointer */
|
||||||
|
|
||||||
CURL_EXTERN CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s,
|
CURL_EXTERN CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s,
|
||||||
int *running_handles);
|
int *running_handles);
|
||||||
@ -273,6 +287,12 @@ typedef enum {
|
|||||||
/* set to 1 to enable pipelining for this multi handle */
|
/* set to 1 to enable pipelining for this multi handle */
|
||||||
CINIT(PIPELINING, LONG, 3),
|
CINIT(PIPELINING, LONG, 3),
|
||||||
|
|
||||||
|
/* This is the timer callback function pointer */
|
||||||
|
CINIT(TIMERFUNCTION, FUNCTIONPOINT, 4),
|
||||||
|
|
||||||
|
/* This is the argument passed to the timer callback */
|
||||||
|
CINIT(TIMERDATA, OBJECTPOINT, 5),
|
||||||
|
|
||||||
CURLMOPT_LASTENTRY /* the last unused */
|
CURLMOPT_LASTENTRY /* the last unused */
|
||||||
} CURLMoption;
|
} CURLMoption;
|
||||||
|
|
||||||
|
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 */
|
/* list of easy handles kept around for doing nice connection closures */
|
||||||
struct closure *closure;
|
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,
|
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);
|
struct Curl_one_easy *easy);
|
||||||
static void add_closure(struct Curl_multi *multi,
|
static void add_closure(struct Curl_multi *multi,
|
||||||
struct SessionHandle *data);
|
struct SessionHandle *data);
|
||||||
|
static int update_timer(struct Curl_multi *multi);
|
||||||
|
|
||||||
/* always use this function to change state, to make debugging easier */
|
/* always use this function to change state, to make debugging easier */
|
||||||
static void multistate(struct Curl_one_easy *easy, CURLMstate state)
|
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 */
|
/* increase the alive-counter */
|
||||||
multi->num_alive++;
|
multi->num_alive++;
|
||||||
|
|
||||||
|
update_timer(multi);
|
||||||
return CURLM_OK;
|
return CURLM_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -610,6 +618,7 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
|
|||||||
|
|
||||||
multi->num_easy--; /* one less to care about now */
|
multi->num_easy--; /* one less to care about now */
|
||||||
|
|
||||||
|
update_timer(multi);
|
||||||
return CURLM_OK;
|
return CURLM_OK;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -1342,6 +1351,8 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
|
|||||||
|
|
||||||
*running_handles = multi->num_alive;
|
*running_handles = multi->num_alive;
|
||||||
|
|
||||||
|
if ( CURLM_OK == returncode )
|
||||||
|
update_timer(multi);
|
||||||
return returncode;
|
return returncode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1673,8 +1684,15 @@ CURLMcode curl_multi_setopt(CURLM *multi_handle,
|
|||||||
case CURLMOPT_PIPELINING:
|
case CURLMOPT_PIPELINING:
|
||||||
multi->pipelining_enabled = (bool)(0 != va_arg(param, long));
|
multi->pipelining_enabled = (bool)(0 != va_arg(param, long));
|
||||||
break;
|
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:
|
default:
|
||||||
res = CURLM_UNKNOWN_OPTION;
|
res = CURLM_UNKNOWN_OPTION;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
va_end(param);
|
va_end(param);
|
||||||
return res;
|
return res;
|
||||||
@ -1684,26 +1702,26 @@ CURLMcode curl_multi_setopt(CURLM *multi_handle,
|
|||||||
CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s,
|
CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s,
|
||||||
int *running_handles)
|
int *running_handles)
|
||||||
{
|
{
|
||||||
return multi_socket((struct Curl_multi *)multi_handle, FALSE, s,
|
CURLMcode result = multi_socket((struct Curl_multi *)multi_handle, FALSE, s,
|
||||||
running_handles);
|
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)
|
CURLMcode curl_multi_socket_all(CURLM *multi_handle, int *running_handles)
|
||||||
|
|
||||||
{
|
{
|
||||||
return multi_socket((struct Curl_multi *)multi_handle,
|
CURLMcode result = multi_socket((struct Curl_multi *)multi_handle,
|
||||||
TRUE, CURL_SOCKET_BAD, running_handles);
|
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,
|
static CURLMcode multi_timeout(struct Curl_multi *multi,
|
||||||
long *timeout_ms)
|
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) {
|
if(multi->timetree) {
|
||||||
/* we have a tree of expire times */
|
/* we have a tree of expire times */
|
||||||
struct timeval now = Curl_tvnow();
|
struct timeval now = Curl_tvnow();
|
||||||
@ -1724,6 +1742,44 @@ CURLMcode curl_multi_timeout(CURLM *multi_handle,
|
|||||||
return CURLM_OK;
|
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
|
/* 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() */
|
this'-time for the transfer, to be extracted by curl_multi_timeout() */
|
||||||
void Curl_expire(struct SessionHandle *data, long milli)
|
void Curl_expire(struct SessionHandle *data, long milli)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user