curl-library
Re: [PATCH] Call progress function when poll()/select() is interrupted
Date: Wed, 16 Apr 2008 04:56:00 +0200
2008/4/16, Pierre Ynard wrote:
> So I will add a function like Curl_checkAbort(), which will basically
> call the user's progress callback, passing the current (old) state
> data, without doing all the costly updating stuff in Curl_pgrsUpdate().
Nope.
There has to be a _new_ user provided callback (abort check callback)
which somehow will find out and tell to libcurl if libcurl should
abort or not.
typedef int (*curl_abortcheck_callback)(void);
This 'abort check callback' should by no means block execution. It
could check the state of a global variable that could be set by a
signal handler. It could check the state of some IPC facility. There
are lots of possibilities here. The only restrictions are that it
_must_ not block and that it should not take too long to execute.
Since this callback must be kept libcurl_internal_agnostic, no
parameter would be needed for it (I hope so). libcurl would only care
about its return value.
> Curl_checkAbort() will be the function called before poll()/select()
> to help minimizing race conditions, since this call is unconditional
> and there should not be much pending to update there, right?
I know I've mentioned a potential Curl_checkAbort() but actually it
might not even be necessary. Before poll()/select() it would be enough
to verify if the user has 'installed' a callback for abort checking
and calling it when available. The following is closer to what I
actually mean for select.c...
do {
if(timeout_ms < 0)
pending_ms = -1;
else if(!timeout_ms)
pending_ms = 0;
if(timeout_ms && data->set.fabortcheck) {
r = data->set.fabortcheck();
if(r)
r = CURL_CSELECT_ABORT;
break;
}
r = poll(pfd, num, pending_ms);
if(r != -1)
break;
error = SOCKERRNO;
if(error && error_not_EINTR)
break;
if(Curl_pgrsUpdate(conn)) {
r = CURL_CSELECT_ABORT;
break;
}
if(timeout_ms > 0) {
pending_ms = timeout_ms - elapsed_ms;
if(pending_ms <= 0)
break;
}
} while(r == -1);
And for progress.c something like...
int Curl_pgrsUpdate(struct connectdata *conn)
{
struct timeval now;
[...]
struct SessionHandle *data = conn->data;
[...]
bool shownow=FALSE;
if(data->set.fabortcheck) {
r = data->set.fabortcheck();
if(r) {
failf(data, "Callback aborted");
return CURL_CSELECT_ABORT;
}
}
now = Curl_tvnow(); /* what time is it */
[...]
> After and if poll()/select() is aborted, should I also only call this
> Curl_checkAbort(), or it is worth calling Curl_pgrsUpdate() this time?
If Curl_pgrsUpdate() starts as I propose above, then the call _could_
be to Curl_pgrsUpdate() as I've written much above, this in turn would
call fabortcheck() if set.
But your last question makes me think twice ;-)
It is true that here Curl_pgrsUpdate() would only get called when
poll()/select() is interrupted. But...when this happens...
Who knows which part of libcurl could be executing Curl_socket_ready()
or Curl_poll() ?
So, to stay on the safe side, I actually think that it is better to
call fabortcheck() instead of Curl_pgrsUpdate() once that
poll()/select() is interrupted. _And_ also keep the call to
fabortcheck() inside Curl_pgrsUpdate() so that it also benefits of the
new callback if the user has provided it.
-- -=[Yang]=-Received on 2008-04-16